mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
ams: delete exo1
This commit is contained in:
parent
c75e61a40b
commit
282f8f6612
135 changed files with 0 additions and 19262 deletions
|
@ -1,180 +0,0 @@
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
.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 src/dbg
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include ../libraries/libvapours/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)) \
|
|
||||||
$(TOPDIR)/lp0fw \
|
|
||||||
$(TOPDIR)/sc7fw \
|
|
||||||
$(TOPDIR)/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)/*.*))) sc7fw.bin lp0fw.bin 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) build_sc7fw build_lp0fw build_rebootstub clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
check_sc7fw:
|
|
||||||
@$(MAKE) -C sc7fw all
|
|
||||||
|
|
||||||
check_lp0fw:
|
|
||||||
@$(MAKE) -C lp0fw all
|
|
||||||
|
|
||||||
check_rebootstub:
|
|
||||||
@$(MAKE) -C rebootstub all
|
|
||||||
|
|
||||||
$(BUILD): check_sc7fw check_lp0fw check_rebootstub
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
|
||||||
@echo clean ...
|
|
||||||
@$(MAKE) -C $(TOPDIR)/sc7fw clean
|
|
||||||
@$(MAKE) -C $(TOPDIR)/lp0fw clean
|
|
||||||
@$(MAKE) -C $(TOPDIR)/rebootstub 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)
|
|
||||||
|
|
||||||
my_libc.o: CFLAGS += -fno-builtin
|
|
||||||
|
|
||||||
%.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
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
|
@ -1,6 +0,0 @@
|
||||||
Exosphère
|
|
||||||
=====
|
|
||||||
|
|
||||||
![License](https://img.shields.io/badge/License-GPLv2-blue.svg)
|
|
||||||
|
|
||||||
Exosphère is a Secure Monitor implementation for the Nintendo Switch.
|
|
|
@ -1,269 +0,0 @@
|
||||||
OUTPUT_ARCH(aarch64)
|
|
||||||
ENTRY(__start_cold)
|
|
||||||
|
|
||||||
MEMORY
|
|
||||||
{
|
|
||||||
NULL : ORIGIN = 0, LENGTH = 4K
|
|
||||||
ccrt0 : ORIGIN = 0x040006000, LENGTH = 4K
|
|
||||||
glob : ORIGIN = 0x040020000, LENGTH = 128K
|
|
||||||
tzram : ORIGIN = 0x07C010000, LENGTH = 64K
|
|
||||||
/*
|
|
||||||
The warmboot crt0 is preceeded by the exception vector page and the L2 and L3 translation tables.
|
|
||||||
Normally the main code immediately follows the warmboot crt0, aligned to 256 bytes.
|
|
||||||
We can't ensure or replicate that behavior properly so we'll just give 2K to the warmboot crt0.
|
|
||||||
*/
|
|
||||||
warmboot_crt0 : ORIGIN = ORIGIN(tzram) + 12K, LENGTH = 2K
|
|
||||||
|
|
||||||
/* 8K are the MMU L2 and L3 tables & 2K from the evt page */
|
|
||||||
main : ORIGIN = 0x1F01E0000 + LENGTH(warmboot_crt0), LENGTH = LENGTH(tzram) - LENGTH(pk2ldr) - LENGTH(evt) - LENGTH(warmboot_crt0) - 10K
|
|
||||||
pk2ldr : ORIGIN = ORIGIN(main) - LENGTH(warmboot_crt0) + LENGTH(tzram), LENGTH = 8K
|
|
||||||
/* The first half of the page are exception entry stacks, the other half are the vectors themselves */
|
|
||||||
evt : ORIGIN = ORIGIN(pk2ldr) + 40K + 2K, LENGTH = 2K
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
PROVIDE(__start__ = 0x040006000);
|
|
||||||
. = __start__;
|
|
||||||
|
|
||||||
.cold_crt0 :
|
|
||||||
{
|
|
||||||
. = ALIGN(64);
|
|
||||||
__cold_crt0_start__ = ABSOLUTE(.);
|
|
||||||
__glob_origin__ = ORIGIN(glob);
|
|
||||||
KEEP (*(.cold_crt0.text.start)) /* MUST be first */
|
|
||||||
KEEP (*(.cold_crt0.text*))
|
|
||||||
KEEP (coldboot_init.o(.text*))
|
|
||||||
*(.cold_crt0.rodata*)
|
|
||||||
coldboot_init.o(.rodata*)
|
|
||||||
*(.cold_crt0.data*)
|
|
||||||
coldboot_init.o(.data*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
*(.cold_crt0.bss*)
|
|
||||||
coldboot_init.o(.bss* COMMON)
|
|
||||||
. = ALIGN(64);
|
|
||||||
__cold_crt0_end__ = ABSOLUTE(.);
|
|
||||||
} >ccrt0 AT>glob
|
|
||||||
|
|
||||||
.pk2ldr :
|
|
||||||
{
|
|
||||||
. = ALIGN(4096);
|
|
||||||
__pk2ldr_lma__ = LOADADDR(.pk2ldr);
|
|
||||||
__pk2ldr_start__ = ABSOLUTE(.);
|
|
||||||
KEEP (package2.o(.text*))
|
|
||||||
package2.o(.rodata*)
|
|
||||||
package2.o(.data*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >pk2ldr AT>glob
|
|
||||||
|
|
||||||
.pk2ldr.bss :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
__pk2ldr_bss_start__ = ABSOLUTE(.);
|
|
||||||
package2.o(.bss* COMMON)
|
|
||||||
. = ALIGN(8);
|
|
||||||
__pk2ldr_end__ = ABSOLUTE(.);
|
|
||||||
} >pk2ldr AT>glob
|
|
||||||
|
|
||||||
.vectors :
|
|
||||||
{
|
|
||||||
. = ALIGN(2048);
|
|
||||||
__vectors_lma__ = LOADADDR(.vectors);
|
|
||||||
__vectors_start__ = ABSOLUTE(.);
|
|
||||||
KEEP (*(.vectors*))
|
|
||||||
. = ALIGN(8);
|
|
||||||
__vectors_end__ = ABSOLUTE(.);
|
|
||||||
} >evt AT>glob
|
|
||||||
|
|
||||||
.warm_crt0 :
|
|
||||||
{
|
|
||||||
. = ALIGN(64);
|
|
||||||
__warmboot_crt0_lma__ = LOADADDR(.warm_crt0);
|
|
||||||
__warmboot_crt0_start__ = ABSOLUTE(.);
|
|
||||||
KEEP (*(.warm_crt0.text.start)) /* Should be first */
|
|
||||||
KEEP (*(.warm_crt0.text*))
|
|
||||||
KEEP (warmboot_init.o(.text*))
|
|
||||||
*(.warm_crt0.rodata*)
|
|
||||||
warmboot_init.o(.rodata*)
|
|
||||||
*(.warm_crt0.data*)
|
|
||||||
warmboot_init.o(.data*)
|
|
||||||
. = ALIGN(8);
|
|
||||||
*(.warm_crt0.bss*)
|
|
||||||
warmboot_init.o(.bss*)
|
|
||||||
. = ALIGN(64);
|
|
||||||
__warmboot_crt0_end__ = ABSOLUTE(.);
|
|
||||||
} >warmboot_crt0 AT>glob
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
. = ALIGN(256);
|
|
||||||
__main_lma__ = LOADADDR(.text);
|
|
||||||
__main_start__ = ABSOLUTE(.);
|
|
||||||
*(.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(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.init :
|
|
||||||
{
|
|
||||||
KEEP( *(.init) )
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.plt :
|
|
||||||
{
|
|
||||||
*(.plt)
|
|
||||||
*(.iplt)
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
|
|
||||||
.fini :
|
|
||||||
{
|
|
||||||
KEEP( *(.fini) )
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
|
||||||
SORT(CONSTRUCTORS)
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.got : { __got_start__ = ABSOLUTE(.); *(.got) *(.igot) } >main AT>glob
|
|
||||||
.got.plt : { *(.got.plt) *(.igot.plt) __got_end__ = ABSOLUTE(.);} >main AT>glob
|
|
||||||
|
|
||||||
.preinit_array :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE (__preinit_array_start = .);
|
|
||||||
KEEP (*(.preinit_array))
|
|
||||||
PROVIDE (__preinit_array_end = .);
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.init_array :
|
|
||||||
{
|
|
||||||
PROVIDE (__init_array_start = .);
|
|
||||||
KEEP (*(SORT(.init_array.*)))
|
|
||||||
KEEP (*(.init_array))
|
|
||||||
PROVIDE (__init_array_end = .);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.fini_array :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
PROVIDE (__fini_array_start = .);
|
|
||||||
KEEP (*(.fini_array))
|
|
||||||
KEEP (*(SORT(.fini_array.*)))
|
|
||||||
PROVIDE (__fini_array_end = .);
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.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 AT>glob
|
|
||||||
|
|
||||||
.dtors ALIGN(8) :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
KEEP (*crtbegin.o(.dtors))
|
|
||||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
|
||||||
KEEP (*(SORT(.dtors.*)))
|
|
||||||
KEEP (*(.dtors))
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
.data ALIGN(8) :
|
|
||||||
{
|
|
||||||
*(.data .data.* .gnu.linkonce.d.*)
|
|
||||||
CONSTRUCTORS
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
|
|
||||||
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } >main AT>glob
|
|
||||||
.eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob
|
|
||||||
.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob
|
|
||||||
.gnu_extab : { *(.gnu_extab*) } >main AT>glob
|
|
||||||
.exception_ranges : { *(.exception_ranges .exception_ranges*) } >main AT>glob
|
|
||||||
|
|
||||||
.dynamic : { *(.dynamic) } >main AT>glob
|
|
||||||
.interp : { *(.interp) } >main AT>glob
|
|
||||||
.note.gnu.build-id : { *(.note.gnu.build-id) } >main AT>glob
|
|
||||||
.hash : { *(.hash) } >main AT>glob
|
|
||||||
.gnu.hash : { *(.gnu.hash) } >main AT>glob
|
|
||||||
.gnu.version : { *(.gnu.version) } >main AT>glob
|
|
||||||
.gnu.version_d : { *(.gnu.version_d) } >main AT>glob
|
|
||||||
.gnu.version_r : { *(.gnu.version_r) } >main AT>glob
|
|
||||||
.dynsym : { *(.dynsym) } >main AT>glob
|
|
||||||
.dynstr : { *(.dynstr) } >main AT>glob
|
|
||||||
.rela.dyn : { *(.rela.*); __main_end__ = ABSOLUTE(.);} >main AT>glob
|
|
||||||
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
__main_bss_start__ = ABSOLUTE(.);
|
|
||||||
__loaded_end_lma__ = LOADADDR(.bss);
|
|
||||||
*(.dynbss)
|
|
||||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(8);
|
|
||||||
__main_end__ = ABSOLUTE(.);
|
|
||||||
} >main AT>glob
|
|
||||||
|
|
||||||
__end__ = ABSOLUTE(.) ;
|
|
||||||
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
__argdata__ = 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) }
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
%rename link old_link
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
|
|
@ -1,154 +0,0 @@
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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 ../../libraries/libvapours/include
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# options for code generation
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
|
||||||
|
|
||||||
CFLAGS := \
|
|
||||||
-g \
|
|
||||||
-Os \
|
|
||||||
-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
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
|
@ -1,24 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
%rename link old_link
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "emc.h"
|
|
||||||
#include "lp0.h"
|
|
||||||
|
|
||||||
static inline uint32_t 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: reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t 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: reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
|
|
||||||
static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
|
|
||||||
|
|
||||||
static uint32_t g_clk_clr_reg_offsets[NUM_CAR_BANKS] = {0x324, 0x32C, 0x334, 0x444, 0x44C, 0x228, 0x2A0};
|
|
||||||
|
|
||||||
void car_configure_oscillators(void) {
|
|
||||||
/* Enable the crystal oscillator, setting drive strength to the saved value in PMC. */
|
|
||||||
CLK_RST_CONTROLLER_OSC_CTRL_0 = (CLK_RST_CONTROLLER_OSC_CTRL_0 & 0xFFFFFC0E) | 1 | (((APBDEV_PMC_OSC_EDPD_OVER_0 >> 1) & 0x3F) << 4);
|
|
||||||
|
|
||||||
/* Set CLK_M_DIVISOR to 1 (causes actual division by 2.) */
|
|
||||||
CLK_RST_CONTROLLER_SPARE_REG0_0 = (1 << 2);
|
|
||||||
/* Reading the register after writing it is required to ensure value takes. */
|
|
||||||
(void)(CLK_RST_CONTROLLER_SPARE_REG0_0);
|
|
||||||
|
|
||||||
/* Set TIMERUS_USEC_CFG to cycle at 0x60 / 0x5 = 19.2 MHz. */
|
|
||||||
/* Value is (dividend << 8) | (divisor). */
|
|
||||||
TIMERUS_USEC_CFG_0 = 0x45F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void car_mbist_workaround(void) {
|
|
||||||
/* This code works around MBIST bug. */
|
|
||||||
|
|
||||||
/* Clear LVL2_CLK_GATE_OVR* registers. */
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA_0 = 0;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB_0 = 0;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC_0 = 0;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 = 0;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE_0 = 0;
|
|
||||||
|
|
||||||
/* Clear bit patterns in CAR. */
|
|
||||||
/* L: Reset all but RTC, TMR, GPIO, BPMP Cache (CACHE2). */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[0]) = MAKE_CAR_REG(g_clk_reg_offsets[0]) & 0x7FFFFECF;
|
|
||||||
/* H: Reset all but MC, PMC, FUSE, EMC. */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[1]) = MAKE_CAR_REG(g_clk_reg_offsets[1]) & 0xFDFFFF3E;
|
|
||||||
/* U: Reset all but CSITE, IRAM[A-D], BPMP Cache RAM (CRAM2). */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[2]) = MAKE_CAR_REG(g_clk_reg_offsets[2]) & 0xFE0FFDFF;
|
|
||||||
/* V: Reset all but MSELECT, S/PDIF audio doubler, TZRAM, SE. */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[3]) = MAKE_CAR_REG(g_clk_reg_offsets[3]) & 0x3FBFFFF7;
|
|
||||||
/* W: Reset all but PCIERX[0-5], ENTROPY. */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[4]) = MAKE_CAR_REG(g_clk_reg_offsets[4]) & 0xFFDFFF03;
|
|
||||||
/* X: Reset all but ETC, MCLK, MCLK2, I2C6, EMC_DLL, GPU, DBGAPB, PLLG_REF, . */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[5]) = MAKE_CAR_REG(g_clk_reg_offsets[5]) & 0xDCFFB87F;
|
|
||||||
/* Y: Reset all but MC_CDPA, MC_CCPA. */
|
|
||||||
MAKE_CAR_REG(g_clk_clr_reg_offsets[6]) = MAKE_CAR_REG(g_clk_reg_offsets[6]) & 0xFFFFFCFF;
|
|
||||||
|
|
||||||
/* Enable clock to MC1, if CH1 is enabled in EMC. */
|
|
||||||
if (EMC_FBIO_CFG7_0 & 4) { /* CH1_ENABLE */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_W_SET_0 |= 0x40000000; /* SET_CLK_ENB_MC1 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clk_enable(CarDevice dev) {
|
|
||||||
uint32_t 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clkrst_enable_fuse_regs(bool enable) {
|
|
||||||
CLK_RST_CONTROLLER_MISC_CLK_ENB_0 = ((CLK_RST_CONTROLLER_MISC_CLK_ENB_0 & 0xEFFFFFFF) | ((enable & 1) << 28));
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_CLOCK_AND_RESET_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_CLOCK_AND_RESET_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define CAR_BASE 0x60006000
|
|
||||||
|
|
||||||
#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_OSC_CTRL_0 MAKE_CAR_REG(0x050)
|
|
||||||
#define CLK_RST_CONTROLLER_PLLX_BASE_0 MAKE_CAR_REG(0x0E0)
|
|
||||||
#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 CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER_0 MAKE_CAR_REG(0x36C)
|
|
||||||
#define CLK_RST_CONTROLLER_SUPER_CCLKP_DIVIDER_0 MAKE_CAR_REG(0x374)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5_0 MAKE_CAR_REG(0x128)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF_0 MAKE_CAR_REG(0x62C)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC_0 MAKE_CAR_REG(0x630)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0 MAKE_CAR_REG(0x388)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT_0 MAKE_CAR_REG(0x3B4)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA_0 MAKE_CAR_REG(0x0F8)
|
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB_0 MAKE_CAR_REG(0x0FC)
|
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC_0 MAKE_CAR_REG(0x3A0)
|
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 MAKE_CAR_REG(0x3A4)
|
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE_0 MAKE_CAR_REG(0x554)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CCLKG_BURST_POLICY_0 MAKE_CAR_REG(0x368)
|
|
||||||
#define CLK_RST_CONTROLLER_CCLKP_BURST_POLICY_0 MAKE_CAR_REG(0x370)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEVICES_H_0 MAKE_CAR_REG(0x008)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_SPARE_REG0_0 MAKE_CAR_REG(0x55C)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_H_SET_0 MAKE_CAR_REG(0x308)
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_U_SET_0 MAKE_CAR_REG(0x310)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_H_CLR_0 MAKE_CAR_REG(0x30C)
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_U_CLR_0 MAKE_CAR_REG(0x314)
|
|
||||||
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR_0 MAKE_CAR_REG(0x434)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_L_SET_0 MAKE_CAR_REG(0x320)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_H_SET_0 MAKE_CAR_REG(0x328)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_U_SET_0 MAKE_CAR_REG(0x330)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET_0 MAKE_CAR_REG(0x440)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET_0 MAKE_CAR_REG(0x448)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET_0 MAKE_CAR_REG(0x29C)
|
|
||||||
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR_0 MAKE_CAR_REG(0x32C)
|
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR_0 MAKE_CAR_REG(0x44C)
|
|
||||||
|
|
||||||
#define NUM_CAR_BANKS 7
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CARDEVICE_UARTA = ((0 << 5) | 0x6),
|
|
||||||
CARDEVICE_UARTB = ((0 << 5) | 0x7),
|
|
||||||
CARDEVICE_UARTC = ((1 << 5) | 0x17),
|
|
||||||
CARDEVICE_I2C1 = ((0 << 5) | 0xC),
|
|
||||||
CARDEVICE_I2C5 = ((1 << 5) | 0xF),
|
|
||||||
CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
|
|
||||||
CARDEVICE_SE = ((3 << 5) | 0x1F),
|
|
||||||
CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
|
|
||||||
CARDEVICE_TSEC = ((2 << 5) | 0x13),
|
|
||||||
CARDEVICE_SOR_SAFE = ((6 << 5) | 0x1E),
|
|
||||||
CARDEVICE_SOR0 = ((5 << 5) | 0x16),
|
|
||||||
CARDEVICE_SOR1 = ((5 << 5) | 0x17),
|
|
||||||
CARDEVICE_KFUSE = ((1 << 5) | 0x8),
|
|
||||||
CARDEVICE_CL_DVFS = ((4 << 5) | 0x1B),
|
|
||||||
CARDEVICE_CORESIGHT = ((2 << 5) | 0x9),
|
|
||||||
CARDEVICE_ACTMON = ((3 << 5) | 0x17),
|
|
||||||
CARDEVICE_BPMP = ((0 << 5) | 0x1)
|
|
||||||
} CarDevice;
|
|
||||||
|
|
||||||
void car_configure_oscillators(void);
|
|
||||||
void car_mbist_workaround(void);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
void clkrst_enable_fuse_regs(bool enable);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,163 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "cluster.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "flow.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
|
|
||||||
static void cluster_pmc_enable_partition(uint32_t mask, uint32_t toggle) {
|
|
||||||
/* Set toggle if unset. */
|
|
||||||
if (!(APBDEV_PMC_PWRGATE_STATUS_0 & mask)) {
|
|
||||||
APBDEV_PMC_PWRGATE_TOGGLE_0 = toggle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until toggle set. */
|
|
||||||
while (!(APBDEV_PMC_PWRGATE_STATUS_0 & mask)) { }
|
|
||||||
|
|
||||||
/* Remove clamping. */
|
|
||||||
APBDEV_PMC_REMOVE_CLAMPING_CMD_0 = mask;
|
|
||||||
while (APBDEV_PMC_CLAMP_STATUS_0 & mask) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
void cluster_initialize_cpu(void) {
|
|
||||||
/* Hold CoreSight in reset. */
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_U_SET_0 = 0x200;
|
|
||||||
|
|
||||||
/* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */
|
|
||||||
CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0 &= 0xFFFFF000;
|
|
||||||
|
|
||||||
/* Restore SB_AA64_RESET values from PMC scratch. */
|
|
||||||
SB_AA64_RESET_LOW_0 = APBDEV_PMC_SECURE_SCRATCH34_0 | 1;
|
|
||||||
SB_AA64_RESET_HIGH_0 = APBDEV_PMC_SECURE_SCRATCH35_0;
|
|
||||||
|
|
||||||
/* Set CDIV_ENB for CCLKG/CCLKP. */
|
|
||||||
CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER_0 = 0x80000000;
|
|
||||||
CLK_RST_CONTROLLER_SUPER_CCLKP_DIVIDER_0 = 0x80000000;
|
|
||||||
|
|
||||||
/* Enable CoreSight clock, take CoreSight out of reset. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_U_SET_0 = 0x200;
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_U_CLR_0 = 0x200;
|
|
||||||
|
|
||||||
/* Configure MSELECT to divide by 4, enable MSELECT clock. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT_0 = 6; /* (6/2) + 1 = 4. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_V_SET_0 = 0x8;
|
|
||||||
|
|
||||||
/* Wait 2 us, then take MSELECT out of reset. */
|
|
||||||
timer_wait(2);
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_V_CLR_0 = 0x8;
|
|
||||||
|
|
||||||
/* Set MSELECT WRAP_TO_SLAVE_INCR[0-2], clear ERR_RESP_EN_SLAVE[1-2]. */
|
|
||||||
MSELECT_CONFIG_0 = (MSELECT_CONFIG_0 & 0xFCFFFFFF) | 0x38000000;
|
|
||||||
|
|
||||||
/* Clear PLLX_ENABLE. */
|
|
||||||
CLK_RST_CONTROLLER_PLLX_BASE_0 &= 0xBFFFFFFF;
|
|
||||||
|
|
||||||
/* Clear PMC scratch 190, disable PMC DPD then wait 10 us. */
|
|
||||||
APBDEV_PMC_SCRATCH190_0 &= 0xFFFFFFFE;
|
|
||||||
APBDEV_PMC_DPD_SAMPLE_0 = 0;
|
|
||||||
timer_wait(10);
|
|
||||||
|
|
||||||
/* Configure UART2 via GPIO controller 2 G. */
|
|
||||||
MAKE_REG32(0x6000D108) |= 4; /* GPIO_CNF */
|
|
||||||
MAKE_REG32(0x6000D118) |= 4; /* GPIO_OE */
|
|
||||||
MAKE_REG32(0x6000D128) &= ~4; /* GPIO_OUT */
|
|
||||||
|
|
||||||
/* Set CL_DVFS RSVD0 + TRISTATE, read register to make it stick. */
|
|
||||||
PINMUX_AUX_DVFS_PWM_0 = 0x11;
|
|
||||||
(void)PINMUX_AUX_DVFS_PWM_0;
|
|
||||||
|
|
||||||
/* Configure I2C. */
|
|
||||||
PINMUX_AUX_PWR_I2C_SCL_0 = 0x40;
|
|
||||||
PINMUX_AUX_PWR_I2C_SDA_0 = 0x40;
|
|
||||||
|
|
||||||
/* Enable clock to CL_DVFS, and set its source/divider. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_W_SET_0 = 0x08000000;
|
|
||||||
CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF_0 = 0xE;
|
|
||||||
CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC_0 = 0xE;
|
|
||||||
|
|
||||||
/* Power on I2C5, wait 5 us, set source + take out of reset. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_H_SET_0 = 0x8000;
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_H_SET_0 = 0x8000;
|
|
||||||
timer_wait(5);
|
|
||||||
CLK_RST_CONTROLLER_CLK_SOURCE_I2C5_0 = 0x4;
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_H_CLR_0 = 0x8000;
|
|
||||||
|
|
||||||
/* Enable the PMIC, wait 2ms. */
|
|
||||||
i2c_enable_pmic();
|
|
||||||
timer_wait(2000);
|
|
||||||
|
|
||||||
/* Enable power to the CRAIL partition. */
|
|
||||||
cluster_pmc_enable_partition(1, 0x100);
|
|
||||||
|
|
||||||
/* Remove SW clamp to CRAIL. */
|
|
||||||
APBDEV_PMC_SET_SW_CLAMP_0 = 0;
|
|
||||||
APBDEV_PMC_REMOVE_CLAMPING_CMD_0 = 1;
|
|
||||||
while (APBDEV_PMC_CLAMP_STATUS_0 & 1) { }
|
|
||||||
|
|
||||||
/* Nintendo manually counts down from 8. I am not sure why this happens. */
|
|
||||||
{
|
|
||||||
volatile int32_t counter = 8;
|
|
||||||
while (counter >= 0) {
|
|
||||||
counter--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Power off I2C5. */
|
|
||||||
CLK_RST_CONTROLLER_RST_DEV_H_SET_0 = 0x8000;
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_H_CLR_0 = 0x8000;
|
|
||||||
|
|
||||||
/* Disable clock to CL_DVFS */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_W_CLR_0 = 0x08000000;
|
|
||||||
|
|
||||||
/* Perform RAM repair if necessary. */
|
|
||||||
flow_perform_ram_repair();
|
|
||||||
|
|
||||||
/* Enable power to the non-CPU partition. */
|
|
||||||
cluster_pmc_enable_partition(0x8000, 0x10F);
|
|
||||||
|
|
||||||
/* Enable clock to PLLP_OUT_CPU, wait 2 us. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_Y_SET_0 = 0x80000000;
|
|
||||||
timer_wait(2);
|
|
||||||
|
|
||||||
/* Enable clock to CPU, CPUG, wait 10 us. */
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_L_SET_0 = 1;
|
|
||||||
CLK_RST_CONTROLLER_CLK_ENB_V_SET_0 = 1;
|
|
||||||
timer_wait(10);
|
|
||||||
|
|
||||||
/* Set CPU clock sources to PLLP_OUT_0 + state to RUN, wait 10 us. */
|
|
||||||
CLK_RST_CONTROLLER_CCLKG_BURST_POLICY_0 = 0x20004444;
|
|
||||||
CLK_RST_CONTROLLER_CCLKP_BURST_POLICY_0 = 0x20004444;
|
|
||||||
timer_wait(10);
|
|
||||||
|
|
||||||
/* Take non-CPU out of reset (write CLR_NONCPURESET). */
|
|
||||||
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = 0x20000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cluster_power_on_cpu(void) {
|
|
||||||
/* Enable power to CE0 partition. */
|
|
||||||
cluster_pmc_enable_partition(0x4000, 0x10E);
|
|
||||||
|
|
||||||
/* Clear CPU reset. */
|
|
||||||
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = 0x10001;
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 naehrwert
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_CLUSTER_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_CLUSTER_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define MSELECT_CONFIG_0 MAKE_REG32(0x50060000)
|
|
||||||
|
|
||||||
void cluster_initialize_cpu(void);
|
|
||||||
void cluster_power_on_cpu(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "lp0.h"
|
|
||||||
#include "emc.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
void emc_configure_pmacro_training(void) {
|
|
||||||
/* Set DISABLE_CFG_BYTEN for all N. */
|
|
||||||
EMC_PMACRO_CFG_PM_GLOBAL_0_0 = 0xFF0000;
|
|
||||||
|
|
||||||
/* Set CHN_TRAINING_E_WRPTR for channel 0 + channel 1. */
|
|
||||||
EMC_PMACRO_TRAINING_CTRL_0_0 = 8;
|
|
||||||
EMC_PMACRO_TRAINING_CTRL_1_0 = 8;
|
|
||||||
|
|
||||||
/* Clear DISABLE_CFG_BYTEN for all N. */
|
|
||||||
EMC_PMACRO_CFG_PM_GLOBAL_0_0 = 0x0;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_EMC_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_EMC_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define EMC_BASE (0x7001B000)
|
|
||||||
|
|
||||||
#define EMC0_BASE (0x7001E000)
|
|
||||||
#define EMC1_BASE (0x7001F000)
|
|
||||||
|
|
||||||
|
|
||||||
#define MAKE_EMC_REG(ofs) (MAKE_REG32(EMC_BASE + ofs))
|
|
||||||
|
|
||||||
#define MAKE_EMC0_REG(ofs) (MAKE_REG32(EMC0_BASE + ofs))
|
|
||||||
#define MAKE_EMC1_REG(ofs) (MAKE_REG32(EMC1_BASE + ofs))
|
|
||||||
|
|
||||||
#define EMC_CFG_0 MAKE_EMC_REG(0x00C)
|
|
||||||
|
|
||||||
#define EMC_ADR_CFG_0 MAKE_EMC_REG(0x10)
|
|
||||||
|
|
||||||
#define EMC_TIMING_CONTROL_0 MAKE_EMC_REG(0x028)
|
|
||||||
|
|
||||||
#define EMC_SELF_REF_0 MAKE_EMC_REG(0x0E0)
|
|
||||||
|
|
||||||
#define EMC_MRW_0 MAKE_EMC_REG(0x0E8)
|
|
||||||
|
|
||||||
#define EMC_FBIO_CFG5_0 MAKE_EMC_REG(0x104)
|
|
||||||
|
|
||||||
#define EMC_MRW3_0 MAKE_EMC_REG(0x138)
|
|
||||||
|
|
||||||
#define EMC_AUTO_CAL_CONFIG_0 MAKE_EMC_REG(0x2A4)
|
|
||||||
|
|
||||||
#define EMC_REQ_CTRL_0 MAKE_EMC_REG(0x2B0)
|
|
||||||
|
|
||||||
#define EMC_EMC_STATUS_0 MAKE_EMC_REG(0x2B4)
|
|
||||||
#define EMC0_EMC_STATUS_0 MAKE_EMC0_REG(0x2B4)
|
|
||||||
#define EMC1_EMC_STATUS_0 MAKE_EMC1_REG(0x2B4)
|
|
||||||
|
|
||||||
#define EMC_CFG_DIG_DLL_0 MAKE_EMC_REG(0x2BC)
|
|
||||||
#define EMC0_CFG_DIG_DLL_0 MAKE_EMC0_REG(0x2BC)
|
|
||||||
#define EMC1_CFG_DIG_DLL_0 MAKE_EMC1_REG(0x2BC)
|
|
||||||
|
|
||||||
#define EMC_ZCAL_INTERVAL_0 MAKE_EMC_REG(0x2E0)
|
|
||||||
|
|
||||||
#define EMC_PMC_SCRATCH3_0 MAKE_EMC_REG(0x448)
|
|
||||||
|
|
||||||
#define EMC_FBIO_CFG7_0 MAKE_EMC_REG(0x584)
|
|
||||||
|
|
||||||
#define EMC_PMACRO_CFG_PM_GLOBAL_0_0 MAKE_EMC_REG(0xC30)
|
|
||||||
#define EMC_PMACRO_TRAINING_CTRL_0_0 MAKE_EMC_REG(0xCF8)
|
|
||||||
#define EMC_PMACRO_TRAINING_CTRL_1_0 MAKE_EMC_REG(0xCFC)
|
|
||||||
|
|
||||||
void emc_configure_pmacro_training(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "flow.h"
|
|
||||||
|
|
||||||
void flow_perform_ram_repair(void) {
|
|
||||||
/* Perform repair only if not active cluster. */
|
|
||||||
if (!(FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 & 1)) {
|
|
||||||
/* Set REQ, to begin RAM repair. */
|
|
||||||
FLOW_CTLR_RAM_REPAIR_0 = 1;
|
|
||||||
|
|
||||||
/* Wait for STS to say RAM repair has completed. */
|
|
||||||
while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_FLOW_CTLR_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_FLOW_CTLR_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define FLOW_BASE (0x60007000)
|
|
||||||
|
|
||||||
#define MAKE_FLOW_REG(ofs) MAKE_REG32(FLOW_BASE + ofs)
|
|
||||||
|
|
||||||
#define FLOW_CTLR_HALT_COP_EVENTS_0 MAKE_FLOW_REG(0x004)
|
|
||||||
#define FLOW_CTLR_RAM_REPAIR_0 MAKE_FLOW_REG(0x040)
|
|
||||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 MAKE_FLOW_REG(0x098)
|
|
||||||
|
|
||||||
void flow_perform_ram_repair(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
|
|
||||||
#define NUM_FUSE_BYPASS_ENTRIES 0
|
|
||||||
|
|
||||||
bool fuse_check_downgrade_status(void) {
|
|
||||||
/* We aren't going to implement anti-downgrade. */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_disable_programming(void) {
|
|
||||||
FUSE_REGS->FUSE_DISABLEREGPROGRAM = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fuse_bypass_data_t g_fuse_bypass_entries[NUM_FUSE_BYPASS_ENTRIES] = {
|
|
||||||
/* No entries here. */
|
|
||||||
};
|
|
||||||
|
|
||||||
void fuse_configure_fuse_bypass(void) {
|
|
||||||
/* Make all fuse registers visible. */
|
|
||||||
clkrst_enable_fuse_regs(true);
|
|
||||||
|
|
||||||
/* Configure bypass/override, only if programming is allowed. */
|
|
||||||
if (!(FUSE_REGS->FUSE_DISABLEREGPROGRAM & 1)) {
|
|
||||||
/* Enable write access and flush status. */
|
|
||||||
FUSE_REGS->FUSE_WRITE_ACCESS_SW = (FUSE_REGS->FUSE_WRITE_ACCESS_SW & ~0x1) | 0x10000;
|
|
||||||
|
|
||||||
/* Enable fuse bypass config. */
|
|
||||||
FUSE_REGS->FUSE_FUSEBYPASS = 1;
|
|
||||||
|
|
||||||
/* Override fuses. */
|
|
||||||
for (size_t i = 0; i < NUM_FUSE_BYPASS_ENTRIES; i++) {
|
|
||||||
MAKE_FUSE_REG(g_fuse_bypass_entries[i].offset) = g_fuse_bypass_entries[i].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable fuse write access. */
|
|
||||||
FUSE_REGS->FUSE_WRITE_ACCESS_SW |= 1;
|
|
||||||
|
|
||||||
/* Enable fuse bypass config. */
|
|
||||||
/* I think this is a bug, and Nintendo meant to write 0 here? */
|
|
||||||
FUSE_REGS->FUSE_FUSEBYPASS = 1;
|
|
||||||
|
|
||||||
/* This...clears the disable programming bit(?). */
|
|
||||||
/* I have no idea why this happens. What? */
|
|
||||||
/* This is probably also either a bug or does nothing. */
|
|
||||||
/* Is this bit even clearable? */
|
|
||||||
FUSE_REGS->FUSE_DISABLEREGPROGRAM &= 0xFFFFFFFE;
|
|
||||||
|
|
||||||
/* Restore saved private key disable bit. */
|
|
||||||
FUSE_REGS->FUSE_PRIVATEKEYDISABLE |= (APBDEV_PMC_SECURE_SCRATCH21_0 & 0x10);
|
|
||||||
|
|
||||||
/* Lock private key disable secure scratch. */
|
|
||||||
APBDEV_PMC_SEC_DISABLE2_0 |= 0x4000000;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_FUSE_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_FUSE_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t FUSE_FUSECTRL;
|
|
||||||
uint32_t FUSE_FUSEADDR;
|
|
||||||
uint32_t FUSE_FUSERDATA;
|
|
||||||
uint32_t FUSE_FUSEWDATA;
|
|
||||||
uint32_t FUSE_FUSETIME_RD1;
|
|
||||||
uint32_t FUSE_FUSETIME_RD2;
|
|
||||||
uint32_t FUSE_FUSETIME_PGM1;
|
|
||||||
uint32_t FUSE_FUSETIME_PGM2;
|
|
||||||
uint32_t FUSE_PRIV2INTFC_START;
|
|
||||||
uint32_t FUSE_FUSEBYPASS;
|
|
||||||
uint32_t FUSE_PRIVATEKEYDISABLE;
|
|
||||||
uint32_t FUSE_DISABLEREGPROGRAM;
|
|
||||||
uint32_t FUSE_WRITE_ACCESS_SW;
|
|
||||||
uint32_t FUSE_PWR_GOOD_SW;
|
|
||||||
uint32_t _0x38;
|
|
||||||
uint32_t FUSE_PRIV2RESHIFT;
|
|
||||||
uint32_t _0x40[0x3];
|
|
||||||
uint32_t FUSE_FUSETIME_RD3;
|
|
||||||
uint32_t _0x50[0xC];
|
|
||||||
uint32_t FUSE_PRIVATE_KEY0_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY1_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY2_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY3_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY4_NONZERO;
|
|
||||||
uint32_t _0x90[0x1C];
|
|
||||||
} tegra_fuse_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t FUSE_PRODUCTION_MODE;
|
|
||||||
uint32_t FUSE_JTAG_SECUREID_VALID;
|
|
||||||
uint32_t FUSE_ODM_LOCK;
|
|
||||||
uint32_t FUSE_OPT_OPENGL_EN;
|
|
||||||
uint32_t FUSE_SKU_INFO;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_0_CALIB;
|
|
||||||
uint32_t FUSE_CPU_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_DAC_CRT_CALIB;
|
|
||||||
uint32_t FUSE_DAC_HDTV_CALIB;
|
|
||||||
uint32_t FUSE_DAC_SDTV_CALIB;
|
|
||||||
uint32_t FUSE_OPT_FT_REV;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_1_CALIB;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_2_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_0_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_1_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_2_CALIB;
|
|
||||||
uint32_t FUSE_SOC_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_RESERVED_PRODUCTION_WP;
|
|
||||||
uint32_t FUSE_FA;
|
|
||||||
uint32_t FUSE_RESERVED_PRODUCTION;
|
|
||||||
uint32_t FUSE_HDMI_LANE0_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE1_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE2_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE3_CALIB;
|
|
||||||
uint32_t FUSE_ENCRYPTION_RATE;
|
|
||||||
uint32_t FUSE_PUBLIC_KEY[0x8];
|
|
||||||
uint32_t FUSE_TSENSOR1_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR2_CALIB;
|
|
||||||
uint32_t FUSE_VSENSOR_CALIB;
|
|
||||||
uint32_t FUSE_OPT_CP_REV;
|
|
||||||
uint32_t FUSE_OPT_PFG;
|
|
||||||
uint32_t FUSE_TSENSOR0_CALIB;
|
|
||||||
uint32_t FUSE_FIRST_BOOTROM_PATCH_SIZE;
|
|
||||||
uint32_t FUSE_SECURITY_MODE;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY[0x5];
|
|
||||||
uint32_t FUSE_ARM_JTAG_DIS;
|
|
||||||
uint32_t FUSE_BOOT_DEVICE_INFO;
|
|
||||||
uint32_t FUSE_RESERVED_SW;
|
|
||||||
uint32_t FUSE_OPT_VP9_DISABLE;
|
|
||||||
uint32_t FUSE_RESERVED_ODM[0x8];
|
|
||||||
uint32_t FUSE_OBS_DIS;
|
|
||||||
uint32_t FUSE_NOR_INFO;
|
|
||||||
uint32_t FUSE_USB_CALIB;
|
|
||||||
uint32_t FUSE_SKU_DIRECT_CONFIG;
|
|
||||||
uint32_t FUSE_KFUSE_PRIVKEY_CTRL;
|
|
||||||
uint32_t FUSE_PACKAGE_INFO;
|
|
||||||
uint32_t FUSE_OPT_VENDOR_CODE;
|
|
||||||
uint32_t FUSE_OPT_FAB_CODE;
|
|
||||||
uint32_t FUSE_OPT_LOT_CODE_0;
|
|
||||||
uint32_t FUSE_OPT_LOT_CODE_1;
|
|
||||||
uint32_t FUSE_OPT_WAFER_ID;
|
|
||||||
uint32_t FUSE_OPT_X_COORDINATE;
|
|
||||||
uint32_t FUSE_OPT_Y_COORDINATE;
|
|
||||||
uint32_t FUSE_OPT_SEC_DEBUG_EN;
|
|
||||||
uint32_t FUSE_OPT_OPS_RESERVED;
|
|
||||||
uint32_t FUSE_SATA_CALIB;
|
|
||||||
uint32_t FUSE_GPU_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR3_CALIB;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_L;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_H;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_U;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_V;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_W;
|
|
||||||
uint32_t FUSE_OPT_SAMPLE_TYPE;
|
|
||||||
uint32_t FUSE_OPT_SUBREVISION;
|
|
||||||
uint32_t FUSE_OPT_SW_RESERVED_0;
|
|
||||||
uint32_t FUSE_OPT_SW_RESERVED_1;
|
|
||||||
uint32_t FUSE_TSENSOR4_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR5_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR6_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR7_CALIB;
|
|
||||||
uint32_t FUSE_OPT_PRIV_SEC_EN;
|
|
||||||
uint32_t FUSE_PKC_DISABLE;
|
|
||||||
uint32_t _0x16C;
|
|
||||||
uint32_t _0x170;
|
|
||||||
uint32_t _0x174;
|
|
||||||
uint32_t _0x178;
|
|
||||||
uint32_t FUSE_FUSE2TSEC_DEBUG_DISABLE;
|
|
||||||
uint32_t FUSE_TSENSOR_COMMON;
|
|
||||||
uint32_t FUSE_OPT_CP_BIN;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_FT_BIN;
|
|
||||||
uint32_t FUSE_OPT_DONE_MAP;
|
|
||||||
uint32_t _0x194;
|
|
||||||
uint32_t FUSE_APB2JTAG_DISABLE;
|
|
||||||
uint32_t FUSE_ODM_INFO;
|
|
||||||
uint32_t _0x1A0;
|
|
||||||
uint32_t _0x1A4;
|
|
||||||
uint32_t FUSE_ARM_CRYPT_DE_FEATURE;
|
|
||||||
uint32_t _0x1AC;
|
|
||||||
uint32_t _0x1B0;
|
|
||||||
uint32_t _0x1B4;
|
|
||||||
uint32_t _0x1B8;
|
|
||||||
uint32_t _0x1BC;
|
|
||||||
uint32_t FUSE_WOA_SKU_FLAG;
|
|
||||||
uint32_t FUSE_ECO_RESERVE_1;
|
|
||||||
uint32_t FUSE_GCPLEX_CONFIG_FUSE;
|
|
||||||
uint32_t FUSE_PRODUCTION_MONTH;
|
|
||||||
uint32_t FUSE_RAM_REPAIR_INDICATOR;
|
|
||||||
uint32_t FUSE_TSENSOR9_CALIB;
|
|
||||||
uint32_t _0x1D8;
|
|
||||||
uint32_t FUSE_VMIN_CALIBRATION;
|
|
||||||
uint32_t FUSE_AGING_SENSOR_CALIBRATION;
|
|
||||||
uint32_t FUSE_DEBUG_AUTHENTICATION;
|
|
||||||
uint32_t FUSE_SECURE_PROVISION_INDEX;
|
|
||||||
uint32_t FUSE_SECURE_PROVISION_INFO;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_SPARE_ENDIS;
|
|
||||||
uint32_t FUSE_ECO_RESERVE_0;
|
|
||||||
uint32_t _0x1FC;
|
|
||||||
uint32_t _0x200;
|
|
||||||
uint32_t FUSE_RESERVED_CALIB0;
|
|
||||||
uint32_t FUSE_RESERVED_CALIB1;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_TSENSOR10_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR10_CALIB_AUX;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_DP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_PDP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_REG;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_SP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_SMPDP;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_USB_CALIB_EXT;
|
|
||||||
uint32_t FUSE_RESERVED_FIELD;
|
|
||||||
uint32_t FUSE_OPT_ECC_EN;
|
|
||||||
uint32_t _0x25C;
|
|
||||||
uint32_t _0x260;
|
|
||||||
uint32_t _0x264;
|
|
||||||
uint32_t _0x268;
|
|
||||||
uint32_t _0x26C;
|
|
||||||
uint32_t _0x270;
|
|
||||||
uint32_t _0x274;
|
|
||||||
uint32_t _0x278;
|
|
||||||
uint32_t FUSE_SPARE_REALIGNMENT_REG;
|
|
||||||
uint32_t FUSE_SPARE_BIT[0x20];
|
|
||||||
} tegra_fuse_chip_t;
|
|
||||||
|
|
||||||
#define FUSE_REGS ((volatile tegra_fuse_t *)(0x7000F800))
|
|
||||||
#define FUSE_CHIP_REGS ((volatile tegra_fuse_chip_t *)(0x7000F900))
|
|
||||||
|
|
||||||
#define MAKE_FUSE_REG(n) MAKE_REG32(0x7000F800 + n)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t value;
|
|
||||||
} fuse_bypass_data_t;
|
|
||||||
|
|
||||||
bool fuse_check_downgrade_status(void);
|
|
||||||
void fuse_configure_fuse_bypass(void);
|
|
||||||
void fuse_disable_programming(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "i2c.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
|
||||||
void i2c_set_test_master_config_load(void);
|
|
||||||
void i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes);
|
|
||||||
void i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b);
|
|
||||||
|
|
||||||
/* Load hardware config for I2C5. */
|
|
||||||
void i2c_set_test_master_config_load(void) {
|
|
||||||
/* Set MSTR_CONFIG_LOAD. */
|
|
||||||
I2C_I2C_CONFIG_LOAD_0 = 0x1;
|
|
||||||
|
|
||||||
while (I2C_I2C_CONFIG_LOAD_0 & 1) {
|
|
||||||
/* Wait forever until it's unset. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a value to an i2c device. */
|
|
||||||
void i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes) {
|
|
||||||
if (num_bytes > 4) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit mode. */
|
|
||||||
I2C_I2C_CMD_ADDR0_0 = device << 1;
|
|
||||||
|
|
||||||
/* Load in data to write. */
|
|
||||||
I2C_I2C_CMD_DATA1_0 = val;
|
|
||||||
|
|
||||||
/* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800;
|
|
||||||
|
|
||||||
i2c_set_test_master_config_load();
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800 | 0x200;
|
|
||||||
|
|
||||||
|
|
||||||
while (I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
while (I2C_I2C_STATUS_0 & 0xF) {
|
|
||||||
/* Wait until write successful. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a byte val to reg for given device. */
|
|
||||||
void i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b) {
|
|
||||||
uint32_t val = (reg) | (b << 8);
|
|
||||||
/* Write 1 byte (reg) + 1 byte (value) */
|
|
||||||
i2c_write(device, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable the PMIC. */
|
|
||||||
void i2c_enable_pmic(void) {
|
|
||||||
/* Write 00 to Device 27 Reg 00. */
|
|
||||||
i2c_send_byte_command(27, 0, 0x80);
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_I2C_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_I2C_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/* I2C_BASE = I2C5. */
|
|
||||||
#define I2C_BASE (0x7000D000)
|
|
||||||
|
|
||||||
#define MAKE_I2C_REG(ofs) (MAKE_REG32(I2C_BASE + ofs))
|
|
||||||
|
|
||||||
#define I2C_I2C_CNFG_0 MAKE_I2C_REG(0x000)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_ADDR0_0 MAKE_I2C_REG(0x004)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_DATA1_0 MAKE_I2C_REG(0x00C)
|
|
||||||
|
|
||||||
#define I2C_I2C_STATUS_0 MAKE_I2C_REG(0x01C)
|
|
||||||
|
|
||||||
#define I2C_INTERRUPT_STATUS_REGISTER_0 MAKE_I2C_REG(0x068)
|
|
||||||
|
|
||||||
#define I2C_I2C_CLK_DIVISOR_REGISTER_0 MAKE_I2C_REG(0x06C)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_CONFIG_0 MAKE_I2C_REG(0x084)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_STATUS_0 MAKE_I2C_REG(0x088)
|
|
||||||
|
|
||||||
|
|
||||||
#define I2C_I2C_CONFIG_LOAD_0 MAKE_I2C_REG(0x08C)
|
|
||||||
|
|
||||||
void i2c_enable_pmic(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "lp0.h"
|
|
||||||
#include "mc.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "emc.h"
|
|
||||||
#include "cluster.h"
|
|
||||||
#include "flow.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "secmon.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) {
|
|
||||||
const uint32_t target_firmware = meta->target_firmware;
|
|
||||||
/* Before doing anything else, ensure some sanity. */
|
|
||||||
if (meta->magic != WARMBOOT_MAGIC || target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [4.0.0+] First thing warmboot does is disable BPMP access to memory. */
|
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
disable_bpmp_access_to_dram();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure debugging depending on FUSE_PRODUCTION_MODE */
|
|
||||||
misc_configure_device_dbg_settings();
|
|
||||||
|
|
||||||
/* Check for downgrade. */
|
|
||||||
/* NOTE: We implemented this as "return false" */
|
|
||||||
if (fuse_check_downgrade_status()) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
|
|
||||||
/* Nintendo's firmware checks APBDEV_PMC_SECURE_SCRATCH32_0 against a per-warmboot binary value here. */
|
|
||||||
/* We won't bother with that. */
|
|
||||||
if (false /* APBDEV_PMC_SECURE_SCRATCH32_0 == WARMBOOT_MAGIC_NUMBER */) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Check that we're running at the correct physical address. */
|
|
||||||
|
|
||||||
/* Setup fuses, disable bypass. */
|
|
||||||
fuse_configure_fuse_bypass();
|
|
||||||
|
|
||||||
/* Configure oscillators/timing in CAR. */
|
|
||||||
car_configure_oscillators();
|
|
||||||
|
|
||||||
/* Restore RAM configuration. */
|
|
||||||
misc_restore_ram_svop();
|
|
||||||
emc_configure_pmacro_training();
|
|
||||||
|
|
||||||
/* Setup clock output for all devices, working around mbist bug. */
|
|
||||||
car_mbist_workaround();
|
|
||||||
|
|
||||||
/* Initialize the CPU cluster. */
|
|
||||||
cluster_initialize_cpu();
|
|
||||||
|
|
||||||
secmon_restore_to_tzram(target_firmware);
|
|
||||||
|
|
||||||
/* Power on the CPU cluster. */
|
|
||||||
cluster_power_on_cpu();
|
|
||||||
|
|
||||||
/* Nintendo clears most of warmboot.bin out of IRAM here. We're not gonna bother. */
|
|
||||||
/* memset( ... ); */
|
|
||||||
|
|
||||||
const uint32_t halt_val = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? 0x40000000 : 0x50000000;
|
|
||||||
while (true) {
|
|
||||||
/* Halt the BPMP. */
|
|
||||||
FLOW_CTLR_HALT_COP_EVENTS_0 = halt_val;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 target_firmware;
|
|
||||||
uint32_t padding[2];
|
|
||||||
} warmboot_metadata_t;
|
|
||||||
|
|
||||||
void lp0_entry_main(warmboot_metadata_t *meta);
|
|
||||||
|
|
||||||
void __attribute__((noreturn)) reboot(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "mc.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
void disable_bpmp_access_to_dram(void) {
|
|
||||||
/* Modify carveout 4 to prevent BPMP access to dram (TZ will fix it). */
|
|
||||||
volatile security_carveout_t *carveout = (volatile security_carveout_t *)(MC_BASE + 0xC08 + 0x50 * (4 - CARVEOUT_ID_MIN));
|
|
||||||
carveout->paddr_low = 0;
|
|
||||||
carveout->paddr_high = 0;
|
|
||||||
carveout->size_big_pages = 1; /* 128 KiB */
|
|
||||||
carveout->client_access_0 = 0;
|
|
||||||
carveout->client_access_1 = 0;
|
|
||||||
carveout->client_access_2 = 0;
|
|
||||||
carveout->client_access_3 = 0;
|
|
||||||
carveout->client_access_4 = 0;
|
|
||||||
carveout->client_force_internal_access_0 = BIT(CSR_AVPCARM7R);
|
|
||||||
carveout->client_force_internal_access_1 = BIT(CSW_AVPCARM7W);
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
/* Set config to LOCKED, TZ-SECURE, untranslated addresses only. */
|
|
||||||
carveout->config = 0x8F;
|
|
||||||
}
|
|
|
@ -1,622 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_MC_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_MC_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define MC_BASE_PHYS 0x70019000
|
|
||||||
|
|
||||||
#define MC_BASE (MC_BASE_PHYS)
|
|
||||||
#define MAKE_MC_REG(n) MAKE_REG32(MC_BASE + n)
|
|
||||||
|
|
||||||
#define MC_INTSTATUS 0x0
|
|
||||||
#define MC_INTMASK 0x4
|
|
||||||
#define MC_ERR_STATUS 0x8
|
|
||||||
#define MC_ERR_ADR 0xc
|
|
||||||
#define MC_SMMU_CONFIG 0x10
|
|
||||||
#define MC_SMMU_TLB_CONFIG 0x14
|
|
||||||
#define MC_SMMU_PTC_CONFIG 0x18
|
|
||||||
#define MC_SMMU_PTB_ASID 0x1c
|
|
||||||
#define MC_SMMU_PTB_DATA 0x20
|
|
||||||
#define MC_SMMU_TLB_FLUSH 0x30
|
|
||||||
#define MC_SMMU_PTC_FLUSH 0x34
|
|
||||||
#define MC_SMMU_ASID_SECURITY 0x38
|
|
||||||
#define MC_SMMU_ASID_SECURITY_1 0x3c
|
|
||||||
#define MC_SMMU_ASID_SECURITY_2 0x9e0
|
|
||||||
#define MC_SMMU_ASID_SECURITY_3 0x9e4
|
|
||||||
#define MC_SMMU_ASID_SECURITY_4 0x9e8
|
|
||||||
#define MC_SMMU_ASID_SECURITY_5 0x9ec
|
|
||||||
#define MC_SMMU_ASID_SECURITY_6 0x9f0
|
|
||||||
#define MC_SMMU_ASID_SECURITY_7 0x9f4
|
|
||||||
#define MC_SMMU_AFI_ASID 0x238
|
|
||||||
#define MC_SMMU_AVPC_ASID 0x23c
|
|
||||||
#define MC_SMMU_PPCS1_ASID 0x298
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG3 0xddc
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG4 0xde0
|
|
||||||
#define MC_EMEM_CFG 0x50
|
|
||||||
#define MC_EMEM_ADR_CFG 0x54
|
|
||||||
#define MC_EMEM_ADR_CFG_DEV0 0x58
|
|
||||||
#define MC_EMEM_ADR_CFG_DEV1 0x5c
|
|
||||||
#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c
|
|
||||||
#define MC_SECURITY_CFG0 0x70
|
|
||||||
#define MC_SECURITY_CFG1 0x74
|
|
||||||
#define MC_SECURITY_CFG3 0x9bc
|
|
||||||
#define MC_SECURITY_RSV 0x7c
|
|
||||||
#define MC_EMEM_ARB_CFG 0x90
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
|
||||||
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
|
||||||
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
|
||||||
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
|
||||||
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
|
||||||
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
|
||||||
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
|
||||||
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
|
||||||
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
|
||||||
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
|
||||||
#define MC_EMEM_ARB_TIMING_W2W 0xbc
|
|
||||||
#define MC_EMEM_ARB_TIMING_R2W 0xc0
|
|
||||||
#define MC_EMEM_ARB_TIMING_W2R 0xc4
|
|
||||||
#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0
|
|
||||||
#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4
|
|
||||||
#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0
|
|
||||||
#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4
|
|
||||||
#define MC_EMEM_ARB_DA_TURNS 0xd0
|
|
||||||
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
|
||||||
#define MC_EMEM_ARB_MISC0 0xd8
|
|
||||||
#define MC_EMEM_ARB_MISC1 0xdc
|
|
||||||
#define MC_EMEM_ARB_MISC2 0xc8
|
|
||||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
|
||||||
#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0
|
|
||||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
|
||||||
#define MC_EMEM_ARB_RSV 0xec
|
|
||||||
#define MC_CLKEN_OVERRIDE 0xf4
|
|
||||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
|
||||||
#define MC_TIMING_CONTROL 0xfc
|
|
||||||
#define MC_STAT_CONTROL 0x100
|
|
||||||
#define MC_STAT_STATUS 0x104
|
|
||||||
#define MC_STAT_EMC_CLOCK_LIMIT 0x108
|
|
||||||
#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c
|
|
||||||
#define MC_STAT_EMC_CLOCKS 0x110
|
|
||||||
#define MC_STAT_EMC_CLOCKS_MSBS 0x114
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c
|
|
||||||
#define MC_STAT_EMC_SET0_COUNT 0x138
|
|
||||||
#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c
|
|
||||||
#define MC_STAT_EMC_SET1_COUNT 0x178
|
|
||||||
#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c
|
|
||||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140
|
|
||||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144
|
|
||||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180
|
|
||||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184
|
|
||||||
#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148
|
|
||||||
#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c
|
|
||||||
#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188
|
|
||||||
#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c
|
|
||||||
#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150
|
|
||||||
#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0
|
|
||||||
#define MC_CLIENT_HOTRESET_CTRL 0x200
|
|
||||||
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
|
|
||||||
#define MC_CLIENT_HOTRESET_STATUS 0x204
|
|
||||||
#define MC_CLIENT_HOTRESET_STATUS_1 0x974
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_0 0x218
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_1 0x21c
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_2 0x220
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_3 0x224
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_4 0xb84
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0
|
|
||||||
#define MC_EMEM_ARB_DHYST_CTRL 0xbcc
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec
|
|
||||||
#define MC_RESERVED_RSV 0x3fc
|
|
||||||
#define MC_DISB_EXTRA_SNAP_LEVELS 0x408
|
|
||||||
#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4
|
|
||||||
#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0
|
|
||||||
#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18
|
|
||||||
#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08
|
|
||||||
#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10
|
|
||||||
#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c
|
|
||||||
#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40
|
|
||||||
#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414
|
|
||||||
#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc
|
|
||||||
#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c
|
|
||||||
#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14
|
|
||||||
#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0
|
|
||||||
#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac
|
|
||||||
#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c
|
|
||||||
#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48
|
|
||||||
#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8
|
|
||||||
#define MC_USBX_EXTRA_SNAP_LEVELS 0x404
|
|
||||||
#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8
|
|
||||||
#define MC_SD_EXTRA_SNAP_LEVELS 0xa04
|
|
||||||
#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c
|
|
||||||
#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8
|
|
||||||
#define MC_GK_EXTRA_SNAP_LEVELS 0xa00
|
|
||||||
#define MC_VE2_EXTRA_SNAP_LEVELS 0x410
|
|
||||||
#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44
|
|
||||||
#define MC_VIDEO_PROTECT_BOM 0x648
|
|
||||||
#define MC_VIDEO_PROTECT_SIZE_MB 0x64c
|
|
||||||
#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978
|
|
||||||
#define MC_VIDEO_PROTECT_REG_CTRL 0x650
|
|
||||||
#define MC_ERR_VPR_STATUS 0x654
|
|
||||||
#define MC_ERR_VPR_ADR 0x658
|
|
||||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418
|
|
||||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590
|
|
||||||
#define MC_IRAM_BOM 0x65c
|
|
||||||
#define MC_IRAM_TOM 0x660
|
|
||||||
#define MC_IRAM_ADR_HI 0x980
|
|
||||||
#define MC_IRAM_REG_CTRL 0x964
|
|
||||||
#define MC_EMEM_CFG_ACCESS_CTRL 0x664
|
|
||||||
#define MC_TZ_SECURITY_CTRL 0x668
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4
|
|
||||||
#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80
|
|
||||||
#define MC_SEC_CARVEOUT_BOM 0x670
|
|
||||||
#define MC_SEC_CARVEOUT_SIZE_MB 0x674
|
|
||||||
#define MC_SEC_CARVEOUT_ADR_HI 0x9d4
|
|
||||||
#define MC_SEC_CARVEOUT_REG_CTRL 0x678
|
|
||||||
#define MC_ERR_SEC_STATUS 0x67c
|
|
||||||
#define MC_ERR_SEC_ADR 0x680
|
|
||||||
#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684
|
|
||||||
#define MC_STUTTER_CONTROL 0x688
|
|
||||||
#define MC_RESERVED_RSV_1 0x958
|
|
||||||
#define MC_DVFS_PIPE_SELECT 0x95c
|
|
||||||
#define MC_AHB_PTSA_MIN 0x4e0
|
|
||||||
#define MC_AUD_PTSA_MIN 0x54c
|
|
||||||
#define MC_MLL_MPCORER_PTSA_RATE 0x44c
|
|
||||||
#define MC_RING2_PTSA_RATE 0x440
|
|
||||||
#define MC_USBD_PTSA_RATE 0x530
|
|
||||||
#define MC_USBX_PTSA_MIN 0x528
|
|
||||||
#define MC_USBD_PTSA_MIN 0x534
|
|
||||||
#define MC_APB_PTSA_MAX 0x4f0
|
|
||||||
#define MC_JPG_PTSA_RATE 0x584
|
|
||||||
#define MC_DIS_PTSA_MIN 0x420
|
|
||||||
#define MC_AVP_PTSA_MAX 0x4fc
|
|
||||||
#define MC_AVP_PTSA_RATE 0x4f4
|
|
||||||
#define MC_RING1_PTSA_MIN 0x480
|
|
||||||
#define MC_DIS_PTSA_MAX 0x424
|
|
||||||
#define MC_SD_PTSA_MAX 0x4d8
|
|
||||||
#define MC_MSE_PTSA_RATE 0x4c4
|
|
||||||
#define MC_VICPC_PTSA_MIN 0x558
|
|
||||||
#define MC_PCX_PTSA_MAX 0x4b4
|
|
||||||
#define MC_ISP_PTSA_RATE 0x4a0
|
|
||||||
#define MC_A9AVPPC_PTSA_MIN 0x48c
|
|
||||||
#define MC_RING2_PTSA_MAX 0x448
|
|
||||||
#define MC_AUD_PTSA_RATE 0x548
|
|
||||||
#define MC_HOST_PTSA_MIN 0x51c
|
|
||||||
#define MC_MLL_MPCORER_PTSA_MAX 0x454
|
|
||||||
#define MC_SD_PTSA_MIN 0x4d4
|
|
||||||
#define MC_RING1_PTSA_RATE 0x47c
|
|
||||||
#define MC_JPG_PTSA_MIN 0x588
|
|
||||||
#define MC_HDAPC_PTSA_MIN 0x62c
|
|
||||||
#define MC_AVP_PTSA_MIN 0x4f8
|
|
||||||
#define MC_JPG_PTSA_MAX 0x58c
|
|
||||||
#define MC_VE_PTSA_MAX 0x43c
|
|
||||||
#define MC_DFD_PTSA_MAX 0x63c
|
|
||||||
#define MC_VICPC_PTSA_RATE 0x554
|
|
||||||
#define MC_GK_PTSA_MAX 0x544
|
|
||||||
#define MC_VICPC_PTSA_MAX 0x55c
|
|
||||||
#define MC_SDM_PTSA_MAX 0x624
|
|
||||||
#define MC_SAX_PTSA_RATE 0x4b8
|
|
||||||
#define MC_PCX_PTSA_MIN 0x4b0
|
|
||||||
#define MC_APB_PTSA_MIN 0x4ec
|
|
||||||
#define MC_GK2_PTSA_MIN 0x614
|
|
||||||
#define MC_PCX_PTSA_RATE 0x4ac
|
|
||||||
#define MC_RING1_PTSA_MAX 0x484
|
|
||||||
#define MC_HDAPC_PTSA_RATE 0x628
|
|
||||||
#define MC_MLL_MPCORER_PTSA_MIN 0x450
|
|
||||||
#define MC_GK2_PTSA_MAX 0x618
|
|
||||||
#define MC_AUD_PTSA_MAX 0x550
|
|
||||||
#define MC_GK2_PTSA_RATE 0x610
|
|
||||||
#define MC_ISP_PTSA_MAX 0x4a8
|
|
||||||
#define MC_DISB_PTSA_RATE 0x428
|
|
||||||
#define MC_VE2_PTSA_MAX 0x49c
|
|
||||||
#define MC_DFD_PTSA_MIN 0x638
|
|
||||||
#define MC_FTOP_PTSA_RATE 0x50c
|
|
||||||
#define MC_A9AVPPC_PTSA_RATE 0x488
|
|
||||||
#define MC_VE2_PTSA_MIN 0x498
|
|
||||||
#define MC_USBX_PTSA_MAX 0x52c
|
|
||||||
#define MC_DIS_PTSA_RATE 0x41c
|
|
||||||
#define MC_USBD_PTSA_MAX 0x538
|
|
||||||
#define MC_A9AVPPC_PTSA_MAX 0x490
|
|
||||||
#define MC_USBX_PTSA_RATE 0x524
|
|
||||||
#define MC_FTOP_PTSA_MAX 0x514
|
|
||||||
#define MC_HDAPC_PTSA_MAX 0x630
|
|
||||||
#define MC_SD_PTSA_RATE 0x4d0
|
|
||||||
#define MC_DFD_PTSA_RATE 0x634
|
|
||||||
#define MC_FTOP_PTSA_MIN 0x510
|
|
||||||
#define MC_SDM_PTSA_RATE 0x61c
|
|
||||||
#define MC_AHB_PTSA_RATE 0x4dc
|
|
||||||
#define MC_SMMU_SMMU_PTSA_MAX 0x460
|
|
||||||
#define MC_RING2_PTSA_MIN 0x444
|
|
||||||
#define MC_SDM_PTSA_MIN 0x620
|
|
||||||
#define MC_APB_PTSA_RATE 0x4e8
|
|
||||||
#define MC_MSE_PTSA_MIN 0x4c8
|
|
||||||
#define MC_HOST_PTSA_RATE 0x518
|
|
||||||
#define MC_VE_PTSA_RATE 0x434
|
|
||||||
#define MC_AHB_PTSA_MAX 0x4e4
|
|
||||||
#define MC_SAX_PTSA_MIN 0x4bc
|
|
||||||
#define MC_SMMU_SMMU_PTSA_MIN 0x45c
|
|
||||||
#define MC_ISP_PTSA_MIN 0x4a4
|
|
||||||
#define MC_HOST_PTSA_MAX 0x520
|
|
||||||
#define MC_SAX_PTSA_MAX 0x4c0
|
|
||||||
#define MC_VE_PTSA_MIN 0x438
|
|
||||||
#define MC_GK_PTSA_MIN 0x540
|
|
||||||
#define MC_MSE_PTSA_MAX 0x4cc
|
|
||||||
#define MC_DISB_PTSA_MAX 0x430
|
|
||||||
#define MC_DISB_PTSA_MIN 0x42c
|
|
||||||
#define MC_SMMU_SMMU_PTSA_RATE 0x458
|
|
||||||
#define MC_VE2_PTSA_RATE 0x494
|
|
||||||
#define MC_GK_PTSA_RATE 0x53c
|
|
||||||
#define MC_PTSA_GRANT_DECREMENT 0x960
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc
|
|
||||||
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
|
|
||||||
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
|
|
||||||
#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec
|
|
||||||
#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec
|
|
||||||
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
|
|
||||||
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SATA_0 0x350
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HDA_0 0x318
|
|
||||||
#define MC_MIN_LENGTH_APE_0 0xb34
|
|
||||||
#define MC_MIN_LENGTH_DCB_2 0x8a8
|
|
||||||
#define MC_MIN_LENGTH_A9AVP_0 0x950
|
|
||||||
#define MC_MIN_LENGTH_TSEC_0 0x93c
|
|
||||||
#define MC_MIN_LENGTH_DC_1 0x898
|
|
||||||
#define MC_MIN_LENGTH_AXIAP_0 0x94c
|
|
||||||
#define MC_MIN_LENGTH_ISP2B_0 0x930
|
|
||||||
#define MC_MIN_LENGTH_VI2_0 0x944
|
|
||||||
#define MC_MIN_LENGTH_DCB_0 0x8a0
|
|
||||||
#define MC_MIN_LENGTH_DCB_1 0x8a4
|
|
||||||
#define MC_MIN_LENGTH_PPCS_1 0x8f4
|
|
||||||
#define MC_MIN_LENGTH_NVJPG_0 0xb3c
|
|
||||||
#define MC_MIN_LENGTH_HDA_0 0x8c4
|
|
||||||
#define MC_MIN_LENGTH_NVENC_0 0x8d4
|
|
||||||
#define MC_MIN_LENGTH_SDMMC_0 0xb18
|
|
||||||
#define MC_MIN_LENGTH_ISP2B_1 0x934
|
|
||||||
#define MC_MIN_LENGTH_HC_1 0x8c0
|
|
||||||
#define MC_MIN_LENGTH_DC_3 0xb20
|
|
||||||
#define MC_MIN_LENGTH_AVPC_0 0x890
|
|
||||||
#define MC_MIN_LENGTH_VIC_0 0x940
|
|
||||||
#define MC_MIN_LENGTH_ISP2_0 0x91c
|
|
||||||
#define MC_MIN_LENGTH_HC_0 0x8bc
|
|
||||||
#define MC_MIN_LENGTH_SE_0 0xb38
|
|
||||||
#define MC_MIN_LENGTH_NVDEC_0 0xb30
|
|
||||||
#define MC_MIN_LENGTH_SATA_0 0x8fc
|
|
||||||
#define MC_MIN_LENGTH_DC_0 0x894
|
|
||||||
#define MC_MIN_LENGTH_XUSB_1 0x92c
|
|
||||||
#define MC_MIN_LENGTH_DC_2 0x89c
|
|
||||||
#define MC_MIN_LENGTH_SDMMCAA_0 0xb14
|
|
||||||
#define MC_MIN_LENGTH_GPU_0 0xb04
|
|
||||||
#define MC_MIN_LENGTH_ETR_0 0xb44
|
|
||||||
#define MC_MIN_LENGTH_AFI_0 0x88c
|
|
||||||
#define MC_MIN_LENGTH_PPCS_0 0x8f0
|
|
||||||
#define MC_MIN_LENGTH_ISP2_1 0x920
|
|
||||||
#define MC_MIN_LENGTH_XUSB_0 0x928
|
|
||||||
#define MC_MIN_LENGTH_MPCORE_0 0x8cc
|
|
||||||
#define MC_MIN_LENGTH_TSECB_0 0xb48
|
|
||||||
#define MC_MIN_LENGTH_SDMMCA_0 0xb10
|
|
||||||
#define MC_MIN_LENGTH_GPU2_0 0xb40
|
|
||||||
#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c
|
|
||||||
#define MC_MIN_LENGTH_PTC_0 0x8f8
|
|
||||||
#define MC_EMEM_ARB_OVERRIDE_1 0x968
|
|
||||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984
|
|
||||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988
|
|
||||||
#define MC_EMEM_ARB_STATS_0 0x990
|
|
||||||
#define MC_EMEM_ARB_STATS_1 0x994
|
|
||||||
#define MC_MTS_CARVEOUT_BOM 0x9a0
|
|
||||||
#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4
|
|
||||||
#define MC_MTS_CARVEOUT_ADR_HI 0x9a8
|
|
||||||
#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac
|
|
||||||
#define MC_ERR_MTS_STATUS 0x9b0
|
|
||||||
#define MC_ERR_MTS_ADR 0x9b4
|
|
||||||
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
|
|
||||||
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10
|
|
||||||
#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CFG0 0xc58
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CFG0 0xc08
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68
|
|
||||||
#define MC_SECURITY_CARVEOUT3_BOM 0xcac
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CFG0 0xca8
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88
|
|
||||||
#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64
|
|
||||||
#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50
|
|
||||||
#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14
|
|
||||||
#define MC_SECURITY_CARVEOUT1_BOM 0xc0c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8
|
|
||||||
#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60
|
|
||||||
#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80
|
|
||||||
#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc
|
|
||||||
#define MC_SECURITY_CARVEOUT4_BOM 0xcfc
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CFG0 0xd48
|
|
||||||
#define MC_SECURITY_CARVEOUT2_BOM 0xc5c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_BOM 0xd4c
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0
|
|
||||||
#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08
|
|
||||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
|
||||||
#define MC_DA_CONFIG0 0x9dc
|
|
||||||
|
|
||||||
/* Virtual aliases */
|
|
||||||
#define VIRT_MC_SECURITY_CFG3 MAKE_MC_REG(MC_SECURITY_CFG3)
|
|
||||||
|
|
||||||
/* Memory Controller clients */
|
|
||||||
#define CLIENT_ACCESS_NUM_CLIENTS 32
|
|
||||||
typedef enum {
|
|
||||||
/* _ACCESS0 */
|
|
||||||
CSR_PTCR = (0 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0A = (1 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0AB = (2 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0B = (3 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0BB = (4 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0C = (5 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0CB = (6 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_AFIR = (14 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_AVPCARM7R = (15 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAYHC = (16 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAYHCB = (17 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HDAR = (21 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HOST1XDMAR = (22 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HOST1XR = (23 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_NVENCSRD = (28 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_PPCSAHBDMAR = (29 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_PPCSAHBSLVR = (30 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_SATAR = (31 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
|
|
||||||
/* _ACCESS1 */
|
|
||||||
CSR_VDEBSEVR = (34 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDEMBER = (35 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDEMCER = (36 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDETPER = (37 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_MPCORELPR = (38 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_MPCORER = (39 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_NVENCSWR = (43 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_AFIW = (49 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_AVPCARM7W = (50 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_HDAW = (53 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_HOST1XW = (54 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_MPCORELPW = (56 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_MPCOREW = (57 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_PPCSAHBDMAW = (59 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_PPCSAHBSLVW = (60 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_SATAW = (61 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_VDEBSEVW = (62 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_VDEDBGW = (63 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
|
|
||||||
/* _ACCESS2 */
|
|
||||||
CSW_VDEMBEW = (64 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_VDETPMW = (65 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_ISPRA = (68 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWA = (70 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWB = (71 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_XUSB_HOSTR = (74 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_XUSB_HOSTW = (75 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_XUSB_DEVR = (76 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_XUSB_DEVW = (77 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_ISPRAB = (78 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWAB = (80 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWBB = (81 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_TSECSRD = (84 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_TSECSWR = (85 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_A9AVPSCR = (86 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_A9AVPSCW = (87 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_GPUSRD = (88 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_GPUSWR = (89 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_DISPLAYT = (90 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
|
|
||||||
/* _ACCESS3 */
|
|
||||||
CSR_SDMMCRA = (96 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCRAA = (97 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCR = (98 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCRAB = (99 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWA = (100 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWAA = (101 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCW = (102 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWAB = (103 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_VICSRD = (108 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_VICSWR = (109 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_VIW = (114 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_DISPLAYD = (115 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_NVDECSRD = (120 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_NVDECSWR = (121 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_APER = (122 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_APEW = (123 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_NVJPGSRD = (126 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_NVJPGSWR = (127 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
|
|
||||||
/* _ACCESS4 */
|
|
||||||
CSR_SESRD = (128 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_SESWR = (129 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_AXIAPR = (130 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_AXIAPW = (131 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_ETRR = (132 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_ETRW = (133 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_TSECSRDB = (134 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_TSECSWRB = (135 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_GPUSRD2 = (136 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_GPUSWR2 = (137 - (CLIENT_ACCESS_NUM_CLIENTS * 4))
|
|
||||||
} McClient;
|
|
||||||
|
|
||||||
/* Memory Controller carveouts */
|
|
||||||
#define CARVEOUT_ID_MIN 1
|
|
||||||
#define CARVEOUT_ID_MAX 5
|
|
||||||
typedef struct {
|
|
||||||
uint32_t config;
|
|
||||||
uint32_t paddr_low;
|
|
||||||
uint32_t paddr_high;
|
|
||||||
uint32_t size_big_pages;
|
|
||||||
uint32_t client_access_0;
|
|
||||||
uint32_t client_access_1;
|
|
||||||
uint32_t client_access_2;
|
|
||||||
uint32_t client_access_3;
|
|
||||||
uint32_t client_access_4;
|
|
||||||
uint32_t client_force_internal_access_0;
|
|
||||||
uint32_t client_force_internal_access_1;
|
|
||||||
uint32_t client_force_internal_access_2;
|
|
||||||
uint32_t client_force_internal_access_3;
|
|
||||||
uint32_t client_force_internal_access_4;
|
|
||||||
uint8_t padding[0x18];
|
|
||||||
} security_carveout_t;
|
|
||||||
|
|
||||||
void disable_bpmp_access_to_dram(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
|
|
||||||
void misc_configure_device_dbg_settings(void) {
|
|
||||||
/* Set APB_MISC_PP_CONFIG_CTL_TBE (enables RTCK daisy-chaining). */
|
|
||||||
APB_MISC_PP_CONFIG_CTL_0 = 0x80;
|
|
||||||
|
|
||||||
/* Configure JTAG and debug bits. */
|
|
||||||
if (FUSE_CHIP_REGS->FUSE_SECURITY_MODE == 1) {
|
|
||||||
uint32_t secure_boot_val = 0b0100; /* Set NIDEN for aarch64. */
|
|
||||||
uint32_t pp_config_ctl_val = 0x40; /* Set APB_MISC_PP_CONFIG_CTL_JTAG. */
|
|
||||||
if (APBDEV_PMC_STICKY_BITS_0 & 0x40) {
|
|
||||||
pp_config_ctl_val = 0x0;
|
|
||||||
} else {
|
|
||||||
secure_boot_val = 0b1101; /* Set SPNIDEN, NIDEN, DBGEN for aarch64. */
|
|
||||||
}
|
|
||||||
SB_PFCFG_0 = (SB_PFCFG_0 & ~0b1111) | secure_boot_val; /* Configure debug bits. */
|
|
||||||
APB_MISC_PP_CONFIG_CTL_0 |= pp_config_ctl_val; /* Configure JTAG. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set HDA_LPBK_DIS if FUSE_SECURITY_MODE is set (disables HDA codec loopback). */
|
|
||||||
APBDEV_PMC_STICKY_BITS_0 |= FUSE_CHIP_REGS->FUSE_SECURITY_MODE;
|
|
||||||
|
|
||||||
/* Set E_INPUT in PINMUX_AUX_GPIO_PA6_0 (needed by the XUSB and SATA controllers). */
|
|
||||||
PINMUX_AUX_GPIO_PA6_0 |= 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
void misc_restore_ram_svop(void) {
|
|
||||||
/* This sets CFG2TMC_RAM_SVOP_PDP to 0x2. */
|
|
||||||
APB_MISC_GP_ASDBGREG_0 = (APB_MISC_GP_ASDBGREG_0 & 0xFCFFFFFF) | 0x02000000;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_MISC_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_MISC_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define MISC_BASE (0x70000000)
|
|
||||||
|
|
||||||
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
|
|
||||||
|
|
||||||
#define APB_MISC_PP_CONFIG_CTL_0 MAKE_MISC_REG(0x024)
|
|
||||||
#define APB_MISC_GP_ASDBGREG_0 MAKE_MISC_REG(0x810)
|
|
||||||
|
|
||||||
#define PINMUX_AUX_PWR_I2C_SCL_0 MAKE_MISC_REG(0x30DC)
|
|
||||||
#define PINMUX_AUX_PWR_I2C_SDA_0 MAKE_MISC_REG(0x30E0)
|
|
||||||
#define PINMUX_AUX_DVFS_PWM_0 MAKE_MISC_REG(0x3184)
|
|
||||||
#define PINMUX_AUX_GPIO_PA6_0 MAKE_MISC_REG(0x3244)
|
|
||||||
|
|
||||||
void misc_configure_device_dbg_settings(void);
|
|
||||||
void misc_restore_ram_svop(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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_TOGGLE_0 MAKE_PMC_REG(0x030)
|
|
||||||
#define APBDEV_PMC_REMOVE_CLAMPING_CMD_0 MAKE_PMC_REG(0x034)
|
|
||||||
#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_SCRATCH190_0 MAKE_PMC_REG(0x818)
|
|
||||||
#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4)
|
|
||||||
#define APBDEV_PMC_STICKY_BITS_0 MAKE_PMC_REG(0x2C0)
|
|
||||||
#define APBDEV_PMC_SEC_DISABLE2_0 MAKE_PMC_REG(0x2C4)
|
|
||||||
#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH24_0 MAKE_PMC_REG(0x340)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH25_0 MAKE_PMC_REG(0x344)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH26_0 MAKE_PMC_REG(0x348)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH27_0 MAKE_PMC_REG(0x34C)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH34_0 MAKE_PMC_REG(0x368)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH35_0 MAKE_PMC_REG(0x36C)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH112_0 MAKE_PMC_REG(0xB18)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH113_0 MAKE_PMC_REG(0xB1C)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH114_0 MAKE_PMC_REG(0xB20)
|
|
||||||
#define APBDEV_PMC_SECURE_SCRATCH115_0 MAKE_PMC_REG(0xB24)
|
|
||||||
#define APBDEV_PMC_FUSE_CTRL MAKE_PMC_REG(0x450)
|
|
||||||
#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
|
|
|
@ -1,266 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "lp0.h"
|
|
||||||
#include "se.h"
|
|
||||||
|
|
||||||
static void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
|
||||||
|
|
||||||
/* Initialize a SE linked list. */
|
|
||||||
static void __attribute__((__noinline__)) ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
|
||||||
ll->num_entries = 0; /* 1 Entry. */
|
|
||||||
|
|
||||||
if (buffer != NULL) {
|
|
||||||
ll->addr_info.address = (uint32_t) buffer;
|
|
||||||
ll->addr_info.size = (uint32_t) size;
|
|
||||||
} else {
|
|
||||||
ll->addr_info.address = 0;
|
|
||||||
ll->addr_info.size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_check_error_status_reg(void) {
|
|
||||||
if (se_get_regs()->SE_ERR_STATUS) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_check_for_error(void) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
if (se->SE_INT_STATUS & 0x10000 || se->SE_STATUS & 3 || se->SE_ERR_STATUS) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_verify_flags_cleared(void) {
|
|
||||||
if (se_get_regs()->SE_STATUS & 3) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_aes_keyslot(unsigned int keyslot) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Zero out the whole keyslot and IV. */
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
se->SE_CRYPTO_KEYTABLE_ADDR = (keyslot << 4) | i;
|
|
||||||
se->SE_CRYPTO_KEYTABLE_DATA = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_rsa_keyslot(unsigned int keyslot) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Zero out the whole keyslot. */
|
|
||||||
for (unsigned int i = 0; i < 0x40; i++) {
|
|
||||||
/* Select Keyslot Modulus[i] */
|
|
||||||
se->SE_RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
|
|
||||||
se->SE_RSA_KEYTABLE_DATA = 0;
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < 0x40; i++) {
|
|
||||||
/* Select Keyslot Expontent[i] */
|
|
||||||
se->SE_RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
|
||||||
se->SE_RSA_KEYTABLE_DATA = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_aes_keyslot_iv(unsigned int keyslot) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < (0x10 >> 2); i++) {
|
|
||||||
se->SE_CRYPTO_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
|
||||||
se->SE_CRYPTO_KEYTABLE_DATA = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrypt_data_into_keyslot_256(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
se->SE_CONFIG = (0x202 << 16) | (ALG_AES_DEC | DST_KEYTAB);
|
|
||||||
se->SE_CRYPTO_CONFIG = keyslot_src << 24;
|
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
|
||||||
se->SE_CRYPTO_KEYTABLE_DST = keyslot_dst << 8;
|
|
||||||
|
|
||||||
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
se_ll_t in_ll;
|
|
||||||
se_ll_t out_ll;
|
|
||||||
|
|
||||||
ll_init(&in_ll, (void *)src, src_size);
|
|
||||||
ll_init(&out_ll, dst, dst_size);
|
|
||||||
|
|
||||||
/* Set the LLs. */
|
|
||||||
se->SE_IN_LL_ADDR = (uint32_t)(&in_ll);
|
|
||||||
se->SE_OUT_LL_ADDR = (uint32_t) (&out_ll);
|
|
||||||
|
|
||||||
/* Set registers for operation. */
|
|
||||||
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
|
|
||||||
se->SE_INT_STATUS = se->SE_INT_STATUS;
|
|
||||||
se->SE_OPERATION = op;
|
|
||||||
|
|
||||||
while (!(se->SE_INT_STATUS & 0x10)) { /* Wait a while */ }
|
|
||||||
se_check_for_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Secure AES Functionality. */
|
|
||||||
void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
uint8_t block[0x10] = {0};
|
|
||||||
|
|
||||||
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load src data into block. */
|
|
||||||
if (src_size != 0) {
|
|
||||||
memcpy(block, src, src_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger AES operation. */
|
|
||||||
se_get_regs()->SE_CRYPTO_LAST_BLOCK = 0;
|
|
||||||
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
|
||||||
|
|
||||||
/* Copy output data into dst. */
|
|
||||||
if (dst_size != 0) {
|
|
||||||
memcpy(dst, block, dst_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set configuration high (256-bit vs 128-bit) based on parameter. */
|
|
||||||
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
|
|
||||||
se->SE_CRYPTO_CONFIG = keyslot << 24 | 0x100;
|
|
||||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
se->SE_CONFIG = (ALG_AES_DEC | DST_MEMORY);
|
|
||||||
se->SE_CRYPTO_CONFIG = keyslot << 24;
|
|
||||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shift_left_xor_rb(uint8_t *key) {
|
|
||||||
uint8_t prev_high_bit = 0;
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
uint8_t cur_byte = key[0xF - i];
|
|
||||||
key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
|
|
||||||
prev_high_bit = cur_byte >> 7;
|
|
||||||
}
|
|
||||||
if (prev_high_bit) {
|
|
||||||
key[0xF] ^= 0x87;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate the derived key, to be XOR'd with final output block. */
|
|
||||||
uint8_t ALIGN(16) derived_key[0x10] = {0};
|
|
||||||
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
|
|
||||||
shift_left_xor_rb(derived_key);
|
|
||||||
if (data_size & 0xF) {
|
|
||||||
shift_left_xor_rb(derived_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
se->SE_CONFIG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
|
||||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
|
|
||||||
clear_aes_keyslot_iv(keyslot);
|
|
||||||
|
|
||||||
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
|
||||||
/* Handle aligned blocks. */
|
|
||||||
if (num_blocks > 1) {
|
|
||||||
se->SE_CRYPTO_LAST_BLOCK = num_blocks - 2;
|
|
||||||
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
|
||||||
se->SE_CRYPTO_CONFIG |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create final block. */
|
|
||||||
uint8_t ALIGN(16) last_block[0x10] = {0};
|
|
||||||
if (data_size & 0xF) {
|
|
||||||
memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
|
|
||||||
last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
|
|
||||||
} else if (data_size >= 0x10) {
|
|
||||||
memcpy(last_block, data + data_size - 0x10, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
last_block[i] ^= derived_key[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform last operation. */
|
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
|
||||||
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
|
|
||||||
|
|
||||||
/* Copy output CMAC. */
|
|
||||||
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
|
|
||||||
((uint32_t *)cmac)[i] = ((volatile uint32_t *)se->SE_HASH_RESULT)[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
|
|
||||||
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_aes_256_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
se->SE_CONFIG = (ALG_AES_DEC | DST_MEMORY) | (0x202 << 16);
|
|
||||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x66;
|
|
||||||
clear_aes_keyslot_iv(keyslot);
|
|
||||||
se->SE_CRYPTO_LAST_BLOCK = (src_size >> 4) - 1;
|
|
||||||
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
|
|
||||||
}
|
|
|
@ -1,179 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_SE_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_SE_H
|
|
||||||
|
|
||||||
#define SE_BASE 0x70012000
|
|
||||||
#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n)
|
|
||||||
|
|
||||||
#define KEYSLOT_SWITCH_LP0TZRAMKEK 0x2
|
|
||||||
#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x3
|
|
||||||
#define KEYSLOT_SWITCH_SRKGENKEY 0x8
|
|
||||||
#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
|
|
||||||
#define KEYSLOT_SWITCH_TEMPKEY 0x9
|
|
||||||
#define KEYSLOT_SWITCH_SESSIONKEY 0xA
|
|
||||||
#define KEYSLOT_SWITCH_RNGKEY 0xB
|
|
||||||
#define KEYSLOT_SWITCH_MASTERKEY 0xC
|
|
||||||
#define KEYSLOT_SWITCH_DEVICEKEY 0xD
|
|
||||||
|
|
||||||
/* This keyslot was added in 4.0.0. */
|
|
||||||
#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
|
|
||||||
#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
|
|
||||||
#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
|
|
||||||
|
|
||||||
/* This keyslot was added in 5.0.0. */
|
|
||||||
#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
|
|
||||||
|
|
||||||
#define KEYSLOT_AES_MAX 0x10
|
|
||||||
#define KEYSLOT_RSA_MAX 0x2
|
|
||||||
|
|
||||||
#define KEYSIZE_AES_MAX 0x20
|
|
||||||
#define KEYSIZE_RSA_MAX 0x100
|
|
||||||
|
|
||||||
#define ALG_SHIFT (12)
|
|
||||||
#define ALG_DEC_SHIFT (8)
|
|
||||||
#define ALG_NOP (0 << ALG_SHIFT)
|
|
||||||
#define ALG_AES_ENC (1 << ALG_SHIFT)
|
|
||||||
#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
|
|
||||||
#define ALG_RNG (2 << ALG_SHIFT)
|
|
||||||
#define ALG_SHA (3 << ALG_SHIFT)
|
|
||||||
#define ALG_RSA (4 << ALG_SHIFT)
|
|
||||||
|
|
||||||
#define DST_SHIFT (2)
|
|
||||||
#define DST_MEMORY (0 << DST_SHIFT)
|
|
||||||
#define DST_HASHREG (1 << DST_SHIFT)
|
|
||||||
#define DST_KEYTAB (2 << DST_SHIFT)
|
|
||||||
#define DST_SRK (3 << DST_SHIFT)
|
|
||||||
#define DST_RSAREG (4 << DST_SHIFT)
|
|
||||||
|
|
||||||
#define ENCMODE_SHIFT (24)
|
|
||||||
#define DECMODE_SHIFT (16)
|
|
||||||
#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT)
|
|
||||||
|
|
||||||
#define HASH_DISABLE (0x0)
|
|
||||||
#define HASH_ENABLE (0x1)
|
|
||||||
|
|
||||||
#define OP_ABORT 0
|
|
||||||
#define OP_START 1
|
|
||||||
#define OP_RESTART 2
|
|
||||||
#define OP_CTX_SAVE 3
|
|
||||||
#define OP_RESTART_IN 4
|
|
||||||
|
|
||||||
#define CTX_SAVE_SRC_SHIFT 29
|
|
||||||
#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
|
|
||||||
#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
|
|
||||||
#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
|
|
||||||
#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
|
|
||||||
#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
|
|
||||||
|
|
||||||
#define CTX_SAVE_KEY_LOW_BITS 0
|
|
||||||
#define CTX_SAVE_KEY_HIGH_BITS 1
|
|
||||||
#define CTX_SAVE_KEY_ORIGINAL_IV 2
|
|
||||||
#define CTX_SAVE_KEY_UPDATED_IV 3
|
|
||||||
|
|
||||||
#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
|
|
||||||
#define CTX_SAVE_KEY_INDEX_SHIFT 8
|
|
||||||
#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
|
|
||||||
#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
|
|
||||||
|
|
||||||
#define RSA_2048_BYTES 0x100
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t SE_SE_SECURITY;
|
|
||||||
uint32_t SE_TZRAM_SECURITY;
|
|
||||||
uint32_t SE_OPERATION;
|
|
||||||
uint32_t SE_INT_ENABLE;
|
|
||||||
uint32_t SE_INT_STATUS;
|
|
||||||
uint32_t SE_CONFIG;
|
|
||||||
uint32_t SE_IN_LL_ADDR;
|
|
||||||
uint32_t SE_IN_CUR_BYTE_ADDR;
|
|
||||||
uint32_t SE_IN_CUR_LL_ID;
|
|
||||||
uint32_t SE_OUT_LL_ADDR;
|
|
||||||
uint32_t SE_OUT_CUR_BYTE_ADDR;
|
|
||||||
uint32_t SE_OUT_CUR_LL_ID;
|
|
||||||
uint32_t SE_HASH_RESULT[0x10];
|
|
||||||
uint32_t SE_CTX_SAVE_CONFIG;
|
|
||||||
uint32_t _0x74[0x63];
|
|
||||||
uint32_t SE_SHA_CONFIG;
|
|
||||||
uint32_t SE_SHA_MSG_LENGTH[0x4];
|
|
||||||
uint32_t SE_SHA_MSG_LEFT[0x4];
|
|
||||||
uint32_t _0x224[0x17];
|
|
||||||
uint32_t SE_CRYPTO_SECURITY_PERKEY;
|
|
||||||
uint32_t SE_CRYPTO_KEYTABLE_ACCESS[0x10];
|
|
||||||
uint32_t _0x2C4[0x10];
|
|
||||||
uint32_t SE_CRYPTO_CONFIG;
|
|
||||||
uint32_t SE_CRYPTO_LINEAR_CTR[0x4];
|
|
||||||
uint32_t SE_CRYPTO_LAST_BLOCK;
|
|
||||||
uint32_t SE_CRYPTO_KEYTABLE_ADDR;
|
|
||||||
uint32_t SE_CRYPTO_KEYTABLE_DATA;
|
|
||||||
uint32_t _0x324[0x3];
|
|
||||||
uint32_t SE_CRYPTO_KEYTABLE_DST;
|
|
||||||
uint32_t _0x334[0x3];
|
|
||||||
uint32_t SE_RNG_CONFIG;
|
|
||||||
uint32_t SE_RNG_SRC_CONFIG;
|
|
||||||
uint32_t SE_RNG_RESEED_INTERVAL;
|
|
||||||
uint32_t _0x34C[0x2D];
|
|
||||||
uint32_t SE_RSA_CONFIG;
|
|
||||||
uint32_t SE_RSA_KEY_SIZE;
|
|
||||||
uint32_t SE_RSA_EXP_SIZE;
|
|
||||||
uint32_t SE_RSA_SECURITY_PERKEY;
|
|
||||||
uint32_t SE_RSA_KEYTABLE_ACCESS[0x2];
|
|
||||||
uint32_t _0x418[0x2];
|
|
||||||
uint32_t SE_RSA_KEYTABLE_ADDR;
|
|
||||||
uint32_t SE_RSA_KEYTABLE_DATA;
|
|
||||||
uint32_t SE_RSA_OUTPUT[0x40];
|
|
||||||
uint32_t _0x528[0xB6];
|
|
||||||
uint32_t SE_STATUS;
|
|
||||||
uint32_t SE_ERR_STATUS;
|
|
||||||
uint32_t SE_MISC;
|
|
||||||
uint32_t SE_SPARE;
|
|
||||||
uint32_t SE_ENTROPY_DEBUG_COUNTER;
|
|
||||||
uint32_t _0x814;
|
|
||||||
uint32_t _0x818;
|
|
||||||
uint32_t _0x81C;
|
|
||||||
uint32_t _0x820[0x5F8];
|
|
||||||
} tegra_se_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t address;
|
|
||||||
uint32_t size;
|
|
||||||
} se_addr_info_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t num_entries; /* Set to total entries - 1 */
|
|
||||||
se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
|
|
||||||
} se_ll_t;
|
|
||||||
|
|
||||||
static inline volatile tegra_se_t *se_get_regs(void) {
|
|
||||||
return (volatile tegra_se_t *)SE_BASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_check_error_status_reg(void);
|
|
||||||
void se_check_for_error(void);
|
|
||||||
|
|
||||||
void se_verify_flags_cleared(void);
|
|
||||||
|
|
||||||
void clear_aes_keyslot(unsigned int keyslot);
|
|
||||||
void clear_rsa_keyslot(unsigned int keyslot);
|
|
||||||
void clear_aes_keyslot_iv(unsigned int keyslot);
|
|
||||||
|
|
||||||
void decrypt_data_into_keyslot_256(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size);
|
|
||||||
|
|
||||||
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
|
|
||||||
void se_aes_256_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,129 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "lp0.h"
|
|
||||||
#include "secmon.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
|
|
||||||
/* "private" functions. */
|
|
||||||
static bool secmon_should_clear_aes_keyslot(unsigned int keyslot);
|
|
||||||
static void secmon_clear_unused_keyslots(void);
|
|
||||||
static void secmon_decrypt_saved_image(void *dst, const void *src, size_t size);
|
|
||||||
|
|
||||||
void secmon_restore_to_tzram(const uint32_t target_firmware) {
|
|
||||||
/* Newer warmboot binaries clear the untouched keyslots for safety. */
|
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
secmon_clear_unused_keyslots();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decrypt Secure Monitor from DRAM into TZRAM. */
|
|
||||||
void *tzram_src = (void *)(0x80010000);
|
|
||||||
void *tzram_dst = (void *)(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0 ? 0x7C012000 : 0x7C010000);
|
|
||||||
const size_t tzram_size = 0xE000;
|
|
||||||
secmon_decrypt_saved_image(tzram_dst, tzram_src, tzram_size);
|
|
||||||
|
|
||||||
/* Nintendo clears DRAM, but I'm not sure why, given they lock out BPMP access to DRAM. */
|
|
||||||
for (size_t i = 0; i < tzram_size/sizeof(uint32_t); i++) {
|
|
||||||
((volatile uint32_t *)tzram_src)[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make security engine require secure busmaster. */
|
|
||||||
se_get_regs()->SE_TZRAM_SECURITY = 0;
|
|
||||||
|
|
||||||
/* TODO: se_verify_keys_unreadable(); */
|
|
||||||
|
|
||||||
/* TODO: pmc_lockout_wb_scratch_registers(); */
|
|
||||||
|
|
||||||
/* Disable fuse programming. */
|
|
||||||
fuse_disable_programming();
|
|
||||||
}
|
|
||||||
|
|
||||||
void secmon_decrypt_saved_image(void *dst, const void *src, size_t size) {
|
|
||||||
/* Derive the key used for context save. */
|
|
||||||
{
|
|
||||||
const uint32_t key_source[4] = { APBDEV_PMC_SECURE_SCRATCH24_0, APBDEV_PMC_SECURE_SCRATCH25_0, APBDEV_PMC_SECURE_SCRATCH26_0, APBDEV_PMC_SECURE_SCRATCH27_0 };
|
|
||||||
|
|
||||||
clear_aes_keyslot(KEYSLOT_SWITCH_LP0TZRAMKEY);
|
|
||||||
decrypt_data_into_keyslot_256(KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_LP0TZRAMKEK, key_source, sizeof(key_source));
|
|
||||||
|
|
||||||
clear_aes_keyslot(KEYSLOT_SWITCH_LP0TZRAMKEK);
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH24_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH25_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH26_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH27_0 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First, AES-256-CBC decrypt the image into TZRAM. */
|
|
||||||
se_aes_256_cbc_decrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, dst, size, src, size);
|
|
||||||
|
|
||||||
/* Next, calculate CMAC. */
|
|
||||||
uint32_t tzram_cmac[4] = {0, 0, 0, 0};
|
|
||||||
se_compute_aes_256_cmac(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_cmac, sizeof(tzram_cmac), dst, size);
|
|
||||||
|
|
||||||
/* Validate the MAC against saved one in PMC scratch. */
|
|
||||||
if (tzram_cmac[0] != APBDEV_PMC_SECURE_SCRATCH112_0 ||
|
|
||||||
tzram_cmac[1] != APBDEV_PMC_SECURE_SCRATCH113_0 ||
|
|
||||||
tzram_cmac[2] != APBDEV_PMC_SECURE_SCRATCH114_0 ||
|
|
||||||
tzram_cmac[3] != APBDEV_PMC_SECURE_SCRATCH115_0) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the PMC scratch registers that hold the CMAC. */
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH112_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH113_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH114_0 = 0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH115_0 = 0;
|
|
||||||
|
|
||||||
/* Clear keyslot now that we're done with it. */
|
|
||||||
clear_aes_keyslot(KEYSLOT_SWITCH_LP0TZRAMKEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool secmon_should_clear_aes_keyslot(unsigned int keyslot) {
|
|
||||||
/* We'll just compare keyslot against a hardcoded list of keys. */
|
|
||||||
static const uint8_t saved_keyslots[6] = {
|
|
||||||
KEYSLOT_SWITCH_LP0TZRAMKEK,
|
|
||||||
KEYSLOT_SWITCH_SESSIONKEY,
|
|
||||||
KEYSLOT_SWITCH_RNGKEY,
|
|
||||||
KEYSLOT_SWITCH_MASTERKEY,
|
|
||||||
KEYSLOT_SWITCH_DEVICEKEY,
|
|
||||||
KEYSLOT_SWITCH_4XOLDDEVICEKEY
|
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(saved_keyslots)/sizeof(saved_keyslots[0]); i++) {
|
|
||||||
if (keyslot == saved_keyslots[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void secmon_clear_unused_keyslots(void) {
|
|
||||||
/* Clear unused keyslots. */
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
|
||||||
if (secmon_should_clear_aes_keyslot(i)) {
|
|
||||||
clear_aes_keyslot(i);
|
|
||||||
}
|
|
||||||
clear_aes_keyslot_iv(i);
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
|
||||||
clear_rsa_keyslot(i);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_SECMON_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_SECMON_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
void secmon_restore_to_tzram(const uint32_t target_firmware);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.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
|
|
||||||
|
|
||||||
.global _metadata
|
|
||||||
_metadata:
|
|
||||||
.ascii "WBT0" /* Magic number */
|
|
||||||
.word 0x00000000 /* Target firmware. */
|
|
||||||
.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
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_SYSREG_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_SYSREG_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define SYSREG_BASE (0x6000C000)
|
|
||||||
|
|
||||||
#define SB_BASE (SYSREG_BASE + 0x200)
|
|
||||||
|
|
||||||
#define MAKE_SYSREG(n) MAKE_REG32(SYSREG_BASE + n)
|
|
||||||
#define MAKE_SB_REG(n) MAKE_REG32(SB_BASE + n)
|
|
||||||
|
|
||||||
#define AHB_ARBITRATION_DISABLE_0 MAKE_SYSREG(0x004)
|
|
||||||
|
|
||||||
#define SB_CSR_0 MAKE_SB_REG(0x00)
|
|
||||||
#define SB_PIROM_START_0 MAKE_SB_REG(0x04)
|
|
||||||
#define SB_PFCFG_0 MAKE_SB_REG(0x08)
|
|
||||||
#define SB_SECURE_SPAREREG_0_0 MAKE_SB_REG(0x0C)
|
|
||||||
#define SB_SECURE_SPAREREG_1_0 MAKE_SB_REG(0x10)
|
|
||||||
#define SB_SECURE_SPAREREG_2_0 MAKE_SB_REG(0x14)
|
|
||||||
#define SB_SECURE_SPAREREG_3_0 MAKE_SB_REG(0x18)
|
|
||||||
#define SB_SECURE_SPAREREG_4_0 MAKE_SB_REG(0x1C)
|
|
||||||
#define SB_SECURE_SPAREREG_5_0 MAKE_SB_REG(0x20)
|
|
||||||
#define SB_SECURE_SPAREREG_6_0 MAKE_SB_REG(0x24)
|
|
||||||
#define SB_SECURE_SPAREREG_7_0 MAKE_SB_REG(0x28)
|
|
||||||
#define SB_AA64_RESET_LOW_0 MAKE_SB_REG(0x30)
|
|
||||||
#define SB_AA64_RESET_HIGH_0 MAKE_SB_REG(0x34)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_TIMER_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_TIMER_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define TIMERUS_CNTR_1US_0 MAKE_REG32(0x60005010)
|
|
||||||
#define TIMERUS_USEC_CFG_0 MAKE_REG32(0x60005014)
|
|
||||||
|
|
||||||
static inline void timer_wait(uint32_t microseconds) {
|
|
||||||
const 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
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_WARMBOOT_BIN_UTILS_H
|
|
||||||
#define EXOSPHERE_WARMBOOT_BIN_UTILS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vapours/ams_version.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))
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,154 +0,0 @@
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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 \
|
|
||||||
-Os \
|
|
||||||
-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
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
|
@ -1,18 +0,0 @@
|
||||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
|
||||||
OUTPUT_ARCH(arm)
|
|
||||||
|
|
||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x4003F000;
|
|
||||||
|
|
||||||
__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(.);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
%rename link old_link
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
|
@ -1,169 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "max77620.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
|
||||||
void i2c_load_config(void);
|
|
||||||
int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes);
|
|
||||||
int i2c_read(unsigned int device, void *dst, unsigned num_bytes);
|
|
||||||
int i2c_query(uint8_t device, uint8_t r, void *dst, size_t num_bytes);
|
|
||||||
int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b);
|
|
||||||
|
|
||||||
/* Load hardware config for I2C4. */
|
|
||||||
void i2c_load_config(void) {
|
|
||||||
/* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */
|
|
||||||
I2C_I2C_CONFIG_LOAD_0 = 0x25;
|
|
||||||
|
|
||||||
/* Wait a bit for master config to be loaded. */
|
|
||||||
for (unsigned int i = 0; i < 20; i++) {
|
|
||||||
timer_wait(1);
|
|
||||||
if (!(I2C_I2C_CONFIG_LOAD_0 & 1)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize I2C4. */
|
|
||||||
void i2c_init(void) {
|
|
||||||
/* Setup divisor, and clear the bus. */
|
|
||||||
I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001;
|
|
||||||
I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003;
|
|
||||||
|
|
||||||
/* Load hardware configuration. */
|
|
||||||
i2c_load_config();
|
|
||||||
|
|
||||||
/* Wait a while until BUS_CLEAR_DONE is set. */
|
|
||||||
for (unsigned int i = 0; i < 10; i++) {
|
|
||||||
timer_wait(20000);
|
|
||||||
if (I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the BUS_CLEAR_STATUS. Result doesn't matter. */
|
|
||||||
I2C_I2C_BUS_CLEAR_STATUS_0;
|
|
||||||
|
|
||||||
/* Read and set the Interrupt Status. */
|
|
||||||
uint32_t int_status = I2C_INTERRUPT_STATUS_REGISTER_0;
|
|
||||||
I2C_INTERRUPT_STATUS_REGISTER_0 = int_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a value to an i2c device. */
|
|
||||||
int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes) {
|
|
||||||
if (num_bytes > 4) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit mode. */
|
|
||||||
I2C_I2C_CMD_ADDR0_0 = device << 1;
|
|
||||||
|
|
||||||
/* Load in data to write. */
|
|
||||||
I2C_I2C_CMD_DATA1_0 = val;
|
|
||||||
|
|
||||||
/* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800;
|
|
||||||
|
|
||||||
i2c_load_config();
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
I2C_I2C_CNFG_0 |= 0x200;
|
|
||||||
|
|
||||||
|
|
||||||
while (I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */
|
|
||||||
return (I2C_I2C_STATUS_0 & 0xF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reads a value from an i2c device. */
|
|
||||||
int i2c_read(unsigned device, void *dst, unsigned num_bytes) {
|
|
||||||
if (num_bytes > 4) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit read mode. */
|
|
||||||
I2C_I2C_CMD_ADDR0_0 = (device << 1) | 1;
|
|
||||||
|
|
||||||
/* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2840;
|
|
||||||
|
|
||||||
i2c_load_config();
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
I2C_I2C_CNFG_0 |= 0x200;
|
|
||||||
|
|
||||||
|
|
||||||
while (I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure success. */
|
|
||||||
if ((I2C_I2C_STATUS_0 & 0xF) != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t val = I2C_I2C_CMD_DATA1_0;
|
|
||||||
for (size_t i = 0; i < num_bytes; i++) {
|
|
||||||
((uint8_t *)dst)[i] = ((uint8_t *)&val)[i];
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Queries the value of a register. */
|
|
||||||
int i2c_query(uint8_t device, uint8_t r, void *dst, size_t num_bytes) {
|
|
||||||
/* Limit output size to 32-bits. */
|
|
||||||
if (num_bytes > 4) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write single byte register ID to device. */
|
|
||||||
if (!i2c_write(device, r, 1)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i2c_read(device, dst, num_bytes);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a byte val to reg for given device. */
|
|
||||||
int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b) {
|
|
||||||
uint32_t val = (reg) | (b << 8);
|
|
||||||
/* Write 1 byte (reg) + 1 byte (value) */
|
|
||||||
return i2c_write(device, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void i2c_stop_rtc_alarm(void) {
|
|
||||||
i2c_send_byte_command(MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCUPDATE0, 0x10);
|
|
||||||
|
|
||||||
uint8_t val = 0;
|
|
||||||
for (int i = 0; i < 14; i++) {
|
|
||||||
if (i2c_query(MAX77620_RTC_I2C_ADDR, 0x0E + i, &val, 1)) {
|
|
||||||
val &= 0x7F;
|
|
||||||
i2c_send_byte_command(MAX77620_RTC_I2C_ADDR, 0x0E + i, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i2c_send_byte_command(MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCUPDATE0, 0x01);
|
|
||||||
}
|
|
||||||
|
|
||||||
void i2c_send_shutdown_cmd(void) {
|
|
||||||
i2c_send_byte_command(MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_REBOOTSTUB_I2C_H
|
|
||||||
#define EXOSPHERE_REBOOTSTUB_I2C_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/* I2C_BASE = I2C4. */
|
|
||||||
#define I2C_BASE (0x7000D000)
|
|
||||||
|
|
||||||
#define MAKE_I2C_REG(ofs) (MAKE_REG32(I2C_BASE + ofs))
|
|
||||||
|
|
||||||
#define I2C_I2C_CNFG_0 MAKE_I2C_REG(0x000)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_ADDR0_0 MAKE_I2C_REG(0x004)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_DATA1_0 MAKE_I2C_REG(0x00C)
|
|
||||||
|
|
||||||
#define I2C_I2C_STATUS_0 MAKE_I2C_REG(0x01C)
|
|
||||||
|
|
||||||
#define I2C_INTERRUPT_STATUS_REGISTER_0 MAKE_I2C_REG(0x068)
|
|
||||||
|
|
||||||
#define I2C_I2C_CLK_DIVISOR_REGISTER_0 MAKE_I2C_REG(0x06C)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_CONFIG_0 MAKE_I2C_REG(0x084)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_STATUS_0 MAKE_I2C_REG(0x088)
|
|
||||||
|
|
||||||
|
|
||||||
#define I2C_I2C_CONFIG_LOAD_0 MAKE_I2C_REG(0x08C)
|
|
||||||
|
|
||||||
void i2c_init(void);
|
|
||||||
|
|
||||||
void i2c_stop_rtc_alarm(void);
|
|
||||||
void i2c_send_shutdown_cmd(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,360 +0,0 @@
|
||||||
/*
|
|
||||||
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MFD_MAX77620_H_
|
|
||||||
#define _MFD_MAX77620_H_
|
|
||||||
|
|
||||||
#define MAX77620_I2C_ADDR 0x3C
|
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
|
||||||
|
|
||||||
/* RTC Registers */
|
|
||||||
#define MAX77620_REG_RTCINT 0x00
|
|
||||||
#define MAX77620_REG_RTCINTM 0x01
|
|
||||||
#define MAX77620_REG_RTCCNTLM 0x02
|
|
||||||
#define MAX77620_REG_RTCCNTL 0x03
|
|
||||||
#define MAX77620_REG_RTCUPDATE0 0x04
|
|
||||||
#define MAX77620_REG_RTCUPDATE1 0x05
|
|
||||||
#define MAX77620_REG_RTCSMPL 0x06
|
|
||||||
#define MAX77620_REG_RTCSEC 0x07
|
|
||||||
#define MAX77620_REG_RTCMIN 0x08
|
|
||||||
#define MAX77620_REG_RTCHOUR 0x09
|
|
||||||
#define MAX77620_REG_RTCDOW 0x0A
|
|
||||||
#define MAX77620_REG_RTCMONTH 0x0B
|
|
||||||
#define MAX77620_REG_RTCYEAR 0x0C
|
|
||||||
#define MAX77620_REG_RTCDOM 0x0D
|
|
||||||
#define MAX77620_REG_RTCSECA1 0x0E
|
|
||||||
#define MAX77620_REG_RTCMINA1 0x0F
|
|
||||||
#define MAX77620_REG_RTCHOURA1 0x10
|
|
||||||
#define MAX77620_REG_RTCDOWA1 0x11
|
|
||||||
#define MAX77620_REG_RTCMONTHA1 0x12
|
|
||||||
#define MAX77620_REG_RTCYEARA1 0x13
|
|
||||||
#define MAX77620_REG_RTCDOMA1 0x14
|
|
||||||
#define MAX77620_REG_RTCSECA2 0x15
|
|
||||||
#define MAX77620_REG_RTCMINA2 0x16
|
|
||||||
#define MAX77620_REG_RTCHOURA2 0x17
|
|
||||||
#define MAX77620_REG_RTCDOWA2 0x18
|
|
||||||
#define MAX77620_REG_RTCMONTHA2 0x19
|
|
||||||
#define MAX77620_REG_RTCYEARA2 0x1A
|
|
||||||
#define MAX77620_REG_RTCDOMA2 0x1B
|
|
||||||
|
|
||||||
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
|
||||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
|
||||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
|
||||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
|
||||||
#define MAX77620_REG_CNFG1_32K 0x03
|
|
||||||
#define MAX77620_REG_CNFGBBC 0x04
|
|
||||||
#define MAX77620_REG_IRQTOP 0x05
|
|
||||||
#define MAX77620_REG_INTLBT 0x06
|
|
||||||
#define MAX77620_REG_IRQSD 0x07
|
|
||||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
|
||||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
|
||||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
|
||||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
|
||||||
#define MAX77620_REG_NVERC 0x0C
|
|
||||||
#define MAX77620_REG_IRQTOPM 0x0D
|
|
||||||
#define MAX77620_REG_INTENLBT 0x0E
|
|
||||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
|
||||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
|
||||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
|
||||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
|
||||||
#define MAX77620_REG_STATLBT 0x13
|
|
||||||
#define MAX77620_REG_STATSD 0x14
|
|
||||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
|
||||||
|
|
||||||
/* SD and LDO Registers */
|
|
||||||
#define MAX77620_REG_SD0 0x16
|
|
||||||
#define MAX77620_REG_SD1 0x17
|
|
||||||
#define MAX77620_REG_SD2 0x18
|
|
||||||
#define MAX77620_REG_SD3 0x19
|
|
||||||
#define MAX77620_REG_SD4 0x1A
|
|
||||||
#define MAX77620_REG_DVSSD0 0x1B
|
|
||||||
#define MAX77620_REG_DVSSD1 0x1C
|
|
||||||
#define MAX77620_REG_SD0_CFG 0x1D
|
|
||||||
#define MAX77620_REG_SD1_CFG 0x1E
|
|
||||||
#define MAX77620_REG_SD2_CFG 0x1F
|
|
||||||
#define MAX77620_REG_SD3_CFG 0x20
|
|
||||||
#define MAX77620_REG_SD4_CFG 0x21
|
|
||||||
#define MAX77620_REG_SD_CFG2 0x22
|
|
||||||
#define MAX77620_REG_LDO0_CFG 0x23
|
|
||||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
|
||||||
#define MAX77620_REG_LDO1_CFG 0x25
|
|
||||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
|
||||||
#define MAX77620_REG_LDO2_CFG 0x27
|
|
||||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
|
||||||
#define MAX77620_REG_LDO3_CFG 0x29
|
|
||||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
|
||||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
|
||||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
|
||||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
|
||||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
|
||||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
|
||||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
|
||||||
#define MAX77620_REG_LDO7_CFG 0x31
|
|
||||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
|
||||||
#define MAX77620_REG_LDO8_CFG 0x33
|
|
||||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
|
||||||
#define MAX77620_REG_LDO_CFG3 0x35
|
|
||||||
|
|
||||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
|
||||||
|
|
||||||
/* LDO Configuration 3 */
|
|
||||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
|
||||||
#define MAX77620_TRACK4_SHIFT 5
|
|
||||||
|
|
||||||
/* Voltage */
|
|
||||||
#define MAX77620_SDX_VOLT_MASK 0xFF
|
|
||||||
#define MAX77620_SD0_VOLT_MASK 0x3F
|
|
||||||
#define MAX77620_SD1_VOLT_MASK 0x7F
|
|
||||||
#define MAX77620_LDO_VOLT_MASK 0x3F
|
|
||||||
|
|
||||||
#define MAX77620_REG_GPIO0 0x36
|
|
||||||
#define MAX77620_REG_GPIO1 0x37
|
|
||||||
#define MAX77620_REG_GPIO2 0x38
|
|
||||||
#define MAX77620_REG_GPIO3 0x39
|
|
||||||
#define MAX77620_REG_GPIO4 0x3A
|
|
||||||
#define MAX77620_REG_GPIO5 0x3B
|
|
||||||
#define MAX77620_REG_GPIO6 0x3C
|
|
||||||
#define MAX77620_REG_GPIO7 0x3D
|
|
||||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
|
||||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
|
||||||
#define MAX77620_REG_AME_GPIO 0x40
|
|
||||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
|
||||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
|
||||||
|
|
||||||
/* FPS Registers */
|
|
||||||
#define MAX77620_REG_FPS_CFG0 0x43
|
|
||||||
#define MAX77620_REG_FPS_CFG1 0x44
|
|
||||||
#define MAX77620_REG_FPS_CFG2 0x45
|
|
||||||
#define MAX77620_REG_FPS_LDO0 0x46
|
|
||||||
#define MAX77620_REG_FPS_LDO1 0x47
|
|
||||||
#define MAX77620_REG_FPS_LDO2 0x48
|
|
||||||
#define MAX77620_REG_FPS_LDO3 0x49
|
|
||||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
|
||||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
|
||||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
|
||||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
|
||||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
|
||||||
#define MAX77620_REG_FPS_SD0 0x4F
|
|
||||||
#define MAX77620_REG_FPS_SD1 0x50
|
|
||||||
#define MAX77620_REG_FPS_SD2 0x51
|
|
||||||
#define MAX77620_REG_FPS_SD3 0x52
|
|
||||||
#define MAX77620_REG_FPS_SD4 0x53
|
|
||||||
#define MAX77620_REG_FPS_NONE 0
|
|
||||||
|
|
||||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
|
||||||
#define MAX77620_FPS_SRC_SHIFT 6
|
|
||||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
|
||||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
|
||||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
|
||||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
|
||||||
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
|
||||||
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
|
||||||
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
|
||||||
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
|
||||||
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
|
||||||
#define MAX77620_FPS_ENFPS_SW 0x01
|
|
||||||
|
|
||||||
/* Minimum and maximum FPS period time (in microseconds) are
|
|
||||||
* different for MAX77620 and Max20024.
|
|
||||||
*/
|
|
||||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
|
||||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
|
||||||
|
|
||||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
|
||||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
|
||||||
|
|
||||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
|
||||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
|
||||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
|
||||||
#define MAX77620_REG_FPS_RSO 0x57
|
|
||||||
#define MAX77620_REG_CID0 0x58
|
|
||||||
#define MAX77620_REG_CID1 0x59
|
|
||||||
#define MAX77620_REG_CID2 0x5A
|
|
||||||
#define MAX77620_REG_CID3 0x5B
|
|
||||||
#define MAX77620_REG_CID4 0x5C
|
|
||||||
#define MAX77620_REG_CID5 0x5D
|
|
||||||
|
|
||||||
#define MAX77620_REG_DVSSD4 0x5E
|
|
||||||
#define MAX20024_REG_MAX_ADD 0x70
|
|
||||||
|
|
||||||
#define MAX77620_CID_DIDM_MASK 0xF0
|
|
||||||
#define MAX77620_CID_DIDM_SHIFT 4
|
|
||||||
|
|
||||||
/* CNCG2SD */
|
|
||||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
|
||||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
|
||||||
|
|
||||||
/* Device Identification Metal */
|
|
||||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
|
||||||
/* Device Indentification OTP */
|
|
||||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
|
||||||
|
|
||||||
/* SD CNFG1 */
|
|
||||||
#define MAX77620_SD_SR_MASK 0xC0
|
|
||||||
#define MAX77620_SD_SR_SHIFT 6
|
|
||||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
|
||||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
|
||||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
|
||||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
|
||||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
|
||||||
#define MAX77620_SD_FPWM_MASK 0x04
|
|
||||||
#define MAX77620_SD_FPWM_SHIFT 2
|
|
||||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
|
||||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
|
||||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
|
||||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
|
||||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
|
||||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
|
||||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
|
||||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
|
||||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
|
||||||
|
|
||||||
/* LDO_CNFG2 */
|
|
||||||
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
|
||||||
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
|
||||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
|
||||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
|
||||||
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
|
|
||||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
|
||||||
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
|
||||||
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
|
||||||
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
|
||||||
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
|
||||||
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
|
||||||
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
|
||||||
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
|
||||||
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
|
||||||
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
|
||||||
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
|
|
||||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
|
||||||
|
|
||||||
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
|
||||||
|
|
||||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
|
||||||
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
|
||||||
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
|
||||||
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
|
||||||
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
|
||||||
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
|
||||||
|
|
||||||
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
|
||||||
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
|
||||||
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
|
||||||
|
|
||||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
|
||||||
|
|
||||||
#define MAX77620_WDTC_MASK 0x3
|
|
||||||
#define MAX77620_WDTOFFC (1 << 4)
|
|
||||||
#define MAX77620_WDTSLPC (1 << 3)
|
|
||||||
#define MAX77620_WDTEN (1 << 2)
|
|
||||||
|
|
||||||
#define MAX77620_TWD_MASK 0x3
|
|
||||||
#define MAX77620_TWD_2s 0x0
|
|
||||||
#define MAX77620_TWD_16s 0x1
|
|
||||||
#define MAX77620_TWD_64s 0x2
|
|
||||||
#define MAX77620_TWD_128s 0x3
|
|
||||||
|
|
||||||
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
|
||||||
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
|
||||||
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
|
||||||
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
|
|
||||||
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
|
|
||||||
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
|
|
||||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
|
||||||
|
|
||||||
/* CNFG BBC registers */
|
|
||||||
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
|
||||||
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
|
||||||
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
|
||||||
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
|
||||||
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
|
||||||
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
|
||||||
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
|
||||||
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
|
||||||
|
|
||||||
#define MAX77620_FPS_COUNT 3
|
|
||||||
|
|
||||||
/* Interrupts */
|
|
||||||
enum {
|
|
||||||
MAX77620_IRQ_TOP_GLBL, /* Low-Battery */
|
|
||||||
MAX77620_IRQ_TOP_SD, /* SD power fail */
|
|
||||||
MAX77620_IRQ_TOP_LDO, /* LDO power fail */
|
|
||||||
MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */
|
|
||||||
MAX77620_IRQ_TOP_RTC, /* RTC */
|
|
||||||
MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */
|
|
||||||
MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */
|
|
||||||
MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */
|
|
||||||
MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */
|
|
||||||
MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* GPIOs */
|
|
||||||
enum {
|
|
||||||
MAX77620_GPIO0,
|
|
||||||
MAX77620_GPIO1,
|
|
||||||
MAX77620_GPIO2,
|
|
||||||
MAX77620_GPIO3,
|
|
||||||
MAX77620_GPIO4,
|
|
||||||
MAX77620_GPIO5,
|
|
||||||
MAX77620_GPIO6,
|
|
||||||
MAX77620_GPIO7,
|
|
||||||
MAX77620_GPIO_NR,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* FPS Source */
|
|
||||||
enum max77620_fps_src {
|
|
||||||
MAX77620_FPS_SRC_0,
|
|
||||||
MAX77620_FPS_SRC_1,
|
|
||||||
MAX77620_FPS_SRC_2,
|
|
||||||
MAX77620_FPS_SRC_NONE,
|
|
||||||
MAX77620_FPS_SRC_DEF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum max77620_chip_id {
|
|
||||||
MAX77620,
|
|
||||||
MAX20024,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _MFD_MAX77620_H_ */
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
void do_shutdown(void) {
|
|
||||||
/* Initialize i2c. */
|
|
||||||
i2c_init();
|
|
||||||
|
|
||||||
/* Stop alarm, shutdown. */
|
|
||||||
i2c_stop_rtc_alarm();
|
|
||||||
i2c_send_shutdown_cmd();
|
|
||||||
|
|
||||||
while (true) { }
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.section .text.start
|
|
||||||
.align 4
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
ldr r0, reboot_type
|
|
||||||
cmp r0, #0x0
|
|
||||||
beq do_shutdown
|
|
||||||
b jump_to_reboot_payload
|
|
||||||
reboot_type:
|
|
||||||
.word 0x00000001
|
|
||||||
|
|
||||||
.global jump_to_reboot_payload
|
|
||||||
.type jump_to_reboot_payload, %function
|
|
||||||
jump_to_reboot_payload:
|
|
||||||
@ clear all registers
|
|
||||||
ldr r0, =0x52425430 @ RBT0
|
|
||||||
mov r1, #0x0
|
|
||||||
mov r2, #0x0
|
|
||||||
mov r3, #0x0
|
|
||||||
mov r4, #0x0
|
|
||||||
mov r5, #0x0
|
|
||||||
mov r6, #0x0
|
|
||||||
mov r7, #0x0
|
|
||||||
mov r8, #0x0
|
|
||||||
mov r9, #0x0
|
|
||||||
mov r10, #0x0
|
|
||||||
mov r11, #0x0
|
|
||||||
mov r12, #0x0
|
|
||||||
mov lr, #0x0
|
|
||||||
ldr sp, =0x40010000
|
|
||||||
ldr pc, =0x40010000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_REBOOTSTUB_TIMER_H
|
|
||||||
#define EXOSPHERE_REBOOTSTUB_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
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_REBOOTSTUB_UTILS_H
|
|
||||||
#define EXOSPHERE_REBOOTSTUB_UTILS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.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))
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,154 +0,0 @@
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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 \
|
|
||||||
-Os \
|
|
||||||
-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
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
|
@ -1,21 +0,0 @@
|
||||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
|
||||||
OUTPUT_ARCH(arm)
|
|
||||||
|
|
||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x40003000;
|
|
||||||
|
|
||||||
__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(.);
|
|
||||||
|
|
||||||
__stack_top__ = 0x40005000;
|
|
||||||
__stack_bottom__ = 0x40004000;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
%rename link old_link
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "sc7.h"
|
|
||||||
#include "emc.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
static void emc_trigger_timing_update(void) {
|
|
||||||
EMC_TIMING_CONTROL_0 = 1;
|
|
||||||
while (EMC_EMC_STATUS_0 & 0x800000) {
|
|
||||||
/* Wait until TIMING_UPDATE_STALLED is unset. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Puts DRAM into self refresh mode. */
|
|
||||||
void emc_put_dram_in_self_refresh_mode(void) {
|
|
||||||
/* Verify CH1_ENABLE [PMC]. */
|
|
||||||
if (!(EMC_FBIO_CFG7_0 & 4)) {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear config. */
|
|
||||||
EMC_CFG_0 = 0;
|
|
||||||
emc_trigger_timing_update();
|
|
||||||
timer_wait(5);
|
|
||||||
|
|
||||||
/* Set calibration intervals. */
|
|
||||||
EMC_ZCAL_INTERVAL_0 = 0;
|
|
||||||
EMC_AUTO_CAL_CONFIG_0 = 0x600; /* AUTO_CAL_MEASURE_STALL | AUTO_CAL_UPDATE_STALL */
|
|
||||||
|
|
||||||
/* If EMC0 mirror is set, clear digital DLL. */
|
|
||||||
if (EMC0_CFG_DIG_DLL_0 & 1) {
|
|
||||||
EMC_CFG_DIG_DLL_0 &= 0xFFFFFFFE;
|
|
||||||
emc_trigger_timing_update();
|
|
||||||
while (EMC0_CFG_DIG_DLL_0 & 1) { /* Wait for EMC0 to clear. */ }
|
|
||||||
while (EMC1_CFG_DIG_DLL_0 & 1) { /* Wait for EMC1 to clear. */ }
|
|
||||||
} else {
|
|
||||||
emc_trigger_timing_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stall all transactions to DRAM. */
|
|
||||||
EMC_REQ_CTRL_0 = 3; /* STALL_ALL_WRITES | STALL_ALL_READS. */
|
|
||||||
while (!(EMC0_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC0. */ }
|
|
||||||
while (!(EMC1_EMC_STATUS_0 & 4)) { /* Wait for NO_OUTSTANDING_TRANSACTIONS for EMC1. */ }
|
|
||||||
|
|
||||||
/* Enable Self-Refresh Mode. */
|
|
||||||
EMC_SELF_REF_0 |= 1;
|
|
||||||
|
|
||||||
|
|
||||||
/* Wait until we see the right devices in self refresh mode. */
|
|
||||||
uint32_t num_populated_devices = 1;
|
|
||||||
if (EMC_ADR_CFG_0) {
|
|
||||||
num_populated_devices = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (((EMC0_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC0 DRAM_IN_SELF_REFRESH to be correct. */ }
|
|
||||||
while (((EMC1_EMC_STATUS_0 >> 8) & 3) != num_populated_devices) { /* Wait for EMC1 DRAM_IN_SELF_REFRESH to be correct. */ }
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_EMC_H
|
|
||||||
#define EXOSPHERE_BPMPFW_EMC_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define EMC_BASE (0x7001B000)
|
|
||||||
|
|
||||||
#define EMC0_BASE (0x7001E000)
|
|
||||||
#define EMC1_BASE (0x7001F000)
|
|
||||||
|
|
||||||
|
|
||||||
#define MAKE_EMC_REG(ofs) (MAKE_REG32(EMC_BASE + ofs))
|
|
||||||
|
|
||||||
#define MAKE_EMC0_REG(ofs) (MAKE_REG32(EMC0_BASE + ofs))
|
|
||||||
#define MAKE_EMC1_REG(ofs) (MAKE_REG32(EMC1_BASE + ofs))
|
|
||||||
|
|
||||||
#define EMC_CFG_0 MAKE_EMC_REG(0x00C)
|
|
||||||
|
|
||||||
#define EMC_ADR_CFG_0 MAKE_EMC_REG(0x10)
|
|
||||||
|
|
||||||
#define EMC_TIMING_CONTROL_0 MAKE_EMC_REG(0x028)
|
|
||||||
|
|
||||||
#define EMC_SELF_REF_0 MAKE_EMC_REG(0x0E0)
|
|
||||||
|
|
||||||
#define EMC_MRW_0 MAKE_EMC_REG(0x0E8)
|
|
||||||
|
|
||||||
#define EMC_FBIO_CFG5_0 MAKE_EMC_REG(0x104)
|
|
||||||
|
|
||||||
#define EMC_MRW3_0 MAKE_EMC_REG(0x138)
|
|
||||||
|
|
||||||
#define EMC_AUTO_CAL_CONFIG_0 MAKE_EMC_REG(0x2A4)
|
|
||||||
|
|
||||||
#define EMC_REQ_CTRL_0 MAKE_EMC_REG(0x2B0)
|
|
||||||
|
|
||||||
#define EMC_EMC_STATUS_0 MAKE_EMC_REG(0x2B4)
|
|
||||||
#define EMC0_EMC_STATUS_0 MAKE_EMC0_REG(0x2B4)
|
|
||||||
#define EMC1_EMC_STATUS_0 MAKE_EMC1_REG(0x2B4)
|
|
||||||
|
|
||||||
#define EMC_CFG_DIG_DLL_0 MAKE_EMC_REG(0x2BC)
|
|
||||||
#define EMC0_CFG_DIG_DLL_0 MAKE_EMC0_REG(0x2BC)
|
|
||||||
#define EMC1_CFG_DIG_DLL_0 MAKE_EMC1_REG(0x2BC)
|
|
||||||
|
|
||||||
#define EMC_ZCAL_INTERVAL_0 MAKE_EMC_REG(0x2E0)
|
|
||||||
|
|
||||||
#define EMC_PMC_SCRATCH3_0 MAKE_EMC_REG(0x448)
|
|
||||||
|
|
||||||
#define EMC_FBIO_CFG7_0 MAKE_EMC_REG(0x584)
|
|
||||||
|
|
||||||
void emc_put_dram_in_self_refresh_mode(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "i2c.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
|
||||||
void i2c_load_config(void);
|
|
||||||
int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes);
|
|
||||||
int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b);
|
|
||||||
|
|
||||||
/* Load hardware config for I2C4. */
|
|
||||||
void i2c_load_config(void) {
|
|
||||||
/* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */
|
|
||||||
I2C_I2C_CONFIG_LOAD_0 = 0x25;
|
|
||||||
|
|
||||||
/* Wait a bit for master config to be loaded. */
|
|
||||||
for (unsigned int i = 0; i < 20; i++) {
|
|
||||||
timer_wait(1);
|
|
||||||
if (!(I2C_I2C_CONFIG_LOAD_0 & 1)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize I2C4. */
|
|
||||||
void i2c_init(void) {
|
|
||||||
/* Setup divisor, and clear the bus. */
|
|
||||||
I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001;
|
|
||||||
I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003;
|
|
||||||
|
|
||||||
/* Load hardware configuration. */
|
|
||||||
i2c_load_config();
|
|
||||||
|
|
||||||
/* Wait a while until BUS_CLEAR_DONE is set. */
|
|
||||||
for (unsigned int i = 0; i < 10; i++) {
|
|
||||||
timer_wait(20000);
|
|
||||||
if (I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the BUS_CLEAR_STATUS. Result doesn't matter. */
|
|
||||||
I2C_I2C_BUS_CLEAR_STATUS_0;
|
|
||||||
|
|
||||||
/* Read and set the Interrupt Status. */
|
|
||||||
uint32_t int_status = I2C_INTERRUPT_STATUS_REGISTER_0;
|
|
||||||
I2C_INTERRUPT_STATUS_REGISTER_0 = int_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a value to an i2c device. */
|
|
||||||
int i2c_write(unsigned int device, uint32_t val, unsigned int num_bytes) {
|
|
||||||
if (num_bytes > 4) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit mode. */
|
|
||||||
I2C_I2C_CMD_ADDR0_0 = device << 1;
|
|
||||||
|
|
||||||
/* Load in data to write. */
|
|
||||||
I2C_I2C_CMD_DATA1_0 = val;
|
|
||||||
|
|
||||||
/* Set config with LENGTH = num_bytes, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
I2C_I2C_CNFG_0 = ((num_bytes << 1) - 2) | 0x2800;
|
|
||||||
|
|
||||||
i2c_load_config();
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
I2C_I2C_CNFG_0 |= 0x200;
|
|
||||||
|
|
||||||
|
|
||||||
while (I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */
|
|
||||||
return (I2C_I2C_STATUS_0 & 0xF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a byte val to reg for given device. */
|
|
||||||
int i2c_send_byte_command(unsigned int device, unsigned char reg, unsigned char b) {
|
|
||||||
uint32_t val = (reg) | (b << 8);
|
|
||||||
/* Write 1 byte (reg) + 1 byte (value) */
|
|
||||||
return i2c_write(device, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actually reset device 27. This might turn off the screen? */
|
|
||||||
int i2c_send_reset_cmd(void) {
|
|
||||||
/* Write 00 to Device 27 Reg 00. */
|
|
||||||
return i2c_send_byte_command(27, 0, 0);
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_I2C_H
|
|
||||||
#define EXOSPHERE_BPMPFW_I2C_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/* I2C_BASE = I2C4. */
|
|
||||||
#define I2C_BASE (0x7000D000)
|
|
||||||
|
|
||||||
#define MAKE_I2C_REG(ofs) (MAKE_REG32(I2C_BASE + ofs))
|
|
||||||
|
|
||||||
#define I2C_I2C_CNFG_0 MAKE_I2C_REG(0x000)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_ADDR0_0 MAKE_I2C_REG(0x004)
|
|
||||||
|
|
||||||
#define I2C_I2C_CMD_DATA1_0 MAKE_I2C_REG(0x00C)
|
|
||||||
|
|
||||||
#define I2C_I2C_STATUS_0 MAKE_I2C_REG(0x01C)
|
|
||||||
|
|
||||||
#define I2C_INTERRUPT_STATUS_REGISTER_0 MAKE_I2C_REG(0x068)
|
|
||||||
|
|
||||||
#define I2C_I2C_CLK_DIVISOR_REGISTER_0 MAKE_I2C_REG(0x06C)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_CONFIG_0 MAKE_I2C_REG(0x084)
|
|
||||||
|
|
||||||
#define I2C_I2C_BUS_CLEAR_STATUS_0 MAKE_I2C_REG(0x088)
|
|
||||||
|
|
||||||
|
|
||||||
#define I2C_I2C_CONFIG_LOAD_0 MAKE_I2C_REG(0x08C)
|
|
||||||
|
|
||||||
void i2c_init(void);
|
|
||||||
|
|
||||||
int i2c_send_reset_cmd(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_PMC_H
|
|
||||||
#define EXOSPHERE_BPMPFW_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
|
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "sc7.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "emc.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
#define CACHE_CTRL MAKE_REG32(0x50040000)
|
|
||||||
|
|
||||||
#define PRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004038)
|
|
||||||
#define SEC_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004138)
|
|
||||||
#define TRI_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004238)
|
|
||||||
#define QUAD_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004338)
|
|
||||||
#define PENTA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004438)
|
|
||||||
#define HEXA_ICTLR_COP_IER_CLR_0 MAKE_REG32(0x60004538)
|
|
||||||
|
|
||||||
void reboot(void) {
|
|
||||||
/* Write MAIN_RST */
|
|
||||||
APBDEV_PMC_CNTRL_0 = 0x10;
|
|
||||||
while (true) {
|
|
||||||
/* Wait for reboot. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void set_pmc_dpd_io_pads(void) {
|
|
||||||
/* Read val from EMC_PMC scratch, configure accordingly. */
|
|
||||||
uint32_t emc_pmc_val = EMC_PMC_SCRATCH3_0;
|
|
||||||
APBDEV_PMC_DDR_CNTRL_0 = emc_pmc_val & 0x7FFFF;
|
|
||||||
if (emc_pmc_val & 0x40000000) {
|
|
||||||
APBDEV_PMC_WEAK_BIAS_0 = 0x7FFF0000;
|
|
||||||
}
|
|
||||||
/* Request to put pads in Deep Power Down. */
|
|
||||||
APBDEV_PMC_IO_DPD3_REQ_0 = 0x8FFFFFFF;
|
|
||||||
while (APBDEV_PMC_IO_DPD3_STATUS_0 != 0xFFFFFFF) { /* Wait a while. */ }
|
|
||||||
spinlock_wait(32);
|
|
||||||
APBDEV_PMC_IO_DPD4_REQ_0 = 0x8FFFFFFF;
|
|
||||||
while (APBDEV_PMC_IO_DPD4_STATUS_0 != 0xFFF1FFF) { /* Wait a while. */ }
|
|
||||||
spinlock_wait(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc7_entry_main(void) {
|
|
||||||
/* Disable the BPMP Cache. */
|
|
||||||
CACHE_CTRL |= 0xC00;
|
|
||||||
|
|
||||||
/* Wait until the CPU Rail is turned off. */
|
|
||||||
while (APBDEV_PMC_PWRGATE_STATUS_0 & 1) { /* Wait for TrustZone to finish. */ }
|
|
||||||
|
|
||||||
/* Clamp the CPU Rail. */
|
|
||||||
APBDEV_PMC_SET_SW_CLAMP_0 |= 0x1;
|
|
||||||
while (!(APBDEV_PMC_CLAMP_STATUS_0 & 1)) { /* Wait for CPU Rail to be clamped. */ }
|
|
||||||
|
|
||||||
/* Waste some time. */
|
|
||||||
spinlock_wait(10);
|
|
||||||
|
|
||||||
/* Reset device 27 over I2C, then wait a while. */
|
|
||||||
i2c_init();
|
|
||||||
i2c_send_reset_cmd();
|
|
||||||
timer_wait(700);
|
|
||||||
|
|
||||||
/* Clear Interrupt Enable for BPMP in all ICTLRs. */
|
|
||||||
PRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
SEC_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
TRI_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
QUAD_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
PENTA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
HEXA_ICTLR_COP_IER_CLR_0 = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
/* Write EMC's DRAM op into PMC scratch. */
|
|
||||||
if ((EMC_FBIO_CFG5_0 & 3) != 1) {
|
|
||||||
/* If DRAM_TYPE != LPDDR4, something's gone wrong. Reboot. */
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
/* Write MRW3_OP into scratch. */
|
|
||||||
APBDEV_PMC_SCRATCH18_0 = (APBDEV_PMC_SCRATCH18_0 & 0xFFFFFF3F) | (EMC_MRW3_0 & 0xC0);
|
|
||||||
uint32_t mrw3_op = ((EMC_MRW3_0 & 0xC0) << 8) | (EMC_MRW3_0 & 0xC0);
|
|
||||||
APBDEV_PMC_SCRATCH12_0 = (APBDEV_PMC_SCRATCH12_0 & 0xFFFF3F3F) | mrw3_op;
|
|
||||||
APBDEV_PMC_SCRATCH13_0 = (APBDEV_PMC_SCRATCH13_0 & 0xFFFF3F3F) | mrw3_op;
|
|
||||||
|
|
||||||
/* Ready DRAM for deep sleep. */
|
|
||||||
emc_put_dram_in_self_refresh_mode();
|
|
||||||
|
|
||||||
/* Setup LPDDR MRW based on device config. */
|
|
||||||
EMC_MRW_0 = 0x88110000;
|
|
||||||
if (EMC_ADR_CFG_0 & 1) {
|
|
||||||
EMC_MRW_0 = 0x48110000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put IO pads in Deep Power Down. */
|
|
||||||
set_pmc_dpd_io_pads();
|
|
||||||
|
|
||||||
/* Enable pad sampling during deep sleep. */
|
|
||||||
APBDEV_PMC_DPD_SAMPLE_0 |= 1;
|
|
||||||
|
|
||||||
/* Waste some more time. */
|
|
||||||
spinlock_wait(0x128);
|
|
||||||
|
|
||||||
/* Enter deep sleep. */
|
|
||||||
APBDEV_PMC_DPD_ENABLE_0 |= 1;
|
|
||||||
|
|
||||||
while (true) { /* Wait until we're asleep. */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_SC7_H
|
|
||||||
#define EXOSPHERE_BPMPFW_SC7_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
void sc7_entry_main(void);
|
|
||||||
|
|
||||||
void reboot(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.section .text.start
|
|
||||||
.align 4
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
b crt0
|
|
||||||
.global _reboot
|
|
||||||
b reboot
|
|
||||||
|
|
||||||
.global crt0
|
|
||||||
.type crt0, %function
|
|
||||||
crt0:
|
|
||||||
@ setup to call sc7_entry_main
|
|
||||||
msr cpsr_cxsf, #0xD3
|
|
||||||
ldr sp, =__stack_top__
|
|
||||||
ldr lr, =reboot
|
|
||||||
b sc7_entry_main
|
|
||||||
|
|
||||||
|
|
||||||
.global spinlock_wait
|
|
||||||
.type spinlock_wait, %function
|
|
||||||
spinlock_wait:
|
|
||||||
subs r0, r0, #1
|
|
||||||
bgt spinlock_wait
|
|
||||||
bx lr
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_TIMER_H
|
|
||||||
#define EXOSPHERE_BPMPFW_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
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMPFW_UTILS_H
|
|
||||||
#define EXOSPHERE_BPMPFW_UTILS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.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))
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "actmon.h"
|
|
||||||
|
|
||||||
static void (*g_actmon_callback)(void) = NULL;
|
|
||||||
|
|
||||||
void actmon_set_callback(void (*callback)(void)) {
|
|
||||||
g_actmon_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void actmon_on_bpmp_wakeup(void) {
|
|
||||||
/* This gets set as the actmon interrupt handler on 4.x. */
|
|
||||||
panic(0xF0A00036);
|
|
||||||
}
|
|
||||||
|
|
||||||
void actmon_interrupt_handler(void) {
|
|
||||||
ACTMON_COP_CTRL_0 = 0;
|
|
||||||
ACTMON_COP_INTR_STATUS_0 = ACTMON_COP_INTR_STATUS_0;
|
|
||||||
if (g_actmon_callback != NULL) {
|
|
||||||
g_actmon_callback();
|
|
||||||
g_actmon_callback = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_ACTIVITY_MONITOR_H
|
|
||||||
#define EXOSPHERE_ACTIVITY_MONITOR_H
|
|
||||||
|
|
||||||
#include "sysreg.h"
|
|
||||||
|
|
||||||
/* Exosphere Driver for the Tegra X1 Activity Monitor. */
|
|
||||||
|
|
||||||
/* NOTE: ACTMON registers lie in the SYSREG region! */
|
|
||||||
#define ACTMON_BASE (SYSREG_BASE + 0x800)
|
|
||||||
|
|
||||||
#define MAKE_ACTMON_REG(n) MAKE_REG32(ACTMON_BASE + n)
|
|
||||||
|
|
||||||
#define ACTMON_GLB_STATUS_0 MAKE_ACTMON_REG(0x000)
|
|
||||||
#define ACTMON_GLB_PERIOD_CTRL_0 MAKE_ACTMON_REG(0x004)
|
|
||||||
#define ACTMON_COP_CTRL_0 MAKE_ACTMON_REG(0x0C0)
|
|
||||||
#define ACTMON_COP_UPPER_WMARK_0 MAKE_ACTMON_REG(0x0C4)
|
|
||||||
#define ACTMON_COP_INTR_STATUS_0 MAKE_ACTMON_REG(0x0E4)
|
|
||||||
|
|
||||||
void actmon_interrupt_handler(void);
|
|
||||||
|
|
||||||
void actmon_on_bpmp_wakeup(void);
|
|
||||||
|
|
||||||
void actmon_set_callback(void (*callback)(void));
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_ARM_H
|
|
||||||
#define EXOSPHERE_ARM_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void tlb_invalidate_all(void);
|
|
||||||
void tlb_invalidate_all_inner_shareable(void);
|
|
||||||
|
|
||||||
void tlb_invalidate_page(const volatile void *page);
|
|
||||||
void tlb_invalidate_page_inner_shareable(const void *page);
|
|
||||||
|
|
||||||
void flush_dcache_all(void);
|
|
||||||
void invalidate_dcache_all(void);
|
|
||||||
|
|
||||||
void flush_dcache_range(const void *start, const void *end);
|
|
||||||
void invalidate_dcache_range(const void *start, const void *end);
|
|
||||||
|
|
||||||
void invalidate_icache_all_inner_shareable(void);
|
|
||||||
void invalidate_icache_all(void);
|
|
||||||
|
|
||||||
void finalize_powerdown(void);
|
|
||||||
void call_with_stack_pointer(uintptr_t stack_pointer, void (*function)(void));
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,316 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define cpuactlr_el1 s3_1_c15_c2_0
|
|
||||||
#define cpuectlr_el1 s3_1_c15_c2_1
|
|
||||||
|
|
||||||
.section .text.tlb_invalidate_all, "ax", %progbits
|
|
||||||
.type tlb_invalidate_all, %function
|
|
||||||
.global tlb_invalidate_all
|
|
||||||
tlb_invalidate_all:
|
|
||||||
dsb sy
|
|
||||||
tlbi alle3
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .text.tlb_invalidate_all_inner_shareable, "ax", %progbits
|
|
||||||
.type tlb_invalidate_all_inner_shareable, %function
|
|
||||||
.global tlb_invalidate_all_inner_shareable
|
|
||||||
tlb_invalidate_all_inner_shareable:
|
|
||||||
dsb ish
|
|
||||||
tlbi alle3is
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .text.tlb_invalidate_page, "ax", %progbits
|
|
||||||
.type tlb_invalidate_page, %function
|
|
||||||
.global tlb_invalidate_page
|
|
||||||
tlb_invalidate_page:
|
|
||||||
lsr x8, x0, #12
|
|
||||||
dsb sy
|
|
||||||
tlbi vale3, x8
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .text.tlb_invalidate_page_inner_shareable, "ax", %progbits
|
|
||||||
.type tlb_invalidate_page_inner_shareable, %function
|
|
||||||
.global tlb_invalidate_page_inner_shareable
|
|
||||||
tlb_invalidate_page_inner_shareable:
|
|
||||||
lsr x8, x0, #12
|
|
||||||
dsb ish
|
|
||||||
tlbi vale3is, x8
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* The following functions are taken/adapted from https://github.com/u-boot/u-boot/blob/master/arch/arm/cpu/armv8/cache.S */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (C) Copyright 2013
|
|
||||||
* David Feng <fenghua@phytium.com.cn>
|
|
||||||
*
|
|
||||||
* This file is based on sample code from ARMv8 ARM.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void __asm_dcache_level(level)
|
|
||||||
*
|
|
||||||
* flush or invalidate one level cache.
|
|
||||||
*
|
|
||||||
* x0: cache level
|
|
||||||
* x1: 0 clean & invalidate, 1 invalidate only
|
|
||||||
* x2~x9: clobbered
|
|
||||||
*/
|
|
||||||
.section .warm_crt0.text.__asm_dcache_level, "ax", %progbits
|
|
||||||
.type __asm_dcache_level, %function
|
|
||||||
__asm_dcache_level:
|
|
||||||
lsl x12, x0, #1
|
|
||||||
msr csselr_el1, x12 /* select cache level */
|
|
||||||
isb /* sync change of cssidr_el1 */
|
|
||||||
mrs x6, ccsidr_el1 /* read the new cssidr_el1 */
|
|
||||||
and x2, x6, #7 /* x2 <- log2(cache line size)-4 */
|
|
||||||
add x2, x2, #4 /* x2 <- log2(cache line size) */
|
|
||||||
mov x3, #0x3ff
|
|
||||||
and x3, x3, x6, lsr #3 /* x3 <- max number of #ways */
|
|
||||||
clz w5, w3 /* bit position of #ways */
|
|
||||||
mov x4, #0x7fff
|
|
||||||
and x4, x4, x6, lsr #13 /* x4 <- max number of #sets */
|
|
||||||
/* x12 <- cache level << 1 */
|
|
||||||
/* x2 <- line length offset */
|
|
||||||
/* x3 <- number of cache ways - 1 */
|
|
||||||
/* x4 <- number of cache sets - 1 */
|
|
||||||
/* x5 <- bit position of #ways */
|
|
||||||
|
|
||||||
loop_set:
|
|
||||||
mov x6, x3 /* x6 <- working copy of #ways */
|
|
||||||
loop_way:
|
|
||||||
lsl x7, x6, x5
|
|
||||||
orr x9, x12, x7 /* map way and level to cisw value */
|
|
||||||
lsl x7, x4, x2
|
|
||||||
orr x9, x9, x7 /* map set number to cisw value */
|
|
||||||
tbz w1, #0, 1f
|
|
||||||
dc isw, x9
|
|
||||||
b 2f
|
|
||||||
1: dc cisw, x9 /* clean & invalidate by set/way */
|
|
||||||
2: subs x6, x6, #1 /* decrement the way */
|
|
||||||
b.ge loop_way
|
|
||||||
subs x4, x4, #1 /* decrement the set */
|
|
||||||
b.ge loop_set
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void __asm_flush_dcache_all(int invalidate_only)
|
|
||||||
*
|
|
||||||
* x0: 0 clean & invalidate, 1 invalidate only
|
|
||||||
*
|
|
||||||
* flush or invalidate all data cache by SET/WAY.
|
|
||||||
*/
|
|
||||||
.section .warm_crt0.text.__asm_dcache_all, "ax", %progbits
|
|
||||||
.type __asm_dcache_all, %function
|
|
||||||
__asm_dcache_all:
|
|
||||||
mov x1, x0
|
|
||||||
dsb sy
|
|
||||||
mrs x10, clidr_el1 /* read clidr_el1 */
|
|
||||||
lsr x11, x10, #24
|
|
||||||
and x11, x11, #0x7 /* x11 <- loc */
|
|
||||||
cbz x11, finished /* if loc is 0, exit */
|
|
||||||
mov x15, lr
|
|
||||||
mov x0, #0 /* start flush at cache level 0 */
|
|
||||||
/* x0 <- cache level */
|
|
||||||
/* x10 <- clidr_el1 */
|
|
||||||
/* x11 <- loc */
|
|
||||||
/* x15 <- return address */
|
|
||||||
|
|
||||||
loop_level:
|
|
||||||
lsl x12, x0, #1
|
|
||||||
add x12, x12, x0 /* x0 <- tripled cache level */
|
|
||||||
lsr x12, x10, x12
|
|
||||||
and x12, x12, #7 /* x12 <- cache type */
|
|
||||||
cmp x12, #2
|
|
||||||
b.lt skip /* skip if no cache or icache */
|
|
||||||
bl __asm_dcache_level /* x1 = 0 flush, 1 invalidate */
|
|
||||||
skip:
|
|
||||||
add x0, x0, #1 /* increment cache level */
|
|
||||||
cmp x11, x0
|
|
||||||
b.gt loop_level
|
|
||||||
|
|
||||||
mov x0, #0
|
|
||||||
msr csselr_el1, x0 /* restore csselr_el1 */
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
mov lr, x15
|
|
||||||
|
|
||||||
finished:
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .warm_crt0.text.flush_dcache_all, "ax", %progbits
|
|
||||||
.type flush_dcache_all, %function
|
|
||||||
.global flush_dcache_all
|
|
||||||
flush_dcache_all:
|
|
||||||
mov x0, #0
|
|
||||||
b __asm_dcache_all
|
|
||||||
|
|
||||||
.section .warm_crt0.text.invalidate_dcache_all, "ax", %progbits
|
|
||||||
.type invalidate_dcache_all, %function
|
|
||||||
.global invalidate_dcache_all
|
|
||||||
invalidate_dcache_all:
|
|
||||||
mov x0, #1
|
|
||||||
b __asm_dcache_all
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void __asm_flush_dcache_range(start, end) (renamed -> flush_dcache_range)
|
|
||||||
*
|
|
||||||
* clean & invalidate data cache in the range
|
|
||||||
*
|
|
||||||
* x0: start address
|
|
||||||
* x1: end address
|
|
||||||
*/
|
|
||||||
.section .warm_crt0.text.flush_dcache_range, "ax", %progbits
|
|
||||||
.type flush_dcache_range, %function
|
|
||||||
.global flush_dcache_range
|
|
||||||
flush_dcache_range:
|
|
||||||
mrs x3, ctr_el0
|
|
||||||
lsr x3, x3, #16
|
|
||||||
and x3, x3, #0xf
|
|
||||||
mov x2, #4
|
|
||||||
lsl x2, x2, x3 /* cache line size */
|
|
||||||
|
|
||||||
/* x2 <- minimal cache line size in cache system */
|
|
||||||
sub x3, x2, #1
|
|
||||||
bic x0, x0, x3
|
|
||||||
1: dc civac, x0 /* clean & invalidate data or unified cache */
|
|
||||||
add x0, x0, x2
|
|
||||||
cmp x0, x1
|
|
||||||
b.lo 1b
|
|
||||||
dsb sy
|
|
||||||
ret
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void __asm_invalidate_dcache_range(start, end) (-> invalidate_dcache_range)
|
|
||||||
*
|
|
||||||
* invalidate data cache in the range
|
|
||||||
*
|
|
||||||
* x0: start address
|
|
||||||
* x1: end address
|
|
||||||
*/
|
|
||||||
.section .warm_crt0.text.invalidate_dcache_range, "ax", %progbits
|
|
||||||
.type invalidate_dcache_range, %function
|
|
||||||
.global invalidate_dcache_range
|
|
||||||
invalidate_dcache_range:
|
|
||||||
mrs x3, ctr_el0
|
|
||||||
ubfm x3, x3, #16, #19
|
|
||||||
mov x2, #4
|
|
||||||
lsl x2, x2, x3 /* cache line size */
|
|
||||||
|
|
||||||
/* x2 <- minimal cache line size in cache system */
|
|
||||||
sub x3, x2, #1
|
|
||||||
bic x0, x0, x3
|
|
||||||
1: dc ivac, x0 /* invalidate data or unified cache */
|
|
||||||
add x0, x0, x2
|
|
||||||
cmp x0, x1
|
|
||||||
b.lo 1b
|
|
||||||
dsb sy
|
|
||||||
ret
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void __asm_invalidate_icache_all(void) (-> invalidate_icache_inner_shareable)
|
|
||||||
*
|
|
||||||
* invalidate all icache entries.
|
|
||||||
*/
|
|
||||||
.section .warm_crt0.text.invalidate_icache_all_inner_shareable, "ax", %progbits
|
|
||||||
.type invalidate_icache_all_inner_shareable, %function
|
|
||||||
.global invalidate_icache_all_inner_shareable
|
|
||||||
invalidate_icache_all_inner_shareable:
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ic ialluis
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .warm_crt0.text.invalidate_icache_all, "ax", %progbits
|
|
||||||
.type invalidate_icache_all, %function
|
|
||||||
.global invalidate_icache_all
|
|
||||||
invalidate_icache_all:
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ic iallu
|
|
||||||
dsb ish
|
|
||||||
isb
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* Final steps before power down. */
|
|
||||||
.section .text.finalize_powerdown, "ax", %progbits
|
|
||||||
.type finalize_powerdown, %function
|
|
||||||
.global finalize_powerdown
|
|
||||||
finalize_powerdown:
|
|
||||||
/*
|
|
||||||
Make all data access to Normal memory from EL0/EL1 + all Normal Memory accesses to EL0/1 stage 1 translation tables
|
|
||||||
non-cacheable for all levels, unified cache.
|
|
||||||
*/
|
|
||||||
mrs x0, sctlr_el1
|
|
||||||
bic x0, x0, #(1 << 2)
|
|
||||||
msr sctlr_el1, x0
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Same as above, for EL3. */
|
|
||||||
mrs x0, sctlr_el3
|
|
||||||
bic x0, x0, #(1 << 2)
|
|
||||||
msr sctlr_el3, x0
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Disable table walk descriptor access prefetch, disable instruction prefetch, disable data prefetch. */
|
|
||||||
mrs x0, cpuectlr_el1
|
|
||||||
orr x0, x0, #(1 << 38)
|
|
||||||
bic x0, x0, #(3 << 35)
|
|
||||||
bic x0, x0, #(3 << 32)
|
|
||||||
msr cpuectlr_el1, x0
|
|
||||||
isb
|
|
||||||
dsb sy
|
|
||||||
bl flush_dcache_all
|
|
||||||
|
|
||||||
/* Disable receiving instruction cache/tbl maintenance operations. */
|
|
||||||
mrs x0, cpuectlr_el1
|
|
||||||
bic x0, x0, #(1 << 6)
|
|
||||||
msr cpuectlr_el1, x0
|
|
||||||
|
|
||||||
/* Prepare GICC */
|
|
||||||
bl intr_prepare_gicc_for_sleep
|
|
||||||
|
|
||||||
/* Set OS double lock */
|
|
||||||
mrs x0, osdlr_el1
|
|
||||||
orr x0, x0, #1
|
|
||||||
msr osdlr_el1, x0
|
|
||||||
|
|
||||||
isb
|
|
||||||
dsb sy
|
|
||||||
wait_for_power_off:
|
|
||||||
wfi
|
|
||||||
b wait_for_power_off
|
|
||||||
|
|
||||||
/* Call a function with desired stack pointer. */
|
|
||||||
.section .text.call_with_stack_pointer, "ax", %progbits
|
|
||||||
.type call_with_stack_pointer, %function
|
|
||||||
.global call_with_stack_pointer
|
|
||||||
call_with_stack_pointer:
|
|
||||||
mov sp, x0
|
|
||||||
br x1
|
|
|
@ -1,164 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "configitem.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "bootconfig.h"
|
|
||||||
|
|
||||||
static boot_reason_t g_boot_reason = {0};
|
|
||||||
static uint64_t g_package2_hash_for_recovery[4] = {0};
|
|
||||||
|
|
||||||
bool bootconfig_matches_hardware_info(void) {
|
|
||||||
uint32_t hardware_info[4];
|
|
||||||
fuse_get_hardware_info(hardware_info);
|
|
||||||
return memcmp(LOADED_BOOTCONFIG->signed_config.hardware_info, hardware_info, sizeof(hardware_info)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_load_and_verify(const bootconfig_t *bootconfig) {
|
|
||||||
static const uint8_t bootconfig_modulus[RSA_2048_BYTES] = {
|
|
||||||
0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64,
|
|
||||||
0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33,
|
|
||||||
0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB,
|
|
||||||
0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9,
|
|
||||||
0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B,
|
|
||||||
0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25,
|
|
||||||
0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49,
|
|
||||||
0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24,
|
|
||||||
0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF,
|
|
||||||
0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E,
|
|
||||||
0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6,
|
|
||||||
0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9,
|
|
||||||
0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12,
|
|
||||||
0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5,
|
|
||||||
0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93,
|
|
||||||
0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D
|
|
||||||
};
|
|
||||||
memcpy(LOADED_BOOTCONFIG, bootconfig, sizeof(bootconfig_t));
|
|
||||||
/* TODO: Should these restrictions be loosened for Exosphere? */
|
|
||||||
if (configitem_is_retail()
|
|
||||||
|| se_rsa2048_pss_verify(LOADED_BOOTCONFIG->signature, RSA_2048_BYTES, bootconfig_modulus, RSA_2048_BYTES, &LOADED_BOOTCONFIG->signed_config, sizeof(LOADED_BOOTCONFIG->signed_config)) != 0
|
|
||||||
|| !bootconfig_matches_hardware_info()) {
|
|
||||||
/* Clear signed config. */
|
|
||||||
memset(&LOADED_BOOTCONFIG->signed_config, 0, sizeof(LOADED_BOOTCONFIG->signed_config));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_clear(void){
|
|
||||||
memset(LOADED_BOOTCONFIG, 0, sizeof(bootconfig_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actual configuration getters. */
|
|
||||||
bool bootconfig_is_package2_plaintext(void) {
|
|
||||||
return (LOADED_BOOTCONFIG->signed_config.package2_config & 1) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bootconfig_is_package2_unsigned(void) {
|
|
||||||
return (LOADED_BOOTCONFIG->signed_config.package2_config & 2) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_set_package2_plaintext_and_unsigned(void) {
|
|
||||||
LOADED_BOOTCONFIG->signed_config.package2_config |= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bootconfig_disable_program_verification(void) {
|
|
||||||
return LOADED_BOOTCONFIG->signed_config.disable_program_verification != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bootconfig_is_debug_mode(void) {
|
|
||||||
return (LOADED_BOOTCONFIG->unsigned_config.data[0x10] & 2) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bootconfig_take_extabt_serror_to_el3(void) {
|
|
||||||
return (LOADED_BOOTCONFIG->unsigned_config.data[0x10] & 6) != 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_value_for_sysctr0(void) {
|
|
||||||
if (LOADED_BOOTCONFIG->unsigned_config.data[0x24] & 1) {
|
|
||||||
return *(volatile uint64_t *)(&(LOADED_BOOTCONFIG->unsigned_config.data[0x30]));
|
|
||||||
} else {
|
|
||||||
return 0ULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_memory_arrangement(void) {
|
|
||||||
/* TODO: This function has changed pretty significantly since we implemented it. */
|
|
||||||
/* Not relevant for retail, but we'll probably want this to be accurate sooner or later. */
|
|
||||||
if (bootconfig_is_debug_mode()) {
|
|
||||||
if (fuse_get_dram_id() == 4) {
|
|
||||||
if (LOADED_BOOTCONFIG->unsigned_config.data[0x23]) {
|
|
||||||
return (uint64_t)(LOADED_BOOTCONFIG->unsigned_config.data[0x23]);
|
|
||||||
} else {
|
|
||||||
return 0x11ull;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (LOADED_BOOTCONFIG->unsigned_config.data[0x23]) {
|
|
||||||
if ((LOADED_BOOTCONFIG->unsigned_config.data[0x23] & 0x30) == 0) {
|
|
||||||
return (uint64_t)(LOADED_BOOTCONFIG->unsigned_config.data[0x23]);
|
|
||||||
} else {
|
|
||||||
return 1ull;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 1ull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 1ull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_kernel_configuration(void) {
|
|
||||||
if (bootconfig_is_debug_mode()) {
|
|
||||||
uint64_t high_val = 0;
|
|
||||||
if (fuse_get_dram_id() == 4) {
|
|
||||||
if (LOADED_BOOTCONFIG->unsigned_config.data[0x23]) {
|
|
||||||
high_val = ((uint64_t)(LOADED_BOOTCONFIG->unsigned_config.data[0x23]) >> 4) & 0x3;
|
|
||||||
} else {
|
|
||||||
high_val = 0x1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (high_val << 16) | (((uint64_t)(LOADED_BOOTCONFIG->unsigned_config.data[0x21])) << 8) | ((uint64_t)(LOADED_BOOTCONFIG->unsigned_config.data[0x11]));
|
|
||||||
} else {
|
|
||||||
return 0ull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_load_boot_reason(volatile boot_reason_t *boot_reason) {
|
|
||||||
g_boot_reason = *boot_reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_set_package2_hash_for_recovery(const void *package2, size_t package2_size) {
|
|
||||||
se_calculate_sha256(g_package2_hash_for_recovery, package2, package2_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootconfig_get_package2_hash_for_recovery(uint64_t *out_hash) {
|
|
||||||
for (unsigned int i = 0; i < 4; i++) {
|
|
||||||
out_hash[i] = g_package2_hash_for_recovery[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bootconfig_is_recovery_boot(void) {
|
|
||||||
return ((g_boot_reason.bootloader_attribute & 0x01) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_boot_reason(void) {
|
|
||||||
return ((uint64_t)g_boot_reason.boot_reason_state << 24) | (g_boot_reason.boot_reason_value & 0xFFFFFF);
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BOOTCONFIG_H
|
|
||||||
#define EXOSPHERE_BOOTCONFIG_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* This is kind of ConfigItem, but it's stored in BootConfig, so... */
|
|
||||||
typedef enum {
|
|
||||||
KERNELCONFIGFLAG_INITIALIZE_MEMORY_TO_PATTERN = (1 << 0),
|
|
||||||
KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS = (1 << 1),
|
|
||||||
KERNELCONFIGFLAG_ENABLE_USER_PMU_ACCESS = (1 << 2),
|
|
||||||
KERNELCONFIGFLAG_CALL_SMC_PANIC_ON_KERNEL_ERROR = (1 << 8),
|
|
||||||
} KernelConfigFlag;
|
|
||||||
|
|
||||||
/* This provides management for Switch BootConfig. */
|
|
||||||
|
|
||||||
#define LOADED_BOOTCONFIG (get_loaded_bootconfig())
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t data[0x200];
|
|
||||||
} bootconfig_unsigned_config_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t _0x0[8];
|
|
||||||
uint8_t package2_config;
|
|
||||||
uint8_t _0x9[7];
|
|
||||||
uint8_t hardware_info[0x10];
|
|
||||||
uint8_t disable_program_verification;
|
|
||||||
uint8_t _0x21[0xDF];
|
|
||||||
} bootconfig_signed_config_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bootconfig_unsigned_config_t unsigned_config;
|
|
||||||
uint8_t signature[0x100];
|
|
||||||
bootconfig_signed_config_t signed_config;
|
|
||||||
} bootconfig_t;
|
|
||||||
|
|
||||||
static inline bootconfig_t *get_loaded_bootconfig(void) {
|
|
||||||
/* this is also get_exception_entry_stack_address(2) */
|
|
||||||
return (bootconfig_t *)(TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x180);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t bootloader_version;
|
|
||||||
uint32_t bootloader_start_block;
|
|
||||||
uint32_t bootloader_start_page;
|
|
||||||
uint32_t bootloader_attribute;
|
|
||||||
uint32_t boot_reason_value;
|
|
||||||
uint32_t boot_reason_state;
|
|
||||||
} boot_reason_t;
|
|
||||||
|
|
||||||
void bootconfig_load_and_verify(const bootconfig_t *bootconfig);
|
|
||||||
void bootconfig_clear(void);
|
|
||||||
|
|
||||||
void bootconfig_load_boot_reason(volatile boot_reason_t *boot_reason);
|
|
||||||
|
|
||||||
void bootconfig_set_package2_hash_for_recovery(const void *package2, size_t package2_size);
|
|
||||||
void bootconfig_get_package2_hash_for_recovery(uint64_t *out_hash);
|
|
||||||
|
|
||||||
/* Actual configuration getters. */
|
|
||||||
bool bootconfig_is_package2_plaintext(void);
|
|
||||||
bool bootconfig_is_package2_unsigned(void);
|
|
||||||
void bootconfig_set_package2_plaintext_and_unsigned(void);
|
|
||||||
bool bootconfig_disable_program_verification(void);
|
|
||||||
bool bootconfig_is_debug_mode(void);
|
|
||||||
|
|
||||||
bool bootconfig_take_extabt_serror_to_el3(void);
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_value_for_sysctr0(void);
|
|
||||||
|
|
||||||
uint64_t bootconfig_get_memory_arrangement(void);
|
|
||||||
uint64_t bootconfig_get_kernel_configuration(void);
|
|
||||||
|
|
||||||
bool bootconfig_is_recovery_boot(void);
|
|
||||||
uint64_t bootconfig_get_boot_reason(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,381 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdbool.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bootup.h"
|
|
||||||
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "bpmp.h"
|
|
||||||
#include "flow.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "mc.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "masterkey.h"
|
|
||||||
#include "configitem.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "uart.h"
|
|
||||||
#include "bpmp.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
#include "cpu_context.h"
|
|
||||||
#include "actmon.h"
|
|
||||||
#include "sysctr0.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "synchronization.h"
|
|
||||||
|
|
||||||
static bool g_has_booted_up = false;
|
|
||||||
|
|
||||||
void setup_dram_magic_numbers(void) {
|
|
||||||
/* These DRAM writes test and set values for the GPU UCODE carveout. */
|
|
||||||
unsigned int target_fw = exosphere_get_target_firmware();
|
|
||||||
(*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC; /* Access test value. */
|
|
||||||
flush_dcache_range((void *)0x8005FFFC, (void *)0x80060000);
|
|
||||||
if (ATMOSPHERE_TARGET_FIRMWARE_6_0_0 <= target_fw) {
|
|
||||||
(*(volatile uint32_t *)(0x8005FF00)) = 0x00000083; /* SKU code. */
|
|
||||||
(*(volatile uint32_t *)(0x8005FF04)) = 0x00000002;
|
|
||||||
(*(volatile uint32_t *)(0x8005FF08)) = 0x00000210; /* Tegra210 code. */
|
|
||||||
flush_dcache_range((void *)0x8005FF00, (void *)0x8005FF0C);
|
|
||||||
}
|
|
||||||
__dsb_sy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootup_misc_mmio(void) {
|
|
||||||
/* Initialize Fuse registers. */
|
|
||||||
fuse_init();
|
|
||||||
|
|
||||||
/* Verify Security Engine sanity. */
|
|
||||||
se_set_in_context_save_mode(false);
|
|
||||||
/* TODO: se_verify_keys_unreadable(); */
|
|
||||||
se_validate_stored_vector();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_SWITCH_SESSIONKEY; i++) {
|
|
||||||
clear_aes_keyslot(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
|
||||||
clear_rsa_keyslot(i);
|
|
||||||
}
|
|
||||||
se_initialize_rng(KEYSLOT_SWITCH_RNGKEY);
|
|
||||||
se_generate_random_key(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY);
|
|
||||||
se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY);
|
|
||||||
|
|
||||||
if (!g_has_booted_up && (ATMOSPHERE_TARGET_FIRMWARE_6_0_0 > exosphere_get_target_firmware())) {
|
|
||||||
setup_dram_magic_numbers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On 9.0.0+, Nintendo writes random values to context save scratch here, and locks the SRK scratch. */
|
|
||||||
/* There's no real need for us to do this, so we won't. */
|
|
||||||
|
|
||||||
/* Mark TMR5, TMR6, TMR7, TMR8, WDT0, WDT1, WDT2 and WDT3 as secure. */
|
|
||||||
SHARED_TIMER_SECURE_CFG_0 = 0xF1E0;
|
|
||||||
|
|
||||||
FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 = 4; /* ACTIVE_CLUSTER_LOCK. */
|
|
||||||
FLOW_CTLR_FLOW_DBG_QUAL_0 = 0x10000000; /* Enable FIQ2CCPLEX */
|
|
||||||
|
|
||||||
/* Disable Deep Power Down. */
|
|
||||||
APBDEV_PMC_DPD_ENABLE_0 = 0;
|
|
||||||
|
|
||||||
/* Setup MC carveouts. */
|
|
||||||
MAKE_MC_REG(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 1;
|
|
||||||
MAKE_MC_REG(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0;
|
|
||||||
MAKE_MC_REG(MC_VIDEO_PROTECT_BOM) = 0;
|
|
||||||
MAKE_MC_REG(MC_VIDEO_PROTECT_SIZE_MB) = 0;
|
|
||||||
MAKE_MC_REG(MC_VIDEO_PROTECT_REG_CTRL) = 1;
|
|
||||||
MAKE_MC_REG(MC_SEC_CARVEOUT_BOM) = 0;
|
|
||||||
MAKE_MC_REG(MC_SEC_CARVEOUT_SIZE_MB) = 0;
|
|
||||||
MAKE_MC_REG(MC_SEC_CARVEOUT_REG_CTRL) = 1;
|
|
||||||
MAKE_MC_REG(MC_MTS_CARVEOUT_BOM) = 0;
|
|
||||||
MAKE_MC_REG(MC_MTS_CARVEOUT_SIZE_MB) = 0;
|
|
||||||
MAKE_MC_REG(MC_MTS_CARVEOUT_ADR_HI) = 0;
|
|
||||||
MAKE_MC_REG(MC_MTS_CARVEOUT_REG_CTRL) = 1;
|
|
||||||
MAKE_MC_REG(MC_SECURITY_CFG0) = 0;
|
|
||||||
MAKE_MC_REG(MC_SECURITY_CFG1) = 0;
|
|
||||||
MAKE_MC_REG(MC_SECURITY_CFG3) = 3;
|
|
||||||
configure_default_carveouts();
|
|
||||||
|
|
||||||
/* Mark registers secure world only. */
|
|
||||||
if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 = APB_SSER0_SATA_AUX | APB_SSER0_DTV | APB_SSER0_QSPI | APB_SSER0_SATA | APB_SSER0_LA;
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 = APB_SSER1_SPI1 | APB_SSER1_SPI2 | APB_SSER1_SPI3 | APB_SSER1_SPI5 | APB_SSER1_SPI6 | APB_SSER1_I2C4 | APB_SSER1_I2C6;
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = 1 << 4 | 1 << 5 | APB_SSER2_DDS; /* bits 4 and 5 are not labeled in 21.1.7.3 */
|
|
||||||
} else {
|
|
||||||
/* Mark SATA_AUX, DTV, QSPI, SE, SATA, LA secure only. */
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 = APB_SSER0_SATA_AUX | APB_SSER0_DTV | APB_SSER0_QSPI | APB_SSER0_SE | APB_SSER0_SATA | APB_SSER0_LA;
|
|
||||||
|
|
||||||
/* By default, mark SPI1, SPI2, SPI3, SPI5, SPI6, I2C6 secure only. */
|
|
||||||
uint32_t sec_disable_1 = APB_SSER1_SPI1 | APB_SSER1_SPI2 | APB_SSER1_SPI3 | APB_SSER1_SPI5 | APB_SSER1_SPI6 | APB_SSER1_I2C6;
|
|
||||||
/* By default, mark SDMMC3, DDS, DP2 secure only. */
|
|
||||||
uint32_t sec_disable_2 = APB_SSER2_SDMMC3 | APB_SSER2_DDS | APB_SSER2_DP2;
|
|
||||||
uint64_t hardware_type = configitem_get_hardware_type();
|
|
||||||
if (hardware_type != 1) {
|
|
||||||
/* Also mark I2C4 secure only, */
|
|
||||||
sec_disable_1 |= APB_SSER1_I2C4;
|
|
||||||
}
|
|
||||||
if (hardware_type != 0 && exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
/* Starting on 4.x on non-dev units, mark UARTB, UARTC, SPI4, I2C3 secure only. */
|
|
||||||
sec_disable_1 |= APB_SSER1_UART_B | APB_SSER1_UART_C | APB_SSER1_SPI4 | APB_SSER1_I2C3;
|
|
||||||
/* Starting on 4.x on non-dev units, mark SDMMC1 secure only. */
|
|
||||||
sec_disable_2 |= APB_SSER2_SDMMC1;
|
|
||||||
}
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 = sec_disable_1;
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = sec_disable_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset Translation Enable registers. */
|
|
||||||
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_0) = 0xFFFFFFFF;
|
|
||||||
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_1) = 0xFFFFFFFF;
|
|
||||||
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_2) = 0xFFFFFFFF;
|
|
||||||
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_3) = 0xFFFFFFFF;
|
|
||||||
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_4) = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
/* Set SMMU ASID security registers. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0xE;
|
|
||||||
} else {
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0x0;
|
|
||||||
}
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_1) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_2) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_3) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_4) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_5) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_6) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_7) = 0;
|
|
||||||
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTB_ASID) = 0;
|
|
||||||
}
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTB_DATA) = 0;
|
|
||||||
MAKE_MC_REG(MC_SMMU_TLB_CONFIG) = 0x30000030;
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTC_CONFIG) = 0x2800003F;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTC_FLUSH) = 0;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_TLB_FLUSH) = 0;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_CONFIG) = 1; /* Enable SMMU. */
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
|
|
||||||
/* Clear RESET Vector, setup CPU Secure Boot RESET Vectors. */
|
|
||||||
uint32_t reset_vec;
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
reset_vec = TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN);
|
|
||||||
} else {
|
|
||||||
reset_vec = TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN);
|
|
||||||
}
|
|
||||||
EVP_CPU_RESET_VECTOR_0 = 0;
|
|
||||||
SB_AA64_RESET_LOW_0 = reset_vec | 1;
|
|
||||||
SB_AA64_RESET_HIGH_0 = 0;
|
|
||||||
|
|
||||||
/* Lock Non-Secure writes to Secure Boot RESET Vector. */
|
|
||||||
SB_CSR_0 = 2;
|
|
||||||
|
|
||||||
/* Setup PMC Secure Scratch RESET Vector for warmboot. */
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH34_0 = reset_vec;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH35_0 = 0;
|
|
||||||
APBDEV_PMC_SEC_DISABLE3_0 = 0x500000;
|
|
||||||
|
|
||||||
/* Setup FIQs. */
|
|
||||||
|
|
||||||
/* And assign "se_operation_completed" to Interrupt 0x5A. */
|
|
||||||
intr_set_priority(INTERRUPT_ID_SECURITY_ENGINE, 0);
|
|
||||||
intr_set_group(INTERRUPT_ID_SECURITY_ENGINE, 0);
|
|
||||||
intr_set_enabled(INTERRUPT_ID_SECURITY_ENGINE, 1);
|
|
||||||
intr_set_cpu_mask(INTERRUPT_ID_SECURITY_ENGINE, 8);
|
|
||||||
intr_set_edge_level(INTERRUPT_ID_SECURITY_ENGINE, 0);
|
|
||||||
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
intr_set_priority(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0);
|
|
||||||
intr_set_group(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0);
|
|
||||||
intr_set_enabled(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 1);
|
|
||||||
intr_set_cpu_mask(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 8);
|
|
||||||
intr_set_edge_level(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_has_booted_up) {
|
|
||||||
/* N doesn't do this, but we should for compatibility. */
|
|
||||||
uart_config(UART_A);
|
|
||||||
clkrst_reboot(CARDEVICE_UARTA);
|
|
||||||
uart_init(UART_A, 115200);
|
|
||||||
|
|
||||||
intr_register_handler(INTERRUPT_ID_SECURITY_ENGINE, se_operation_completed);
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
intr_register_handler(INTERRUPT_ID_ACTIVITY_MONITOR_4X, actmon_interrupt_handler);
|
|
||||||
}
|
|
||||||
for (unsigned int core = 1; core < NUM_CPU_CORES; core++) {
|
|
||||||
set_core_is_active(core, false);
|
|
||||||
}
|
|
||||||
g_has_booted_up = true;
|
|
||||||
} else if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
/* Disable AHB redirect. */
|
|
||||||
MAKE_MC_REG(MC_IRAM_BOM) = 0xFFFFF000;
|
|
||||||
MAKE_MC_REG(MC_IRAM_TOM) = 0;
|
|
||||||
MAKE_MC_REG(MC_IRAM_REG_CTRL) |= 1;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 &= 0xFFF7FFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_4x_mmio(void) {
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
configure_gpu_ucode_carveout();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable AHB redirect. */
|
|
||||||
MAKE_MC_REG(MC_IRAM_BOM) = 0xFFFFF000;
|
|
||||||
MAKE_MC_REG(MC_IRAM_TOM) = 0;
|
|
||||||
MAKE_MC_REG(MC_IRAM_REG_CTRL) |= 1;
|
|
||||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 &= 0xFFF7FFFF;
|
|
||||||
|
|
||||||
/* TODO: What are these PMC scratch writes? */
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH51_0 = (APBDEV_PMC_SECURE_SCRATCH51_0 & 0xFFFF8000) | 0x4000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH16_0 &= 0x3FFFFFFF;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH55_0 = (APBDEV_PMC_SECURE_SCRATCH55_0 & 0xFF000FFF) | 0x1000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH74_0 = 0x40008000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH75_0 = 0x40000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH76_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH77_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH78_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH99_0 = 0x40008000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH100_0 = 0x40000;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH101_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH102_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH103_0 = 0x0;
|
|
||||||
APBDEV_PMC_SECURE_SCRATCH39_0 = (APBDEV_PMC_SECURE_SCRATCH39_0 & 0xF8000000) | 0x88;
|
|
||||||
|
|
||||||
/* TODO: Do we want to bother locking the secure scratch registers? */
|
|
||||||
/* 4.x Jamais Vu mitigations. */
|
|
||||||
/* Overwrite exception vectors. */
|
|
||||||
BPMP_VECTOR_RESET = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_UNDEF = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_SWI = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_PREFETCH_ABORT = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_DATA_ABORT = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_UNK = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_IRQ = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
BPMP_VECTOR_FIQ = BPMP_MITIGATION_RESET_VAL;
|
|
||||||
|
|
||||||
/* Disable AHB arbitration for the BPMP. */
|
|
||||||
AHB_ARBITRATION_DISABLE_0 |= 2;
|
|
||||||
|
|
||||||
/* Set SMMU for BPMP/APB-DMA to point to TZRAM. */
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTB_ASID) = 1;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTB_DATA) = 0x70012;
|
|
||||||
MAKE_MC_REG(MC_SMMU_AVPC_ASID) = 0x80000001;
|
|
||||||
MAKE_MC_REG(MC_SMMU_PPCS1_ASID) = 0x80000001;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_PTC_FLUSH) = 0;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
MAKE_MC_REG(MC_SMMU_TLB_FLUSH) = 0;
|
|
||||||
(void)MAKE_MC_REG(MC_SMMU_TLB_CONFIG);
|
|
||||||
|
|
||||||
/* Wait for the BPMP to halt. */
|
|
||||||
while ((FLOW_CTLR_HALT_COP_EVENTS_0 >> 29) != 2) {
|
|
||||||
wait(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If not in a debugging context, setup the activity monitor. */
|
|
||||||
if ((get_debug_authentication_status() & 3) != 3) {
|
|
||||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000;
|
|
||||||
clkrst_reboot(CARDEVICE_ACTMON);
|
|
||||||
/* Sample every microsecond. */
|
|
||||||
ACTMON_GLB_PERIOD_CTRL_0 = 0x100;
|
|
||||||
/* Fire interrupt every wakeup. */
|
|
||||||
ACTMON_COP_UPPER_WMARK_0 = 0;
|
|
||||||
/* Cause a panic() on BPMP wakeup. */
|
|
||||||
actmon_set_callback(actmon_on_bpmp_wakeup);
|
|
||||||
/* Enable interrupt when above watermark, periodic sampling. */
|
|
||||||
ACTMON_COP_CTRL_0 = 0xC0040000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_current_core_state(void) {
|
|
||||||
uint64_t temp_reg;
|
|
||||||
|
|
||||||
/* Setup system registers. */
|
|
||||||
SET_SYSREG(spsr_el3, 0b1111 << 6 | 0b0101); /* use EL2h+DAIF set initially, may be overwritten later. Not in official code */
|
|
||||||
|
|
||||||
SET_SYSREG(actlr_el3, 0x73ull);
|
|
||||||
SET_SYSREG(actlr_el2, 0x73ull);
|
|
||||||
SET_SYSREG(hcr_el2, 0x80000000ull);
|
|
||||||
SET_SYSREG(dacr32_el2, 0xFFFFFFFFull);
|
|
||||||
SET_SYSREG(sctlr_el1, 0xC50838ull);
|
|
||||||
SET_SYSREG(sctlr_el2, 0x30C50838ull);
|
|
||||||
|
|
||||||
__isb();
|
|
||||||
|
|
||||||
SET_SYSREG(cntfrq_el0, SYSCTR0_CNTFID0_0);
|
|
||||||
SET_SYSREG(cnthctl_el2, 3ull);
|
|
||||||
|
|
||||||
__isb();
|
|
||||||
|
|
||||||
/* Setup Interrupts, flow. */
|
|
||||||
flow_clear_csr0_and_events(get_core_id());
|
|
||||||
intr_initialize_gic();
|
|
||||||
intr_set_priority(INTERRUPT_ID_1C, 0);
|
|
||||||
intr_set_group(INTERRUPT_ID_1C, 0);
|
|
||||||
intr_set_enabled(INTERRUPT_ID_1C, 1);
|
|
||||||
|
|
||||||
/* Restore current core context. */
|
|
||||||
restore_current_core_context();
|
|
||||||
}
|
|
||||||
|
|
||||||
void identity_unmap_iram_cd_tzram(void) {
|
|
||||||
/* See also: configure_ttbls (in coldboot_init.c). */
|
|
||||||
/*uintptr_t *mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
|
|
||||||
uintptr_t *mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE);*/
|
|
||||||
uintptr_t *mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE);
|
|
||||||
|
|
||||||
mmu_unmap_range(3, mmu_l3_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_IRAM_A_CCRT0), IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_IRAM_A_CCRT0));
|
|
||||||
mmu_unmap_range(3, mmu_l3_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_IRAM_CD), IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_IRAM_CD));
|
|
||||||
/*mmu_unmap_range(3, mmu_l3_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_TZRAM), IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_TZRAM));
|
|
||||||
|
|
||||||
mmu_unmap(2, mmu_l2_tbl, 0x40000000);
|
|
||||||
mmu_unmap(2, mmu_l2_tbl, 0x7C000000);
|
|
||||||
|
|
||||||
mmu_unmap(1, mmu_l1_tbl, 0x40000000);*/
|
|
||||||
|
|
||||||
tlb_invalidate_all_inner_shareable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void secure_additional_devices(void) {
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 |= APB_SSER0_PMC; /* make PMC secure-only (2.x+) */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 |= APB_SSER1_MC0 | APB_SSER1_MC1 | APB_SSER1_MCB; /* make MC0, MC1, MCB secure-only (4.x+) */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_extabt_serror_taken_to_el3(bool taken_to_el3) {
|
|
||||||
uint64_t temp_scr_el3;
|
|
||||||
__asm__ __volatile__ ("mrs %0, scr_el3" : "=r"(temp_scr_el3) :: "memory");
|
|
||||||
|
|
||||||
temp_scr_el3 &= 0xFFFFFFF7;
|
|
||||||
temp_scr_el3 |= taken_to_el3 ? 8 : 0;
|
|
||||||
|
|
||||||
__asm__ __volatile__ ("msr scr_el3, %0" :: "r"(temp_scr_el3) : "memory");
|
|
||||||
__isb();
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BOOTUP_H
|
|
||||||
#define EXOSPHERE_BOOTUP_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* 21.1.7 AP Control Registers */
|
|
||||||
/* 21.1.7.1 APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 slaves */
|
|
||||||
typedef enum {
|
|
||||||
APB_SSER0_MISC_REGS = 1 << 1, /* PP, SC1x pads and GP registers */
|
|
||||||
APB_SSER0_SATA_AUX = 1 << 2,
|
|
||||||
APB_SSER0_PINMUX_AUX = 1 << 3,
|
|
||||||
APB_SSER0_APE = 1 << 4,
|
|
||||||
|
|
||||||
APB_SSER0_DTV = 1 << 6,
|
|
||||||
|
|
||||||
APB_SSER0_PWM = 1 << 8, /* PWFM */
|
|
||||||
APB_SSER0_QSPI = 1 << 9,
|
|
||||||
APB_SSER0_CSITE = 1 << 10, /* Core Site */
|
|
||||||
APB_SSER0_RTC = 1 << 11,
|
|
||||||
|
|
||||||
APB_SSER0_PMC = 1 << 13,
|
|
||||||
APB_SSER0_SE = 1 << 14, /* Security Engine */
|
|
||||||
APB_SSER0_FUSE = 1 << 15,
|
|
||||||
APB_SSER0_KFUSE = 1 << 16,
|
|
||||||
|
|
||||||
APB_SSER0_UNUSED = 1 << 18, /* reserved, unused but listed as accessible */
|
|
||||||
|
|
||||||
APB_SSER0_SATA = 1 << 20,
|
|
||||||
APB_SSER0_HDA = 1 << 21,
|
|
||||||
APB_SSER0_LA = 1 << 22,
|
|
||||||
APB_SSER0_ATOMICS = 1 << 23,
|
|
||||||
APB_SSER0_CEC = 1 << 24,
|
|
||||||
|
|
||||||
STM = 1 << 29
|
|
||||||
} APB_SSER0;
|
|
||||||
|
|
||||||
/* 21.1.7.2 APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 slaves */
|
|
||||||
typedef enum {
|
|
||||||
APB_SSER1_MC0 = 1 << 4,
|
|
||||||
APB_SSER1_EMC0 = 1 << 5,
|
|
||||||
|
|
||||||
APB_SSER1_MC1 = 1 << 8,
|
|
||||||
APB_SSER1_EMC1 = 1 << 9,
|
|
||||||
APB_SSER1_MCB = 1 << 10,
|
|
||||||
APB_SSER1_EMBC = 1 << 11,
|
|
||||||
APB_SSER1_UART_A = 1 << 12,
|
|
||||||
APB_SSER1_UART_B = 1 << 13,
|
|
||||||
APB_SSER1_UART_C = 1 << 14,
|
|
||||||
APB_SSER1_UART_D = 1 << 15,
|
|
||||||
|
|
||||||
APB_SSER1_SPI1 = 1 << 20,
|
|
||||||
APB_SSER1_SPI2 = 1 << 21,
|
|
||||||
APB_SSER1_SPI3 = 1 << 22,
|
|
||||||
APB_SSER1_SPI4 = 1 << 23,
|
|
||||||
APB_SSER1_SPI5 = 1 << 24,
|
|
||||||
APB_SSER1_SPI6 = 1 << 25,
|
|
||||||
APB_SSER1_I2C1 = 1 << 26,
|
|
||||||
APB_SSER1_I2C2 = 1 << 27,
|
|
||||||
APB_SSER1_I2C3 = 1 << 28,
|
|
||||||
APB_SSER1_I2C4 = 1 << 29,
|
|
||||||
APB_SSER1_DVC = 1 << 30,
|
|
||||||
APB_SSER1_I2C5 = 1 << 30,
|
|
||||||
APB_SSER1_I2C6 = 1 << 31 /* this will show as negative because of the 32bit sign bit being set */
|
|
||||||
} APB_SSER1;
|
|
||||||
|
|
||||||
/* 21.1.7.3 APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 slaves */
|
|
||||||
typedef enum {
|
|
||||||
APB_SSER2_SDMMC1 = 1 << 0,
|
|
||||||
APB_SSER2_SDMMC2 = 1 << 1,
|
|
||||||
APB_SSER2_SDMMC3 = 1 << 2,
|
|
||||||
APB_SSER2_SDMMC4 = 1 << 3,
|
|
||||||
|
|
||||||
APB_SSER2_MIPIBIF = 1 << 7, /* reserved */
|
|
||||||
APB_SSER2_DDS = 1 << 8,
|
|
||||||
APB_SSER2_DP2 = 1 << 9,
|
|
||||||
APB_SSER2_SOC_THERM = 1 << 10,
|
|
||||||
APB_SSER2_APB2JTAG = 1 << 11,
|
|
||||||
APB_SSER2_XUSB_HOST = 1 << 12,
|
|
||||||
APB_SSER2_XUSB_DEV = 1 << 13,
|
|
||||||
APB_SSER2_XUSB_PADCTL = 1 << 14,
|
|
||||||
APB_SSER2_MIPI_CAL = 1 << 15,
|
|
||||||
APB_SSER2_DVFS = 1 << 16
|
|
||||||
} APB_SSER2;
|
|
||||||
|
|
||||||
void bootup_misc_mmio(void);
|
|
||||||
|
|
||||||
void setup_4x_mmio(void);
|
|
||||||
|
|
||||||
void setup_dram_magic_numbers(void);
|
|
||||||
|
|
||||||
void setup_current_core_state(void);
|
|
||||||
|
|
||||||
void identity_unmap_iram_cd_tzram(void);
|
|
||||||
|
|
||||||
void secure_additional_devices(void);
|
|
||||||
|
|
||||||
void set_extabt_serror_taken_to_el3(bool taken_to_el3);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_BPMP_H
|
|
||||||
#define EXOSPHERE_BPMP_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere register definitions for the Tegra X1 BPMP vectors. */
|
|
||||||
|
|
||||||
static inline uintptr_t get_bpmp_vector_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_EXCEPTION_VECTORS);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BPMP_VECTOR_BASE (get_bpmp_vector_base())
|
|
||||||
|
|
||||||
#define EVP_CPU_RESET_VECTOR_0 MAKE_REG32(BPMP_VECTOR_BASE + 0x100)
|
|
||||||
|
|
||||||
#define BPMP_VECTOR_RESET MAKE_REG32(BPMP_VECTOR_BASE + 0x200)
|
|
||||||
#define BPMP_VECTOR_UNDEF MAKE_REG32(BPMP_VECTOR_BASE + 0x204)
|
|
||||||
#define BPMP_VECTOR_SWI MAKE_REG32(BPMP_VECTOR_BASE + 0x208)
|
|
||||||
#define BPMP_VECTOR_PREFETCH_ABORT MAKE_REG32(BPMP_VECTOR_BASE + 0x20C)
|
|
||||||
#define BPMP_VECTOR_DATA_ABORT MAKE_REG32(BPMP_VECTOR_BASE + 0x210)
|
|
||||||
#define BPMP_VECTOR_UNK MAKE_REG32(BPMP_VECTOR_BASE + 0x214)
|
|
||||||
#define BPMP_VECTOR_IRQ MAKE_REG32(BPMP_VECTOR_BASE + 0x218)
|
|
||||||
#define BPMP_VECTOR_FIQ MAKE_REG32(BPMP_VECTOR_BASE + 0x21C)
|
|
||||||
|
|
||||||
#define BPMP_MITIGATION_RESET_VAL 0x7D000000
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "utils.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "timers.h"
|
|
||||||
|
|
||||||
static inline uint32_t 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: generic_panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t 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: generic_panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
|
|
||||||
static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
|
|
||||||
|
|
||||||
void clk_enable(CarDevice dev) {
|
|
||||||
uint32_t 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clkrst_enable_fuse_regs(bool enable) {
|
|
||||||
CLK_RST_CONTROLLER_MISC_CLK_ENB_0 = ((CLK_RST_CONTROLLER_MISC_CLK_ENB_0 & 0xEFFFFFFF) | ((enable & 1) << 28));
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_CLOCK_AND_RESET_H
|
|
||||||
#define EXOSPHERE_CLOCK_AND_RESET_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere Driver for the Tegra X1 Clock and Reset registers. */
|
|
||||||
|
|
||||||
#define CAR_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_CLKRST))
|
|
||||||
|
|
||||||
#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);
|
|
||||||
|
|
||||||
void clkrst_enable_fuse_regs(bool enable);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
#include "utils.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "package2.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
|
|
||||||
#undef MAILBOX_NX_BOOTLOADER_BASE
|
|
||||||
#undef TIMERS_BASE
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (MMIO_GET_DEVICE_7X_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX)) : (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX))
|
|
||||||
#define TIMERS_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_TMRs_WDTs))
|
|
||||||
|
|
||||||
extern const uint8_t __start_cold[];
|
|
||||||
|
|
||||||
/* warboot_init.c */
|
|
||||||
extern unsigned int g_exosphere_target_firmware_for_init;
|
|
||||||
void init_dma_controllers(unsigned int target_firmware);
|
|
||||||
void set_memory_registers_enable_mmu_1x_ttbr0(void);
|
|
||||||
void set_memory_registers_enable_mmu_5x_ttbr0(void);
|
|
||||||
|
|
||||||
static void identity_map_all_mappings(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl) {
|
|
||||||
static const uintptr_t addrs[] = { TUPLE_FOLD_LEFT_0(EVAL(IDENTIY_MAPPING_ID_MAX), _MMAPID, COMMA) };
|
|
||||||
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(IDENTIY_MAPPING_ID_MAX), _MMAPID, COMMA) };
|
|
||||||
static const uint64_t attribs[] = { TUPLE_FOLD_LEFT_2(EVAL(IDENTIY_MAPPING_ID_MAX), _MMAPID, COMMA) };
|
|
||||||
static const uint64_t is_block[] = { TUPLE_FOLD_LEFT_3(EVAL(IDENTIY_MAPPING_ID_MAX), _MMAPID, COMMA) };
|
|
||||||
|
|
||||||
for(size_t i = 0; i < IDENTIY_MAPPING_ID_MAX; i++) {
|
|
||||||
identity_map_mapping(mmu_l1_tbl, mmu_l3_tbl, addrs[i], sizes[i], attribs[i], is_block[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mmio_map_all_devices(uintptr_t *mmu_l3_tbl, unsigned int target_firmware) {
|
|
||||||
static const uintptr_t pas[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
|
|
||||||
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
|
|
||||||
static const bool is_secure[] = { TUPLE_FOLD_LEFT_2(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
|
|
||||||
|
|
||||||
static const uintptr_t pas_7x[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV7X, COMMA) };
|
|
||||||
|
|
||||||
for(size_t i = 0, offset = 0; i < MMIO_DEVID_MAX; i++) {
|
|
||||||
uintptr_t pa = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? pas[i] : pas_7x[i];
|
|
||||||
mmio_map_device(mmu_l3_tbl, MMIO_BASE + offset, pa, sizes[i], is_secure[i]);
|
|
||||||
offset += sizes[i];
|
|
||||||
offset += 0x1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lp0_entry_map_all_ram_segments(uintptr_t *mmu_l3_tbl) {
|
|
||||||
static const uintptr_t pas[] = { TUPLE_FOLD_LEFT_0(EVAL(LP0_ENTRY_RAM_SEGMENT_ID_MAX), _MMAPLP0ES, COMMA) };
|
|
||||||
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(LP0_ENTRY_RAM_SEGMENT_ID_MAX), _MMAPLP0ES, COMMA) };
|
|
||||||
static const uint64_t attribs[] = { TUPLE_FOLD_LEFT_2(EVAL(LP0_ENTRY_RAM_SEGMENT_ID_MAX), _MMAPLP0ES, COMMA) };
|
|
||||||
|
|
||||||
for(size_t i = 0, offset = 0; i < LP0_ENTRY_RAM_SEGMENT_ID_MAX; i++) {
|
|
||||||
lp0_entry_map_ram_segment(mmu_l3_tbl, LP0_ENTRY_RAM_SEGMENT_BASE + offset, pas[i], sizes[i], attribs[i]);
|
|
||||||
offset += 0x10000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void warmboot_map_all_ram_segments(uintptr_t *mmu_l3_tbl) {
|
|
||||||
static const uintptr_t pas[] = { TUPLE_FOLD_LEFT_0(EVAL(WARMBOOT_RAM_SEGMENT_ID_MAX), _MMAPWBS, COMMA) };
|
|
||||||
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(WARMBOOT_RAM_SEGMENT_ID_MAX), _MMAPWBS, COMMA) };
|
|
||||||
static const uint64_t attribs[] = { TUPLE_FOLD_LEFT_2(EVAL(WARMBOOT_RAM_SEGMENT_ID_MAX), _MMAPWBS, COMMA) };
|
|
||||||
|
|
||||||
for(size_t i = 0, offset = 0; i < WARMBOOT_RAM_SEGMENT_ID_MAX; i++) {
|
|
||||||
warmboot_map_ram_segment(mmu_l3_tbl, WARMBOOT_RAM_SEGMENT_BASE + offset, pas[i], sizes[i], attribs[i]);
|
|
||||||
offset += sizes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tzram_map_all_segments(uintptr_t *mmu_l3_tbl, unsigned int target_firmware) {
|
|
||||||
static const uintptr_t offs[] = { TUPLE_FOLD_LEFT_0(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) };
|
|
||||||
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) };
|
|
||||||
static const size_t increments[] = { TUPLE_FOLD_LEFT_2(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) };
|
|
||||||
static const bool is_executable[] = { TUPLE_FOLD_LEFT_3(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) };
|
|
||||||
|
|
||||||
static const uintptr_t offs_5x[] = { TUPLE_FOLD_LEFT_0(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZ5XS, COMMA) };
|
|
||||||
|
|
||||||
for(size_t i = 0, offset = 0; i < TZRAM_SEGMENT_ID_MAX; i++) {
|
|
||||||
uintptr_t off = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) ? offs[i] : offs_5x[i];
|
|
||||||
tzram_map_segment(mmu_l3_tbl, TZRAM_SEGMENT_BASE + offset, 0x7C010000ull + off, sizes[i], is_executable[i]);
|
|
||||||
offset += increments[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void configure_ttbls(unsigned int target_firmware) {
|
|
||||||
uintptr_t *mmu_l1_tbl;
|
|
||||||
uintptr_t *mmu_l2_tbl;
|
|
||||||
uintptr_t *mmu_l3_tbl;
|
|
||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
|
|
||||||
mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE);
|
|
||||||
mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE);
|
|
||||||
} else {
|
|
||||||
mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
|
|
||||||
mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE);
|
|
||||||
mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mmu_init_table(mmu_l1_tbl, 64); /* 33-bit address space */
|
|
||||||
mmu_init_table(mmu_l2_tbl, 4096);
|
|
||||||
/*
|
|
||||||
Nintendo uses the same L3 table for everything, but they make sure
|
|
||||||
nothing clashes.
|
|
||||||
*/
|
|
||||||
mmu_init_table(mmu_l3_tbl, 4096);
|
|
||||||
|
|
||||||
mmu_map_table(1, mmu_l1_tbl, 0x40000000, mmu_l2_tbl, 0);
|
|
||||||
mmu_map_table(1, mmu_l1_tbl, 0x1C0000000, mmu_l2_tbl, 0);
|
|
||||||
|
|
||||||
mmu_map_table(2, mmu_l2_tbl, 0x40000000, mmu_l3_tbl, 0);
|
|
||||||
mmu_map_table(2, mmu_l2_tbl, 0x7C000000, mmu_l3_tbl, 0);
|
|
||||||
mmu_map_table(2, mmu_l2_tbl, 0x1F0000000ull, mmu_l3_tbl, 0);
|
|
||||||
|
|
||||||
identity_map_all_mappings(mmu_l1_tbl, mmu_l3_tbl);
|
|
||||||
mmio_map_all_devices(mmu_l3_tbl, target_firmware);
|
|
||||||
lp0_entry_map_all_ram_segments(mmu_l3_tbl);
|
|
||||||
warmboot_map_all_ram_segments(mmu_l3_tbl);
|
|
||||||
tzram_map_all_segments(mmu_l3_tbl, target_firmware);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_relocation(const coldboot_crt0_reloc_list_t *reloc_list, size_t index) {
|
|
||||||
extern const uint8_t __glob_origin__[];
|
|
||||||
uint64_t *p_vma = (uint64_t *)reloc_list->relocs[index].vma;
|
|
||||||
bool is_clear = reloc_list->relocs[index].lma == 0;
|
|
||||||
size_t offset = reloc_list->relocs[index].lma - (uintptr_t)__glob_origin__;
|
|
||||||
const uint64_t *p_lma = (const uint64_t *)(reloc_list->reloc_base + offset);
|
|
||||||
size_t size = reloc_list->relocs[index].end_vma - reloc_list->relocs[index].vma;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < size / 8; i++) {
|
|
||||||
p_vma[i] = is_clear ? 0 : p_lma[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_coldboot_crt0_temp_stack_address(void) {
|
|
||||||
return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_coldboot_crt0_stack_address(void) {
|
|
||||||
if (exosphere_get_target_firmware_for_init() < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
|
|
||||||
} else {
|
|
||||||
return TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, uintptr_t start_cold) {
|
|
||||||
//MAILBOX_NX_SECMON_BOOT_TIME = TIMERUS_CNTR_1US_0;
|
|
||||||
|
|
||||||
/* Custom approach */
|
|
||||||
reloc_list->reloc_base = start_cold;
|
|
||||||
|
|
||||||
/* TODO: Set NX BOOTLOADER clock time field */
|
|
||||||
|
|
||||||
/* This at least copies .warm_crt0 to its VMA. */
|
|
||||||
for(size_t i = 0; i < reloc_list->nb_relocs_pre_mmu_init; i++) {
|
|
||||||
do_relocation(reloc_list, i);
|
|
||||||
}
|
|
||||||
/* At this point, we can (and will) access functions located in .warm_crt0 */
|
|
||||||
|
|
||||||
/*
|
|
||||||
From https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf :
|
|
||||||
Caches may write back dirty lines at any time:
|
|
||||||
- To make space for new allocations
|
|
||||||
- Even if MMU is off
|
|
||||||
- Even if Cacheable accesses are disabled (caches are never 'off')
|
|
||||||
|
|
||||||
It should be fine to clear that here and not before.
|
|
||||||
*/
|
|
||||||
flush_dcache_all();
|
|
||||||
invalidate_icache_all();
|
|
||||||
|
|
||||||
/* Set target firmware. */
|
|
||||||
g_exosphere_target_firmware_for_init = exosphere_get_target_firmware_for_init();
|
|
||||||
|
|
||||||
/* Initialize DMA controllers, and write to AHB_GIZMO_TZRAM. */
|
|
||||||
/* TZRAM accesses should work normally after this point. */
|
|
||||||
init_dma_controllers(g_exosphere_target_firmware_for_init);
|
|
||||||
|
|
||||||
configure_ttbls(g_exosphere_target_firmware_for_init);
|
|
||||||
if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
set_memory_registers_enable_mmu_1x_ttbr0();
|
|
||||||
} else {
|
|
||||||
set_memory_registers_enable_mmu_5x_ttbr0();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy or clear the remaining sections */
|
|
||||||
for(size_t i = 0; i < reloc_list->nb_relocs_post_mmu_init; i++) {
|
|
||||||
do_relocation(reloc_list, reloc_list->nb_relocs_pre_mmu_init + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
flush_dcache_all();
|
|
||||||
invalidate_icache_all();
|
|
||||||
/* At this point we can access all the mapped segments (all other functions, data...) normally */
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
#include "utils.h"
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "cpu_context.h"
|
|
||||||
|
|
||||||
extern uint8_t __pk2ldr_start__[], __pk2ldr_end__[];
|
|
||||||
|
|
||||||
void coldboot_main(void) {
|
|
||||||
uintptr_t *mmu_l3_table = (uintptr_t *)TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE);
|
|
||||||
uintptr_t pk2ldr = TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_PK2LDR);
|
|
||||||
|
|
||||||
/* Clear and unmap pk2ldr (which is reused as exception entry stacks) */
|
|
||||||
memset((void *)pk2ldr, 0, __pk2ldr_end__ - __pk2ldr_start__);
|
|
||||||
mmu_unmap_range(3, mmu_l3_table, pk2ldr, __pk2ldr_end__ - __pk2ldr_start__);
|
|
||||||
tlb_invalidate_all_inner_shareable();
|
|
||||||
|
|
||||||
core_jump_to_lower_el();
|
|
||||||
}
|
|
|
@ -1,308 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <vapours/ams_version.h>
|
|
||||||
|
|
||||||
#include "bootconfig.h"
|
|
||||||
#include "configitem.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
#include "package2.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "masterkey.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
#include "smc_ams.h"
|
|
||||||
#include "arm.h"
|
|
||||||
|
|
||||||
#define u8 uint8_t
|
|
||||||
#define u32 uint32_t
|
|
||||||
#include "rebootstub_bin.h"
|
|
||||||
#undef u8
|
|
||||||
#undef u32
|
|
||||||
|
|
||||||
static bool g_hiz_mode_enabled = false;
|
|
||||||
static bool g_debugmode_override_user = false, g_debugmode_override_priv = false;
|
|
||||||
static bool g_enable_usermode_exception_handlers = true;
|
|
||||||
static bool g_enable_usermode_pmu_access = false;
|
|
||||||
|
|
||||||
uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) {
|
|
||||||
switch (item) {
|
|
||||||
case CONFIGITEM_HIZMODE:
|
|
||||||
g_hiz_mode_enabled = (value != 0);
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEEDS_REBOOT:
|
|
||||||
/* Force a reboot, if requested. */
|
|
||||||
{
|
|
||||||
switch (value) {
|
|
||||||
case REBOOT_KIND_NO_REBOOT:
|
|
||||||
return 0;
|
|
||||||
case REBOOT_KIND_TO_RCM:
|
|
||||||
/* Set reboot kind = rcm. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x2;
|
|
||||||
break;
|
|
||||||
case REBOOT_KIND_TO_WB_PAYLOAD:
|
|
||||||
/* Set reboot kind = warmboot. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x1;
|
|
||||||
/* Patch SDRAM init to perform an SVC immediately after second write */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x634ull) = 0x2E38DFFF;
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x638ull) = 0x6001DC28;
|
|
||||||
/* Set SVC handler to jump to reboot stub in IRAM. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x520ull) = 0x4003F000;
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x53Cull) = 0x6000F208;
|
|
||||||
|
|
||||||
/* Copy reboot stub payload. */
|
|
||||||
ams_map_irampage(0x4003F000);
|
|
||||||
for (unsigned int i = 0; i < rebootstub_bin_size; i += 4) {
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_AMS_IRAM_PAGE) + i) = read32le(rebootstub_bin, i);
|
|
||||||
}
|
|
||||||
ams_unmap_irampage();
|
|
||||||
|
|
||||||
/* Ensure stub is flushed. */
|
|
||||||
flush_dcache_all();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
|
|
||||||
while (1) { }
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEEDS_SHUTDOWN:
|
|
||||||
/* Force a shutdown, if requested. */
|
|
||||||
{
|
|
||||||
if (value == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Set reboot kind = warmboot. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x1;
|
|
||||||
/* Patch SDRAM init to perform an SVC immediately after second write */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x634ull) = 0x2E38DFFF;
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x638ull) = 0x6001DC28;
|
|
||||||
/* Set SVC handler to jump to reboot stub in IRAM. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x520ull) = 0x4003F000;
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x53Cull) = 0x6000F208;
|
|
||||||
|
|
||||||
/* Copy reboot stub payload. */
|
|
||||||
ams_map_irampage(0x4003F000);
|
|
||||||
for (unsigned int i = 0; i < rebootstub_bin_size; i += 4) {
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_AMS_IRAM_PAGE) + i) = read32le(rebootstub_bin, i);
|
|
||||||
}
|
|
||||||
/* Tell rebootstub to shut down. */
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_AMS_IRAM_PAGE) + 0x10) = 0x0;
|
|
||||||
ams_unmap_irampage();
|
|
||||||
|
|
||||||
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
|
|
||||||
while (1) { }
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configitem_is_recovery_boot(void) {
|
|
||||||
uint64_t is_recovery_boot;
|
|
||||||
if (configitem_get(true, CONFIGITEM_ISRECOVERYBOOT, &is_recovery_boot) != 0) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_recovery_boot != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configitem_is_retail(void) {
|
|
||||||
uint64_t is_retail;
|
|
||||||
if (configitem_get(true, CONFIGITEM_ISRETAIL, &is_retail) != 0) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_retail != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configitem_is_hiz_mode_enabled(void) {
|
|
||||||
return g_hiz_mode_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configitem_set_hiz_mode_enabled(bool enabled) {
|
|
||||||
g_hiz_mode_enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configitem_is_debugmode_priv(void) {
|
|
||||||
uint64_t debugmode = 0;
|
|
||||||
if (configitem_get(true, CONFIGITEM_ISDEBUGMODE, &debugmode) != 0) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return debugmode != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t configitem_get_hardware_type(void) {
|
|
||||||
uint64_t hardware_type;
|
|
||||||
if (configitem_get(true, CONFIGITEM_HARDWARETYPE, &hardware_type) != 0) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
return hardware_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configitem_set_debugmode_override(bool user, bool priv) {
|
|
||||||
g_debugmode_override_user = user;
|
|
||||||
g_debugmode_override_priv = priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configitem_disable_usermode_exception_handlers(void) {
|
|
||||||
g_enable_usermode_exception_handlers = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configitem_enable_usermode_pmu_access(void) {
|
|
||||||
g_enable_usermode_pmu_access = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) {
|
|
||||||
uint32_t result = 0;
|
|
||||||
switch (item) {
|
|
||||||
case CONFIGITEM_DISABLEPROGRAMVERIFICATION:
|
|
||||||
*p_outvalue = (int)(bootconfig_disable_program_verification());
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_DRAMID:
|
|
||||||
*p_outvalue = fuse_get_dram_id();
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_SECURITYENGINEIRQ:
|
|
||||||
/* SE is interrupt #0x2C. */
|
|
||||||
*p_outvalue = INTERRUPT_ID_USER_SECURITY_ENGINE;
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_VERSION:
|
|
||||||
*p_outvalue = fuse_get_expected_fuse_version(exosphere_get_target_firmware());
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_HARDWARETYPE:
|
|
||||||
*p_outvalue = fuse_get_hardware_type(exosphere_get_target_firmware());
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_ISRETAIL:
|
|
||||||
*p_outvalue = fuse_get_retail_type();
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_ISRECOVERYBOOT:
|
|
||||||
*p_outvalue = (int)(bootconfig_is_recovery_boot());
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_DEVICEID:
|
|
||||||
*p_outvalue = fuse_get_device_id();
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_BOOTREASON:
|
|
||||||
/* For some reason, Nintendo removed it on 4.0 */
|
|
||||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
*p_outvalue = bootconfig_get_boot_reason();
|
|
||||||
} else {
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_MEMORYARRANGE:
|
|
||||||
*p_outvalue = bootconfig_get_memory_arrangement();
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_ISDEBUGMODE:
|
|
||||||
if ((privileged && g_debugmode_override_priv) || (!privileged && g_debugmode_override_user)) {
|
|
||||||
*p_outvalue = 1;
|
|
||||||
} else {
|
|
||||||
*p_outvalue = (int)(bootconfig_is_debug_mode());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_KERNELCONFIGURATION:
|
|
||||||
{
|
|
||||||
uint64_t config = bootconfig_get_kernel_configuration();
|
|
||||||
/* Enable usermode exception handlers by default. */
|
|
||||||
if (g_enable_usermode_exception_handlers) {
|
|
||||||
config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS;
|
|
||||||
}
|
|
||||||
/* Allow for enabling usermode pmu access. */
|
|
||||||
if (g_enable_usermode_pmu_access) {
|
|
||||||
config |= KERNELCONFIGFLAG_ENABLE_USER_PMU_ACCESS;
|
|
||||||
}
|
|
||||||
*p_outvalue = config;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_HIZMODE:
|
|
||||||
*p_outvalue = (int)g_hiz_mode_enabled;
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_ISQUESTUNIT:
|
|
||||||
/* Added on 3.0, used to determine whether console is a kiosk unit. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
|
|
||||||
*p_outvalue = (fuse_get_reserved_odm(4) >> 10) & 1;
|
|
||||||
} else {
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEWHARDWARETYPE_5X:
|
|
||||||
/* Added in 5.x, currently hardcoded to 0. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
*p_outvalue = 0;
|
|
||||||
} else {
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEWKEYGENERATION_5X:
|
|
||||||
/* Added in 5.x. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
*p_outvalue = fuse_get_5x_key_generation();
|
|
||||||
} else {
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_PACKAGE2HASH_5X:
|
|
||||||
/* Added in 5.x. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0 && bootconfig_is_recovery_boot()) {
|
|
||||||
bootconfig_get_package2_hash_for_recovery(p_outvalue);
|
|
||||||
} else {
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_EXOSPHERE_VERSION:
|
|
||||||
/* UNOFFICIAL: Gets information about the current exosphere version. */
|
|
||||||
*p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56ull) |
|
|
||||||
((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48ull) |
|
|
||||||
((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40ull) |
|
|
||||||
((uint64_t)(mkey_get_revision() & 0xFF) << 32ull) |
|
|
||||||
((uint64_t)(exosphere_get_target_firmware()) << 0ull);
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEEDS_REBOOT:
|
|
||||||
/* UNOFFICIAL: The fact that we are executing means we aren't in the process of rebooting. */
|
|
||||||
*p_outvalue = 0;
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_NEEDS_SHUTDOWN:
|
|
||||||
/* UNOFFICIAL: The fact that we are executing means we aren't in the process of shutting down. */
|
|
||||||
*p_outvalue = 0;
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_EXOSPHERE_VERHASH:
|
|
||||||
/* UNOFFICIAL: Gets information about the current exosphere git commit hash. */
|
|
||||||
*p_outvalue = ATMOSPHERE_RELEASE_VERSION_HASH;
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_HAS_RCM_BUG_PATCH:
|
|
||||||
/* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */
|
|
||||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_SHOULD_BLANK_PRODINFO:
|
|
||||||
/* UNOFFICIAL: Gets whether this unit should simulate a "blanked" PRODINFO. */
|
|
||||||
*p_outvalue = exosphere_should_blank_prodinfo();
|
|
||||||
break;
|
|
||||||
case CONFIGITEM_ALLOW_CAL_WRITES:
|
|
||||||
/* UNOFFICIAL: Gets whether this unit should allow writing to the calibration partition. */
|
|
||||||
*p_outvalue = exosphere_should_allow_writing_to_cal();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_CFG_ITEM_H
|
|
||||||
#define EXOSPHERE_CFG_ITEM_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CONFIGITEM_DISABLEPROGRAMVERIFICATION = 1,
|
|
||||||
CONFIGITEM_DRAMID = 2,
|
|
||||||
CONFIGITEM_SECURITYENGINEIRQ = 3,
|
|
||||||
CONFIGITEM_VERSION = 4,
|
|
||||||
CONFIGITEM_HARDWARETYPE = 5,
|
|
||||||
CONFIGITEM_ISRETAIL = 6,
|
|
||||||
CONFIGITEM_ISRECOVERYBOOT = 7,
|
|
||||||
CONFIGITEM_DEVICEID = 8,
|
|
||||||
CONFIGITEM_BOOTREASON = 9,
|
|
||||||
CONFIGITEM_MEMORYARRANGE = 10,
|
|
||||||
CONFIGITEM_ISDEBUGMODE = 11,
|
|
||||||
CONFIGITEM_KERNELCONFIGURATION = 12,
|
|
||||||
CONFIGITEM_HIZMODE = 13,
|
|
||||||
CONFIGITEM_ISQUESTUNIT = 14,
|
|
||||||
CONFIGITEM_NEWHARDWARETYPE_5X = 15,
|
|
||||||
CONFIGITEM_NEWKEYGENERATION_5X = 16,
|
|
||||||
CONFIGITEM_PACKAGE2HASH_5X = 17,
|
|
||||||
|
|
||||||
/* These are unofficial, for usage by Exosphere. */
|
|
||||||
CONFIGITEM_EXOSPHERE_VERSION = 65000,
|
|
||||||
CONFIGITEM_NEEDS_REBOOT = 65001,
|
|
||||||
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
|
|
||||||
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
|
|
||||||
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
|
|
||||||
CONFIGITEM_SHOULD_BLANK_PRODINFO = 65005,
|
|
||||||
CONFIGITEM_ALLOW_CAL_WRITES = 65006,
|
|
||||||
} ConfigItem;
|
|
||||||
|
|
||||||
#define REBOOT_KIND_NO_REBOOT 0
|
|
||||||
#define REBOOT_KIND_TO_RCM 1
|
|
||||||
#define REBOOT_KIND_TO_WB_PAYLOAD 2
|
|
||||||
|
|
||||||
uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value);
|
|
||||||
uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue);
|
|
||||||
|
|
||||||
bool configitem_is_recovery_boot(void);
|
|
||||||
bool configitem_is_retail(void);
|
|
||||||
bool configitem_is_hiz_mode_enabled(void);
|
|
||||||
bool configitem_is_debugmode_priv(void);
|
|
||||||
|
|
||||||
void configitem_set_debugmode_override(bool user, bool priv);
|
|
||||||
void configitem_disable_usermode_exception_handlers(void);
|
|
||||||
void configitem_enable_usermode_pmu_access(void);
|
|
||||||
void configitem_set_hiz_mode_enabled(bool enabled);
|
|
||||||
|
|
||||||
uint64_t configitem_get_hardware_type(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,235 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdint.h>
|
|
||||||
#include "arm.h"
|
|
||||||
#include "cpu_context.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
#include "flow.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "smc_api.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "synchronization.h"
|
|
||||||
#include "preprocessor.h"
|
|
||||||
|
|
||||||
#define SAVE_SYSREG64(reg) do { __asm__ __volatile__ ("mrs %0, " #reg : "=r"(temp_reg) :: "memory"); g_cpu_contexts[current_core].reg = temp_reg; } while(false)
|
|
||||||
#define SAVE_SYSREG32(reg) do { __asm__ __volatile__ ("mrs %0, " #reg : "=r"(temp_reg) :: "memory"); g_cpu_contexts[current_core].reg = (uint32_t)temp_reg; } while(false)
|
|
||||||
#define SAVE_BP_REG(i, _) SAVE_SYSREG64(DBGBVR##i##_EL1); SAVE_SYSREG64(DBGBCR##i##_EL1);
|
|
||||||
#define SAVE_WP_REG(i, _) SAVE_SYSREG64(DBGWVR##i##_EL1); SAVE_SYSREG64(DBGWCR##i##_EL1);
|
|
||||||
|
|
||||||
#define RESTORE_SYSREG64(reg) do { temp_reg = g_cpu_contexts[current_core].reg; __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
|
|
||||||
#define RESTORE_SYSREG32(reg) RESTORE_SYSREG64(reg)
|
|
||||||
#define RESTORE_BP_REG(i, _) RESTORE_SYSREG64(DBGBVR##i##_EL1); RESTORE_SYSREG64(DBGBCR##i##_EL1);
|
|
||||||
#define RESTORE_WP_REG(i, _) RESTORE_SYSREG64(DBGWVR##i##_EL1); RESTORE_SYSREG64(DBGWCR##i##_EL1);
|
|
||||||
|
|
||||||
/* start.s */
|
|
||||||
void __attribute__((noreturn)) __jump_to_lower_el(uint64_t arg, uintptr_t ep, uint32_t spsr);
|
|
||||||
|
|
||||||
static saved_cpu_context_t g_cpu_contexts[NUM_CPU_CORES] = {0};
|
|
||||||
|
|
||||||
void use_core_entrypoint_and_argument(uint32_t core, uintptr_t *entrypoint_addr, uint64_t *argument) {
|
|
||||||
saved_cpu_context_t *ctx = &g_cpu_contexts[core];
|
|
||||||
if(ctx->ELR_EL3 == 0 || ctx->is_active) {
|
|
||||||
panic(0xF7F00007); /* invalid context */
|
|
||||||
}
|
|
||||||
|
|
||||||
*entrypoint_addr = ctx->ELR_EL3;
|
|
||||||
*argument = ctx->argument;
|
|
||||||
|
|
||||||
ctx->ELR_EL3 = 0;
|
|
||||||
ctx->argument = 0;
|
|
||||||
ctx->is_active = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_core_entrypoint_and_argument(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
|
|
||||||
g_cpu_contexts[core].ELR_EL3 = entrypoint_addr;
|
|
||||||
g_cpu_contexts[core].argument = argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __attribute__((target("cmodel=large"), noinline))
|
|
||||||
critical_section_t *get_boot_critical_section(void) {
|
|
||||||
return &g_boot_critical_section;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __attribute__((noreturn)) core_jump_to_lower_el(void) {
|
|
||||||
uintptr_t ep;
|
|
||||||
uint64_t arg;
|
|
||||||
unsigned int core_id = get_core_id();
|
|
||||||
uint32_t spsr = get_spsr();
|
|
||||||
critical_section_t *critsec = get_boot_critical_section();
|
|
||||||
|
|
||||||
use_core_entrypoint_and_argument(core_id, &ep, &arg);
|
|
||||||
critical_section_leave(critsec);
|
|
||||||
flush_dcache_range(critsec, (uint8_t *)critsec + sizeof(critical_section_t));
|
|
||||||
/* already does a dsb sy */
|
|
||||||
__sev();
|
|
||||||
|
|
||||||
/* Nintendo hardcodes EL1, but we can boot fine using other EL1/EL2 modes as well */
|
|
||||||
__jump_to_lower_el(arg, ep, 0b1111 << 6 | (spsr & 0b1101)); /* only keep EL, SPSel, set DAIF */
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
|
|
||||||
/* Is core valid? */
|
|
||||||
if (core >= NUM_CPU_CORES) {
|
|
||||||
return 0xFFFFFFFE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is core already on? */
|
|
||||||
if (g_cpu_contexts[core].is_active) {
|
|
||||||
return 0xFFFFFFFC;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_core_entrypoint_and_argument(core, entrypoint_addr, argument);
|
|
||||||
|
|
||||||
static const uint32_t status_masks[NUM_CPU_CORES] = {0x4000, 0x200, 0x400, 0x800};
|
|
||||||
static const uint32_t toggle_vals[NUM_CPU_CORES] = {0xE, 0x9, 0xA, 0xB};
|
|
||||||
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
/* Reset the core */
|
|
||||||
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 = (1 << (core + 0x10)) | (1 << core);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we're already in the correct state. */
|
|
||||||
if ((APBDEV_PMC_PWRGATE_STATUS_0 & status_masks[core]) != status_masks[core]) {
|
|
||||||
uint32_t counter = 5001;
|
|
||||||
|
|
||||||
/* Poll the start bit until 0 */
|
|
||||||
while (APBDEV_PMC_PWRGATE_TOGGLE_0 & 0x100) {
|
|
||||||
wait(1);
|
|
||||||
counter--;
|
|
||||||
if (counter < 1) {
|
|
||||||
goto CPU_ON_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Program PWRGATE_TOGGLE with the START bit set to 1, selecting CE[N] */
|
|
||||||
APBDEV_PMC_PWRGATE_TOGGLE_0 = toggle_vals[core] | 0x100;
|
|
||||||
|
|
||||||
/* Poll until we're in the correct state. */
|
|
||||||
counter = 5001;
|
|
||||||
while (counter > 0) {
|
|
||||||
if ((APBDEV_PMC_PWRGATE_STATUS_0 & status_masks[core]) == status_masks[core]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
wait(1);
|
|
||||||
counter--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU_ON_SUCCESS:
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
/* Start the core */
|
|
||||||
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = (1 << (core + 0x10)) | (1 << core);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void power_down_current_core(void) {
|
|
||||||
unsigned int current_core = get_core_id();
|
|
||||||
flow_set_csr(current_core, 0);
|
|
||||||
flow_set_halt_events(current_core, false);
|
|
||||||
flow_set_cc4_ctrl(current_core, 0);
|
|
||||||
save_current_core_context();
|
|
||||||
g_cpu_contexts[current_core].is_active = 0;
|
|
||||||
flush_dcache_all();
|
|
||||||
finalize_powerdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_off(void) {
|
|
||||||
unsigned int current_core = get_core_id();
|
|
||||||
if (current_core == 3) {
|
|
||||||
power_down_current_core();
|
|
||||||
} else {
|
|
||||||
clear_priv_smc_in_progress();
|
|
||||||
call_with_stack_pointer(get_exception_entry_stack_address(current_core), power_down_current_core);
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
/* Wait forever. */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_current_core_context(void) {
|
|
||||||
unsigned int current_core = get_core_id();
|
|
||||||
uint64_t temp_reg = 1;
|
|
||||||
/* Write 1 to OS lock .*/
|
|
||||||
__asm__ __volatile__ ("msr oslar_el1, %0" : : "r"(temp_reg));
|
|
||||||
|
|
||||||
/* Save system registers. */
|
|
||||||
|
|
||||||
SAVE_SYSREG32(OSDTRRX_EL1);
|
|
||||||
SAVE_SYSREG32(OSDTRTX_EL1);
|
|
||||||
SAVE_SYSREG32(MDSCR_EL1);
|
|
||||||
SAVE_SYSREG32(OSECCR_EL1);
|
|
||||||
SAVE_SYSREG32(MDCCINT_EL1);
|
|
||||||
SAVE_SYSREG32(DBGCLAIMCLR_EL1);
|
|
||||||
SAVE_SYSREG32(DBGVCR32_EL2);
|
|
||||||
SAVE_SYSREG32(SDER32_EL3);
|
|
||||||
SAVE_SYSREG32(MDCR_EL2);
|
|
||||||
SAVE_SYSREG32(MDCR_EL3);
|
|
||||||
SAVE_SYSREG32(SPSR_EL3);
|
|
||||||
|
|
||||||
EVAL(REPEAT(6, SAVE_BP_REG, ~));
|
|
||||||
EVAL(REPEAT(4, SAVE_WP_REG, ~));
|
|
||||||
|
|
||||||
/* Mark context as saved. */
|
|
||||||
g_cpu_contexts[current_core].is_saved = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void restore_current_core_context(void) {
|
|
||||||
unsigned int current_core = get_core_id();
|
|
||||||
uint64_t temp_reg;
|
|
||||||
|
|
||||||
if (g_cpu_contexts[current_core].is_saved) {
|
|
||||||
RESTORE_SYSREG32(OSDTRRX_EL1);
|
|
||||||
RESTORE_SYSREG32(OSDTRTX_EL1);
|
|
||||||
RESTORE_SYSREG32(MDSCR_EL1);
|
|
||||||
RESTORE_SYSREG32(OSECCR_EL1);
|
|
||||||
RESTORE_SYSREG32(MDCCINT_EL1);
|
|
||||||
RESTORE_SYSREG32(DBGCLAIMCLR_EL1);
|
|
||||||
RESTORE_SYSREG32(DBGVCR32_EL2);
|
|
||||||
RESTORE_SYSREG32(SDER32_EL3);
|
|
||||||
RESTORE_SYSREG32(MDCR_EL2);
|
|
||||||
RESTORE_SYSREG32(MDCR_EL3);
|
|
||||||
RESTORE_SYSREG32(SPSR_EL3);
|
|
||||||
|
|
||||||
EVAL(REPEAT(6, RESTORE_BP_REG, ~));
|
|
||||||
EVAL(REPEAT(4, RESTORE_WP_REG, ~));
|
|
||||||
|
|
||||||
g_cpu_contexts[current_core].is_saved = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_core_active(uint32_t core) {
|
|
||||||
return g_cpu_contexts[core].is_active != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_core_is_active(uint32_t core, bool is_active) {
|
|
||||||
g_cpu_contexts[core].is_active = (is_active) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_current_core_active(void) {
|
|
||||||
set_core_is_active(get_core_id(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_current_core_inactive(void) {
|
|
||||||
set_core_is_active(get_core_id(), false);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_CPU_CTX_H
|
|
||||||
#define EXOSPHERE_CPU_CTX_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "synchronization.h"
|
|
||||||
|
|
||||||
/* Exosphere CPU Management functionality. */
|
|
||||||
|
|
||||||
extern critical_section_t g_boot_critical_section;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t argument;
|
|
||||||
uint64_t ELR_EL3;
|
|
||||||
int is_active;
|
|
||||||
int is_saved;
|
|
||||||
uint32_t OSDTRRX_EL1;
|
|
||||||
uint32_t OSDTRTX_EL1;
|
|
||||||
uint32_t MDSCR_EL1;
|
|
||||||
uint32_t OSECCR_EL1;
|
|
||||||
uint32_t MDCCINT_EL1;
|
|
||||||
uint32_t DBGCLAIMCLR_EL1;
|
|
||||||
uint32_t DBGVCR32_EL2;
|
|
||||||
uint32_t SDER32_EL3;
|
|
||||||
uint32_t MDCR_EL2;
|
|
||||||
uint32_t MDCR_EL3;
|
|
||||||
uint32_t SPSR_EL3; /* not in official code */
|
|
||||||
uint64_t DBGBVR0_EL1;
|
|
||||||
uint64_t DBGBCR0_EL1;
|
|
||||||
uint64_t DBGBVR1_EL1;
|
|
||||||
uint64_t DBGBCR1_EL1;
|
|
||||||
uint64_t DBGBVR2_EL1;
|
|
||||||
uint64_t DBGBCR2_EL1;
|
|
||||||
uint64_t DBGBVR3_EL1;
|
|
||||||
uint64_t DBGBCR3_EL1;
|
|
||||||
uint64_t DBGBVR4_EL1;
|
|
||||||
uint64_t DBGBCR4_EL1;
|
|
||||||
uint64_t DBGBVR5_EL1;
|
|
||||||
uint64_t DBGBCR5_EL1;
|
|
||||||
uint64_t DBGWVR0_EL1;
|
|
||||||
uint64_t DBGWCR0_EL1;
|
|
||||||
uint64_t DBGWVR1_EL1;
|
|
||||||
uint64_t DBGWCR1_EL1;
|
|
||||||
uint64_t DBGWVR2_EL1;
|
|
||||||
uint64_t DBGWCR2_EL1;
|
|
||||||
uint64_t DBGWVR3_EL1;
|
|
||||||
uint64_t DBGWCR3_EL1;
|
|
||||||
} saved_cpu_context_t;
|
|
||||||
|
|
||||||
#define NUM_CPU_CORES 4
|
|
||||||
|
|
||||||
void save_current_core_context(void);
|
|
||||||
void restore_current_core_context(void);
|
|
||||||
|
|
||||||
bool is_core_active(uint32_t core);
|
|
||||||
void set_core_is_active(uint32_t core, bool is_active);
|
|
||||||
void set_current_core_active(void);
|
|
||||||
void set_current_core_inactive(void);
|
|
||||||
|
|
||||||
void use_core_entrypoint_and_argument(uint32_t core, uintptr_t *entrypoint_addr, uint64_t *argument);
|
|
||||||
void set_core_entrypoint_and_argument(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument);
|
|
||||||
void __attribute__((noreturn)) core_jump_to_lower_el(void);
|
|
||||||
|
|
||||||
uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument);
|
|
||||||
uint32_t cpu_off(void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_EMUMMC_CONFIG_H
|
|
||||||
#define EXOSPHERE_EMUMMC_CONFIG_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vapours/ams_version.h>
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/* "EFS0" */
|
|
||||||
#define MAGIC_EMUMMC_CONFIG (0x30534645)
|
|
||||||
|
|
||||||
#define EMUMMC_FILE_PATH_MAX (0x80)
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EMUMMC_TYPE_NONE = 0,
|
|
||||||
EMUMMC_TYPE_PARTITION = 1,
|
|
||||||
EMUMMC_TYPE_FILES = 2,
|
|
||||||
} emummc_type_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EMUMMC_MMC_NAND = 0,
|
|
||||||
EMUMMC_MMC_SD = 1,
|
|
||||||
EMUMMC_MMC_GC = 2,
|
|
||||||
} emummc_mmc_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t type;
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t fs_version;
|
|
||||||
} emummc_base_config_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t start_sector;
|
|
||||||
} emummc_partition_config_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char path[EMUMMC_FILE_PATH_MAX];
|
|
||||||
} emummc_file_config_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
emummc_base_config_t base_cfg;
|
|
||||||
union {
|
|
||||||
emummc_partition_config_t partition_cfg;
|
|
||||||
emummc_file_config_t file_cfg;
|
|
||||||
};
|
|
||||||
char emu_dir_path[EMUMMC_FILE_PATH_MAX];
|
|
||||||
} exo_emummc_config_t;
|
|
||||||
|
|
||||||
_Static_assert(sizeof(exo_emummc_config_t) == 0x110, "exo_emummc_config_t definition!");
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,254 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
||||||
/* Actual Vectors for Exosphere. */
|
|
||||||
.global exosphere_vectors
|
|
||||||
vector_base exosphere_vectors
|
|
||||||
|
|
||||||
/* Current EL, SP0 */
|
|
||||||
.global unknown_exception
|
|
||||||
unknown_exception:
|
|
||||||
vector_entry synch_sp0
|
|
||||||
/* Panic with color FF7700, code 10. */
|
|
||||||
mov x0, #0x10
|
|
||||||
movk x0, #0x07F0,lsl#16
|
|
||||||
b panic
|
|
||||||
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
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
/* Verify SMC. */
|
|
||||||
mrs x30, esr_el3
|
|
||||||
lsr w29, w30, #0x1A
|
|
||||||
cmp w29, #0x17
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
b.ne unknown_exception
|
|
||||||
/* Call appropriate handler. */
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
mrs x29, mpidr_el1
|
|
||||||
and x29, x29, #0x3
|
|
||||||
cmp x29, #0x3
|
|
||||||
b.ne handle_core012_smc_exception
|
|
||||||
bl handle_core3_smc_exception
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
eret
|
|
||||||
check_vector_size synch_a64
|
|
||||||
|
|
||||||
vector_entry irq_a64
|
|
||||||
b unknown_exception
|
|
||||||
check_vector_size irq_a64
|
|
||||||
|
|
||||||
vector_entry fiq_a64
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
mrs x29, mpidr_el1
|
|
||||||
and x29, x29, #0x3
|
|
||||||
cmp x29, #0x3
|
|
||||||
b.ne unknown_exception
|
|
||||||
stp x28, x29, [sp, #-0x10]!
|
|
||||||
stp x26, x27, [sp, #-0x10]!
|
|
||||||
bl handle_fiq_exception
|
|
||||||
ldp x26, x27, [sp],#0x10
|
|
||||||
ldp x28, x29, [sp],#0x10
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
eret
|
|
||||||
check_vector_size fiq_a64
|
|
||||||
|
|
||||||
vector_entry serror_a64
|
|
||||||
b unknown_exception
|
|
||||||
.endfunc
|
|
||||||
.cfi_endproc
|
|
||||||
/* To save space, insert in an unused vector segment. */
|
|
||||||
.global handle_core012_smc_exception
|
|
||||||
.type handle_core012_smc_exception, %function
|
|
||||||
handle_core012_smc_exception:
|
|
||||||
stp x6, x7, [sp, #-0x10]!
|
|
||||||
stp x4, x5, [sp, #-0x10]!
|
|
||||||
stp x2, x3, [sp, #-0x10]!
|
|
||||||
stp x0, x1, [sp, #-0x10]!
|
|
||||||
bl set_priv_smc_in_progress
|
|
||||||
bl get_smc_core012_stack_address
|
|
||||||
mov x29, x0
|
|
||||||
ldp x0, x1, [sp],#0x10
|
|
||||||
ldp x2, x3, [sp],#0x10
|
|
||||||
ldp x4, x5, [sp],#0x10
|
|
||||||
ldp x6, x7, [sp],#0x10
|
|
||||||
mov x30, sp
|
|
||||||
mov sp, x29
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
bl handle_core3_smc_exception
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
mov sp, x30
|
|
||||||
stp x6, x7, [sp, #-0x10]!
|
|
||||||
stp x4, x5, [sp, #-0x10]!
|
|
||||||
stp x2, x3, [sp, #-0x10]!
|
|
||||||
stp x0, x1, [sp, #-0x10]!
|
|
||||||
bl clear_priv_smc_in_progress
|
|
||||||
ldp x0, x1, [sp],#0x10
|
|
||||||
ldp x2, x3, [sp],#0x10
|
|
||||||
ldp x4, x5, [sp],#0x10
|
|
||||||
ldp x6, x7, [sp],#0x10
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
eret
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
.global handle_fiq_exception
|
|
||||||
.type handle_fiq_exception, %function
|
|
||||||
handle_fiq_exception:
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
stp x24, x25, [sp, #-0x10]!
|
|
||||||
stp x22, x23, [sp, #-0x10]!
|
|
||||||
stp x20, x21, [sp, #-0x10]!
|
|
||||||
stp x18, x19, [sp, #-0x10]!
|
|
||||||
stp x16, x17, [sp, #-0x10]!
|
|
||||||
stp x14, x15, [sp, #-0x10]!
|
|
||||||
stp x12, x13, [sp, #-0x10]!
|
|
||||||
stp x10, x11, [sp, #-0x10]!
|
|
||||||
stp x8, x9, [sp, #-0x10]!
|
|
||||||
stp x6, x7, [sp, #-0x10]!
|
|
||||||
stp x4, x5, [sp, #-0x10]!
|
|
||||||
stp x2, x3, [sp, #-0x10]!
|
|
||||||
stp x0, x1, [sp, #-0x10]!
|
|
||||||
bl handle_registered_interrupt
|
|
||||||
ldp x0, x1, [sp],#0x10
|
|
||||||
ldp x2, x3, [sp],#0x10
|
|
||||||
ldp x4, x5, [sp],#0x10
|
|
||||||
ldp x6, x7, [sp],#0x10
|
|
||||||
ldp x8, x9, [sp],#0x10
|
|
||||||
ldp x10, x11, [sp],#0x10
|
|
||||||
ldp x12, x13, [sp],#0x10
|
|
||||||
ldp x14, x15, [sp],#0x10
|
|
||||||
ldp x16, x17, [sp],#0x10
|
|
||||||
ldp x18, x19, [sp],#0x10
|
|
||||||
ldp x20, x21, [sp],#0x10
|
|
||||||
ldp x22, x23, [sp],#0x10
|
|
||||||
ldp x24, x25, [sp],#0x10
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
ret
|
|
||||||
|
|
||||||
vector_entry serror_a32
|
|
||||||
b unknown_exception
|
|
||||||
.endfunc
|
|
||||||
.cfi_endproc
|
|
||||||
/* To save space, insert in an unused vector segment. */
|
|
||||||
.global handle_core3_smc_exception
|
|
||||||
.type handle_core3_smc_exception, %function
|
|
||||||
handle_core3_smc_exception:
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
stp x18, x19, [sp, #-0x10]!
|
|
||||||
stp x16, x17, [sp, #-0x10]!
|
|
||||||
stp x14, x15, [sp, #-0x10]!
|
|
||||||
stp x12, x13, [sp, #-0x10]!
|
|
||||||
stp x10, x11, [sp, #-0x10]!
|
|
||||||
stp x8, x9, [sp, #-0x10]!
|
|
||||||
stp x6, x7, [sp, #-0x10]!
|
|
||||||
stp x4, x5, [sp, #-0x10]!
|
|
||||||
stp x2, x3, [sp, #-0x10]!
|
|
||||||
stp x0, x1, [sp, #-0x10]!
|
|
||||||
mrs x0, esr_el3
|
|
||||||
and x0, x0, #0xFFFF
|
|
||||||
mov x1, sp
|
|
||||||
bl call_smc_handler
|
|
||||||
ldp x0, x1, [sp],#0x10
|
|
||||||
ldp x2, x3, [sp],#0x10
|
|
||||||
ldp x4, x5, [sp],#0x10
|
|
||||||
ldp x6, x7, [sp],#0x10
|
|
||||||
ldp x8, x9, [sp],#0x10
|
|
||||||
ldp x10, x11, [sp],#0x10
|
|
||||||
ldp x12, x13, [sp],#0x10
|
|
||||||
ldp x14, x15, [sp],#0x10
|
|
||||||
ldp x16, x17, [sp],#0x10
|
|
||||||
ldp x18, x19, [sp],#0x10
|
|
||||||
ldp x29, x30, [sp],#0x10
|
|
||||||
ret
|
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdbool.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
static exosphere_config_t g_exosphere_cfg = {MAGIC_EXOSPHERE_CONFIG, ATMOSPHERE_TARGET_FIRMWARE_CURRENT, EXOSPHERE_FLAGS_DEFAULT};
|
|
||||||
static bool g_has_loaded_config = false;
|
|
||||||
|
|
||||||
#define EXOSPHERE_CHECK_FLAG(flag) ((g_exosphere_cfg.flags & flag) != 0)
|
|
||||||
|
|
||||||
static unsigned int exosphere_is_emummc() {
|
|
||||||
return g_exosphere_cfg.emummc_cfg.base_cfg.magic == MAGIC_EMUMMC_CONFIG && g_exosphere_cfg.emummc_cfg.base_cfg.type != EMUMMC_TYPE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read config out of IRAM, return target firmware version. */
|
|
||||||
unsigned int exosphere_load_config(void) {
|
|
||||||
if (g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
g_has_loaded_config = true;
|
|
||||||
|
|
||||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
|
|
||||||
|
|
||||||
if (magic == MAGIC_EXOSPHERE_CONFIG) {
|
|
||||||
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_exosphere_cfg.target_firmware;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_get_target_firmware(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_exosphere_cfg.target_firmware;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_perform_620_keygen(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_override_debugmode_priv(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_override_debugmode_user(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_enable_usermode_pmu_access(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_blank_prodinfo(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_BLANK_PRODINFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exosphere_should_allow_writing_to_cal(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exosphere_is_emummc()) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const exo_emummc_config_t *exosphere_get_emummc_config(void) {
|
|
||||||
if (!g_has_loaded_config) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return &g_exosphere_cfg.emummc_cfg;
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_EXOSPHERE_CONFIG_H
|
|
||||||
#define EXOSPHERE_EXOSPHERE_CONFIG_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vapours/ams_version.h>
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "emummc_cfg.h"
|
|
||||||
|
|
||||||
/* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */
|
|
||||||
|
|
||||||
/* "EXO0" */
|
|
||||||
#define MAGIC_EXOSPHERE_CONFIG (0x304F5845)
|
|
||||||
|
|
||||||
#define EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG 1
|
|
||||||
|
|
||||||
#define MAILBOX_EXOSPHERE_CONFIG (*((volatile exosphere_config_t *)(0x8000F000ull)))
|
|
||||||
|
|
||||||
/* Exosphere config in DRAM shares physical/virtual mapping. */
|
|
||||||
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
|
|
||||||
|
|
||||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u)
|
|
||||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
|
||||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
|
||||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
|
||||||
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
|
|
||||||
#define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
|
|
||||||
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
|
|
||||||
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t target_firmware;
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t reserved[5];
|
|
||||||
exo_emummc_config_t emummc_cfg;
|
|
||||||
} exosphere_config_t;
|
|
||||||
|
|
||||||
_Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), "exosphere config definition");
|
|
||||||
|
|
||||||
unsigned int exosphere_load_config(void);
|
|
||||||
unsigned int exosphere_get_target_firmware(void);
|
|
||||||
unsigned int exosphere_should_perform_620_keygen(void);
|
|
||||||
unsigned int exosphere_should_override_debugmode_priv(void);
|
|
||||||
unsigned int exosphere_should_override_debugmode_user(void);
|
|
||||||
unsigned int exosphere_should_disable_usermode_exception_handlers(void);
|
|
||||||
unsigned int exosphere_should_enable_usermode_pmu_access(void);
|
|
||||||
unsigned int exosphere_should_blank_prodinfo(void);
|
|
||||||
unsigned int exosphere_should_allow_writing_to_cal(void);
|
|
||||||
|
|
||||||
const exo_emummc_config_t *exosphere_get_emummc_config(void);
|
|
||||||
|
|
||||||
static inline unsigned int exosphere_get_target_firmware_for_init(void) {
|
|
||||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;
|
|
||||||
if (magic == MAGIC_EXOSPHERE_CONFIG) {
|
|
||||||
return MAILBOX_EXOSPHERE_CONFIG_PHYS.target_firmware;
|
|
||||||
} else {
|
|
||||||
return ATMOSPHERE_TARGET_FIRMWARE_CURRENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_FLOW_CTLR_H
|
|
||||||
#define EXOSPHERE_FLOW_CTLR_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "cpu_context.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere register definitions for the Tegra X1 Flow Controller. */
|
|
||||||
|
|
||||||
static inline uintptr_t get_flow_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_FLOWCTRL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FLOW_BASE (get_flow_base())
|
|
||||||
|
|
||||||
#define MAKE_FLOW_REG(ofs) MAKE_REG32(FLOW_BASE + ofs)
|
|
||||||
|
|
||||||
#define FLOW_CTLR_HALT_COP_EVENTS_0 MAKE_FLOW_REG(0x004)
|
|
||||||
#define FLOW_CTLR_FLOW_DBG_QUAL_0 MAKE_FLOW_REG(0x050)
|
|
||||||
#define FLOW_CTLR_L2FLUSH_CONTROL_0 MAKE_FLOW_REG(0x094)
|
|
||||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 MAKE_FLOW_REG(0x098)
|
|
||||||
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
unsigned int CPUN_CSR_OFS;
|
|
||||||
unsigned int HALT_CPUN_EVENTS_OFS;
|
|
||||||
unsigned int CC4_COREN_CTRL_OFS;
|
|
||||||
} g_flow_core_offsets[NUM_CPU_CORES] = {
|
|
||||||
{0x008, 0x000, 0x06C},
|
|
||||||
{0x018, 0x014, 0x070},
|
|
||||||
{0x020, 0x01C, 0x074},
|
|
||||||
{0x028, 0x024, 0x078},
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void flow_set_cc4_ctrl(uint32_t core, uint32_t cc4_ctrl) {
|
|
||||||
MAKE_FLOW_REG(g_flow_core_offsets[core].CC4_COREN_CTRL_OFS) = cc4_ctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void flow_set_halt_events(uint32_t core, bool halt_events) {
|
|
||||||
MAKE_FLOW_REG(g_flow_core_offsets[core].HALT_CPUN_EVENTS_OFS) = (halt_events ? 0x40000F00 : 0x40000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void flow_set_csr(uint32_t core, uint32_t csr) {
|
|
||||||
MAKE_FLOW_REG(g_flow_core_offsets[core].CPUN_CSR_OFS) = (0x100 << core) | (csr << 12) | 0xC001;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void flow_clear_csr0_and_events(uint32_t core) {
|
|
||||||
MAKE_FLOW_REG(g_flow_core_offsets[core].CPUN_CSR_OFS) = 0;
|
|
||||||
MAKE_FLOW_REG(g_flow_core_offsets[core].HALT_CPUN_EVENTS_OFS) = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,335 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
#include <vapours/ams_version.h>
|
|
||||||
|
|
||||||
#include "car.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "masterkey.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "timers.h"
|
|
||||||
|
|
||||||
static bool g_has_checked_for_rcm_bug_patch = false;
|
|
||||||
static bool g_has_rcm_bug_patch = false;
|
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
|
||||||
void fuse_enable_power(void);
|
|
||||||
void fuse_disable_power(void);
|
|
||||||
void fuse_wait_idle(void);
|
|
||||||
|
|
||||||
/* Initialize the fuse driver */
|
|
||||||
void fuse_init(void) {
|
|
||||||
/* Make all fuse registers visible, disable the private key and disable programming. */
|
|
||||||
clkrst_enable_fuse_regs(true);
|
|
||||||
fuse_disable_private_key();
|
|
||||||
fuse_disable_programming();
|
|
||||||
|
|
||||||
/* TODO: Should we allow this to be done later? */
|
|
||||||
if (!g_has_checked_for_rcm_bug_patch) {
|
|
||||||
(void)(fuse_has_rcm_bug_patch());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable access to the private key and set the TZ sticky bit. */
|
|
||||||
void fuse_disable_private_key(void) {
|
|
||||||
FUSE_REGS->FUSE_PRIVATEKEYDISABLE = 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disables all fuse programming. */
|
|
||||||
void fuse_disable_programming(void) {
|
|
||||||
FUSE_REGS->FUSE_DISABLEREGPROGRAM = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable power to the fuse hardware array. */
|
|
||||||
void fuse_enable_power(void) {
|
|
||||||
APBDEV_PMC_FUSE_CTRL &= ~(0x200); /* Clear PMC_FUSE_CTRL_PS18_LATCH_CLEAR. */
|
|
||||||
mdelay(1);
|
|
||||||
APBDEV_PMC_FUSE_CTRL |= 0x100; /* Set PMC_FUSE_CTRL_PS18_LATCH_SET. */
|
|
||||||
mdelay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable power to the fuse hardware array. */
|
|
||||||
void fuse_disable_power(void) {
|
|
||||||
APBDEV_PMC_FUSE_CTRL &= ~(0x100); /* Clear PMC_FUSE_CTRL_PS18_LATCH_SET. */
|
|
||||||
mdelay(1);
|
|
||||||
APBDEV_PMC_FUSE_CTRL |= 0x200; /* Set PMC_FUSE_CTRL_PS18_LATCH_CLEAR. */
|
|
||||||
mdelay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for the fuse driver to go idle. */
|
|
||||||
void fuse_wait_idle(void) {
|
|
||||||
uint32_t ctrl_val = 0;
|
|
||||||
|
|
||||||
/* Wait for STATE_IDLE */
|
|
||||||
while ((ctrl_val & (0xF0000)) != 0x40000)
|
|
||||||
ctrl_val = FUSE_REGS->FUSE_FUSECTRL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a fuse from the hardware array. */
|
|
||||||
uint32_t fuse_hw_read(uint32_t addr) {
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
|
|
||||||
/* Program the target address. */
|
|
||||||
FUSE_REGS->FUSE_FUSEADDR = addr;
|
|
||||||
|
|
||||||
/* Enable read operation in control register. */
|
|
||||||
uint32_t ctrl_val = FUSE_REGS->FUSE_FUSECTRL;
|
|
||||||
ctrl_val &= ~0x3;
|
|
||||||
ctrl_val |= 0x1; /* Set READ command. */
|
|
||||||
FUSE_REGS->FUSE_FUSECTRL = ctrl_val;
|
|
||||||
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
|
|
||||||
return FUSE_REGS->FUSE_FUSERDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a fuse in the hardware array. */
|
|
||||||
void fuse_hw_write(uint32_t value, uint32_t addr) {
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
|
|
||||||
/* Program the target address and value. */
|
|
||||||
FUSE_REGS->FUSE_FUSEADDR = addr;
|
|
||||||
FUSE_REGS->FUSE_FUSEWDATA = value;
|
|
||||||
|
|
||||||
/* Enable write operation in control register. */
|
|
||||||
uint32_t ctrl_val = FUSE_REGS->FUSE_FUSECTRL;
|
|
||||||
ctrl_val &= ~0x3;
|
|
||||||
ctrl_val |= 0x2; /* Set WRITE command. */
|
|
||||||
FUSE_REGS->FUSE_FUSECTRL = ctrl_val;
|
|
||||||
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sense the fuse hardware array into the shadow cache. */
|
|
||||||
void fuse_hw_sense(void) {
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
|
|
||||||
/* Enable sense operation in control register */
|
|
||||||
uint32_t ctrl_val = FUSE_REGS->FUSE_FUSECTRL;
|
|
||||||
ctrl_val &= ~0x3;
|
|
||||||
ctrl_val |= 0x3; /* Set SENSE_CTRL command */
|
|
||||||
FUSE_REGS->FUSE_FUSECTRL = ctrl_val;
|
|
||||||
|
|
||||||
/* Wait for idle state. */
|
|
||||||
fuse_wait_idle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the SKU info register from the shadow cache. */
|
|
||||||
uint32_t fuse_get_sku_info(void) {
|
|
||||||
return FUSE_CHIP_REGS->FUSE_SKU_INFO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the bootrom patch version from a register in the shadow cache. */
|
|
||||||
uint32_t fuse_get_bootrom_patch_version(void) {
|
|
||||||
return FUSE_CHIP_REGS->FUSE_SOC_SPEEDO_1_CALIB;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a spare bit register from the shadow cache */
|
|
||||||
uint32_t fuse_get_spare_bit(uint32_t idx) {
|
|
||||||
if (idx < 32) {
|
|
||||||
return FUSE_CHIP_REGS->FUSE_SPARE_BIT[idx];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a reserved ODM register from the shadow cache. */
|
|
||||||
uint32_t fuse_get_reserved_odm(uint32_t idx) {
|
|
||||||
if (idx < 8) {
|
|
||||||
return FUSE_CHIP_REGS->FUSE_RESERVED_ODM[idx];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the DRAM ID using values in the shadow cache. */
|
|
||||||
uint32_t fuse_get_dram_id(void) {
|
|
||||||
return ((fuse_get_reserved_odm(4) >> 3) & 0x7);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Derive the Device ID using values in the shadow cache. */
|
|
||||||
uint64_t fuse_get_device_id(void) {
|
|
||||||
uint64_t device_id = 0;
|
|
||||||
uint64_t y_coord = FUSE_CHIP_REGS->FUSE_OPT_Y_COORDINATE & 0x1FF;
|
|
||||||
uint64_t x_coord = FUSE_CHIP_REGS->FUSE_OPT_X_COORDINATE & 0x1FF;
|
|
||||||
uint64_t wafer_id = FUSE_CHIP_REGS->FUSE_OPT_WAFER_ID & 0x3F;
|
|
||||||
uint32_t lot_code = FUSE_CHIP_REGS->FUSE_OPT_LOT_CODE_0;
|
|
||||||
uint64_t fab_code = FUSE_CHIP_REGS->FUSE_OPT_FAB_CODE & 0x3F;
|
|
||||||
|
|
||||||
uint64_t derived_lot_code = 0;
|
|
||||||
for (unsigned int i = 0; i < 5; i++) {
|
|
||||||
derived_lot_code = (derived_lot_code * 0x24) + ((lot_code >> (24 - 6*i)) & 0x3F);
|
|
||||||
}
|
|
||||||
derived_lot_code &= 0x03FFFFFF;
|
|
||||||
|
|
||||||
device_id |= y_coord << 0;
|
|
||||||
device_id |= x_coord << 9;
|
|
||||||
device_id |= wafer_id << 18;
|
|
||||||
device_id |= derived_lot_code << 24;
|
|
||||||
device_id |= fab_code << 50;
|
|
||||||
|
|
||||||
return device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Derive the Hardware Type using values in the shadow cache. */
|
|
||||||
uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
|
|
||||||
uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4);
|
|
||||||
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
|
|
||||||
|
|
||||||
/* Firmware from versions 1.0.0 to 3.0.2. */
|
|
||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
|
|
||||||
if (hardware_type >= 1) {
|
|
||||||
return (hardware_type > 2) ? 3 : hardware_type - 1;
|
|
||||||
} else if ((fuse_chip->FUSE_SPARE_BIT[9] & 1) == 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
|
|
||||||
static const uint32_t types[] = {0,1,4,3};
|
|
||||||
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
|
|
||||||
hardware_type--;
|
|
||||||
return (hardware_type > 3) ? 4 : types[hardware_type];
|
|
||||||
} else { /* Firmware versions from 7.0.0 onwards. */
|
|
||||||
/* Always return 0 in retail. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Derive the Retail Type using values in the shadow cache. */
|
|
||||||
uint32_t fuse_get_retail_type(void) {
|
|
||||||
/* Retail Type = IS_RETAIL | UNIT_TYPE. */
|
|
||||||
uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4);
|
|
||||||
uint32_t retail_type = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3));
|
|
||||||
if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */
|
|
||||||
return 1;
|
|
||||||
} else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 2; /* IS_RETAIL | DEV_UNIT */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */
|
|
||||||
void fuse_get_hardware_info(void *dst) {
|
|
||||||
uint32_t hw_info[0x4];
|
|
||||||
|
|
||||||
uint32_t ops_reserved = FUSE_CHIP_REGS->FUSE_OPT_OPS_RESERVED & 0x3F;
|
|
||||||
uint32_t y_coord = FUSE_CHIP_REGS->FUSE_OPT_Y_COORDINATE & 0x1FF;
|
|
||||||
uint32_t x_coord = FUSE_CHIP_REGS->FUSE_OPT_X_COORDINATE & 0x1FF;
|
|
||||||
uint32_t wafer_id = FUSE_CHIP_REGS->FUSE_OPT_WAFER_ID & 0x3F;
|
|
||||||
uint32_t lot_code_0 = FUSE_CHIP_REGS->FUSE_OPT_LOT_CODE_0;
|
|
||||||
uint32_t lot_code_1 = FUSE_CHIP_REGS->FUSE_OPT_LOT_CODE_1 & 0x0FFFFFFF;
|
|
||||||
uint32_t fab_code = FUSE_CHIP_REGS->FUSE_OPT_FAB_CODE & 0x3F;
|
|
||||||
uint32_t vendor_code = FUSE_CHIP_REGS->FUSE_OPT_VENDOR_CODE & 0xF;
|
|
||||||
|
|
||||||
/* Hardware Info = OPS_RESERVED || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID */
|
|
||||||
hw_info[0] = (uint32_t)((lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | (ops_reserved));
|
|
||||||
hw_info[1] = (uint32_t)((lot_code_0 << 26) | (lot_code_1 >> 2));
|
|
||||||
hw_info[2] = (uint32_t)((fab_code << 26) | (lot_code_0 >> 6));
|
|
||||||
hw_info[3] = (uint32_t)(vendor_code);
|
|
||||||
|
|
||||||
memcpy(dst, hw_info, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the Key Generation value. */
|
|
||||||
uint32_t fuse_get_5x_key_generation(void) {
|
|
||||||
if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) {
|
|
||||||
return (fuse_get_reserved_odm(2) & 0x1F);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the fuse version expected for the firmware. */
|
|
||||||
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
|
|
||||||
if (fuse_get_retail_type() != 0) {
|
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
|
|
||||||
return 13;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
|
|
||||||
return 12;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
|
|
||||||
return 11;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
|
|
||||||
return 10;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
|
||||||
return 9;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
|
|
||||||
return 8;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
return 7;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
return 6;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
return 5;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_2) {
|
|
||||||
return 4;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
|
|
||||||
return 3;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
|
|
||||||
return 2;
|
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for RCM bug patches. */
|
|
||||||
bool fuse_has_rcm_bug_patch(void) {
|
|
||||||
/* Only check for RCM bug patch once, and cache our result. */
|
|
||||||
if (!g_has_checked_for_rcm_bug_patch) {
|
|
||||||
/* Some patched units use XUSB in RCM. */
|
|
||||||
if (FUSE_CHIP_REGS->FUSE_RESERVED_SW & 0x80) {
|
|
||||||
g_has_rcm_bug_patch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Other units have a proper ipatch instead. */
|
|
||||||
{
|
|
||||||
uint32_t word_count = FUSE_CHIP_REGS->FUSE_FIRST_BOOTROM_PATCH_SIZE & 0x7f;
|
|
||||||
uint32_t word_addr = 191;
|
|
||||||
|
|
||||||
while (word_count) {
|
|
||||||
uint32_t word0 = fuse_hw_read(word_addr);
|
|
||||||
uint32_t ipatch_count = (word0 >> 16) & 0xf;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < ipatch_count; i++) {
|
|
||||||
uint32_t word = fuse_hw_read(word_addr - (i + 1));
|
|
||||||
uint32_t addr = (word >> 16) * 2;
|
|
||||||
|
|
||||||
if (addr == 0x769a) {
|
|
||||||
g_has_rcm_bug_patch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
word_addr -= word_count;
|
|
||||||
word_count = word0 >> 25;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_has_checked_for_rcm_bug_patch = true;
|
|
||||||
|
|
||||||
return g_has_rcm_bug_patch;
|
|
||||||
}
|
|
|
@ -1,234 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_FUSE_H
|
|
||||||
#define EXOSPHERE_FUSE_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 FUSE registers. */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t FUSE_FUSECTRL;
|
|
||||||
uint32_t FUSE_FUSEADDR;
|
|
||||||
uint32_t FUSE_FUSERDATA;
|
|
||||||
uint32_t FUSE_FUSEWDATA;
|
|
||||||
uint32_t FUSE_FUSETIME_RD1;
|
|
||||||
uint32_t FUSE_FUSETIME_RD2;
|
|
||||||
uint32_t FUSE_FUSETIME_PGM1;
|
|
||||||
uint32_t FUSE_FUSETIME_PGM2;
|
|
||||||
uint32_t FUSE_PRIV2INTFC_START;
|
|
||||||
uint32_t FUSE_FUSEBYPASS;
|
|
||||||
uint32_t FUSE_PRIVATEKEYDISABLE;
|
|
||||||
uint32_t FUSE_DISABLEREGPROGRAM;
|
|
||||||
uint32_t FUSE_WRITE_ACCESS_SW;
|
|
||||||
uint32_t FUSE_PWR_GOOD_SW;
|
|
||||||
uint32_t _0x38;
|
|
||||||
uint32_t FUSE_PRIV2RESHIFT;
|
|
||||||
uint32_t _0x40[0x3];
|
|
||||||
uint32_t FUSE_FUSETIME_RD3;
|
|
||||||
uint32_t _0x50[0xC];
|
|
||||||
uint32_t FUSE_PRIVATE_KEY0_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY1_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY2_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY3_NONZERO;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY4_NONZERO;
|
|
||||||
uint32_t _0x90[0x1C];
|
|
||||||
} tegra_fuse_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t FUSE_PRODUCTION_MODE;
|
|
||||||
uint32_t FUSE_JTAG_SECUREID_VALID;
|
|
||||||
uint32_t FUSE_ODM_LOCK;
|
|
||||||
uint32_t FUSE_OPT_OPENGL_EN;
|
|
||||||
uint32_t FUSE_SKU_INFO;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_0_CALIB;
|
|
||||||
uint32_t FUSE_CPU_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_DAC_CRT_CALIB;
|
|
||||||
uint32_t FUSE_DAC_HDTV_CALIB;
|
|
||||||
uint32_t FUSE_DAC_SDTV_CALIB;
|
|
||||||
uint32_t FUSE_OPT_FT_REV;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_1_CALIB;
|
|
||||||
uint32_t FUSE_CPU_SPEEDO_2_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_0_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_1_CALIB;
|
|
||||||
uint32_t FUSE_SOC_SPEEDO_2_CALIB;
|
|
||||||
uint32_t FUSE_SOC_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_RESERVED_PRODUCTION_WP;
|
|
||||||
uint32_t FUSE_FA;
|
|
||||||
uint32_t FUSE_RESERVED_PRODUCTION;
|
|
||||||
uint32_t FUSE_HDMI_LANE0_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE1_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE2_CALIB;
|
|
||||||
uint32_t FUSE_HDMI_LANE3_CALIB;
|
|
||||||
uint32_t FUSE_ENCRYPTION_RATE;
|
|
||||||
uint32_t FUSE_PUBLIC_KEY[0x8];
|
|
||||||
uint32_t FUSE_TSENSOR1_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR2_CALIB;
|
|
||||||
uint32_t FUSE_VSENSOR_CALIB;
|
|
||||||
uint32_t FUSE_OPT_CP_REV;
|
|
||||||
uint32_t FUSE_OPT_PFG;
|
|
||||||
uint32_t FUSE_TSENSOR0_CALIB;
|
|
||||||
uint32_t FUSE_FIRST_BOOTROM_PATCH_SIZE;
|
|
||||||
uint32_t FUSE_SECURITY_MODE;
|
|
||||||
uint32_t FUSE_PRIVATE_KEY[0x5];
|
|
||||||
uint32_t FUSE_ARM_JTAG_DIS;
|
|
||||||
uint32_t FUSE_BOOT_DEVICE_INFO;
|
|
||||||
uint32_t FUSE_RESERVED_SW;
|
|
||||||
uint32_t FUSE_OPT_VP9_DISABLE;
|
|
||||||
uint32_t FUSE_RESERVED_ODM[0x8];
|
|
||||||
uint32_t FUSE_OBS_DIS;
|
|
||||||
uint32_t FUSE_NOR_INFO;
|
|
||||||
uint32_t FUSE_USB_CALIB;
|
|
||||||
uint32_t FUSE_SKU_DIRECT_CONFIG;
|
|
||||||
uint32_t FUSE_KFUSE_PRIVKEY_CTRL;
|
|
||||||
uint32_t FUSE_PACKAGE_INFO;
|
|
||||||
uint32_t FUSE_OPT_VENDOR_CODE;
|
|
||||||
uint32_t FUSE_OPT_FAB_CODE;
|
|
||||||
uint32_t FUSE_OPT_LOT_CODE_0;
|
|
||||||
uint32_t FUSE_OPT_LOT_CODE_1;
|
|
||||||
uint32_t FUSE_OPT_WAFER_ID;
|
|
||||||
uint32_t FUSE_OPT_X_COORDINATE;
|
|
||||||
uint32_t FUSE_OPT_Y_COORDINATE;
|
|
||||||
uint32_t FUSE_OPT_SEC_DEBUG_EN;
|
|
||||||
uint32_t FUSE_OPT_OPS_RESERVED;
|
|
||||||
uint32_t FUSE_SATA_CALIB;
|
|
||||||
uint32_t FUSE_GPU_IDDQ_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR3_CALIB;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_L;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_H;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_U;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_V;
|
|
||||||
uint32_t FUSE_SKU_BOND_OUT_W;
|
|
||||||
uint32_t FUSE_OPT_SAMPLE_TYPE;
|
|
||||||
uint32_t FUSE_OPT_SUBREVISION;
|
|
||||||
uint32_t FUSE_OPT_SW_RESERVED_0;
|
|
||||||
uint32_t FUSE_OPT_SW_RESERVED_1;
|
|
||||||
uint32_t FUSE_TSENSOR4_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR5_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR6_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR7_CALIB;
|
|
||||||
uint32_t FUSE_OPT_PRIV_SEC_EN;
|
|
||||||
uint32_t FUSE_PKC_DISABLE;
|
|
||||||
uint32_t _0x16C;
|
|
||||||
uint32_t _0x170;
|
|
||||||
uint32_t _0x174;
|
|
||||||
uint32_t _0x178;
|
|
||||||
uint32_t FUSE_FUSE2TSEC_DEBUG_DISABLE;
|
|
||||||
uint32_t FUSE_TSENSOR_COMMON;
|
|
||||||
uint32_t FUSE_OPT_CP_BIN;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_FT_BIN;
|
|
||||||
uint32_t FUSE_OPT_DONE_MAP;
|
|
||||||
uint32_t _0x194;
|
|
||||||
uint32_t FUSE_APB2JTAG_DISABLE;
|
|
||||||
uint32_t FUSE_ODM_INFO;
|
|
||||||
uint32_t _0x1A0;
|
|
||||||
uint32_t _0x1A4;
|
|
||||||
uint32_t FUSE_ARM_CRYPT_DE_FEATURE;
|
|
||||||
uint32_t _0x1AC;
|
|
||||||
uint32_t _0x1B0;
|
|
||||||
uint32_t _0x1B4;
|
|
||||||
uint32_t _0x1B8;
|
|
||||||
uint32_t _0x1BC;
|
|
||||||
uint32_t FUSE_WOA_SKU_FLAG;
|
|
||||||
uint32_t FUSE_ECO_RESERVE_1;
|
|
||||||
uint32_t FUSE_GCPLEX_CONFIG_FUSE;
|
|
||||||
uint32_t FUSE_PRODUCTION_MONTH;
|
|
||||||
uint32_t FUSE_RAM_REPAIR_INDICATOR;
|
|
||||||
uint32_t FUSE_TSENSOR9_CALIB;
|
|
||||||
uint32_t _0x1D8;
|
|
||||||
uint32_t FUSE_VMIN_CALIBRATION;
|
|
||||||
uint32_t FUSE_AGING_SENSOR_CALIBRATION;
|
|
||||||
uint32_t FUSE_DEBUG_AUTHENTICATION;
|
|
||||||
uint32_t FUSE_SECURE_PROVISION_INDEX;
|
|
||||||
uint32_t FUSE_SECURE_PROVISION_INFO;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_SPARE_ENDIS;
|
|
||||||
uint32_t FUSE_ECO_RESERVE_0;
|
|
||||||
uint32_t _0x1FC;
|
|
||||||
uint32_t _0x200;
|
|
||||||
uint32_t FUSE_RESERVED_CALIB0;
|
|
||||||
uint32_t FUSE_RESERVED_CALIB1;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_TSENSOR10_CALIB;
|
|
||||||
uint32_t FUSE_TSENSOR10_CALIB_AUX;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_DP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_PDP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_REG;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_SP;
|
|
||||||
uint32_t FUSE_OPT_RAM_SVOP_SMPDP;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC0_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE_CP1;
|
|
||||||
uint32_t FUSE_OPT_GPU_TPC1_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_CPU_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_OPT_GPU_DISABLE_CP2;
|
|
||||||
uint32_t FUSE_USB_CALIB_EXT;
|
|
||||||
uint32_t FUSE_RESERVED_FIELD;
|
|
||||||
uint32_t FUSE_OPT_ECC_EN;
|
|
||||||
uint32_t _0x25C;
|
|
||||||
uint32_t _0x260;
|
|
||||||
uint32_t _0x264;
|
|
||||||
uint32_t _0x268;
|
|
||||||
uint32_t _0x26C;
|
|
||||||
uint32_t _0x270;
|
|
||||||
uint32_t _0x274;
|
|
||||||
uint32_t _0x278;
|
|
||||||
uint32_t FUSE_SPARE_REALIGNMENT_REG;
|
|
||||||
uint32_t FUSE_SPARE_BIT[0x20];
|
|
||||||
} tegra_fuse_chip_t;
|
|
||||||
|
|
||||||
static inline volatile tegra_fuse_t *fuse_get_regs(void) {
|
|
||||||
return (volatile tegra_fuse_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_FUSE) + 0x800);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline volatile tegra_fuse_chip_t *fuse_chip_get_regs(void) {
|
|
||||||
return (volatile tegra_fuse_chip_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_FUSE) + 0x900);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FUSE_REGS (fuse_get_regs())
|
|
||||||
#define FUSE_CHIP_REGS (fuse_chip_get_regs())
|
|
||||||
|
|
||||||
void fuse_init(void);
|
|
||||||
void fuse_disable_programming(void);
|
|
||||||
void fuse_disable_private_key(void);
|
|
||||||
|
|
||||||
uint32_t fuse_get_sku_info(void);
|
|
||||||
uint32_t fuse_get_spare_bit(uint32_t idx);
|
|
||||||
uint32_t fuse_get_reserved_odm(uint32_t idx);
|
|
||||||
uint32_t fuse_get_bootrom_patch_version(void);
|
|
||||||
uint64_t fuse_get_device_id(void);
|
|
||||||
uint32_t fuse_get_dram_id(void);
|
|
||||||
uint32_t fuse_get_hardware_type(uint32_t target_firmware);
|
|
||||||
uint32_t fuse_get_retail_type(void);
|
|
||||||
void fuse_get_hardware_info(void *dst);
|
|
||||||
uint32_t fuse_get_5x_key_generation(void);
|
|
||||||
bool fuse_has_rcm_bug_patch(void);
|
|
||||||
|
|
||||||
uint32_t fuse_hw_read(uint32_t addr);
|
|
||||||
void fuse_hw_write(uint32_t value, uint32_t addr);
|
|
||||||
void fuse_hw_sense(void);
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,229 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
|
|
||||||
#include "arm.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "gcm.h"
|
|
||||||
|
|
||||||
#include "sealedkeys.h"
|
|
||||||
#include "se.h"
|
|
||||||
|
|
||||||
/* Shifts right a little endian 128-bit value. */
|
|
||||||
static void shr_128(uint64_t *val) {
|
|
||||||
val[0] >>= 1;
|
|
||||||
val[0] |= (val[1] & 1) << 63;
|
|
||||||
val[1] >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shifts left a little endian 128-bit value. */
|
|
||||||
static void shl_128(uint64_t *val) {
|
|
||||||
val[1] <<= 1;
|
|
||||||
val[1] |= (val[0] & (1ull << 63)) >> 63;
|
|
||||||
val[0] <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Multiplies two 128-bit numbers X,Y in the GF(128) Galois Field. */
|
|
||||||
static void gf128_mul(uint8_t *dst, const uint8_t *x, const uint8_t *y) {
|
|
||||||
uint8_t x_work[0x10];
|
|
||||||
uint8_t y_work[0x10];
|
|
||||||
uint8_t dst_work[0x10];
|
|
||||||
|
|
||||||
uint64_t *p_x = (uint64_t *)(&x_work[0]);
|
|
||||||
uint64_t *p_y = (uint64_t *)(&y_work[0]);
|
|
||||||
uint64_t *p_dst = (uint64_t *)(&dst_work[0]);
|
|
||||||
|
|
||||||
/* Initialize buffers. */
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
x_work[i] = x[0xF-i];
|
|
||||||
y_work[i] = y[0xF-i];
|
|
||||||
dst_work[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform operation for each bit in y. */
|
|
||||||
for (unsigned int round = 0; round < 0x80; round++) {
|
|
||||||
p_dst[0] ^= p_x[0] * ((y_work[0xF] & 0x80) >> 7);
|
|
||||||
p_dst[1] ^= p_x[1] * ((y_work[0xF] & 0x80) >> 7);
|
|
||||||
shl_128(p_y);
|
|
||||||
uint8_t xval = 0xE1 * (x_work[0] & 1);
|
|
||||||
shr_128(p_x);
|
|
||||||
x_work[0xF] ^= xval;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
dst[i] = dst_work[0xF-i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Performs an AES-GCM GHASH operation over the data into dst. */
|
|
||||||
static void ghash(void *dst, const void *data, size_t data_size, const void *j_block, bool encrypt) {
|
|
||||||
uint8_t x[0x10] = {0};
|
|
||||||
uint8_t h[0x10];
|
|
||||||
|
|
||||||
uint64_t *p_x = (uint64_t *)(&x[0]);
|
|
||||||
uint64_t *p_data = (uint64_t *)data;
|
|
||||||
|
|
||||||
/* H = aes_ecb_encrypt(zeroes) */
|
|
||||||
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, x, 0x10);
|
|
||||||
|
|
||||||
size_t total_size = data_size;
|
|
||||||
|
|
||||||
while (data_size >= 0x10) {
|
|
||||||
/* X = (X ^ current_block) * H */
|
|
||||||
p_x[0] ^= p_data[0];
|
|
||||||
p_x[1] ^= p_data[1];
|
|
||||||
gf128_mul(x, x, h);
|
|
||||||
|
|
||||||
/* Increment p_data by 0x10 bytes. */
|
|
||||||
p_data += 2;
|
|
||||||
data_size -= 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nintendo's code *discards all data in the last block* if unaligned. */
|
|
||||||
/* And treats that block as though it were all-zero. */
|
|
||||||
/* This is a bug, they just forget to XOR with the copy of the last block they save. */
|
|
||||||
if (data_size & 0xF) {
|
|
||||||
gf128_mul(x, x, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t xor_size = total_size << 3;
|
|
||||||
xor_size = __builtin_bswap64(xor_size);
|
|
||||||
|
|
||||||
/* Due to a Nintendo bug, the wrong QWORD gets XOR'd in the "final output block" case. */
|
|
||||||
if (encrypt) {
|
|
||||||
p_x[0] ^= xor_size;
|
|
||||||
} else {
|
|
||||||
p_x[1] ^= xor_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
gf128_mul(x, x, h);
|
|
||||||
|
|
||||||
/* If final output block, XOR with encrypted J block. */
|
|
||||||
if (encrypt) {
|
|
||||||
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, j_block, 0x10);
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
x[i] ^= h[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Copy output. */
|
|
||||||
memcpy(dst, x, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function is a doozy. It decrypts and validates a (non-standard) AES-GCM wrapped keypair. */
|
|
||||||
size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_size, const void *sealed_kek, size_t kek_size, const void *wrapped_key, size_t key_size, unsigned int usecase, bool is_personalized, uint8_t *out_deviceid_high) {
|
|
||||||
if (is_personalized == 0) {
|
|
||||||
/* Devkit keys use a different keyformat without a MAC/Device ID. */
|
|
||||||
if (src_size <= 0x10 || src_size - 0x10 > dst_size) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (src_size <= 0x30 || src_size - 0x20 > dst_size) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t intermediate_buf[0x400] = {0};
|
|
||||||
|
|
||||||
/* Unwrap the key */
|
|
||||||
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, kek_size, usecase);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_key, key_size);
|
|
||||||
|
|
||||||
/* Decrypt the GCM keypair, AES-CTR with CTR = blob[:0x10]. */
|
|
||||||
se_aes_ctr_crypt(KEYSLOT_SWITCH_TEMPKEY, intermediate_buf, dst_size, src + 0x10, src_size - 0x10, src, 0x10);
|
|
||||||
|
|
||||||
if (!is_personalized) {
|
|
||||||
/* Devkit non-personalized keys have no further authentication. */
|
|
||||||
memcpy(dst, intermediate_buf, src_size - 0x10);
|
|
||||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
|
||||||
return src_size - 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* J = GHASH(CTR); */
|
|
||||||
uint8_t j_block[0x10];
|
|
||||||
ghash(j_block, src, 0x10, NULL, false);
|
|
||||||
|
|
||||||
/* MAC = GHASH(PLAINTEXT) ^ ENCRYPT(J) */
|
|
||||||
/* Note: That MAC is calculated over plaintext is non-standard. */
|
|
||||||
/* It is supposed to be over the ciphertext. */
|
|
||||||
uint8_t calc_mac[0x10];
|
|
||||||
ghash(calc_mac, intermediate_buf, src_size - 0x20, j_block, true);
|
|
||||||
|
|
||||||
/* Const-time memcmp. */
|
|
||||||
const uint8_t *src_bytes = src;
|
|
||||||
int different = 0;
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
different |= src_bytes[src_size - 0x10 + i] ^ calc_mac[i];
|
|
||||||
}
|
|
||||||
if (different) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((read64be(intermediate_buf, src_size - 0x28) & 0x00FFFFFFFFFFFFFFULL) != fuse_get_device_id()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_deviceid_high != NULL) {
|
|
||||||
*out_deviceid_high = intermediate_buf[src_size - 0x28];
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(dst, intermediate_buf, src_size - 0x30);
|
|
||||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
|
||||||
return src_size - 0x30;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gcm_encrypt_key(void *dst, size_t dst_size, const void *src, size_t src_size, const void *sealed_kek, size_t kek_size, const void *wrapped_key, size_t key_size, unsigned int usecase, uint64_t deviceid_high) {
|
|
||||||
uint8_t intermediate_buf[0x400] = {0};
|
|
||||||
if (src_size + 0x30 > dst_size) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unwrap the key */
|
|
||||||
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, kek_size, usecase);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_key, key_size);
|
|
||||||
|
|
||||||
/* Generate a random CTR. */
|
|
||||||
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
|
|
||||||
se_generate_random(KEYSLOT_SWITCH_RNGKEY, intermediate_buf, 0x10);
|
|
||||||
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
|
|
||||||
|
|
||||||
/* Copy in the src. */
|
|
||||||
memcpy(intermediate_buf + 0x10, src, src_size);
|
|
||||||
|
|
||||||
/* Write Device ID. */
|
|
||||||
write64be(intermediate_buf, src_size + 0x18, fuse_get_device_id() | (deviceid_high << 56));
|
|
||||||
|
|
||||||
/* J = GHASH(CTR); */
|
|
||||||
uint8_t j_block[0x10];
|
|
||||||
ghash(j_block, intermediate_buf, 0x10, NULL, false);
|
|
||||||
|
|
||||||
/* MAC = GHASH(PLAINTEXT) ^ ENCRYPT(J) */
|
|
||||||
/* Note: That MAC is calculated over plaintext is non-standard. */
|
|
||||||
/* It is supposed to be over the ciphertext. */
|
|
||||||
ghash(intermediate_buf + src_size + 0x20, intermediate_buf + 0x10, src_size + 0x10, j_block, true);
|
|
||||||
|
|
||||||
/* Encrypt the GCM keypair, AES-CTR with CTR = blob[:0x10]. */
|
|
||||||
se_aes_ctr_crypt(KEYSLOT_SWITCH_TEMPKEY, intermediate_buf + 0x10, src_size + 0x10, intermediate_buf + 0x10, src_size + 0x10, intermediate_buf, 0x10);
|
|
||||||
|
|
||||||
/* Copy the wrapped key out. */
|
|
||||||
memcpy(dst, intermediate_buf, src_size + 0x30);
|
|
||||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_GCM_H
|
|
||||||
#define EXOSPHERE_GCM_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
size_t gcm_decrypt_key(void *dst, size_t dst_size,
|
|
||||||
const void *src, size_t src_size,
|
|
||||||
const void *sealed_kek, size_t kek_size,
|
|
||||||
const void *wrapped_key, size_t key_size,
|
|
||||||
unsigned int usecase, bool is_personalized,
|
|
||||||
uint8_t *out_deviceid_high);
|
|
||||||
|
|
||||||
|
|
||||||
void gcm_encrypt_key(void *dst, size_t dst_size,
|
|
||||||
const void *src, size_t src_size,
|
|
||||||
const void *sealed_kek, size_t kek_size,
|
|
||||||
const void *wrapped_key, size_t key_size,
|
|
||||||
unsigned int usecase, uint64_t deviceid_high);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "i2c.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "pinmux.h"
|
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
|
||||||
volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id);
|
|
||||||
void i2c_load_config(volatile tegra_i2c_t *regs);
|
|
||||||
|
|
||||||
bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
|
|
||||||
bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
|
|
||||||
|
|
||||||
bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size);
|
|
||||||
bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size);
|
|
||||||
|
|
||||||
/* Configure I2C pinmux. */
|
|
||||||
void i2c_config(I2CDevice id) {
|
|
||||||
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case I2C_1:
|
|
||||||
pinmux->gen1_i2c_scl = PINMUX_INPUT;
|
|
||||||
pinmux->gen1_i2c_sda = PINMUX_INPUT;
|
|
||||||
break;
|
|
||||||
case I2C_2:
|
|
||||||
pinmux->gen2_i2c_scl = PINMUX_INPUT;
|
|
||||||
pinmux->gen2_i2c_sda = PINMUX_INPUT;
|
|
||||||
break;
|
|
||||||
case I2C_3:
|
|
||||||
pinmux->gen3_i2c_scl = PINMUX_INPUT;
|
|
||||||
pinmux->gen3_i2c_sda = PINMUX_INPUT;
|
|
||||||
break;
|
|
||||||
case I2C_4:
|
|
||||||
pinmux->cam_i2c_scl = PINMUX_INPUT;
|
|
||||||
pinmux->cam_i2c_sda = PINMUX_INPUT;
|
|
||||||
break;
|
|
||||||
case I2C_5:
|
|
||||||
pinmux->pwr_i2c_scl = PINMUX_INPUT;
|
|
||||||
pinmux->pwr_i2c_sda = PINMUX_INPUT;
|
|
||||||
break;
|
|
||||||
case I2C_6:
|
|
||||||
/* Unused. */
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize I2C based on registers. */
|
|
||||||
void i2c_init(I2CDevice id) {
|
|
||||||
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
|
||||||
regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001;
|
|
||||||
regs->I2C_I2C_BUS_CLEAR_CONFIG_0 = 0x90003;
|
|
||||||
|
|
||||||
/* Load hardware configuration. */
|
|
||||||
i2c_load_config(regs);
|
|
||||||
|
|
||||||
/* Wait a while until BUS_CLEAR_DONE is set. */
|
|
||||||
for (unsigned int i = 0; i < 10; i++) {
|
|
||||||
wait(25);
|
|
||||||
if (regs->I2C_INTERRUPT_STATUS_REGISTER_0 & 0x800) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the BUS_CLEAR_STATUS. Result doesn't matter. */
|
|
||||||
regs->I2C_I2C_BUS_CLEAR_STATUS_0;
|
|
||||||
|
|
||||||
/* Read and set the Interrupt Status. */
|
|
||||||
uint32_t int_status = regs->I2C_INTERRUPT_STATUS_REGISTER_0;
|
|
||||||
regs->I2C_INTERRUPT_STATUS_REGISTER_0 = int_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets a bit in a PMIC register over I2C during CPU shutdown. */
|
|
||||||
void i2c_send_pmic_cpu_shutdown_cmd(void) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
/* PMIC == Device 4:3C. */
|
|
||||||
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1);
|
|
||||||
val |= 4;
|
|
||||||
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Queries the value of TI charger bit over I2C. */
|
|
||||||
bool i2c_query_ti_charger_bit_7(void) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
/* TI Charger = Device 0:6B. */
|
|
||||||
i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
|
||||||
return (val & 0x80) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clears TI charger bit over I2C. */
|
|
||||||
void i2c_clear_ti_charger_bit_7(void) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
/* TI Charger = Device 0:6B. */
|
|
||||||
i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
|
||||||
val &= 0x7F;
|
|
||||||
i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets TI charger bit over I2C. */
|
|
||||||
void i2c_set_ti_charger_bit_7(void) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
/* TI Charger = Device 0:6B. */
|
|
||||||
i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
|
||||||
val |= 0x80;
|
|
||||||
i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get registers pointer based on I2C ID. */
|
|
||||||
volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) {
|
|
||||||
switch (id) {
|
|
||||||
case I2C_1:
|
|
||||||
return I2C1_REGS;
|
|
||||||
case I2C_2:
|
|
||||||
return I2C2_REGS;
|
|
||||||
case I2C_3:
|
|
||||||
return I2C3_REGS;
|
|
||||||
case I2C_4:
|
|
||||||
return I2C4_REGS;
|
|
||||||
case I2C_5:
|
|
||||||
return I2C5_REGS;
|
|
||||||
case I2C_6:
|
|
||||||
return I2C6_REGS;
|
|
||||||
default:
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load hardware config for I2C4. */
|
|
||||||
void i2c_load_config(volatile tegra_i2c_t *regs) {
|
|
||||||
/* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */
|
|
||||||
regs->I2C_I2C_CONFIG_LOAD_0 = 0x25;
|
|
||||||
|
|
||||||
/* Wait a bit for master config to be loaded. */
|
|
||||||
for (unsigned int i = 0; i < 20; i++) {
|
|
||||||
wait(1);
|
|
||||||
if (!(regs->I2C_I2C_CONFIG_LOAD_0 & 1)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reads a register from a device over I2C, writes result to output. */
|
|
||||||
bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) {
|
|
||||||
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
|
||||||
uint32_t val = r;
|
|
||||||
|
|
||||||
/* Write single byte register ID to device. */
|
|
||||||
if (!i2c_write(regs, device, &val, 1)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* Limit output size to 32-bits. */
|
|
||||||
if (dst_size > 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i2c_read(regs, device, dst, dst_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes a value to a register over I2C. */
|
|
||||||
bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) {
|
|
||||||
uint32_t val = r;
|
|
||||||
if (src_size == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (src_size <= 3) {
|
|
||||||
memcpy(((uint8_t *)&val) + 1, src, src_size);
|
|
||||||
return i2c_write(i2c_get_registers_from_id(id), device, &val, src_size + 1);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes bytes to device over I2C. */
|
|
||||||
bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size) {
|
|
||||||
if (src_size > 4) {
|
|
||||||
return false;
|
|
||||||
} else if (src_size == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit write mode. */
|
|
||||||
regs->I2C_I2C_CMD_ADDR0_0 = device << 1;
|
|
||||||
|
|
||||||
/* Load in data to write. */
|
|
||||||
regs->I2C_I2C_CMD_DATA1_0 = read32le(src, 0);
|
|
||||||
|
|
||||||
/* Set config with LENGTH = src_size, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
regs->I2C_I2C_CNFG_0 = ((src_size << 1) - 2) | 0x2800;
|
|
||||||
|
|
||||||
i2c_load_config(regs);
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
|
||||||
|
|
||||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return CMD1_STAT == SL1_XFER_SUCCESSFUL. */
|
|
||||||
return (regs->I2C_I2C_STATUS_0 & 0xF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reads bytes from device over I2C. */
|
|
||||||
bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size) {
|
|
||||||
if (dst_size > 4) {
|
|
||||||
return false;
|
|
||||||
} else if (dst_size == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set device for 7-bit read mode. */
|
|
||||||
regs->I2C_I2C_CMD_ADDR0_0 = (device << 1) | 1;
|
|
||||||
|
|
||||||
/* Set config with LENGTH = dst_size, NEW_MASTER_FSM, DEBOUNCE_CNT = 4T. */
|
|
||||||
regs->I2C_I2C_CNFG_0 = ((dst_size << 1) - 2) | 0x2840;
|
|
||||||
|
|
||||||
i2c_load_config(regs);
|
|
||||||
|
|
||||||
/* Config |= SEND; */
|
|
||||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
|
||||||
|
|
||||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
|
||||||
/* Wait until not busy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure success. */
|
|
||||||
if ((regs->I2C_I2C_STATUS_0 & 0xF) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t val = regs->I2C_I2C_CMD_DATA1_0;
|
|
||||||
memcpy(dst, &val, dst_size);
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_I2C_H
|
|
||||||
#define EXOSPHERE_I2C_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 I2C registers. */
|
|
||||||
|
|
||||||
#define MAX77621_CPU_I2C_ADDR 0x1B
|
|
||||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
|
||||||
#define MAX17050_I2C_ADDR 0x36
|
|
||||||
#define MAX77620_PWR_I2C_ADDR 0x3C
|
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
I2C_1 = 0,
|
|
||||||
I2C_2 = 1,
|
|
||||||
I2C_3 = 2,
|
|
||||||
I2C_4 = 3,
|
|
||||||
I2C_5 = 4,
|
|
||||||
I2C_6 = 5,
|
|
||||||
} I2CDevice;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_0;
|
|
||||||
uint32_t I2C_I2C_CMD_ADDR1_0;
|
|
||||||
uint32_t I2C_I2C_CMD_DATA1_0;
|
|
||||||
uint32_t I2C_I2C_CMD_DATA2_0;
|
|
||||||
uint32_t _0x14;
|
|
||||||
uint32_t _0x18;
|
|
||||||
uint32_t I2C_I2C_STATUS_0;
|
|
||||||
uint32_t I2C_I2C_SL_CNFG_0;
|
|
||||||
uint32_t I2C_I2C_SL_RCVD_0;
|
|
||||||
uint32_t I2C_I2C_SL_STATUS_0;
|
|
||||||
uint32_t I2C_I2C_SL_ADDR1_0;
|
|
||||||
uint32_t I2C_I2C_SL_ADDR2_0;
|
|
||||||
uint32_t I2C_I2C_TLOW_SEXT_0;
|
|
||||||
uint32_t _0x38;
|
|
||||||
uint32_t I2C_I2C_SL_DELAY_COUNT_0;
|
|
||||||
uint32_t I2C_I2C_SL_INT_MASK_0;
|
|
||||||
uint32_t I2C_I2C_SL_INT_SOURCE_0;
|
|
||||||
uint32_t I2C_I2C_SL_INT_SET_0;
|
|
||||||
uint32_t _0x4C;
|
|
||||||
uint32_t I2C_I2C_TX_PACKET_FIFO_0;
|
|
||||||
uint32_t I2C_I2C_RX_FIFO_0;
|
|
||||||
uint32_t I2C_PACKET_TRANSFER_STATUS_0;
|
|
||||||
uint32_t I2C_FIFO_CONTROL_0;
|
|
||||||
uint32_t I2C_FIFO_STATUS_0;
|
|
||||||
uint32_t I2C_INTERRUPT_MASK_REGISTER_0;
|
|
||||||
uint32_t I2C_INTERRUPT_STATUS_REGISTER_0;
|
|
||||||
uint32_t I2C_I2C_CLK_DIVISOR_REGISTER_0;
|
|
||||||
uint32_t I2C_I2C_INTERRUPT_SOURCE_REGISTER_0;
|
|
||||||
uint32_t I2C_I2C_INTERRUPT_SET_REGISTER_0;
|
|
||||||
uint32_t I2C_I2C_SLV_TX_PACKET_FIFO_0;
|
|
||||||
uint32_t I2C_I2C_SLV_RX_FIFO_0;
|
|
||||||
uint32_t I2C_I2C_SLV_PACKET_STATUS_0;
|
|
||||||
uint32_t I2C_I2C_BUS_CLEAR_CONFIG_0;
|
|
||||||
uint32_t I2C_I2C_BUS_CLEAR_STATUS_0;
|
|
||||||
uint32_t I2C_I2C_CONFIG_LOAD_0;
|
|
||||||
uint32_t _0x90;
|
|
||||||
uint32_t I2C_I2C_INTERFACE_TIMING_0_0;
|
|
||||||
uint32_t I2C_I2C_INTERFACE_TIMING_1_0;
|
|
||||||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0;
|
|
||||||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0;
|
|
||||||
} tegra_i2c_t;
|
|
||||||
|
|
||||||
static inline uintptr_t get_i2c_dtv_234_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DTV_I2C234);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uintptr_t get_i2c56_spi2b_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_I2C56_SPI2B);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define I2C1_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x000))
|
|
||||||
#define I2C2_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x400))
|
|
||||||
#define I2C3_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x500))
|
|
||||||
#define I2C4_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x700))
|
|
||||||
#define I2C5_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x000))
|
|
||||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x100))
|
|
||||||
|
|
||||||
void i2c_config(I2CDevice id);
|
|
||||||
|
|
||||||
void i2c_init(I2CDevice id);
|
|
||||||
bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size);
|
|
||||||
bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size);
|
|
||||||
|
|
||||||
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
|
||||||
void i2c_clear_ti_charger_bit_7(void);
|
|
||||||
void i2c_set_ti_charger_bit_7(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,131 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdbool.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
/* Global of registered handlers. */
|
|
||||||
static struct {
|
|
||||||
unsigned int id;
|
|
||||||
void (*handler)(void);
|
|
||||||
} g_registered_interrupts[MAX_REGISTERED_INTERRUPTS] = { {0} };
|
|
||||||
|
|
||||||
static unsigned int get_interrupt_id(void) {
|
|
||||||
return GICC_IAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initializes the GIC. This must be called during wakeup. */
|
|
||||||
void intr_initialize_gic(void) {
|
|
||||||
/* Setup interrupts 0-0x1F as nonsecure with highest non-secure priority. */
|
|
||||||
GICD_IGROUPR[0] = 0xFFFFFFFF;
|
|
||||||
for (unsigned int i = 0; i < 0x20; i++) {
|
|
||||||
GICD_IPRIORITYR[i] = GIC_PRI_HIGHEST_NONSECURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup the GICC. */
|
|
||||||
GICC_CTLR = 0x1D9;
|
|
||||||
GICC_PMR = GIC_PRI_HIGHEST_NONSECURE;
|
|
||||||
GICC_BPR = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initializes Interrupt Groups 1-7 in the GIC. Called by pk2ldr. */
|
|
||||||
void intr_initialize_gic_nonsecure(void) {
|
|
||||||
for (unsigned int i = 1; i < 8; i++) {
|
|
||||||
GICD_IGROUPR[i] = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0x20; i < 0xE0; i++) {
|
|
||||||
GICD_IPRIORITYR[i] = GIC_PRI_HIGHEST_NONSECURE;
|
|
||||||
}
|
|
||||||
GICD_CTLR = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets GICC_CTLR to appropriate pre-sleep value. */
|
|
||||||
void intr_prepare_gicc_for_sleep(void) {
|
|
||||||
GICC_CTLR = 0x1E0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt's group in the GICD. */
|
|
||||||
void intr_set_group(unsigned int id, int group) {
|
|
||||||
GICD_IGROUPR[id >> 5] = (GICD_IGROUPR[id >> 5] & (~(1 << (id & 0x1F)))) | ((group & 1) << (id & 0x1F));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt id as pending in the GICD. */
|
|
||||||
void intr_set_pending(unsigned int id) {
|
|
||||||
GICD_ISPENDR[id >> 5] = 1 << (id & 0x1F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt's priority in the GICD. */
|
|
||||||
void intr_set_priority(unsigned int id, uint8_t priority) {
|
|
||||||
GICD_IPRIORITYR[id] = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt's target CPU mask in the GICD. */
|
|
||||||
void intr_set_cpu_mask(unsigned int id, uint8_t mask) {
|
|
||||||
GICD_ITARGETSR[id] = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt's edge/level bits in the GICD. */
|
|
||||||
void intr_set_edge_level(unsigned int id, int edge_level) {
|
|
||||||
GICD_ICFGR[id >> 4] = GICD_ICFGR[id >> 4] & ((~(3 << ((id & 0xF) << 1))) | (((edge_level & 1) << 1) << ((id & 0xF) << 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets an interrupt's enabled status in the GICD. */
|
|
||||||
void intr_set_enabled(unsigned int id, int enabled) {
|
|
||||||
GICD_ISENABLER[id >> 5] = (enabled & 1) << (id & 0x1F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To be called by FIQ handler. */
|
|
||||||
void handle_registered_interrupt(void) {
|
|
||||||
unsigned int interrupt_id = get_interrupt_id();
|
|
||||||
if (interrupt_id <= 0xDF) {
|
|
||||||
bool found_handler = false;
|
|
||||||
for (unsigned int i = 0; i < MAX_REGISTERED_INTERRUPTS; i++) {
|
|
||||||
if (g_registered_interrupts[i].id == interrupt_id) {
|
|
||||||
found_handler = true;
|
|
||||||
g_registered_interrupts[i].handler();
|
|
||||||
/* Mark that interrupt is done. */
|
|
||||||
GICC_EOIR = interrupt_id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* We must have found a handler, or something went wrong. */
|
|
||||||
if (!found_handler) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Registers an interrupt into the global. */
|
|
||||||
void intr_register_handler(unsigned int id, void (*handler)(void)) {
|
|
||||||
bool registered_handler = false;
|
|
||||||
for (unsigned int i = 0; i < MAX_REGISTERED_INTERRUPTS; i++) {
|
|
||||||
if (g_registered_interrupts[i].id == 0) {
|
|
||||||
g_registered_interrupts[i].handler = handler;
|
|
||||||
g_registered_interrupts[i].id = id;
|
|
||||||
registered_handler = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Failure to register is an error condition. */
|
|
||||||
if (!registered_handler) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_INTERRUPT_H
|
|
||||||
#define EXOSPHERE_INTERRUPT_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 GIC-400 registers. */
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_REGISTERED_INTERRUPTS 4
|
|
||||||
#define INTERRUPT_ID_SECURITY_ENGINE 0x5A
|
|
||||||
#define INTERRUPT_ID_ACTIVITY_MONITOR_4X 0x4D
|
|
||||||
#define INTERRUPT_ID_1C 0x1C
|
|
||||||
#define INTERRUPT_ID_USER_SECURITY_ENGINE 0x2C
|
|
||||||
|
|
||||||
static inline uintptr_t get_gicd_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_GICD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uintptr_t get_gicc_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_GICC);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GICD_BASE (get_gicd_base())
|
|
||||||
#define GICC_BASE (get_gicc_base())
|
|
||||||
|
|
||||||
#define GICD_CTLR MAKE_REG32(GICD_BASE + 0x000ull)
|
|
||||||
#define GICD_IGROUPR ((volatile uint32_t *)(GICD_BASE + 0x080ull))
|
|
||||||
#define GICD_ISENABLER ((volatile uint32_t *)(GICD_BASE + 0x100ull))
|
|
||||||
#define GICD_ISPENDR ((volatile uint32_t *)(GICD_BASE + 0x200ull))
|
|
||||||
#define GICD_IPRIORITYR ((volatile uint8_t *)(GICD_BASE + 0x400ull))
|
|
||||||
#define GICD_ITARGETSR ((volatile uint8_t *)(GICD_BASE + 0x800ull))
|
|
||||||
#define GICD_ICFGR ((volatile uint32_t *)(GICD_BASE + 0xC00ull))
|
|
||||||
|
|
||||||
#define GICC_CTLR MAKE_REG32(GICC_BASE + 0x0000ull)
|
|
||||||
#define GICC_PMR MAKE_REG32(GICC_BASE + 0x0004ull)
|
|
||||||
#define GICC_BPR MAKE_REG32(GICC_BASE + 0x0008ull)
|
|
||||||
#define GICC_IAR MAKE_REG32(GICC_BASE + 0x000CULL)
|
|
||||||
#define GICC_EOIR MAKE_REG32(GICC_BASE + 0x0010ull)
|
|
||||||
|
|
||||||
#define GIC_PRI_HIGHEST_SECURE 0x00
|
|
||||||
#define GIC_PRI_HIGHEST_NONSECURE 0x80
|
|
||||||
|
|
||||||
#define GIC_GROUP_SECURE 0
|
|
||||||
#define GIC_GROUP_NONSECURE 1
|
|
||||||
|
|
||||||
/* To be called by FIQ handler. */
|
|
||||||
void handle_registered_interrupt(void);
|
|
||||||
|
|
||||||
/* Initializes the GIC. This must be called during wakeup. */
|
|
||||||
void intr_initialize_gic(void);
|
|
||||||
void intr_initialize_gic_nonsecure(void);
|
|
||||||
|
|
||||||
void intr_prepare_gicc_for_sleep(void);
|
|
||||||
|
|
||||||
|
|
||||||
void intr_register_handler(unsigned int id, void (*handler)(void));
|
|
||||||
void intr_set_group(unsigned int id, int group);
|
|
||||||
void intr_set_pending(unsigned int id);
|
|
||||||
void intr_set_priority(unsigned int id, uint8_t priority);
|
|
||||||
void intr_set_cpu_mask(unsigned int id, uint8_t mask);
|
|
||||||
void intr_set_edge_level(unsigned int id, int edge_level);
|
|
||||||
void intr_set_enabled(unsigned int id, int enabled);
|
|
||||||
#endif
|
|
|
@ -1,156 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "configitem.h"
|
|
||||||
#include "masterkey.h"
|
|
||||||
#include "se.h"
|
|
||||||
|
|
||||||
static unsigned int g_mkey_revision = 0;
|
|
||||||
static bool g_determined_mkey_revision = false;
|
|
||||||
|
|
||||||
static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10];
|
|
||||||
static uint8_t g_old_devicekeys[MASTERKEY_NUM_NEW_DEVICE_KEYS - 1][0x10];
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Extend with new vectors, as needed. */
|
|
||||||
/* Dev unit keys. */
|
|
||||||
static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
|
|
||||||
{
|
|
||||||
{0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */
|
|
||||||
{0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */
|
|
||||||
{0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */
|
|
||||||
{0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */
|
|
||||||
{0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */
|
|
||||||
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
|
||||||
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
|
||||||
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
|
||||||
{0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04}, /* Master key 07 encrypted with Master key 08. */
|
|
||||||
{0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */
|
|
||||||
{0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Retail unit keys. */
|
|
||||||
static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
|
|
||||||
{
|
|
||||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
|
||||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
|
||||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
|
||||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
|
||||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
|
||||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
|
||||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
|
||||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
|
||||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
|
||||||
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
|
|
||||||
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
|
|
||||||
};
|
|
||||||
|
|
||||||
bool check_mkey_revision(unsigned int revision, bool is_retail) {
|
|
||||||
uint8_t final_vector[0x10];
|
|
||||||
|
|
||||||
unsigned int check_keyslot = KEYSLOT_SWITCH_MASTERKEY;
|
|
||||||
if (revision > 0) {
|
|
||||||
/* Generate old master key array. */
|
|
||||||
for (unsigned int i = revision; i > 0; i--) {
|
|
||||||
se_aes_ecb_decrypt_block(check_keyslot, g_old_masterkeys[i-1], 0x10, is_retail ? mkey_vectors[i] : mkey_vectors_dev[i], 0x10);
|
|
||||||
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_masterkeys[i-1], 0x10);
|
|
||||||
check_keyslot = KEYSLOT_SWITCH_TEMPKEY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
se_aes_ecb_decrypt_block(check_keyslot, final_vector, 0x10, is_retail ? mkey_vectors[0] : mkey_vectors_dev[0], 0x10);
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
|
||||||
if (final_vector[i] != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mkey_detect_revision(void) {
|
|
||||||
if (g_determined_mkey_revision) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
|
|
||||||
if (check_mkey_revision(rev, configitem_is_retail())) {
|
|
||||||
g_determined_mkey_revision = true;
|
|
||||||
g_mkey_revision = rev;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We must have determined the master key, or we're not running on a Switch. */
|
|
||||||
if (!g_determined_mkey_revision) {
|
|
||||||
/* Panic in bright red. */
|
|
||||||
panic(0x00F00060);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int mkey_get_revision(void) {
|
|
||||||
if (!g_determined_mkey_revision) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_mkey_revision;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int mkey_get_keyslot(unsigned int revision) {
|
|
||||||
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (revision > g_mkey_revision) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (revision == g_mkey_revision) {
|
|
||||||
return KEYSLOT_SWITCH_MASTERKEY;
|
|
||||||
} else {
|
|
||||||
/* Load into a temp keyslot. */
|
|
||||||
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_masterkeys[revision], 0x10);
|
|
||||||
return KEYSLOT_SWITCH_TEMPKEY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_old_devkey(unsigned int revision, const uint8_t *key) {
|
|
||||||
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], key, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int devkey_get_keyslot(unsigned int revision) {
|
|
||||||
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (revision < MASTERKEY_REVISION_400_410) {
|
|
||||||
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
|
|
||||||
} else if (revision < g_mkey_revision) {
|
|
||||||
/* Load into a temp keyslot. */
|
|
||||||
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
|
|
||||||
return KEYSLOT_SWITCH_TEMPKEY;
|
|
||||||
} else {
|
|
||||||
return KEYSLOT_SWITCH_DEVICEKEY;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MASTERKEY_H
|
|
||||||
#define EXOSPHERE_MASTERKEY_H
|
|
||||||
|
|
||||||
/* This is glue code to enable master key support across versions. */
|
|
||||||
|
|
||||||
/* TODO: Update to 0xC on release of new master key. */
|
|
||||||
#define MASTERKEY_REVISION_MAX 0xB
|
|
||||||
|
|
||||||
#define MASTERKEY_REVISION_100_230 0x00
|
|
||||||
#define MASTERKEY_REVISION_300 0x01
|
|
||||||
#define MASTERKEY_REVISION_301_302 0x02
|
|
||||||
#define MASTERKEY_REVISION_400_410 0x03
|
|
||||||
#define MASTERKEY_REVISION_500_510 0x04
|
|
||||||
#define MASTERKEY_REVISION_600_610 0x05
|
|
||||||
#define MASTERKEY_REVISION_620 0x06
|
|
||||||
#define MASTERKEY_REVISION_700_800 0x07
|
|
||||||
#define MASTERKEY_REVISION_810 0x08
|
|
||||||
#define MASTERKEY_REVISION_900 0x09
|
|
||||||
#define MASTERKEY_REVISION_910_CURRENT 0x0A
|
|
||||||
|
|
||||||
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
|
||||||
|
|
||||||
/* This should be called early on in initialization. */
|
|
||||||
void mkey_detect_revision(void);
|
|
||||||
|
|
||||||
unsigned int mkey_get_revision(void);
|
|
||||||
|
|
||||||
unsigned int mkey_get_keyslot(unsigned int revision);
|
|
||||||
|
|
||||||
void set_old_devkey(unsigned int revision, const uint8_t *key);
|
|
||||||
unsigned int devkey_get_keyslot(unsigned int revision);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,162 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "memory_map.h"
|
|
||||||
#include "mc.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t address;
|
|
||||||
uint64_t size;
|
|
||||||
} saved_carveout_info_t;
|
|
||||||
|
|
||||||
static saved_carveout_info_t g_saved_carveouts[2] = {
|
|
||||||
{0x80060000ull, KERNEL_CARVEOUT_SIZE_MAX},
|
|
||||||
{0x00000000ull, 0x00000000ull}
|
|
||||||
};
|
|
||||||
|
|
||||||
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
|
|
||||||
if (CARVEOUT_ID_MIN <= carveout && carveout <= CARVEOUT_ID_MAX) {
|
|
||||||
return (volatile security_carveout_t *)(MC_BASE + 0xC08ull + 0x50 * (carveout - CARVEOUT_ID_MIN));
|
|
||||||
}
|
|
||||||
generic_panic();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_gpu_ucode_carveout(void) {
|
|
||||||
/* Starting in 6.0.0, Carveout 2 is configured later on and adds read permission to TSEC. */
|
|
||||||
/* This is a helper function to make this easier... */
|
|
||||||
volatile security_carveout_t *carveout = get_carveout_by_id(2);
|
|
||||||
carveout->paddr_low = 0x80020000;
|
|
||||||
carveout->paddr_high = 0;
|
|
||||||
carveout->size_big_pages = 2; /* 0x40000 */
|
|
||||||
carveout->client_access_0 = 0;
|
|
||||||
carveout->client_access_1 = 0;
|
|
||||||
carveout->client_access_2 = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) ? (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR) | BIT(CSR_TSECSRD)) : (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR));
|
|
||||||
carveout->client_access_3 = 0;
|
|
||||||
carveout->client_access_4 = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2));
|
|
||||||
carveout->client_force_internal_access_0 = 0;
|
|
||||||
carveout->client_force_internal_access_1 = 0;
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
carveout->config = 0x440167E;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_default_carveouts(void) {
|
|
||||||
/* Configure Carveout 1 (UNUSED) */
|
|
||||||
volatile security_carveout_t *carveout = get_carveout_by_id(1);
|
|
||||||
carveout->paddr_low = 0;
|
|
||||||
carveout->paddr_high = 0;
|
|
||||||
carveout->size_big_pages = 0;
|
|
||||||
carveout->client_access_0 = 0;
|
|
||||||
carveout->client_access_1 = 0;
|
|
||||||
carveout->client_access_2 = 0;
|
|
||||||
carveout->client_access_3 = 0;
|
|
||||||
carveout->client_access_4 = 0;
|
|
||||||
carveout->client_force_internal_access_0 = 0;
|
|
||||||
carveout->client_force_internal_access_1 = 0;
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
carveout->config = 0x4000006;
|
|
||||||
|
|
||||||
/* Configure Carveout 2 (GPU UCODE) */
|
|
||||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
configure_gpu_ucode_carveout();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure Carveout 3 (UNUSED GPU) */
|
|
||||||
carveout = get_carveout_by_id(3);
|
|
||||||
carveout->paddr_low = 0;
|
|
||||||
carveout->paddr_high = 0;
|
|
||||||
carveout->size_big_pages = 0;
|
|
||||||
carveout->client_access_0 = 0;
|
|
||||||
carveout->client_access_1 = 0;
|
|
||||||
carveout->client_access_2 = (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR));
|
|
||||||
carveout->client_access_3 = 0;
|
|
||||||
carveout->client_access_4 = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2));
|
|
||||||
carveout->client_force_internal_access_0 = 0;
|
|
||||||
carveout->client_force_internal_access_1 = 0;
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
carveout->config = 0x4401E7E;
|
|
||||||
|
|
||||||
/* Configure default Kernel carveouts based on 2.0.0+. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
|
|
||||||
/* Configure Carveout 4 (KERNEL_BUILTINS) */
|
|
||||||
configure_kernel_carveout(4, g_saved_carveouts[0].address, g_saved_carveouts[0].size);
|
|
||||||
|
|
||||||
/* Configure Carveout 5 (KERNEL_UNUSED) */
|
|
||||||
configure_kernel_carveout(5, g_saved_carveouts[1].address, g_saved_carveouts[1].size);
|
|
||||||
} else {
|
|
||||||
for (unsigned int i = 4; i <= 5; i++) {
|
|
||||||
carveout = get_carveout_by_id(i);
|
|
||||||
carveout->paddr_low = 0;
|
|
||||||
carveout->paddr_high = 0;
|
|
||||||
carveout->size_big_pages = 0;
|
|
||||||
carveout->client_access_0 = 0;
|
|
||||||
carveout->client_access_1 = 0;
|
|
||||||
carveout->client_access_2 = 0;
|
|
||||||
carveout->client_access_3 = 0;
|
|
||||||
carveout->client_access_4 = 0;
|
|
||||||
carveout->client_force_internal_access_0 = 0;
|
|
||||||
carveout->client_force_internal_access_1 = 0;
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
carveout->config = 0x4000006;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint64_t size) {
|
|
||||||
if (carveout_id != 4 && carveout_id != 5) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
g_saved_carveouts[carveout_id-4].address = address;
|
|
||||||
g_saved_carveouts[carveout_id-4].size = size;
|
|
||||||
|
|
||||||
volatile security_carveout_t *carveout = get_carveout_by_id(carveout_id);
|
|
||||||
carveout->paddr_low = (uint32_t)(address & 0xFFFFFFFF);
|
|
||||||
carveout->paddr_high = (uint32_t)(address >> 32);
|
|
||||||
carveout->size_big_pages = (uint32_t)(size >> 17);
|
|
||||||
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
|
|
||||||
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
|
|
||||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
|
||||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
|
||||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
|
|
||||||
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
|
|
||||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
|
||||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
|
||||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
|
|
||||||
} else {
|
|
||||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW) | BIT(CSR_TSECSRD) | BIT(CSW_TSECSWR));
|
|
||||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
|
||||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
|
|
||||||
}
|
|
||||||
carveout->client_force_internal_access_0 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) && (carveout_id == 4)) ? BIT(CSR_AVPCARM7R) : 0;
|
|
||||||
carveout->client_force_internal_access_1 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) && (carveout_id == 4)) ? BIT(CSW_AVPCARM7W) : 0;
|
|
||||||
carveout->client_force_internal_access_2 = 0;
|
|
||||||
carveout->client_force_internal_access_3 = 0;
|
|
||||||
carveout->client_force_internal_access_4 = 0;
|
|
||||||
carveout->config = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) ? 0x4CB : 0x8B;
|
|
||||||
}
|
|
|
@ -1,631 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MC_H
|
|
||||||
#define EXOSPHERE_MC_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 Memory Controller. */
|
|
||||||
|
|
||||||
static inline uintptr_t get_mc_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MC_BASE (get_mc_base())
|
|
||||||
#define MAKE_MC_REG(n) MAKE_REG32(MC_BASE + n)
|
|
||||||
|
|
||||||
#define MC_INTSTATUS 0x0
|
|
||||||
#define MC_INTMASK 0x4
|
|
||||||
#define MC_ERR_STATUS 0x8
|
|
||||||
#define MC_ERR_ADR 0xc
|
|
||||||
#define MC_SMMU_CONFIG 0x10
|
|
||||||
#define MC_SMMU_TLB_CONFIG 0x14
|
|
||||||
#define MC_SMMU_PTC_CONFIG 0x18
|
|
||||||
#define MC_SMMU_PTB_ASID 0x1c
|
|
||||||
#define MC_SMMU_PTB_DATA 0x20
|
|
||||||
#define MC_SMMU_TLB_FLUSH 0x30
|
|
||||||
#define MC_SMMU_PTC_FLUSH 0x34
|
|
||||||
#define MC_SMMU_ASID_SECURITY 0x38
|
|
||||||
#define MC_SMMU_ASID_SECURITY_1 0x3c
|
|
||||||
#define MC_SMMU_ASID_SECURITY_2 0x9e0
|
|
||||||
#define MC_SMMU_ASID_SECURITY_3 0x9e4
|
|
||||||
#define MC_SMMU_ASID_SECURITY_4 0x9e8
|
|
||||||
#define MC_SMMU_ASID_SECURITY_5 0x9ec
|
|
||||||
#define MC_SMMU_ASID_SECURITY_6 0x9f0
|
|
||||||
#define MC_SMMU_ASID_SECURITY_7 0x9f4
|
|
||||||
#define MC_SMMU_AFI_ASID 0x238
|
|
||||||
#define MC_SMMU_AVPC_ASID 0x23c
|
|
||||||
#define MC_SMMU_PPCS1_ASID 0x298
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
|
|
||||||
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG3 0xddc
|
|
||||||
#define MC_PCFIFO_CLIENT_CONFIG4 0xde0
|
|
||||||
#define MC_EMEM_CFG 0x50
|
|
||||||
#define MC_EMEM_ADR_CFG 0x54
|
|
||||||
#define MC_EMEM_ADR_CFG_DEV0 0x58
|
|
||||||
#define MC_EMEM_ADR_CFG_DEV1 0x5c
|
|
||||||
#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68
|
|
||||||
#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c
|
|
||||||
#define MC_SECURITY_CFG0 0x70
|
|
||||||
#define MC_SECURITY_CFG1 0x74
|
|
||||||
#define MC_SECURITY_CFG3 0x9bc
|
|
||||||
#define MC_SECURITY_RSV 0x7c
|
|
||||||
#define MC_EMEM_ARB_CFG 0x90
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
|
||||||
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
|
||||||
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
|
||||||
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
|
||||||
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
|
||||||
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
|
||||||
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
|
||||||
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
|
||||||
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
|
||||||
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
|
||||||
#define MC_EMEM_ARB_TIMING_W2W 0xbc
|
|
||||||
#define MC_EMEM_ARB_TIMING_R2W 0xc0
|
|
||||||
#define MC_EMEM_ARB_TIMING_W2R 0xc4
|
|
||||||
#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0
|
|
||||||
#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4
|
|
||||||
#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0
|
|
||||||
#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4
|
|
||||||
#define MC_EMEM_ARB_DA_TURNS 0xd0
|
|
||||||
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
|
||||||
#define MC_EMEM_ARB_MISC0 0xd8
|
|
||||||
#define MC_EMEM_ARB_MISC1 0xdc
|
|
||||||
#define MC_EMEM_ARB_MISC2 0xc8
|
|
||||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
|
||||||
#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0
|
|
||||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
|
||||||
#define MC_EMEM_ARB_RSV 0xec
|
|
||||||
#define MC_CLKEN_OVERRIDE 0xf4
|
|
||||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
|
||||||
#define MC_TIMING_CONTROL 0xfc
|
|
||||||
#define MC_STAT_CONTROL 0x100
|
|
||||||
#define MC_STAT_STATUS 0x104
|
|
||||||
#define MC_STAT_EMC_CLOCK_LIMIT 0x108
|
|
||||||
#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c
|
|
||||||
#define MC_STAT_EMC_CLOCKS 0x110
|
|
||||||
#define MC_STAT_EMC_CLOCKS_MSBS 0x114
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134
|
|
||||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174
|
|
||||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c
|
|
||||||
#define MC_STAT_EMC_SET0_COUNT 0x138
|
|
||||||
#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c
|
|
||||||
#define MC_STAT_EMC_SET1_COUNT 0x178
|
|
||||||
#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c
|
|
||||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140
|
|
||||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144
|
|
||||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180
|
|
||||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184
|
|
||||||
#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148
|
|
||||||
#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c
|
|
||||||
#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188
|
|
||||||
#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c
|
|
||||||
#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150
|
|
||||||
#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc
|
|
||||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0
|
|
||||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0
|
|
||||||
#define MC_CLIENT_HOTRESET_CTRL 0x200
|
|
||||||
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
|
|
||||||
#define MC_CLIENT_HOTRESET_STATUS 0x204
|
|
||||||
#define MC_CLIENT_HOTRESET_STATUS_1 0x974
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214
|
|
||||||
#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_0 0x218
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_1 0x21c
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_2 0x220
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_3 0x224
|
|
||||||
#define MC_EMEM_ARB_HYSTERESIS_4 0xb84
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc
|
|
||||||
#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0
|
|
||||||
#define MC_EMEM_ARB_DHYST_CTRL 0xbcc
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8
|
|
||||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec
|
|
||||||
#define MC_RESERVED_RSV 0x3fc
|
|
||||||
#define MC_DISB_EXTRA_SNAP_LEVELS 0x408
|
|
||||||
#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4
|
|
||||||
#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0
|
|
||||||
#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18
|
|
||||||
#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08
|
|
||||||
#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10
|
|
||||||
#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c
|
|
||||||
#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40
|
|
||||||
#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414
|
|
||||||
#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc
|
|
||||||
#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c
|
|
||||||
#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14
|
|
||||||
#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0
|
|
||||||
#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac
|
|
||||||
#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c
|
|
||||||
#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48
|
|
||||||
#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8
|
|
||||||
#define MC_USBX_EXTRA_SNAP_LEVELS 0x404
|
|
||||||
#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8
|
|
||||||
#define MC_SD_EXTRA_SNAP_LEVELS 0xa04
|
|
||||||
#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c
|
|
||||||
#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8
|
|
||||||
#define MC_GK_EXTRA_SNAP_LEVELS 0xa00
|
|
||||||
#define MC_VE2_EXTRA_SNAP_LEVELS 0x410
|
|
||||||
#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44
|
|
||||||
#define MC_VIDEO_PROTECT_BOM 0x648
|
|
||||||
#define MC_VIDEO_PROTECT_SIZE_MB 0x64c
|
|
||||||
#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978
|
|
||||||
#define MC_VIDEO_PROTECT_REG_CTRL 0x650
|
|
||||||
#define MC_ERR_VPR_STATUS 0x654
|
|
||||||
#define MC_ERR_VPR_ADR 0x658
|
|
||||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418
|
|
||||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590
|
|
||||||
#define MC_IRAM_BOM 0x65c
|
|
||||||
#define MC_IRAM_TOM 0x660
|
|
||||||
#define MC_IRAM_ADR_HI 0x980
|
|
||||||
#define MC_IRAM_REG_CTRL 0x964
|
|
||||||
#define MC_EMEM_CFG_ACCESS_CTRL 0x664
|
|
||||||
#define MC_TZ_SECURITY_CTRL 0x668
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c
|
|
||||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4
|
|
||||||
#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8
|
|
||||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80
|
|
||||||
#define MC_SEC_CARVEOUT_BOM 0x670
|
|
||||||
#define MC_SEC_CARVEOUT_SIZE_MB 0x674
|
|
||||||
#define MC_SEC_CARVEOUT_ADR_HI 0x9d4
|
|
||||||
#define MC_SEC_CARVEOUT_REG_CTRL 0x678
|
|
||||||
#define MC_ERR_SEC_STATUS 0x67c
|
|
||||||
#define MC_ERR_SEC_ADR 0x680
|
|
||||||
#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684
|
|
||||||
#define MC_STUTTER_CONTROL 0x688
|
|
||||||
#define MC_RESERVED_RSV_1 0x958
|
|
||||||
#define MC_DVFS_PIPE_SELECT 0x95c
|
|
||||||
#define MC_AHB_PTSA_MIN 0x4e0
|
|
||||||
#define MC_AUD_PTSA_MIN 0x54c
|
|
||||||
#define MC_MLL_MPCORER_PTSA_RATE 0x44c
|
|
||||||
#define MC_RING2_PTSA_RATE 0x440
|
|
||||||
#define MC_USBD_PTSA_RATE 0x530
|
|
||||||
#define MC_USBX_PTSA_MIN 0x528
|
|
||||||
#define MC_USBD_PTSA_MIN 0x534
|
|
||||||
#define MC_APB_PTSA_MAX 0x4f0
|
|
||||||
#define MC_JPG_PTSA_RATE 0x584
|
|
||||||
#define MC_DIS_PTSA_MIN 0x420
|
|
||||||
#define MC_AVP_PTSA_MAX 0x4fc
|
|
||||||
#define MC_AVP_PTSA_RATE 0x4f4
|
|
||||||
#define MC_RING1_PTSA_MIN 0x480
|
|
||||||
#define MC_DIS_PTSA_MAX 0x424
|
|
||||||
#define MC_SD_PTSA_MAX 0x4d8
|
|
||||||
#define MC_MSE_PTSA_RATE 0x4c4
|
|
||||||
#define MC_VICPC_PTSA_MIN 0x558
|
|
||||||
#define MC_PCX_PTSA_MAX 0x4b4
|
|
||||||
#define MC_ISP_PTSA_RATE 0x4a0
|
|
||||||
#define MC_A9AVPPC_PTSA_MIN 0x48c
|
|
||||||
#define MC_RING2_PTSA_MAX 0x448
|
|
||||||
#define MC_AUD_PTSA_RATE 0x548
|
|
||||||
#define MC_HOST_PTSA_MIN 0x51c
|
|
||||||
#define MC_MLL_MPCORER_PTSA_MAX 0x454
|
|
||||||
#define MC_SD_PTSA_MIN 0x4d4
|
|
||||||
#define MC_RING1_PTSA_RATE 0x47c
|
|
||||||
#define MC_JPG_PTSA_MIN 0x588
|
|
||||||
#define MC_HDAPC_PTSA_MIN 0x62c
|
|
||||||
#define MC_AVP_PTSA_MIN 0x4f8
|
|
||||||
#define MC_JPG_PTSA_MAX 0x58c
|
|
||||||
#define MC_VE_PTSA_MAX 0x43c
|
|
||||||
#define MC_DFD_PTSA_MAX 0x63c
|
|
||||||
#define MC_VICPC_PTSA_RATE 0x554
|
|
||||||
#define MC_GK_PTSA_MAX 0x544
|
|
||||||
#define MC_VICPC_PTSA_MAX 0x55c
|
|
||||||
#define MC_SDM_PTSA_MAX 0x624
|
|
||||||
#define MC_SAX_PTSA_RATE 0x4b8
|
|
||||||
#define MC_PCX_PTSA_MIN 0x4b0
|
|
||||||
#define MC_APB_PTSA_MIN 0x4ec
|
|
||||||
#define MC_GK2_PTSA_MIN 0x614
|
|
||||||
#define MC_PCX_PTSA_RATE 0x4ac
|
|
||||||
#define MC_RING1_PTSA_MAX 0x484
|
|
||||||
#define MC_HDAPC_PTSA_RATE 0x628
|
|
||||||
#define MC_MLL_MPCORER_PTSA_MIN 0x450
|
|
||||||
#define MC_GK2_PTSA_MAX 0x618
|
|
||||||
#define MC_AUD_PTSA_MAX 0x550
|
|
||||||
#define MC_GK2_PTSA_RATE 0x610
|
|
||||||
#define MC_ISP_PTSA_MAX 0x4a8
|
|
||||||
#define MC_DISB_PTSA_RATE 0x428
|
|
||||||
#define MC_VE2_PTSA_MAX 0x49c
|
|
||||||
#define MC_DFD_PTSA_MIN 0x638
|
|
||||||
#define MC_FTOP_PTSA_RATE 0x50c
|
|
||||||
#define MC_A9AVPPC_PTSA_RATE 0x488
|
|
||||||
#define MC_VE2_PTSA_MIN 0x498
|
|
||||||
#define MC_USBX_PTSA_MAX 0x52c
|
|
||||||
#define MC_DIS_PTSA_RATE 0x41c
|
|
||||||
#define MC_USBD_PTSA_MAX 0x538
|
|
||||||
#define MC_A9AVPPC_PTSA_MAX 0x490
|
|
||||||
#define MC_USBX_PTSA_RATE 0x524
|
|
||||||
#define MC_FTOP_PTSA_MAX 0x514
|
|
||||||
#define MC_HDAPC_PTSA_MAX 0x630
|
|
||||||
#define MC_SD_PTSA_RATE 0x4d0
|
|
||||||
#define MC_DFD_PTSA_RATE 0x634
|
|
||||||
#define MC_FTOP_PTSA_MIN 0x510
|
|
||||||
#define MC_SDM_PTSA_RATE 0x61c
|
|
||||||
#define MC_AHB_PTSA_RATE 0x4dc
|
|
||||||
#define MC_SMMU_SMMU_PTSA_MAX 0x460
|
|
||||||
#define MC_RING2_PTSA_MIN 0x444
|
|
||||||
#define MC_SDM_PTSA_MIN 0x620
|
|
||||||
#define MC_APB_PTSA_RATE 0x4e8
|
|
||||||
#define MC_MSE_PTSA_MIN 0x4c8
|
|
||||||
#define MC_HOST_PTSA_RATE 0x518
|
|
||||||
#define MC_VE_PTSA_RATE 0x434
|
|
||||||
#define MC_AHB_PTSA_MAX 0x4e4
|
|
||||||
#define MC_SAX_PTSA_MIN 0x4bc
|
|
||||||
#define MC_SMMU_SMMU_PTSA_MIN 0x45c
|
|
||||||
#define MC_ISP_PTSA_MIN 0x4a4
|
|
||||||
#define MC_HOST_PTSA_MAX 0x520
|
|
||||||
#define MC_SAX_PTSA_MAX 0x4c0
|
|
||||||
#define MC_VE_PTSA_MIN 0x438
|
|
||||||
#define MC_GK_PTSA_MIN 0x540
|
|
||||||
#define MC_MSE_PTSA_MAX 0x4cc
|
|
||||||
#define MC_DISB_PTSA_MAX 0x430
|
|
||||||
#define MC_DISB_PTSA_MIN 0x42c
|
|
||||||
#define MC_SMMU_SMMU_PTSA_RATE 0x458
|
|
||||||
#define MC_VE2_PTSA_RATE 0x494
|
|
||||||
#define MC_GK_PTSA_RATE 0x53c
|
|
||||||
#define MC_PTSA_GRANT_DECREMENT 0x960
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc
|
|
||||||
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
|
|
||||||
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
|
|
||||||
#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec
|
|
||||||
#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec
|
|
||||||
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
|
|
||||||
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SATA_0 0x350
|
|
||||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
|
|
||||||
#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8
|
|
||||||
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac
|
|
||||||
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4
|
|
||||||
#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388
|
|
||||||
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
|
|
||||||
#define MC_LATENCY_ALLOWANCE_HDA_0 0x318
|
|
||||||
#define MC_MIN_LENGTH_APE_0 0xb34
|
|
||||||
#define MC_MIN_LENGTH_DCB_2 0x8a8
|
|
||||||
#define MC_MIN_LENGTH_A9AVP_0 0x950
|
|
||||||
#define MC_MIN_LENGTH_TSEC_0 0x93c
|
|
||||||
#define MC_MIN_LENGTH_DC_1 0x898
|
|
||||||
#define MC_MIN_LENGTH_AXIAP_0 0x94c
|
|
||||||
#define MC_MIN_LENGTH_ISP2B_0 0x930
|
|
||||||
#define MC_MIN_LENGTH_VI2_0 0x944
|
|
||||||
#define MC_MIN_LENGTH_DCB_0 0x8a0
|
|
||||||
#define MC_MIN_LENGTH_DCB_1 0x8a4
|
|
||||||
#define MC_MIN_LENGTH_PPCS_1 0x8f4
|
|
||||||
#define MC_MIN_LENGTH_NVJPG_0 0xb3c
|
|
||||||
#define MC_MIN_LENGTH_HDA_0 0x8c4
|
|
||||||
#define MC_MIN_LENGTH_NVENC_0 0x8d4
|
|
||||||
#define MC_MIN_LENGTH_SDMMC_0 0xb18
|
|
||||||
#define MC_MIN_LENGTH_ISP2B_1 0x934
|
|
||||||
#define MC_MIN_LENGTH_HC_1 0x8c0
|
|
||||||
#define MC_MIN_LENGTH_DC_3 0xb20
|
|
||||||
#define MC_MIN_LENGTH_AVPC_0 0x890
|
|
||||||
#define MC_MIN_LENGTH_VIC_0 0x940
|
|
||||||
#define MC_MIN_LENGTH_ISP2_0 0x91c
|
|
||||||
#define MC_MIN_LENGTH_HC_0 0x8bc
|
|
||||||
#define MC_MIN_LENGTH_SE_0 0xb38
|
|
||||||
#define MC_MIN_LENGTH_NVDEC_0 0xb30
|
|
||||||
#define MC_MIN_LENGTH_SATA_0 0x8fc
|
|
||||||
#define MC_MIN_LENGTH_DC_0 0x894
|
|
||||||
#define MC_MIN_LENGTH_XUSB_1 0x92c
|
|
||||||
#define MC_MIN_LENGTH_DC_2 0x89c
|
|
||||||
#define MC_MIN_LENGTH_SDMMCAA_0 0xb14
|
|
||||||
#define MC_MIN_LENGTH_GPU_0 0xb04
|
|
||||||
#define MC_MIN_LENGTH_ETR_0 0xb44
|
|
||||||
#define MC_MIN_LENGTH_AFI_0 0x88c
|
|
||||||
#define MC_MIN_LENGTH_PPCS_0 0x8f0
|
|
||||||
#define MC_MIN_LENGTH_ISP2_1 0x920
|
|
||||||
#define MC_MIN_LENGTH_XUSB_0 0x928
|
|
||||||
#define MC_MIN_LENGTH_MPCORE_0 0x8cc
|
|
||||||
#define MC_MIN_LENGTH_TSECB_0 0xb48
|
|
||||||
#define MC_MIN_LENGTH_SDMMCA_0 0xb10
|
|
||||||
#define MC_MIN_LENGTH_GPU2_0 0xb40
|
|
||||||
#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c
|
|
||||||
#define MC_MIN_LENGTH_PTC_0 0x8f8
|
|
||||||
#define MC_EMEM_ARB_OVERRIDE_1 0x968
|
|
||||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984
|
|
||||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988
|
|
||||||
#define MC_EMEM_ARB_STATS_0 0x990
|
|
||||||
#define MC_EMEM_ARB_STATS_1 0x994
|
|
||||||
#define MC_MTS_CARVEOUT_BOM 0x9a0
|
|
||||||
#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4
|
|
||||||
#define MC_MTS_CARVEOUT_ADR_HI 0x9a8
|
|
||||||
#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac
|
|
||||||
#define MC_ERR_MTS_STATUS 0x9b0
|
|
||||||
#define MC_ERR_MTS_ADR 0x9b4
|
|
||||||
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
|
|
||||||
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10
|
|
||||||
#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CFG0 0xc58
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CFG0 0xc08
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68
|
|
||||||
#define MC_SECURITY_CARVEOUT3_BOM 0xcac
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CFG0 0xca8
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88
|
|
||||||
#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64
|
|
||||||
#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50
|
|
||||||
#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14
|
|
||||||
#define MC_SECURITY_CARVEOUT1_BOM 0xc0c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8
|
|
||||||
#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60
|
|
||||||
#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80
|
|
||||||
#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc
|
|
||||||
#define MC_SECURITY_CARVEOUT4_BOM 0xcfc
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CFG0 0xd48
|
|
||||||
#define MC_SECURITY_CARVEOUT2_BOM 0xc5c
|
|
||||||
#define MC_SECURITY_CARVEOUT5_BOM 0xd4c
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24
|
|
||||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c
|
|
||||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0
|
|
||||||
#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20
|
|
||||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c
|
|
||||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c
|
|
||||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08
|
|
||||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
|
||||||
#define MC_DA_CONFIG0 0x9dc
|
|
||||||
|
|
||||||
/* Virtual aliases */
|
|
||||||
#define VIRT_MC_SECURITY_CFG3 MAKE_MC_REG(MC_SECURITY_CFG3)
|
|
||||||
|
|
||||||
/* Memory Controller clients */
|
|
||||||
#define CLIENT_ACCESS_NUM_CLIENTS 32
|
|
||||||
typedef enum {
|
|
||||||
/* _ACCESS0 */
|
|
||||||
CSR_PTCR = (0 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0A = (1 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0AB = (2 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0B = (3 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0BB = (4 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0C = (5 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAY0CB = (6 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_AFIR = (14 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_AVPCARM7R = (15 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAYHC = (16 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_DISPLAYHCB = (17 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HDAR = (21 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HOST1XDMAR = (22 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_HOST1XR = (23 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_NVENCSRD = (28 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_PPCSAHBDMAR = (29 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_PPCSAHBSLVR = (30 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
CSR_SATAR = (31 - (CLIENT_ACCESS_NUM_CLIENTS * 0)),
|
|
||||||
|
|
||||||
/* _ACCESS1 */
|
|
||||||
CSR_VDEBSEVR = (34 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDEMBER = (35 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDEMCER = (36 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_VDETPER = (37 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_MPCORELPR = (38 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSR_MPCORER = (39 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_NVENCSWR = (43 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_AFIW = (49 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_AVPCARM7W = (50 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_HDAW = (53 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_HOST1XW = (54 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_MPCORELPW = (56 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_MPCOREW = (57 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_PPCSAHBDMAW = (59 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_PPCSAHBSLVW = (60 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_SATAW = (61 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_VDEBSEVW = (62 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
CSW_VDEDBGW = (63 - (CLIENT_ACCESS_NUM_CLIENTS * 1)),
|
|
||||||
|
|
||||||
/* _ACCESS2 */
|
|
||||||
CSW_VDEMBEW = (64 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_VDETPMW = (65 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_ISPRA = (68 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWA = (70 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWB = (71 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_XUSB_HOSTR = (74 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_XUSB_HOSTW = (75 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_XUSB_DEVR = (76 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_XUSB_DEVW = (77 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_ISPRAB = (78 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWAB = (80 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_ISPWBB = (81 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_TSECSRD = (84 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_TSECSWR = (85 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_A9AVPSCR = (86 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_A9AVPSCW = (87 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_GPUSRD = (88 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSW_GPUSWR = (89 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
CSR_DISPLAYT = (90 - (CLIENT_ACCESS_NUM_CLIENTS * 2)),
|
|
||||||
|
|
||||||
/* _ACCESS3 */
|
|
||||||
CSR_SDMMCRA = (96 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCRAA = (97 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCR = (98 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_SDMMCRAB = (99 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWA = (100 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWAA = (101 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCW = (102 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_SDMMCWAB = (103 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_VICSRD = (108 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_VICSWR = (109 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_VIW = (114 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_DISPLAYD = (115 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_NVDECSRD = (120 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_NVDECSWR = (121 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_APER = (122 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_APEW = (123 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSR_NVJPGSRD = (126 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
CSW_NVJPGSWR = (127 - (CLIENT_ACCESS_NUM_CLIENTS * 3)),
|
|
||||||
|
|
||||||
/* _ACCESS4 */
|
|
||||||
CSR_SESRD = (128 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_SESWR = (129 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_AXIAPR = (130 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_AXIAPW = (131 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_ETRR = (132 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_ETRW = (133 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_TSECSRDB = (134 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_TSECSWRB = (135 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSR_GPUSRD2 = (136 - (CLIENT_ACCESS_NUM_CLIENTS * 4)),
|
|
||||||
CSW_GPUSWR2 = (137 - (CLIENT_ACCESS_NUM_CLIENTS * 4))
|
|
||||||
} McClient;
|
|
||||||
|
|
||||||
/* Memory Controller carveouts */
|
|
||||||
#define CARVEOUT_ID_MIN 1
|
|
||||||
#define CARVEOUT_ID_MAX 5
|
|
||||||
#define KERNEL_CARVEOUT_SIZE_MAX 0x1FFE0000
|
|
||||||
typedef struct {
|
|
||||||
uint32_t config;
|
|
||||||
uint32_t paddr_low;
|
|
||||||
uint32_t paddr_high;
|
|
||||||
uint32_t size_big_pages;
|
|
||||||
uint32_t client_access_0;
|
|
||||||
uint32_t client_access_1;
|
|
||||||
uint32_t client_access_2;
|
|
||||||
uint32_t client_access_3;
|
|
||||||
uint32_t client_access_4;
|
|
||||||
uint32_t client_force_internal_access_0;
|
|
||||||
uint32_t client_force_internal_access_1;
|
|
||||||
uint32_t client_force_internal_access_2;
|
|
||||||
uint32_t client_force_internal_access_3;
|
|
||||||
uint32_t client_force_internal_access_4;
|
|
||||||
uint8_t padding[0x18];
|
|
||||||
} security_carveout_t;
|
|
||||||
|
|
||||||
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout);
|
|
||||||
void configure_default_carveouts(void);
|
|
||||||
void configure_gpu_ucode_carveout(void);
|
|
||||||
void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint64_t size);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MC0_H
|
|
||||||
#define EXOSPHERE_MC0_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 MC0. */
|
|
||||||
|
|
||||||
static inline uintptr_t get_mc0_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MC0_BASE (get_mc0_base())
|
|
||||||
#define MAKE_MC0_REG(n) MAKE_REG32(MC0_BASE + n)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MC0_H
|
|
||||||
#define EXOSPHERE_MC0_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 MC1. */
|
|
||||||
|
|
||||||
static inline uintptr_t get_mc1_base(void) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MC1_BASE (get_mc1_base())
|
|
||||||
#define MAKE_MC1_REG(n) MAKE_REG32(MC1_BASE + n)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,234 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MEMORY_MAP_H
|
|
||||||
#define EXOSPHERE_MEMORY_MAP_H
|
|
||||||
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "preprocessor.h"
|
|
||||||
|
|
||||||
#define ATTRIB_MEMTYPE_NORMAL MMU_PTE_BLOCK_MEMTYPE(MMU_MT_NORMAL)
|
|
||||||
#define ATTRIB_MEMTYPE_DEVICE MMU_PTE_BLOCK_MEMTYPE(MMU_MT_DEVICE_NGNRE)
|
|
||||||
|
|
||||||
/* Identity mappings (addr, size, additional attributes, is block range) */
|
|
||||||
#define _MMAPID0 ( 0x40006000ull, 0x01000ull, 0ull, false ) /* Part of iRAM-A, where our coldboot crt0 is */
|
|
||||||
#define _MMAPID1 ( 0x40020000ull, 0x20000ull, 0ull, false ) /* iRAM-C+D */
|
|
||||||
#define _MMAPID2 ( 0x7C010000ull, 0x10000ull, 0ull, false ) /* TZRAM (contains the secmon's warmboot crt0) */
|
|
||||||
#define _MMAPID3 ( 0x80000000ull, 4ull << 30, MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_NS, true ) /* DRAM (4GB) */
|
|
||||||
|
|
||||||
/* MMIO (addr, size, is secure) */
|
|
||||||
#define _MMAPDEV0 ( 0x50041000ull, 0x1000ull, true ) /* ARM Interrupt Distributor */
|
|
||||||
#define _MMAPDEV1 ( 0x50042000ull, 0x2000ull, true ) /* Interrupt Controller Physical CPU interface */
|
|
||||||
#define _MMAPDEV2 ( 0x70006000ull, 0x1000ull, false ) /* UART */
|
|
||||||
#define _MMAPDEV3 ( 0x60006000ull, 0x1000ull, false ) /* Clock and Reset */
|
|
||||||
#define _MMAPDEV4 ( 0x7000E000ull, 0x1000ull, true ) /* RTC, PMC */
|
|
||||||
#define _MMAPDEV5 ( 0x60005000ull, 0x1000ull, true ) /* TMRs, WDTs */
|
|
||||||
#define _MMAPDEV6 ( 0x6000C000ull, 0x1000ull, true ) /* System Registers */
|
|
||||||
#define _MMAPDEV7 ( 0x70012000ull, 0x2000ull, true ) /* SE */
|
|
||||||
#define _MMAPDEV8 ( 0x700F0000ull, 0x1000ull, true ) /* SYSCTR0 */
|
|
||||||
#define _MMAPDEV9 ( 0x70019000ull, 0x1000ull, true ) /* MC */
|
|
||||||
#define _MMAPDEV10 ( 0x7000F000ull, 0x1000ull, true ) /* FUSE (0x7000F800) */
|
|
||||||
#define _MMAPDEV11 ( 0x70000000ull, 0x4000ull, true ) /* MISC */
|
|
||||||
#define _MMAPDEV12 ( 0x60007000ull, 0x1000ull, true ) /* Flow Controller */
|
|
||||||
#define _MMAPDEV13 ( 0x40002000ull, 0x1000ull, true ) /* NX bootloader mailbox page */
|
|
||||||
#define _MMAPDEV14 ( 0x7000D000ull, 0x1000ull, true ) /* I2C-5,6 - SPI 2B-1 to 4 */
|
|
||||||
#define _MMAPDEV15 ( 0x6000D000ull, 0x1000ull, true ) /* GPIO-1 - GPIO-8 */
|
|
||||||
#define _MMAPDEV16 ( 0x7000C000ull, 0x1000ull, true ) /* I2C-I2C4 */
|
|
||||||
#define _MMAPDEV17 ( 0x6000F000ull, 0x1000ull, true ) /* Exception vectors */
|
|
||||||
#define _MMAPDEV18 ( 0x7001C000ull, 0x1000ull, true ) /* MC0 */
|
|
||||||
#define _MMAPDEV19 ( 0x7001D000ull, 0x1000ull, true ) /* MC1 */
|
|
||||||
#define _MMAPDEV20 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */
|
|
||||||
#define _MMAPDEV21 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */
|
|
||||||
#define _MMAPDEV22 ( 0x40038000ull, 0x1000ull, true ) /* DEBUG: IRAM */
|
|
||||||
|
|
||||||
/* MMIO 7.0.0+. (addr). */
|
|
||||||
#define _MMAPDEV7X0 ( 0x50041000ull ) /* ARM Interrupt Distributor */
|
|
||||||
#define _MMAPDEV7X1 ( 0x50042000ull ) /* Interrupt Controller Physical CPU interface */
|
|
||||||
#define _MMAPDEV7X2 ( 0x70006000ull ) /* UART */
|
|
||||||
#define _MMAPDEV7X3 ( 0x60006000ull ) /* Clock and Reset */
|
|
||||||
#define _MMAPDEV7X4 ( 0x7000E000ull ) /* RTC, PMC */
|
|
||||||
#define _MMAPDEV7X5 ( 0x60005000ull ) /* TMRs, WDTs */
|
|
||||||
#define _MMAPDEV7X6 ( 0x6000C000ull ) /* System Registers */
|
|
||||||
#define _MMAPDEV7X7 ( 0x70012000ull ) /* SE */
|
|
||||||
#define _MMAPDEV7X8 ( 0x700F0000ull ) /* SYSCTR0 */
|
|
||||||
#define _MMAPDEV7X9 ( 0x70019000ull ) /* MC */
|
|
||||||
#define _MMAPDEV7X10 ( 0x7000F000ull ) /* FUSE (0x7000F800) */
|
|
||||||
#define _MMAPDEV7X11 ( 0x70000000ull ) /* MISC */
|
|
||||||
#define _MMAPDEV7X12 ( 0x60007000ull ) /* Flow Controller */
|
|
||||||
#define _MMAPDEV7X13 ( 0x40000000ull ) /* NX bootloader mailbox page */
|
|
||||||
#define _MMAPDEV7X14 ( 0x7000D000ull ) /* I2C-5,6 - SPI 2B-1 to 4 */
|
|
||||||
#define _MMAPDEV7X15 ( 0x6000D000ull ) /* GPIO-1 - GPIO-8 */
|
|
||||||
#define _MMAPDEV7X16 ( 0x7000C000ull ) /* I2C-I2C4 */
|
|
||||||
#define _MMAPDEV7X17 ( 0x6000F000ull ) /* Exception vectors */
|
|
||||||
#define _MMAPDEV7X18 ( 0x7001C000ull ) /* MC0 */
|
|
||||||
#define _MMAPDEV7X19 ( 0x7001D000ull ) /* MC1 */
|
|
||||||
#define _MMAPDEV7X20 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */
|
|
||||||
#define _MMAPDEV7X21 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */
|
|
||||||
#define _MMAPDEV7X22 ( 0x40038000ull ) /* DEBUG: IRAM */
|
|
||||||
|
|
||||||
/* LP0 entry ram segments (addr, size, additional attributes) */
|
|
||||||
#define _MMAPLP0ES0 ( 0x40020000ull, 0x10000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted TZRAM */
|
|
||||||
#define _MMAPLP0ES1 ( 0x40003000ull, 0x01000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* LP0 entry code */
|
|
||||||
#define _MMAPLP0ES2 ( 0x7C010000ull, 0x10000ull, MMU_AP_PRIV_RO | ATTRIB_MEMTYPE_NORMAL ) /* TZRAM to encrypt */
|
|
||||||
|
|
||||||
/* Warmboot data ram segments (addr, size, additional attributes) */
|
|
||||||
#define _MMAPWBS0 ( 0x8000F000ull, 0x01000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted SE state for bootROM */
|
|
||||||
#define _MMAPWBS1 ( 0x80010000ull, 0x10000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted TZRAM for warmboot.bin */
|
|
||||||
|
|
||||||
/* TZRAM segments (offset, size, VA increment, is executable) */
|
|
||||||
#define _MMAPTZS0 ( 0x3000ull, 0x10000 - 0x2000 - 0x3000ull, 0x10000ull, true ) /* Warmboot crt0 sections and main code segment */
|
|
||||||
#define _MMAPTZS1 ( 0x10000 - 0x2000ull, 0x2000ull, 0x04000ull, true ) /* pk2ldr segment */
|
|
||||||
#define _MMAPTZS2 ( 0ull, 0ull, 0x02000ull, false ) /* SPL .bss buffer, NOT mapped at startup */
|
|
||||||
#define _MMAPTZS3 ( 0x10000 - 0x2000ull, 0x1000ull, 0x02000ull, false ) /* Core 0ull1,2 stack */
|
|
||||||
#define _MMAPTZS4 ( 0x10000 - 0x1000ull, 0x1000ull, 0x02000ull, false ) /* Core 3 stack */
|
|
||||||
#define _MMAPTZS5 ( 0ull, 0x1000ull, 0x02000ull, true ) /* Secure Monitor exception vectors, some init stacks */
|
|
||||||
#define _MMAPTZS6 ( 0x1000ull, 0x1000ull, 0x02000ull, false ) /* L2 translation table */
|
|
||||||
#define _MMAPTZS7 ( 0x2000ull, 0x1000ull, 0x02000ull, false ) /* L3 translation table */
|
|
||||||
|
|
||||||
/* TZRAM segments for 5.0.0+. (offset). */
|
|
||||||
#define _MMAPTZ5XS0 ( 0x3000ull ) /* Warmboot crt0 sections and main code segment */
|
|
||||||
#define _MMAPTZ5XS1 ( 0ull ) /* pk2ldr segment */
|
|
||||||
#define _MMAPTZ5XS2 ( 0ull ) /* SPL .bss buffer, NOT mapped at startup */
|
|
||||||
#define _MMAPTZ5XS3 ( 0ull ) /* Core 0ull1,2 stack */
|
|
||||||
#define _MMAPTZ5XS4 ( 0x1000ull ) /* Core 3 stack */
|
|
||||||
#define _MMAPTZ5XS5 ( 0x2000ull ) /* Secure Monitor exception vectors, some init stacks */
|
|
||||||
#define _MMAPTZ5XS6 ( 0x10000 - 0x2000ull ) /* L2 translation table */
|
|
||||||
#define _MMAPTZ5XS7 ( 0x10000 - 0x1000ull ) /* L3 translation table */
|
|
||||||
|
|
||||||
#define MMIO_BASE 0x1F0080000ull
|
|
||||||
#define LP0_ENTRY_RAM_SEGMENT_BASE (MMIO_BASE + 0x000100000ull)
|
|
||||||
#define WARMBOOT_RAM_SEGMENT_BASE (LP0_ENTRY_RAM_SEGMENT_BASE + 0x000047000ull) /* increment seems to be arbitrary ? */
|
|
||||||
#define TZRAM_SEGMENT_BASE (MMIO_BASE + 0x000160000ull)
|
|
||||||
|
|
||||||
#define IDENTITY_MAPPING_IRAM_A_CCRT0 0
|
|
||||||
#define IDENTITY_MAPPING_IRAM_CD 1
|
|
||||||
#define IDENTITY_MAPPING_TZRAM 2
|
|
||||||
#define IDENTITY_MAPPING_DRAM 3
|
|
||||||
#define IDENTIY_MAPPING_ID_MAX 4
|
|
||||||
|
|
||||||
#define MMIO_DEVID_GICD 0
|
|
||||||
#define MMIO_DEVID_GICC 1
|
|
||||||
#define MMIO_DEVID_UART 2
|
|
||||||
#define MMIO_DEVID_CLKRST 3
|
|
||||||
#define MMIO_DEVID_RTC_PMC 4
|
|
||||||
#define MMIO_DEVID_TMRs_WDTs 5
|
|
||||||
#define MMIO_DEVID_SYSREGS 6
|
|
||||||
#define MMIO_DEVID_SE 7
|
|
||||||
#define MMIO_DEVID_SYSCTR0 8
|
|
||||||
#define MMIO_DEVID_MC 9
|
|
||||||
#define MMIO_DEVID_FUSE 10
|
|
||||||
#define MMIO_DEVID_MISC 11
|
|
||||||
#define MMIO_DEVID_FLOWCTRL 12
|
|
||||||
#define MMIO_DEVID_NXBOOTLOADER_MAILBOX 13
|
|
||||||
#define MMIO_DEVID_I2C56_SPI2B 14
|
|
||||||
#define MMIO_DEVID_GPIO 15
|
|
||||||
#define MMIO_DEVID_DTV_I2C234 16
|
|
||||||
#define MMIO_DEVID_EXCEPTION_VECTORS 17
|
|
||||||
#define MMIO_DEVID_MC0 18
|
|
||||||
#define MMIO_DEVID_MC1 19
|
|
||||||
#define MMIO_DEVID_AMS_IRAM_PAGE 20
|
|
||||||
#define MMIO_DEVID_AMS_USER_PAGE 21
|
|
||||||
#define MMIO_DEVID_DEBUG_IRAM 22
|
|
||||||
#define MMIO_DEVID_MAX 23
|
|
||||||
|
|
||||||
#define LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM 0
|
|
||||||
#define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1
|
|
||||||
#define LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM 2
|
|
||||||
#define LP0_ENTRY_RAM_SEGMENT_ID_MAX 3
|
|
||||||
|
|
||||||
#define WARMBOOT_RAM_SEGMENT_ID_SE_STATE 0
|
|
||||||
#define WARMBOOT_RAM_SEGMENT_ID_TZRAM 1
|
|
||||||
#define WARMBOOT_RAM_SEGMENT_ID_MAX 2
|
|
||||||
|
|
||||||
#define TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN 0
|
|
||||||
#define TZRAM_SEGMENT_ID_PK2LDR 1
|
|
||||||
#define TZRAM_SEGMENT_ID_USERPAGE 2
|
|
||||||
#define TZRAM_SEGMENT_ID_CORE012_STACK 3
|
|
||||||
#define TZRAM_SEGMENT_ID_CORE3_STACK 4
|
|
||||||
#define TZRAM_SEGEMENT_ID_SECMON_EVT 5
|
|
||||||
#define TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE 6
|
|
||||||
#define TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE 7
|
|
||||||
#define TZRAM_SEGMENT_ID_MAX 8
|
|
||||||
|
|
||||||
#define IDENTITY_GET_MAPPING_ADDRESS(mapping_id) (TUPLE_ELEM_0(CAT(_MMAPID, EVAL(mapping_id))))
|
|
||||||
#define IDENTITY_GET_MAPPING_SIZE(mapping_id) (TUPLE_ELEM_1(CAT(_MMAPID, EVAL(mapping_id))))
|
|
||||||
#define IDENTITY_GET_MAPPING_ATTRIBS(mapping_id) (TUPLE_ELEM_2(CAT(_MMAPID, EVAL(mapping_id))))
|
|
||||||
#define IDENTITY_IS_MAPPING_BLOCK_RANGE(mapping_id) (TUPLE_ELEM_3(CAT(_MMAPID, EVAL(mapping_id))))
|
|
||||||
|
|
||||||
#define MMIO_GET_DEVICE_PA(device_id) (TUPLE_ELEM_0(CAT(_MMAPDEV, EVAL(device_id))))
|
|
||||||
#define MMIO_GET_DEVICE_7X_PA(device_id) (TUPLE_ELEM_0(CAT(_MMAPDEV, EVAL(device_id))))
|
|
||||||
#define MMIO_GET_DEVICE_ADDRESS(device_id)\
|
|
||||||
(\
|
|
||||||
(TUPLE_FOLD_LEFT_1(EVAL(device_id), _MMAPDEV, PLUS) EVAL(MMIO_BASE)) +\
|
|
||||||
0x1000ull * (device_id)\
|
|
||||||
)
|
|
||||||
#define MMIO_GET_DEVICE_SIZE(device_id) (TUPLE_ELEM_1(CAT(_MMAPDEV, EVAL(device_id))))
|
|
||||||
#define MMIO_IS_DEVICE_SECURE(device_id) (TUPLE_ELEM_2(CAT(_MMAPDEV, EVAL(device_id))))
|
|
||||||
|
|
||||||
#define LP0_ENTRY_GET_RAM_SEGMENT_PA(segment_id) (TUPLE_ELEM_0(CAT(_MMAPLP0ES, EVAL(segment_id))))
|
|
||||||
#define LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(segment_id) (EVAL(LP0_ENTRY_RAM_SEGMENT_BASE) + 0x10000ull * (segment_id))
|
|
||||||
#define LP0_ENTRY_GET_RAM_SEGMENT_SIZE(segment_id) (TUPLE_ELEM_1(CAT(_MMAPLP0ES, EVAL(segment_id))))
|
|
||||||
#define LP0_ENTRY_GET_RAM_SEGMENT_ATTRIBS(segment_id) (TUPLE_ELEM_2(CAT(_MMAPLP0ES, EVAL(segment_id))))
|
|
||||||
|
|
||||||
#define WARMBOOT_GET_RAM_SEGMENT_PA(segment_id) (TUPLE_ELEM_0(CAT(_MMAPWBS, EVAL(segment_id))))
|
|
||||||
#define WARMBOOT_GET_RAM_SEGMENT_ADDRESS(segment_id) (TUPLE_FOLD_LEFT_1(EVAL(segment_id), _MMAPWBS, PLUS) EVAL(WARMBOOT_RAM_SEGMENT_BASE))
|
|
||||||
#define WARMBOOT_GET_RAM_SEGMENT_SIZE(segment_id) (TUPLE_ELEM_1(CAT(_MMAPWBS, EVAL(segment_id))))
|
|
||||||
#define WARMBOOT_GET_RAM_SEGMENT_ATTRIBS(segment_id) (TUPLE_ELEM_2(CAT(_MMAPWBS, EVAL(segment_id))))
|
|
||||||
|
|
||||||
#define TZRAM_GET_SEGMENT_PA(segment_id) (0x7C010000ull + (TUPLE_ELEM_0(CAT(_MMAPTZS, EVAL(segment_id)))))
|
|
||||||
#define TZRAM_GET_SEGMENT_5X_PA(segment_id) (0x7C010000ull + (TUPLE_ELEM_0(CAT(_MMAPTZ5XS, EVAL(segment_id)))))
|
|
||||||
#define TZRAM_GET_SEGMENT_ADDRESS(segment_id) (TUPLE_FOLD_LEFT_2(EVAL(segment_id), _MMAPTZS, PLUS) EVAL(TZRAM_SEGMENT_BASE))
|
|
||||||
#define TZRAM_GET_SEGMENT_SIZE(segment_id) (TUPLE_ELEM_1(CAT(_MMAPTZS, EVAL(segment_id))))
|
|
||||||
#define TZRAM_IS_SEGMENT_EXECUTABLE(segment_id) (TUPLE_ELEM_3(CAT(_MMAPTZS, EVAL(segment_id))))
|
|
||||||
|
|
||||||
/**********************************************************************************************/
|
|
||||||
/* We don't need unmapping functions */
|
|
||||||
|
|
||||||
ALINLINE static inline void identity_map_mapping(uintptr_t *mmu_l1_tbl, uintptr_t *mmu_l3_tbl, uintptr_t addr, size_t size, uint64_t attribs, bool is_block_range) {
|
|
||||||
if (is_block_range) {
|
|
||||||
mmu_map_block_range(1, mmu_l1_tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mmu_map_page_range(mmu_l3_tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ALINLINE static inline void mmio_map_device(uintptr_t *mmu_l3_tbl, uintptr_t addr, uintptr_t pa, size_t size, bool is_secure) {
|
|
||||||
static const uint64_t secure_device_attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_DEVICE;
|
|
||||||
static const uint64_t device_attributes = MMU_PTE_BLOCK_NS | secure_device_attributes;
|
|
||||||
|
|
||||||
uint64_t attributes = is_secure ? secure_device_attributes : device_attributes;
|
|
||||||
mmu_map_page_range(mmu_l3_tbl, addr, pa, size, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALINLINE static inline void lp0_entry_map_ram_segment(uintptr_t *mmu_l3_tbl, uintptr_t addr, uintptr_t pa, size_t size, uint64_t attribs) {
|
|
||||||
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | attribs;
|
|
||||||
|
|
||||||
mmu_map_page_range(mmu_l3_tbl, addr, pa, size, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALINLINE static inline void warmboot_map_ram_segment(uintptr_t *mmu_l3_tbl, uintptr_t addr, uintptr_t pa, size_t size, uint64_t attribs) {
|
|
||||||
uint64_t attributes = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | attribs;
|
|
||||||
|
|
||||||
mmu_map_page_range(mmu_l3_tbl, addr, pa, size, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALINLINE static inline void tzram_map_segment(uintptr_t *mmu_l3_tbl, uintptr_t addr, uintptr_t pa, size_t size, bool is_executable) {
|
|
||||||
uint64_t attributes = (is_executable ? 0 : MMU_PTE_BLOCK_XN) | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL;
|
|
||||||
|
|
||||||
mmu_map_page_range(mmu_l3_tbl, addr, pa, size, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MISC_H
|
|
||||||
#define EXOSPHERE_MISC_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 MISC Registers. */
|
|
||||||
|
|
||||||
#define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC))
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,193 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_MMU_H
|
|
||||||
#define EXOSPHERE_MMU_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef MMU_GRANULE_TYPE
|
|
||||||
#define MMU_GRANULE_TYPE 0 /* 0: 4KB, 1: 64KB, 2: 16KB. The Switch always uses a 4KB granule size. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MMU_GRANULE_TYPE == 0
|
|
||||||
#define MMU_Lx_SHIFT(x) (12 + 9 * (3 - (x)))
|
|
||||||
#define MMU_Lx_MASK(x) MASKL(9)
|
|
||||||
#elif MMU_GRANULE_TYPE == 1
|
|
||||||
/* 64 KB, no L0 here */
|
|
||||||
#define MMU_Lx_SHIFT(x) (16 + 13 * (3 - (x)))
|
|
||||||
#define MMU_Lx_MASK(x) ((x) == 1 ? MASKL(5) : MASKL(13))
|
|
||||||
#elif MMU_GRANULE_TYPE == 2
|
|
||||||
#define MMU_Lx_SHIFT(x) (14 + 11 * (3 - (x)))
|
|
||||||
#define MMU_Lx_MASK(x) ((x) == 0 ? 1 : MASKL(11))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following defines are adapted from uboot:
|
|
||||||
*
|
|
||||||
* (C) Copyright 2013
|
|
||||||
* David Feng <fenghua@phytium.com.cn>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Memory attributes, see set_memory_registers_enable_mmu */
|
|
||||||
#define MMU_MT_NORMAL 0ull
|
|
||||||
#define MMU_MT_DEVICE_NGNRE 1ull
|
|
||||||
#define MMU_MT_DEVICE_NGNRNE 2ull /* not used, also the same as Attr4-7 */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hardware page table definitions.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MMU_PTE_TYPE_MASK 3ull
|
|
||||||
#define MMU_PTE_TYPE_FAULT 0ull
|
|
||||||
#define MMU_PTE_TYPE_TABLE 3ull
|
|
||||||
#define MMU_PTE_TYPE_BLOCK 1ull
|
|
||||||
|
|
||||||
/* L3 only */
|
|
||||||
#define MMU_PTE_TYPE_PAGE 3ull
|
|
||||||
|
|
||||||
#define MMU_PTE_TABLE_PXN BITL(59)
|
|
||||||
#define MMU_PTE_TABLE_XN BITL(60)
|
|
||||||
#define MMU_PTE_TABLE_AP BITL(61)
|
|
||||||
#define MMU_PTE_TABLE_NS BITL(63)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Block
|
|
||||||
*/
|
|
||||||
#define MMU_PTE_BLOCK_MEMTYPE(x) ((uint64_t)((x) << 2))
|
|
||||||
#define MMU_PTE_BLOCK_NS BITL(5)
|
|
||||||
#define MMU_PTE_BLOCK_NON_SHAREABLE (0ull << 8)
|
|
||||||
#define MMU_PTE_BLOCK_OUTER_SHAREABLE (2ull << 8)
|
|
||||||
#define MMU_PTE_BLOCK_INNER_SHAREBLE (3ull << 8)
|
|
||||||
#define MMU_PTE_BLOCK_AF BITL(10)
|
|
||||||
#define MMU_PTE_BLOCK_NG BITL(11)
|
|
||||||
#define MMU_PTE_BLOCK_PXN BITL(53)
|
|
||||||
#define MMU_PTE_BLOCK_UXN BITL(54)
|
|
||||||
#define MMU_PTE_BLOCK_XN MMU_PTE_BLOCK_UXN
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AP[2:1]
|
|
||||||
*/
|
|
||||||
#define MMU_AP_PRIV_RW (0ull << 6)
|
|
||||||
#define MMU_AP_RW (1ull << 6)
|
|
||||||
#define MMU_AP_PRIV_RO (2ull << 6)
|
|
||||||
#define MMU_AP_RO (3ull << 6)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* S2AP[2:1] (for stage2 translations; secmon doesn't use it)
|
|
||||||
*/
|
|
||||||
#define MMU_S2AP_NONE (0ull << 6)
|
|
||||||
#define MMU_S2AP_RO (1ull << 6)
|
|
||||||
#define MMU_S2AP_WO (2ull << 6)
|
|
||||||
#define MMU_S2AP_RW (3ull << 6)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AttrIndx[2:0]
|
|
||||||
*/
|
|
||||||
#define MMU_PMD_ATTRINDX(t) ((uint64_t)((t) << 2))
|
|
||||||
#define MMU_PMD_ATTRINDX_MASK (7ull << 2)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TCR flags.
|
|
||||||
*/
|
|
||||||
#define TCR_T0SZ(x) ((64 - (x)) << 0)
|
|
||||||
#define TCR_IRGN_NC (0 << 8)
|
|
||||||
#define TCR_IRGN_WBWA (1 << 8)
|
|
||||||
#define TCR_IRGN_WT (2 << 8)
|
|
||||||
#define TCR_IRGN_WBNWA (3 << 8)
|
|
||||||
#define TCR_IRGN_MASK (3 << 8)
|
|
||||||
#define TCR_ORGN_NC (0 << 10)
|
|
||||||
#define TCR_ORGN_WBWA (1 << 10)
|
|
||||||
#define TCR_ORGN_WT (2 << 10)
|
|
||||||
#define TCR_ORGN_WBNWA (3 << 10)
|
|
||||||
#define TCR_ORGN_MASK (3 << 10)
|
|
||||||
#define TCR_NOT_SHARED (0 << 12)
|
|
||||||
#define TCR_SHARED_OUTER (2 << 12)
|
|
||||||
#define TCR_SHARED_INNER (3 << 12)
|
|
||||||
#define TCR_TG0_4K (0 << 14)
|
|
||||||
#define TCR_TG0_64K (1 << 14)
|
|
||||||
#define TCR_TG0_16K (2 << 14)
|
|
||||||
#define TCR_PS(x) ((x) << 16)
|
|
||||||
#define TCR_EPD1_DISABLE BIT(23)
|
|
||||||
|
|
||||||
#define TCR_EL1_RSVD BIT(31)
|
|
||||||
#define TCR_EL2_RSVD (BIT(31) | BIT(23))
|
|
||||||
#define TCR_EL3_RSVD (BIT(31) | BIT(23))
|
|
||||||
|
|
||||||
static inline void mmu_init_table(volatile uintptr_t *tbl, size_t num_entries) {
|
|
||||||
for(size_t i = 0; i < num_entries / 8; i++) {
|
|
||||||
tbl[i] = MMU_PTE_TYPE_FAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
All the functions below assume base_addr is valid.
|
|
||||||
They do not invalidate the TLB, which must be done separately.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline unsigned int mmu_compute_index(unsigned int level, uintptr_t base_addr) {
|
|
||||||
return (base_addr >> MMU_Lx_SHIFT(level)) & MMU_Lx_MASK(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_map_table(unsigned int level, uintptr_t *tbl, uintptr_t base_addr, uintptr_t *next_lvl_tbl_pa, uint64_t attrs) {
|
|
||||||
tbl[mmu_compute_index(level, base_addr)] = (uintptr_t)next_lvl_tbl_pa | attrs | MMU_PTE_TYPE_TABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_map_block(unsigned int level, uintptr_t *tbl, uintptr_t base_addr, uintptr_t phys_addr, uint64_t attrs) {
|
|
||||||
tbl[mmu_compute_index(level, base_addr)] = phys_addr | attrs | MMU_PTE_BLOCK_AF | MMU_PTE_TYPE_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_map_page(uintptr_t *tbl, uintptr_t base_addr, uintptr_t phys_addr, uint64_t attrs) {
|
|
||||||
tbl[mmu_compute_index(3, base_addr)] = phys_addr | attrs | MMU_PTE_BLOCK_AF | MMU_PTE_TYPE_PAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_unmap(unsigned int level, uintptr_t *tbl, uintptr_t base_addr) {
|
|
||||||
tbl[mmu_compute_index(level, base_addr)] = MMU_PTE_TYPE_FAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_unmap_page(uintptr_t *tbl, uintptr_t base_addr) {
|
|
||||||
tbl[mmu_compute_index(3, base_addr)] = MMU_PTE_TYPE_FAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_map_block_range(unsigned int level, uintptr_t *tbl, uintptr_t base_addr, uintptr_t phys_addr, size_t size, uint64_t attrs) {
|
|
||||||
size = ((size + (BITL(MMU_Lx_SHIFT(level)) - 1)) >> MMU_Lx_SHIFT(level)) << MMU_Lx_SHIFT(level);
|
|
||||||
for(size_t offset = 0; offset < size; offset += BITL(MMU_Lx_SHIFT(level))) {
|
|
||||||
mmu_map_block(level, tbl, base_addr + offset, phys_addr + offset, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_map_page_range(uintptr_t *tbl, uintptr_t base_addr, uintptr_t phys_addr, size_t size, uint64_t attrs) {
|
|
||||||
size = ((size + (BITL(MMU_Lx_SHIFT(3)) - 1)) >> MMU_Lx_SHIFT(3)) << MMU_Lx_SHIFT(3);
|
|
||||||
for(size_t offset = 0; offset < size; offset += BITL(MMU_Lx_SHIFT(3))) {
|
|
||||||
mmu_map_page(tbl, base_addr + offset, phys_addr + offset, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mmu_unmap_range(unsigned int level, uintptr_t *tbl, uintptr_t base_addr, size_t size) {
|
|
||||||
size = ((size + (BITL(MMU_Lx_SHIFT(level)) - 1)) >> MMU_Lx_SHIFT(level)) << MMU_Lx_SHIFT(level);
|
|
||||||
for(size_t offset = 0; offset < size; offset += BITL(MMU_Lx_SHIFT(level))) {
|
|
||||||
mmu_unmap(level, tbl, base_addr + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,637 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <string.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "bootup.h"
|
|
||||||
#include "cpu_context.h"
|
|
||||||
#include "package2.h"
|
|
||||||
#include "configitem.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
#include "masterkey.h"
|
|
||||||
#include "arm.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "randomcache.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "bootconfig.h"
|
|
||||||
#include "sysctr0.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
#include "smc_api.h"
|
|
||||||
|
|
||||||
extern void *__start_cold_addr;
|
|
||||||
extern size_t __bin_size;
|
|
||||||
|
|
||||||
static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
|
||||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
|
|
||||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
|
|
||||||
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
|
|
||||||
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
|
|
||||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
|
|
||||||
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
|
|
||||||
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
|
|
||||||
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
|
||||||
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
|
|
||||||
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
|
|
||||||
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
|
|
||||||
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
|
|
||||||
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
|
|
||||||
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
|
|
||||||
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
|
||||||
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.x New Device Keygen Source. */
|
|
||||||
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */
|
|
||||||
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
|
|
||||||
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
|
|
||||||
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
|
|
||||||
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 New Device Keygen Source. */
|
|
||||||
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 New Device Keygen Source. */
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static void derive_new_device_keys(unsigned int keygen_keyslot) {
|
|
||||||
uint8_t work_buffer[0x10];
|
|
||||||
bool is_retail = configitem_is_retail();
|
|
||||||
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
|
|
||||||
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
|
|
||||||
|
|
||||||
se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10);
|
|
||||||
if (relative_revision > mkey_get_revision()) {
|
|
||||||
break;
|
|
||||||
} else if (relative_revision == mkey_get_revision()) {
|
|
||||||
/* On 7.0.0, sept will have derived this key for us already. */
|
|
||||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
|
|
||||||
set_old_devkey(relative_revision, work_buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
|
||||||
clear_aes_keyslot(keygen_keyslot);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hardware init, sets up the RNG and SESSION keyslots, derives new DEVICE key. */
|
|
||||||
static void setup_se(void) {
|
|
||||||
uint8_t work_buffer[0x10];
|
|
||||||
|
|
||||||
/* Sanity check the Security Engine. */
|
|
||||||
se_verify_flags_cleared();
|
|
||||||
|
|
||||||
/* Initialize interrupts. */
|
|
||||||
intr_initialize_gic_nonsecure();
|
|
||||||
|
|
||||||
/* Perform some sanity initialization. */
|
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
|
||||||
se->SE_SE_SECURITY &= 0xFFFEFFFF; /* Clear bit 16. */
|
|
||||||
(void)(se->SE_STATUS);
|
|
||||||
__dsb_sy();
|
|
||||||
|
|
||||||
/* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */
|
|
||||||
se->SE_TZRAM_SECURITY = 0;
|
|
||||||
se->SE_CRYPTO_SECURITY_PERKEY = 0;
|
|
||||||
se->SE_RSA_SECURITY_PERKEY = 0;
|
|
||||||
se->SE_SE_SECURITY &= 0xFFFFFFFB;
|
|
||||||
|
|
||||||
/* Currently unknown what each flag does. */
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
|
||||||
set_aes_keyslot_flags(i, 0x15);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 4; i < KEYSLOT_AES_MAX; i++) {
|
|
||||||
set_aes_keyslot_flags(i, 0x40);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
|
||||||
set_rsa_keyslot_flags(i, 0x41);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect Master Key revision. */
|
|
||||||
mkey_detect_revision();
|
|
||||||
|
|
||||||
/* Derive new device keys. */
|
|
||||||
{
|
|
||||||
const uint32_t target_fw = exosphere_get_target_firmware();
|
|
||||||
if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
derive_new_device_keys(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY);
|
|
||||||
} else {
|
|
||||||
/* No new keys to derive */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
|
|
||||||
|
|
||||||
/* Generate random data, transform with device key to get RNG key. */
|
|
||||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_RNGKEY, 0xFF);
|
|
||||||
|
|
||||||
/* Repeat for Session key. */
|
|
||||||
se_generate_random(KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_DEVICEKEY, work_buffer, 0x10);
|
|
||||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
|
|
||||||
|
|
||||||
/* Generate test vector for our keys. */
|
|
||||||
se_generate_stored_vector();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_boot_config(void) {
|
|
||||||
/* Load boot config only if dev unit. */
|
|
||||||
if (configitem_is_retail()) {
|
|
||||||
bootconfig_clear();
|
|
||||||
} else {
|
|
||||||
void *bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER;
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER_6X;
|
|
||||||
}
|
|
||||||
flush_dcache_range((uint8_t *)bootconfig_ptr, (uint8_t *)bootconfig_ptr + sizeof(bootconfig_t));
|
|
||||||
bootconfig_load_and_verify((bootconfig_t *)bootconfig_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
|
|
||||||
/* Derive package2 key. */
|
|
||||||
static const uint8_t package2_key_source[0x10] = {0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
|
||||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
|
||||||
flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size);
|
|
||||||
unsigned int keyslot = mkey_get_keyslot(master_key_rev);
|
|
||||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY, keyslot, package2_key_source, 0x10);
|
|
||||||
|
|
||||||
/* Perform Encryption. */
|
|
||||||
se_aes_ctr_crypt(KEYSLOT_SWITCH_PACKAGE2KEY, dst, dst_size, src, src_size, ctr, ctr_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void verify_header_signature(package2_header_t *header) {
|
|
||||||
const uint8_t *modulus;
|
|
||||||
|
|
||||||
if (configitem_is_retail()) {
|
|
||||||
static const uint8_t package2_modulus_retail[0x100] = {
|
|
||||||
0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59,
|
|
||||||
0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE,
|
|
||||||
0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5,
|
|
||||||
0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74,
|
|
||||||
0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48,
|
|
||||||
0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE,
|
|
||||||
0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32,
|
|
||||||
0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A,
|
|
||||||
0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B,
|
|
||||||
0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3,
|
|
||||||
0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9,
|
|
||||||
0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47,
|
|
||||||
0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D,
|
|
||||||
0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2,
|
|
||||||
0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF,
|
|
||||||
0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F
|
|
||||||
};
|
|
||||||
modulus = package2_modulus_retail;
|
|
||||||
} else {
|
|
||||||
static const uint8_t package2_modulus_dev[0x100] = {
|
|
||||||
0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99,
|
|
||||||
0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7,
|
|
||||||
0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6,
|
|
||||||
0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38,
|
|
||||||
0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83,
|
|
||||||
0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0,
|
|
||||||
0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6,
|
|
||||||
0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50,
|
|
||||||
0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7,
|
|
||||||
0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42,
|
|
||||||
0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E,
|
|
||||||
0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8,
|
|
||||||
0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7,
|
|
||||||
0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4,
|
|
||||||
0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46,
|
|
||||||
0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B
|
|
||||||
};
|
|
||||||
modulus = package2_modulus_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is normally only allowed on dev units, but we'll allow it anywhere. */
|
|
||||||
bool is_unsigned = EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG || bootconfig_is_package2_unsigned();
|
|
||||||
if (!is_unsigned && se_rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
|
|
||||||
panic(0xF0000001); /* Invalid PK21 signature. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_package2_size(package2_meta_t *metadata) {
|
|
||||||
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool validate_package2_metadata(package2_meta_t *metadata) {
|
|
||||||
if (metadata->magic != MAGIC_PK21) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Package2 size, version number is stored XORed in header CTR. */
|
|
||||||
/* Nintendo, what the fuck? */
|
|
||||||
uint32_t package_size = metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
|
||||||
uint8_t header_version = (uint8_t)((metadata->ctr_dwords[1] ^ (metadata->ctr_dwords[1] >> 16) ^ (metadata->ctr_dwords[1] >> 24)) & 0xFF);
|
|
||||||
|
|
||||||
/* Ensure package isn't too big or too small. */
|
|
||||||
if (package_size <= sizeof(package2_header_t) || package_size > PACKAGE2_SIZE_MAX) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate that we're working with a header we know how to handle. */
|
|
||||||
if (header_version > MASTERKEY_REVISION_MAX) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Require aligned entrypoint. */
|
|
||||||
if (metadata->entrypoint & 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate section size sanity. */
|
|
||||||
if (metadata->section_sizes[0] + metadata->section_sizes[1] + metadata->section_sizes[2] + sizeof(package2_header_t) != package_size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool entrypoint_found = false;
|
|
||||||
|
|
||||||
/* Header has space for 4 sections, but only 3 are validated/potentially loaded on hardware. */
|
|
||||||
size_t cur_section_offset = 0;
|
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
|
||||||
/* Validate section size alignment. */
|
|
||||||
if (metadata->section_sizes[section] & 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate section does not overflow. */
|
|
||||||
if (check_32bit_additive_overflow(metadata->section_offsets[section], metadata->section_sizes[section])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for entrypoint presence. */
|
|
||||||
uint32_t section_end = metadata->section_offsets[section] + metadata->section_sizes[section];
|
|
||||||
if (metadata->section_offsets[section] <= metadata->entrypoint && metadata->entrypoint < section_end) {
|
|
||||||
entrypoint_found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure no overlap with later sections. */
|
|
||||||
if (metadata->section_sizes[section] != 0) {
|
|
||||||
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
|
|
||||||
if (metadata->section_sizes[later_section] == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
|
|
||||||
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check_hash = EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG == 0;
|
|
||||||
/* Validate section hashes. */
|
|
||||||
if (metadata->section_sizes[section]) {
|
|
||||||
void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + cur_section_offset);
|
|
||||||
uint8_t calculated_hash[0x20];
|
|
||||||
flush_dcache_range((uint8_t *)section_data, (uint8_t *)section_data + metadata->section_sizes[section]);
|
|
||||||
se_calculate_sha256(calculated_hash, section_data, metadata->section_sizes[section]);
|
|
||||||
if (check_hash && memcmp(calculated_hash, metadata->section_hashes[section], sizeof(metadata->section_hashes[section])) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cur_section_offset += metadata->section_sizes[section];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure that entrypoint is present in one of our sections. */
|
|
||||||
if (!entrypoint_found) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform version checks. */
|
|
||||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
|
||||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decrypts package2 header, and returns the master key revision required. */
|
|
||||||
static uint32_t decrypt_and_validate_header(package2_header_t *header) {
|
|
||||||
package2_meta_t metadata;
|
|
||||||
|
|
||||||
if (bootconfig_is_package2_plaintext() == 0) {
|
|
||||||
uint32_t mkey_rev;
|
|
||||||
|
|
||||||
/* Try to decrypt for all possible master keys. */
|
|
||||||
for (mkey_rev = 0; mkey_rev <= mkey_get_revision(); mkey_rev++) {
|
|
||||||
package2_crypt_ctr(mkey_rev, &metadata, sizeof(package2_meta_t), &header->metadata, sizeof(package2_meta_t), header->metadata.ctr, sizeof(header->metadata.ctr));
|
|
||||||
/* Copy the ctr (which stores information) into the decrypted metadata. */
|
|
||||||
memcpy(metadata.ctr, header->metadata.ctr, sizeof(header->metadata.ctr));
|
|
||||||
/* See if this is the correct key. */
|
|
||||||
if (validate_package2_metadata(&metadata)) {
|
|
||||||
header->metadata = metadata;
|
|
||||||
return mkey_rev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure we successfully decrypted the header. */
|
|
||||||
if (mkey_rev > mkey_get_revision()) {
|
|
||||||
panic(0xFAF00003);
|
|
||||||
}
|
|
||||||
} else if (!validate_package2_metadata(&header->metadata)) {
|
|
||||||
panic(0xFAF0003);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_package2_sections(package2_meta_t *metadata, uint32_t master_key_rev) {
|
|
||||||
/* By default, copy data directly from where NX_BOOTLOADER puts it. */
|
|
||||||
void *load_buf = NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS;
|
|
||||||
|
|
||||||
/* Check whether any of our sections overlap this region. If they do, we must relocate and copy from elsewhere. */
|
|
||||||
bool needs_relocation = false;
|
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
|
||||||
uint64_t section_start = DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section];
|
|
||||||
uint64_t section_end = section_start + (uint64_t)metadata->section_sizes[section];
|
|
||||||
if (overlaps(section_start, section_end, (uint64_t)(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS), (uint64_t)(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS) + PACKAGE2_SIZE_MAX)) {
|
|
||||||
needs_relocation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (needs_relocation) {
|
|
||||||
/* This code should *always* succeed in finding a carveout within seven loops, */
|
|
||||||
/* due to the section size limit, and section number limit. */
|
|
||||||
/* However, Nintendo tries panics after 8 loops if a safe section is not found. */
|
|
||||||
/* This should never be the case, mathematically. */
|
|
||||||
/* We will replicate this behavior. */
|
|
||||||
bool found_safe_carveout = false;
|
|
||||||
uint64_t potential_base_start = DRAM_BASE_PHYSICAL;
|
|
||||||
uint64_t potential_base_end = potential_base_start + PACKAGE2_SIZE_MAX;
|
|
||||||
for (unsigned int i = 0; i < 8; i++) {
|
|
||||||
int is_safe = 1;
|
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
|
||||||
uint64_t section_start = DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section];
|
|
||||||
uint64_t section_end = section_start + (uint64_t)metadata->section_sizes[section];
|
|
||||||
if (overlaps(section_start, section_end, potential_base_start, potential_base_end)) {
|
|
||||||
is_safe = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
found_safe_carveout |= is_safe;
|
|
||||||
if (found_safe_carveout) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
potential_base_start += PACKAGE2_SIZE_MAX;
|
|
||||||
potential_base_end += PACKAGE2_SIZE_MAX;
|
|
||||||
}
|
|
||||||
if (!found_safe_carveout) {
|
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
/* Relocate to new carveout. */
|
|
||||||
memcpy((void *)potential_base_start, load_buf, PACKAGE2_SIZE_MAX);
|
|
||||||
memset(load_buf, 0, PACKAGE2_SIZE_MAX);
|
|
||||||
load_buf = (void *)potential_base_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cur_section_offset = 0;
|
|
||||||
/* Copy each section to its appropriate location, decrypting if necessary. */
|
|
||||||
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
|
|
||||||
if (metadata->section_sizes[section] == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *dst_start = (void *)(DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section]);
|
|
||||||
void *src_start = load_buf + sizeof(package2_header_t) + cur_section_offset;
|
|
||||||
size_t size = (size_t)metadata->section_sizes[section];
|
|
||||||
|
|
||||||
if (bootconfig_is_package2_plaintext() && size != 0) {
|
|
||||||
memcpy(dst_start, src_start, size);
|
|
||||||
} else if (size != 0) {
|
|
||||||
package2_crypt_ctr(master_key_rev, dst_start, size, src_start, size, metadata->section_ctrs[section], 0x10);
|
|
||||||
}
|
|
||||||
cur_section_offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the encrypted package2 from memory. */
|
|
||||||
memset(load_buf, 0, PACKAGE2_SIZE_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copy_warmboot_bin_to_dram() {
|
|
||||||
uint8_t *warmboot_src;
|
|
||||||
|
|
||||||
{
|
|
||||||
const uint32_t target_fw = exosphere_get_target_firmware();
|
|
||||||
if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
|
||||||
warmboot_src = (uint8_t *)0x4003E000;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
warmboot_src = (uint8_t *)0x4003D800;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
warmboot_src = (uint8_t *)0x4003B000;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
|
|
||||||
const size_t warmboot_size = 0x2000;
|
|
||||||
|
|
||||||
/* Flush cache, to ensure warmboot is where we need it to be. */
|
|
||||||
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
|
|
||||||
__dsb_sy();
|
|
||||||
|
|
||||||
/* Copy warmboot. */
|
|
||||||
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
|
|
||||||
write32le(warmboot_dst, i, read32le(warmboot_src, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush cache, to ensure warmboot is where we need it to be. */
|
|
||||||
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
|
|
||||||
__dsb_sy();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sync_with_nx_bootloader(int state) {
|
|
||||||
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE(exosphere_get_target_firmware()) < state) {
|
|
||||||
wait(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void identity_unmap_dram(void) {
|
|
||||||
uintptr_t *mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
|
|
||||||
|
|
||||||
mmu_unmap_range(1, mmu_l1_tbl, IDENTITY_GET_MAPPING_ADDRESS(IDENTITY_MAPPING_DRAM), IDENTITY_GET_MAPPING_SIZE(IDENTITY_MAPPING_DRAM));
|
|
||||||
tlb_invalidate_all_inner_shareable();
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_pk2ldr_stack_address(void) {
|
|
||||||
return TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_PK2LDR) + 0x2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called during coldboot init, and validates a package2. */
|
|
||||||
/* This package2 is read into memory by a concurrent BPMP bootloader. */
|
|
||||||
void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
|
||||||
/* Load Exosphere-specific config. */
|
|
||||||
exosphere_load_config();
|
|
||||||
configitem_set_debugmode_override(exosphere_should_override_debugmode_user() != 0, exosphere_should_override_debugmode_priv() != 0);
|
|
||||||
if (exosphere_should_disable_usermode_exception_handlers() != 0) {
|
|
||||||
configitem_disable_usermode_exception_handlers();
|
|
||||||
}
|
|
||||||
if (exosphere_should_enable_usermode_pmu_access()) {
|
|
||||||
configitem_enable_usermode_pmu_access();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup the Security Engine. */
|
|
||||||
setup_se();
|
|
||||||
|
|
||||||
/* Perform initial PMC register writes, if relevant. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
|
|
||||||
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
|
|
||||||
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
|
|
||||||
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
|
|
||||||
|
|
||||||
const uint32_t target_fw = exosphere_get_target_firmware();
|
|
||||||
if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x105;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x16B;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x0A8;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x087;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x006;
|
|
||||||
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x105;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(1000);
|
|
||||||
|
|
||||||
bootup_misc_mmio();
|
|
||||||
|
|
||||||
setup_current_core_state();
|
|
||||||
|
|
||||||
/* Save boot reason to global. */
|
|
||||||
bootconfig_load_boot_reason((volatile boot_reason_t *)(MAILBOX_NX_BOOTLOADER_BOOT_REASON(exosphere_get_target_firmware())));
|
|
||||||
|
|
||||||
/* Initialize cache'd random bytes for kernel. */
|
|
||||||
randomcache_init();
|
|
||||||
|
|
||||||
/* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
|
|
||||||
/* memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); */
|
|
||||||
|
|
||||||
/* Let NX Bootloader know that we're running. */
|
|
||||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1;
|
|
||||||
|
|
||||||
/* Wait for 1 second, to allow time for NX_BOOTLOADER to draw to the screen. This is useful for debugging. */
|
|
||||||
/* wait(1000000); */
|
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG);
|
|
||||||
|
|
||||||
/* Load Boot Config into global. */
|
|
||||||
setup_boot_config();
|
|
||||||
|
|
||||||
/* Set sysctr0 registers based on bootconfig. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
|
|
||||||
MAKE_SYSCTR0_REG(0x8) = (uint32_t)((sysctr0_val >> 0) & 0xFFFFFFFFULL);
|
|
||||||
MAKE_SYSCTR0_REG(0xC) = (uint32_t)((sysctr0_val >> 32) & 0xFFFFFFFFULL);
|
|
||||||
MAKE_SYSCTR0_REG(0x0) = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X);
|
|
||||||
copy_warmboot_bin_to_dram();
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
|
|
||||||
setup_dram_magic_numbers();
|
|
||||||
}
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X);
|
|
||||||
} else {
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
|
|
||||||
secure_additional_devices();
|
|
||||||
|
|
||||||
/* Remove the identity mapping for iRAM-C+D & TZRAM */
|
|
||||||
/* For our crt0 to work, this doesn't actually unmap TZRAM */
|
|
||||||
identity_unmap_iram_cd_tzram();
|
|
||||||
|
|
||||||
/* Load header from NX_BOOTLOADER-initialized DRAM. */
|
|
||||||
package2_header_t header;
|
|
||||||
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
|
|
||||||
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
|
|
||||||
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
|
|
||||||
|
|
||||||
/* Perform signature checks. */
|
|
||||||
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
|
|
||||||
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
|
|
||||||
bootconfig_set_package2_plaintext_and_unsigned();
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_header_signature(&header);
|
|
||||||
|
|
||||||
/* Decrypt header, get key revision required. */
|
|
||||||
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
|
|
||||||
|
|
||||||
/* Copy hash, if necessary. */
|
|
||||||
if (bootconfig_is_recovery_boot()) {
|
|
||||||
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load Package2 Sections. */
|
|
||||||
load_package2_sections(&header.metadata, package2_mkey_rev);
|
|
||||||
|
|
||||||
/* Clean up cache. */
|
|
||||||
flush_dcache_all();
|
|
||||||
invalidate_icache_all(); /* non-broadcasting */
|
|
||||||
|
|
||||||
/* Set CORE0 entrypoint for Package2. */
|
|
||||||
set_core_entrypoint_and_argument(0, DRAM_BASE_PHYSICAL + header.metadata.entrypoint, 0);
|
|
||||||
|
|
||||||
/* Remove the DRAM identity mapping. */
|
|
||||||
if (0) {
|
|
||||||
identity_unmap_dram();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Synchronize with NX BOOTLOADER. */
|
|
||||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED_4X);
|
|
||||||
setup_4x_mmio();
|
|
||||||
} else {
|
|
||||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare the SMC API with version-dependent SMCs. */
|
|
||||||
set_version_specific_smcs();
|
|
||||||
|
|
||||||
/* Update SCR_EL3 depending on value in Bootconfig. */
|
|
||||||
set_extabt_serror_taken_to_el3(bootconfig_take_extabt_serror_to_el3());
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_PACKAGE2_H
|
|
||||||
#define EXOSPHERE_PACKAGE2_H
|
|
||||||
|
|
||||||
/* This is code responsible for validating a package2. Actual file reading is done by bootloader. */
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bootconfig.h"
|
|
||||||
#include "exocfg.h"
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
/* Physaddr 0x40002EF8 */
|
|
||||||
static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
|
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_NXBOOTLOADER_MAILBOX) + ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (0x000ull) : (0xE00ull));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (get_nx_bootloader_mailbox_base(targetfw))
|
|
||||||
|
|
||||||
#define MAILBOX_NX_SECMON_BOOT_TIME(targetfw) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x08ull)
|
|
||||||
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_SETUP_STATE(targetfw) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0xF8ull)
|
|
||||||
|
|
||||||
#define NX_BOOTLOADER_STATE_INIT 0
|
|
||||||
#define NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG 1
|
|
||||||
|
|
||||||
#define NX_BOOTLOADER_STATE_LOADED_PACKAGE2 2
|
|
||||||
#define NX_BOOTLOADER_STATE_FINISHED 3
|
|
||||||
|
|
||||||
#define NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X 2
|
|
||||||
#define NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X 3
|
|
||||||
#define NX_BOOTLOADER_STATE_FINISHED_4X 4
|
|
||||||
|
|
||||||
/* Physaddr 0x40002EFC */
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(targetfw) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0xFCULL)
|
|
||||||
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_BOOT_REASON(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10ULL)
|
|
||||||
|
|
||||||
#define NX_BOOTLOADER_BOOTCONFIG_POINTER ((void *)(0x4003D000ull))
|
|
||||||
#define NX_BOOTLOADER_BOOTCONFIG_POINTER_6X ((void *)(0x4003F800ull))
|
|
||||||
|
|
||||||
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
|
||||||
|
|
||||||
#define DRAM_BASE_PHYSICAL (0x80000000ull)
|
|
||||||
|
|
||||||
#define MAGIC_PK21 (0x31324B50)
|
|
||||||
#define PACKAGE2_SIZE_MAX 0x7FC000
|
|
||||||
#define PACKAGE2_SECTION_MAX 0x3
|
|
||||||
|
|
||||||
#define PACKAGE2_MINVER_THEORETICAL 0x0
|
|
||||||
#define PACKAGE2_MAXVER_100 0x2
|
|
||||||
#define PACKAGE2_MAXVER_200 0x3
|
|
||||||
#define PACKAGE2_MAXVER_300 0x4
|
|
||||||
#define PACKAGE2_MAXVER_302 0x5
|
|
||||||
#define PACKAGE2_MAXVER_400_410 0x6
|
|
||||||
#define PACKAGE2_MAXVER_500_510 0x7
|
|
||||||
#define PACKAGE2_MAXVER_600_610 0x8
|
|
||||||
#define PACKAGE2_MAXVER_620 0x9
|
|
||||||
#define PACKAGE2_MAXVER_700_800 0xA
|
|
||||||
#define PACKAGE2_MAXVER_810 0xB
|
|
||||||
#define PACKAGE2_MAXVER_900 0xC
|
|
||||||
#define PACKAGE2_MAXVER_910_920 0xD
|
|
||||||
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
|
|
||||||
|
|
||||||
#define PACKAGE2_MINVER_100 0x3
|
|
||||||
#define PACKAGE2_MINVER_200 0x4
|
|
||||||
#define PACKAGE2_MINVER_300 0x5
|
|
||||||
#define PACKAGE2_MINVER_302 0x6
|
|
||||||
#define PACKAGE2_MINVER_400_410 0x7
|
|
||||||
#define PACKAGE2_MINVER_500_510 0x8
|
|
||||||
#define PACKAGE2_MINVER_600_610 0x9
|
|
||||||
#define PACKAGE2_MINVER_620 0xA
|
|
||||||
#define PACKAGE2_MINVER_700_800 0xB
|
|
||||||
#define PACKAGE2_MINVER_810 0xC
|
|
||||||
#define PACKAGE2_MINVER_900 0xD
|
|
||||||
#define PACKAGE2_MINVER_910_920 0xE
|
|
||||||
#define PACKAGE2_MINVER_1000_CURRENT 0xF
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
uint8_t ctr[0x10];
|
|
||||||
uint32_t ctr_dwords[0x4];
|
|
||||||
};
|
|
||||||
uint8_t section_ctrs[4][0x10];
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t entrypoint;
|
|
||||||
uint32_t _0x58;
|
|
||||||
uint8_t version_max; /* Must be > TZ value. */
|
|
||||||
uint8_t version_min; /* Must be < TZ value. */
|
|
||||||
uint16_t _0x5E;
|
|
||||||
uint32_t section_sizes[4];
|
|
||||||
uint32_t section_offsets[4];
|
|
||||||
uint8_t section_hashes[4][0x20];
|
|
||||||
} package2_meta_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t signature[0x100];
|
|
||||||
union {
|
|
||||||
package2_meta_t metadata;
|
|
||||||
uint8_t encrypted_header[0x100];
|
|
||||||
};
|
|
||||||
uint8_t data[];
|
|
||||||
} package2_header_t;
|
|
||||||
|
|
||||||
void load_package2(coldboot_crt0_reloc_list_t *reloc_list);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 EXOSPHERE_PANIC_COLOR_H
|
|
||||||
#define EXOSPHERE_PANIC_COLOR_H
|
|
||||||
|
|
||||||
#define COLOR_0 0x00F00003
|
|
||||||
#define COLOR_1 0x0F000003
|
|
||||||
#define COLOR_2 0xF0000003
|
|
||||||
#define COLOR_3 0x0FF00003
|
|
||||||
#define COLOR_4 0xF0F00003
|
|
||||||
#define COLOR_5 0xFF000003
|
|
||||||
#define COLOR_6 0xFFF00003
|
|
||||||
#define COLOR_7 0xAAF00003
|
|
||||||
#define COLOR_8 0xAFA00003
|
|
||||||
#define COLOR_9 0xFAA00003
|
|
||||||
#define COLOR_A 0x33300003
|
|
||||||
#define COLOR_B 0x06F00003
|
|
||||||
#define COLOR_C 0x14800003
|
|
||||||
#define COLOR_D 0x00300003
|
|
||||||
#define COLOR_E 0x03000003
|
|
||||||
#define COLOR_F 0xB6000003
|
|
||||||
|
|
||||||
#define PANIC_REBOOT 0x20
|
|
||||||
|
|
||||||
#endif
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue