ams: delete exo1

This commit is contained in:
Michael Scire 2020-06-11 01:49:41 -07:00 committed by SciresM
parent c75e61a40b
commit 282f8f6612
135 changed files with 0 additions and 19262 deletions

View file

@ -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
#---------------------------------------------------------------------------------------

View file

@ -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.

View file

@ -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) }
}

View file

@ -1,4 +0,0 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections

View file

@ -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
#---------------------------------------------------------------------------------------

View file

@ -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;
}

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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)) { }
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
#---------------------------------------------------------------------------------------

View file

@ -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(.);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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_ */

View file

@ -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) { }
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
#---------------------------------------------------------------------------------------

View file

@ -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;
}

View file

@ -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

View file

@ -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. */ }
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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. */ }
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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 */
}

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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());
}

View file

@ -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

View file

@ -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