mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
exo2: Initial work on the exosphere rewrite.
exo2: Implement uncompressor stub and boot code up to Main(). exo2: implement some more init (uart/gic) exo2: implement more of init exo2: improve reg api, add keyslot flag setters exo2: implement se aes decryption/enc exo2: fix bugs in loader stub/mmu mappings exo2: start skeletoning bootconfig/global context types arch: fix makefile flags exo2: implement through master key derivation exo2: implement device master keygen exo2: more init through start of SetupSocSecurity exo2: implement pmc secure scratch management se: implement sticky bit validation libexosphere: fix building for arm32 libexo: fix makefile flags libexo: support building for arm64/arm sc7fw: skeleton binary sc7fw: skeleton a little more sc7fw: implement all non-dram functionality exo2: fix DivideUp error sc7fw: implement more dram code, fix reg library errors sc7fw: complete sc7fw impl. exo2: skeleton the rest of SetupSocSecurity exo2: implement fiq interrupt handler exo2: implement all exception handlers exo2: skeleton the entire smc api, implement the svc invoker exo2: implement rest of SetupSocSecurity exo2: correct slave security errors exo2: fix register definition exo2: minor fixes
This commit is contained in:
parent
71e0102f7a
commit
f66b41c027
192 changed files with 15093 additions and 24 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
# Executables
|
# Executables
|
||||||
*.exe
|
*.exe
|
||||||
|
*.lz4
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
*.i*86
|
*.i*86
|
||||||
|
|
38
exosphere2/Makefile
Normal file
38
exosphere2/Makefile
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
TARGETS := exosphere.bin program.lz4
|
||||||
|
CLEAN_TARGETS := exosphere-clean program-clean boot_code-clean
|
||||||
|
|
||||||
|
SUBFOLDERS := $(MODULES)
|
||||||
|
|
||||||
|
all: exosphere.bin
|
||||||
|
|
||||||
|
clean: $(CLEAN_TARGETS)
|
||||||
|
@rm -f exosphere.bin
|
||||||
|
|
||||||
|
exosphere.bin: program.lz4 boot_code.lz4
|
||||||
|
$(MAKE) -C loader_stub
|
||||||
|
@cp loader_stub/loader_stub.bin exosphere.bin
|
||||||
|
@echo "Built exosphere.bin..."
|
||||||
|
|
||||||
|
program.lz4: check_libexo
|
||||||
|
$(MAKE) -C program
|
||||||
|
@cp program/program.lz4 program.lz4
|
||||||
|
@cp program/boot_code.lz4 boot_code.lz4
|
||||||
|
|
||||||
|
boot_code.lz4: program.lz4
|
||||||
|
|
||||||
|
check_libexo:
|
||||||
|
@$(MAKE) --no-print-directory -C ../libraries/libexosphere
|
||||||
|
|
||||||
|
exosphere-clean:
|
||||||
|
$(MAKE) -C loader_stub clean
|
||||||
|
@rm -f exosphere.bin
|
||||||
|
|
||||||
|
program-clean:
|
||||||
|
$(MAKE) -C program clean
|
||||||
|
@rm -f program.lz4
|
||||||
|
|
||||||
|
boot_code-clean:
|
||||||
|
$(MAKE) -C boot_code clean
|
||||||
|
@rm -f boot_code.lz4
|
||||||
|
|
||||||
|
.PHONY: all clean $(CLEAN_TARGETS)
|
130
exosphere2/loader_stub/Makefile
Normal file
130
exosphere2/loader_stub/Makefile
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Define the atmosphere board and cpu
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
|
export ATMOSPHERE_CPU := arm-cortex-a57
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||||
|
$(TOPDIR)/../program
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.c))))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
|
||||||
|
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.cpp))))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
|
||||||
|
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.s))))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
|
||||||
|
|
||||||
|
BINFILES := program.lz4 boot_code.lz4
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 .,_,$(subst -,_,$(BINFILES))))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I.
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all check_program
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD) check_program
|
||||||
|
|
||||||
|
$(BUILD): check_program
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
check_program:
|
||||||
|
@$(MAKE) -C ../program all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).bin
|
||||||
|
|
||||||
|
$(OUTPUT).bin : $(OUTPUT).elf
|
||||||
|
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES) ../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a
|
||||||
|
|
||||||
|
%.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)
|
||||||
|
|
||||||
|
%.lz4.o %_lz4.h: %.lz4
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
182
exosphere2/loader_stub/loader_stub.ld
Normal file
182
exosphere2/loader_stub/loader_stub.ld
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
NULL : ORIGIN = 0, LENGTH = 4K
|
||||||
|
ldr_stub : ORIGIN = 0x040030000, LENGTH = 128K
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* =========== CODE section =========== */
|
||||||
|
PROVIDE(__start__ = 0x040030000);
|
||||||
|
. = __start__;
|
||||||
|
__code_start = . ;
|
||||||
|
|
||||||
|
.crt0 :
|
||||||
|
{
|
||||||
|
KEEP (*(.crt0 .crt0.*))
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.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);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.plt :
|
||||||
|
{
|
||||||
|
*(.plt)
|
||||||
|
*(.iplt)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
|
||||||
|
/* =========== RODATA section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__rodata_start = . ;
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >ldr_stub
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ldr_stub
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >ldr_stub
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >ldr_stub
|
||||||
|
|
||||||
|
.hash : { *(.hash) } >ldr_stub
|
||||||
|
|
||||||
|
/* =========== DATA section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__data_start = . ;
|
||||||
|
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ldr_stub
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >ldr_stub
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >ldr_stub
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >ldr_stub
|
||||||
|
|
||||||
|
.preinit_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.init_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.fini_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.ctors ALIGN(8) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
.dtors ALIGN(8) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
__got_start__ = .;
|
||||||
|
|
||||||
|
.got : { *(.got) *(.igot) } >ldr_stub
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) } >ldr_stub
|
||||||
|
|
||||||
|
__got_end__ = .;
|
||||||
|
|
||||||
|
.data ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
} >ldr_stub
|
||||||
|
|
||||||
|
__bss_start__ = .;
|
||||||
|
.bss ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(16);
|
||||||
|
} >ldr_stub
|
||||||
|
__bss_end__ = .;
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note .interp) }
|
||||||
|
|
||||||
|
/* 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) }
|
||||||
|
}
|
7
exosphere2/loader_stub/loader_stub.specs
Normal file
7
exosphere2/loader_stub/loader_stub.specs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
crti%O%s crtbegin%O%s
|
47
exosphere2/loader_stub/source/secmon_loader_error.cpp
Normal file
47
exosphere2/loader_stub/source/secmon_loader_error.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_loader_error.hpp"
|
||||||
|
|
||||||
|
namespace ams::diag {
|
||||||
|
|
||||||
|
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
|
||||||
|
ams::secmon::loader::ErrorReboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
|
||||||
|
ams::secmon::loader::ErrorReboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void AbortImpl() {
|
||||||
|
ams::secmon::loader::ErrorReboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::secmon::loader {
|
||||||
|
|
||||||
|
NORETURN void ErrorReboot() {
|
||||||
|
/* Invalidate the security engine. */
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
/* Reboot. */
|
||||||
|
while (true) {
|
||||||
|
wdt::Reboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
exosphere2/loader_stub/source/secmon_loader_error.hpp
Normal file
23
exosphere2/loader_stub/source/secmon_loader_error.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ams::secmon::loader {
|
||||||
|
|
||||||
|
NORETURN void ErrorReboot();
|
||||||
|
|
||||||
|
}
|
41
exosphere2/loader_stub/source/secmon_loader_main.cpp
Normal file
41
exosphere2/loader_stub/source/secmon_loader_main.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_loader_uncompress.hpp"
|
||||||
|
#include "program_lz4.h"
|
||||||
|
#include "boot_code_lz4.h"
|
||||||
|
|
||||||
|
namespace ams::secmon::loader {
|
||||||
|
|
||||||
|
NORETURN void UncompressAndExecute() {
|
||||||
|
/* Uncompress the program image. */
|
||||||
|
Uncompress(secmon::MemoryRegionPhysicalTzramFullProgramImage.GetPointer(), secmon::MemoryRegionPhysicalTzramFullProgramImage.GetSize(), program_lz4, program_lz4_size);
|
||||||
|
|
||||||
|
/* Copy the boot image to the end of IRAM */
|
||||||
|
u8 *relocated_boot_code = secmon::MemoryRegionPhysicalIramBootCodeImage.GetEndPointer<u8>() - boot_code_lz4_size;
|
||||||
|
std::memcpy(relocated_boot_code, boot_code_lz4, boot_code_lz4_size);
|
||||||
|
|
||||||
|
/* Uncompress the boot image. */
|
||||||
|
Uncompress(secmon::MemoryRegionPhysicalIramBootCodeImage.GetPointer(), secmon::MemoryRegionPhysicalIramBootCodeImage.GetSize(), relocated_boot_code, boot_code_lz4_size);
|
||||||
|
|
||||||
|
/* Jump to the boot image. */
|
||||||
|
reinterpret_cast<void (*)()>(secmon::MemoryRegionPhysicalIramBootCodeImage.GetAddress())();
|
||||||
|
|
||||||
|
/* We will never reach this point. */
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
exosphere2/loader_stub/source/secmon_loader_uncompress.cpp
Normal file
103
exosphere2/loader_stub/source/secmon_loader_uncompress.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_loader_uncompress.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::loader {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class Lz4Uncompressor {
|
||||||
|
private:
|
||||||
|
const u8 *src;
|
||||||
|
size_t src_size;
|
||||||
|
size_t src_offset;
|
||||||
|
u8 *dst;
|
||||||
|
size_t dst_size;
|
||||||
|
size_t dst_offset;
|
||||||
|
public:
|
||||||
|
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : src(static_cast<const u8 *>(src)), src_size(src_size), src_offset(0), dst(static_cast<u8 *>(dst)), dst_size(dst_size), dst_offset(0) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
void Uncompress() {
|
||||||
|
while (true) {
|
||||||
|
/* Read a control byte. */
|
||||||
|
u8 control = this->ReadByte();
|
||||||
|
|
||||||
|
/* Copy what it specifies we should copy. */
|
||||||
|
this->Copy(this->GetCopySize(control >> 4));
|
||||||
|
|
||||||
|
/* If we've exceeded size, we're done. */
|
||||||
|
if (this->src_offset >= this->src_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the wide copy offset. */
|
||||||
|
u16 wide_offset = this->ReadByte();
|
||||||
|
AMS_ABORT_UNLESS(this->CanRead());
|
||||||
|
wide_offset |= (this->ReadByte() << 8);
|
||||||
|
|
||||||
|
/* Determine the copy size. */
|
||||||
|
const size_t wide_copy_size = this->GetCopySize(control & 0xF);
|
||||||
|
|
||||||
|
/* Copy bytes. */
|
||||||
|
const size_t end_offset = this->dst_offset + wide_copy_size + 4;
|
||||||
|
for (size_t cur_offset = this->dst_offset; cur_offset < end_offset; this->dst_offset = (++cur_offset)) {
|
||||||
|
AMS_ABORT_UNLESS(wide_offset <= cur_offset);
|
||||||
|
|
||||||
|
this->dst[cur_offset] = this->dst[cur_offset - wide_offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
u8 ReadByte() {
|
||||||
|
return this->src[this->src_offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanRead() const {
|
||||||
|
return this->src_offset < this->src_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetCopySize(u8 control) {
|
||||||
|
size_t size = control;
|
||||||
|
|
||||||
|
if (control >= 0xF) {
|
||||||
|
do {
|
||||||
|
AMS_ABORT_UNLESS(this->CanRead());
|
||||||
|
control = this->ReadByte();
|
||||||
|
size += control;
|
||||||
|
} while (control == 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Copy(size_t size) {
|
||||||
|
__builtin_memcpy(this->dst + this->dst_offset, this->src + this->src_offset, size);
|
||||||
|
this->dst_offset += size;
|
||||||
|
this->src_offset += size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Create an execute a decompressor. */
|
||||||
|
Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
exosphere2/loader_stub/source/secmon_loader_uncompress.hpp
Normal file
23
exosphere2/loader_stub/source/secmon_loader_uncompress.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 <vapours.hpp>
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ams::secmon::loader {
|
||||||
|
|
||||||
|
void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
|
|
||||||
|
}
|
105
exosphere2/loader_stub/source/start.s
Normal file
105
exosphere2/loader_stub/source/start.s
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
|
||||||
|
#define cpuactlr_el1 s3_1_c15_c2_0
|
||||||
|
#define cpuectlr_el1 s3_1_c15_c2_1
|
||||||
|
|
||||||
|
.macro RESET_CORE
|
||||||
|
mov x0, #(1 << 63)
|
||||||
|
msr cpuactlr_el1, x0 /* disable regional clock gating */
|
||||||
|
isb
|
||||||
|
mov x0, #3
|
||||||
|
msr rmr_el3, x0
|
||||||
|
isb
|
||||||
|
dsb sy
|
||||||
|
/* Nintendo forgot to copy-paste the branch instruction below. */
|
||||||
|
1:
|
||||||
|
wfi
|
||||||
|
b 1b
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||||
|
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
/* The following comments are mine. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enable invalidates of branch target buffer, then flush
|
||||||
|
the entire instruction cache at the local level, and
|
||||||
|
with the reg change, the branch target buffer, then disable
|
||||||
|
invalidates of the branch target buffer again.
|
||||||
|
*/
|
||||||
|
mrs x0, cpuactlr_el1
|
||||||
|
orr x0, x0, #1
|
||||||
|
msr cpuactlr_el1, x0
|
||||||
|
|
||||||
|
dsb sy
|
||||||
|
isb
|
||||||
|
ic iallu
|
||||||
|
dsb sy
|
||||||
|
isb
|
||||||
|
|
||||||
|
mrs x0, cpuactlr_el1
|
||||||
|
bic x0, x0, #1
|
||||||
|
msr cpuactlr_el1, x0
|
||||||
|
|
||||||
|
.rept 7
|
||||||
|
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
|
||||||
|
.endr
|
||||||
|
|
||||||
|
/* if the OS lock is set, disable it and request a warm reset */
|
||||||
|
mrs x0, oslsr_el1
|
||||||
|
ands x0, x0, #2
|
||||||
|
b.eq 2f
|
||||||
|
mov x0, xzr
|
||||||
|
msr oslar_el1, x0
|
||||||
|
|
||||||
|
RESET_CORE
|
||||||
|
|
||||||
|
.rept 65
|
||||||
|
nop /* guard against speculative excecution */
|
||||||
|
.endr
|
||||||
|
|
||||||
|
2:
|
||||||
|
/* set the OS lock */
|
||||||
|
mov x0, #1
|
||||||
|
msr oslar_el1, x0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .crt0.text.start, "ax", %progbits
|
||||||
|
.align 6
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
/* mask all interrupts */
|
||||||
|
msr daifset, #0xF
|
||||||
|
|
||||||
|
/* Fixup hardware erratum */
|
||||||
|
ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||||
|
|
||||||
|
/* Set the stack pointer to a temporary location. */
|
||||||
|
ldr x20, =0x7C010800
|
||||||
|
mov sp, x20
|
||||||
|
|
||||||
|
/* Call our init array functions. */
|
||||||
|
bl __libc_init_array
|
||||||
|
|
||||||
|
/* Uncompress the program and iram boot code images. */
|
||||||
|
b _ZN3ams6secmon6loader20UncompressAndExecuteEv
|
128
exosphere2/program/Makefile
Normal file
128
exosphere2/program/Makefile
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Define the atmosphere board and cpu
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
|
export ATMOSPHERE_CPU := arm-cortex-a57
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.c))))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
|
||||||
|
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.cpp))))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
|
||||||
|
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.s))))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 .,_,$(subst -,_,$(BINFILES))))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I.
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD) check_libexo
|
||||||
|
|
||||||
|
$(BUILD): check_libexo
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
check_libexo:
|
||||||
|
@$(MAKE) --no-print-directory -C ../../libraries/libexosphere arm64
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).lz4
|
||||||
|
|
||||||
|
$(OUTPUT).lz4 : $(OUTPUT).bin
|
||||||
|
@python ../split_program.py $(OUTPUT).bin $(dir $(OUTPUT))
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).bin : $(OUTPUT).elf
|
||||||
|
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES) ../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a
|
||||||
|
|
||||||
|
secmon_crt0_cpp.o secmon_make_page_table.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
|
||||||
|
#---------------------------------------------------------------------------------------
|
277
exosphere2/program/program.ld
Normal file
277
exosphere2/program/program.ld
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
NULL : ORIGIN = 0, LENGTH = 4K
|
||||||
|
unused_region : ORIGIN = 0x1000, LENGTH = 4K
|
||||||
|
iram_boot_code : ORIGIN = 0x040032000, LENGTH = 48K
|
||||||
|
tzram : ORIGIN = 0x07C010000, LENGTH = 64K
|
||||||
|
|
||||||
|
/* Warmboot code follows the vectors in memory. */
|
||||||
|
/* However, we can't know for sure how big warmboot is, so we'll just say it's 2K. */
|
||||||
|
warmboot_text : ORIGIN = ORIGIN(tzram) + 10K, LENGTH = 2K
|
||||||
|
|
||||||
|
main : ORIGIN = 0x1F00C0000, LENGTH = 48K
|
||||||
|
tzram_boot_code : ORIGIN = 0x1F01C0800, LENGTH = 6K
|
||||||
|
|
||||||
|
glob : ORIGIN = 0x040032000, LENGTH = 64K
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.metadata :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
KEEP (*(.metadata .metadata.*))
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >unused_region AT>glob
|
||||||
|
|
||||||
|
PROVIDE(__glob_start__ = ORIGIN(glob));
|
||||||
|
. = __glob_start__;
|
||||||
|
|
||||||
|
__bootcode_start__ = ABSOLUTE(.);
|
||||||
|
|
||||||
|
.crt0 :
|
||||||
|
{
|
||||||
|
KEEP (*(.crt0 .crt0.*))
|
||||||
|
KEEP (secmon_crt0_cpp.o(.text*))
|
||||||
|
KEEP (secmon_boot_cache.o(.text*))
|
||||||
|
KEEP (secmon_make_page_table.o(.text*))
|
||||||
|
*(.crt0.rodata*)
|
||||||
|
secmon_crt0_cpp.o(.rodata*)
|
||||||
|
secmon_boot_cache.o(.rodata*)
|
||||||
|
secmon_make_page_table.o(.rodata*)
|
||||||
|
*(.crt0.data*)
|
||||||
|
secmon_crt0_cpp.o(.data*)
|
||||||
|
secmon_boot_cache.o(.data*)
|
||||||
|
secmon_make_page_table.o(.data*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >iram_boot_code AT>glob
|
||||||
|
|
||||||
|
.preinit_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} >iram_boot_code AT>glob
|
||||||
|
|
||||||
|
.init_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} >iram_boot_code AT>glob
|
||||||
|
|
||||||
|
.fini_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} >iram_boot_code 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))
|
||||||
|
} >iram_boot_code AT>glob
|
||||||
|
|
||||||
|
.dtors ALIGN(8) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} >iram_boot_code AT>glob
|
||||||
|
|
||||||
|
__bootcode_end__ = ABSOLUTE(.);
|
||||||
|
|
||||||
|
__program_start__ = ABSOLUTE(.);
|
||||||
|
.tzram_boot_code :
|
||||||
|
{
|
||||||
|
KEEP(secmon_main.o(.text*))
|
||||||
|
KEEP(secmon_boot_functions.o(.text*))
|
||||||
|
KEEP(secmon_boot_config.o(.text*))
|
||||||
|
KEEP(secmon_boot_setup.o(.text*))
|
||||||
|
KEEP(secmon_package2.o(.text*))
|
||||||
|
KEEP(secmon_key_data.o(.text*))
|
||||||
|
secmon_main.o(.rodata*)
|
||||||
|
secmon_boot_functions.o(.rodata*)
|
||||||
|
secmon_boot_config.o(.rodata*)
|
||||||
|
secmon_boot_setup.o(.rodata*)
|
||||||
|
secmon_package2.o(.rodata*)
|
||||||
|
secmon_key_data.o(.rodata*)
|
||||||
|
secmon_main.o(.data*)
|
||||||
|
secmon_boot_functions.o(.data*)
|
||||||
|
secmon_boot_config.o(.data*)
|
||||||
|
secmon_boot_setup.o(.data*)
|
||||||
|
secmon_package2.o(.data*)
|
||||||
|
secmon_key_data.o(.data*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >tzram_boot_code AT>glob
|
||||||
|
|
||||||
|
.tzram_boot_code.bss :
|
||||||
|
{
|
||||||
|
__boot_bss_start__ = ABSOLUTE(.);
|
||||||
|
secmon_main.o(.bss* COMMON)
|
||||||
|
secmon_boot_functions.o(.bss* COMMON)
|
||||||
|
secmon_boot_config.o(.bss* COMMON)
|
||||||
|
secmon_boot_setup.o(.bss* COMMON)
|
||||||
|
secmon_package2.o(.bss* COMMON)
|
||||||
|
secmon_key_data.o(.bss* COMMON)
|
||||||
|
__boot_bss_end__ = ABSOLUTE(.);
|
||||||
|
} >tzram_boot_code AT>glob
|
||||||
|
|
||||||
|
.tzram_boot_code.fill :
|
||||||
|
{
|
||||||
|
FILL(0x00000000);
|
||||||
|
. = ORIGIN(tzram_boot_code) + LENGTH(tzram_boot_code) - 1;
|
||||||
|
BYTE(0x00);
|
||||||
|
} > tzram_boot_code AT>glob
|
||||||
|
|
||||||
|
.vectors :
|
||||||
|
{
|
||||||
|
KEEP (*(.vectors*))
|
||||||
|
. = ALIGN(0x100);
|
||||||
|
} >main AT>glob
|
||||||
|
|
||||||
|
|
||||||
|
.warmboot :
|
||||||
|
{
|
||||||
|
KEEP (*(.warmboot.text.start)) /* Should be first */
|
||||||
|
KEEP (*(.warmboot.text*))
|
||||||
|
KEEP(secmon_setup_warm.o(.text*))
|
||||||
|
KEEP(tsec_*.o(.text*))
|
||||||
|
KEEP (*(.warmboot.rodata*))
|
||||||
|
KEEP(secmon_setup_warm.o(.rodata*))
|
||||||
|
KEEP(tsec_*.o(.rodata*))
|
||||||
|
KEEP (*(.warmboot.data*))
|
||||||
|
KEEP(secmon_setup_warm.o(.data*))
|
||||||
|
KEEP(tsec_*.o(.data*))
|
||||||
|
} >warmboot_text AT>glob
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.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 section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__rodata_start = . ;
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main AT>glob
|
||||||
|
|
||||||
|
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >main AT>glob
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >main AT>glob
|
||||||
|
|
||||||
|
.hash : { *(.hash) } >main AT>glob
|
||||||
|
|
||||||
|
/* =========== DATA section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__data_start = . ;
|
||||||
|
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >main AT>glob
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >main AT>glob
|
||||||
|
|
||||||
|
__got_start__ = .;
|
||||||
|
|
||||||
|
.got : { *(.got) *(.igot) } >main AT>glob
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) } >main AT>glob
|
||||||
|
|
||||||
|
__got_end__ = .;
|
||||||
|
|
||||||
|
.data ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
} >main AT>glob
|
||||||
|
|
||||||
|
.bss ALIGN(8) (NOLOAD) :
|
||||||
|
{
|
||||||
|
__bss_start__ = ABSOLUTE(.);
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(16);
|
||||||
|
__bss_end__ = ABSOLUTE(.);
|
||||||
|
} >main AT>glob
|
||||||
|
|
||||||
|
__program_end__ = ABSOLUTE(.);
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note .interp) }
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
}
|
4
exosphere2/program/program.specs
Normal file
4
exosphere2/program/program.specs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
122
exosphere2/program/sc7fw/Makefile
Normal file
122
exosphere2/program/sc7fw/Makefile
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Define the atmosphere board and cpu
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
|
export ATMOSPHERE_CPU := arm7tdmi
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../../libraries/config/templates/exosphere.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.c))))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
|
||||||
|
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.cpp))))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
|
||||||
|
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.s))))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 .,_,$(subst -,_,$(BINFILES))))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I.
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD) check_libexo
|
||||||
|
|
||||||
|
$(BUILD): check_libexo
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
check_libexo:
|
||||||
|
@$(MAKE) --no-print-directory -C ../../../libraries/libexosphere arm
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).bin
|
||||||
|
|
||||||
|
$(OUTPUT).bin : $(OUTPUT).elf
|
||||||
|
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES) ../../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a
|
||||||
|
|
||||||
|
%.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
|
||||||
|
#---------------------------------------------------------------------------------------
|
183
exosphere2/program/sc7fw/sc7fw.ld
Normal file
183
exosphere2/program/sc7fw/sc7fw.ld
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
NULL : ORIGIN = 0, LENGTH = 4K
|
||||||
|
sc7fw : ORIGIN = 0x40003000, LENGTH = 4K
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* =========== CODE section =========== */
|
||||||
|
PROVIDE(__start__ = ORIGIN(sc7fw));
|
||||||
|
. = __start__;
|
||||||
|
__code_start = . ;
|
||||||
|
|
||||||
|
.vectors :
|
||||||
|
{
|
||||||
|
KEEP (*(.vectors .vectors.*))
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.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);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.plt :
|
||||||
|
{
|
||||||
|
*(.plt)
|
||||||
|
*(.iplt)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
|
||||||
|
/* =========== RODATA section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__rodata_start = . ;
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >sc7fw
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >sc7fw
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >sc7fw
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >sc7fw
|
||||||
|
|
||||||
|
.hash : { *(.hash) } >sc7fw
|
||||||
|
|
||||||
|
/* =========== DATA section =========== */
|
||||||
|
. = ALIGN(8);
|
||||||
|
__data_start = . ;
|
||||||
|
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >sc7fw
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >sc7fw
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >sc7fw
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >sc7fw
|
||||||
|
|
||||||
|
.preinit_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.init_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.fini_array ALIGN(8) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.ctors ALIGN(8) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
.dtors ALIGN(8) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
__got_start__ = .;
|
||||||
|
|
||||||
|
.got : { *(.got) *(.igot) } >sc7fw
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) } >sc7fw
|
||||||
|
|
||||||
|
__got_end__ = .;
|
||||||
|
|
||||||
|
.data ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
} >sc7fw
|
||||||
|
|
||||||
|
__bss_start__ = .;
|
||||||
|
.bss ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(16);
|
||||||
|
} >sc7fw
|
||||||
|
__bss_end__ = .;
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note .interp) }
|
||||||
|
|
||||||
|
/* 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) }
|
||||||
|
}
|
7
exosphere2/program/sc7fw/sc7fw.specs
Normal file
7
exosphere2/program/sc7fw/sc7fw.specs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
crti%O%s crtbegin%O%s
|
182
exosphere2/program/sc7fw/source/sc7fw_dram.cpp
Normal file
182
exosphere2/program/sc7fw/source/sc7fw_dram.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "sc7fw_util.hpp"
|
||||||
|
#include "sc7fw_dram.hpp"
|
||||||
|
|
||||||
|
namespace ams::sc7fw {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||||
|
|
||||||
|
void UpdateEmcTiming() {
|
||||||
|
/* Enable timing update. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_TIMING_CONTROL), EMC_REG_BITS_ENUM(TIMING_CONTROL_TIMING_UPDATE, ENABLED));
|
||||||
|
|
||||||
|
/* Wait for the timing update to complete. */
|
||||||
|
while (!reg::HasValue(EMC_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_TIMING_UPDATE_STALLED, DONE))) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestAllPadsPowerDown(uintptr_t addr, uintptr_t expected) {
|
||||||
|
constexpr u32 DpdAllRequestValue = reg::Encode(PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_ON)) | 0x0FFFFFFF;
|
||||||
|
const auto RequestAddress = addr;
|
||||||
|
const auto StatusAddress = addr + 4;
|
||||||
|
|
||||||
|
/* Request all pads enter power down. */
|
||||||
|
reg::Write(PMC + RequestAddress, DpdAllRequestValue);
|
||||||
|
|
||||||
|
/* Wait until the status reflects our expectation (and all pads are shut down). */
|
||||||
|
while (reg::Read(PMC + StatusAddress) != expected) { /* ... */ }
|
||||||
|
|
||||||
|
/* Wait a little while to allow the power down status to propagate. */
|
||||||
|
SpinLoop(0x20);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveEmcFsp() {
|
||||||
|
/* We require that the RAM is LPDDR4. */
|
||||||
|
AMS_ABORT_UNLESS(reg::HasValue(EMC_ADDRESS(EMC_FBIO_CFG5), EMC_REG_BITS_ENUM(FBIO_CFG5_DRAM_TYPE, LPDDR4)));
|
||||||
|
|
||||||
|
/* Read the frequency set points from MRW3. */
|
||||||
|
constexpr u32 FspShift = 6;
|
||||||
|
constexpr u32 FspBits = 2;
|
||||||
|
constexpr u32 FspMask = ((1u << FspBits) - 1) << FspShift;
|
||||||
|
static_assert(FspMask == 0x000000C0);
|
||||||
|
const u32 fsp = (reg::Read(EMC_ADDRESS(EMC_MRW3)) & FspMask) >> FspShift;
|
||||||
|
|
||||||
|
/* Write the fsp to PMC_SCRATCH18, where it will be restored to MRW3 by brom. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH18, REG_BITS_VALUE(FspShift, FspBits, fsp));
|
||||||
|
|
||||||
|
/* Write the fsp twice to PMC_SCRATCH12, where it will be restored to MRW12 by brom. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH12, REG_BITS_VALUE(FspShift, FspBits, fsp), REG_BITS_VALUE(FspShift + 8, FspBits, fsp));
|
||||||
|
|
||||||
|
/* Write the fsp twice to PMC_SCRATCH13, where it will be restored to MRW13 by brom. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH13, REG_BITS_VALUE(FspShift, FspBits, fsp), REG_BITS_VALUE(FspShift + 8, FspBits, fsp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableSdramSelfRefresh() {
|
||||||
|
/* We require that the RAM is dual-channel. */
|
||||||
|
AMS_ABORT_UNLESS(reg::HasValue(EMC_ADDRESS(EMC_FBIO_CFG7), EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE)));
|
||||||
|
|
||||||
|
/* Disable RAM's ability to dynamically self-refresh, and to opportunistically perform powerdown. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_CFG), EMC_REG_BITS_ENUM(CFG_DYN_SELF_REF, DISABLED),
|
||||||
|
EMC_REG_BITS_ENUM(CFG_DRAM_ACPD, NO_POWERDOWN));
|
||||||
|
|
||||||
|
/* Update the EMC timing. */
|
||||||
|
UpdateEmcTiming();
|
||||||
|
|
||||||
|
/* Wait five microseconds. */
|
||||||
|
util::WaitMicroSeconds(5);
|
||||||
|
|
||||||
|
/* Disable ZQ calibration. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_ZCAL_INTERVAL), 0);
|
||||||
|
|
||||||
|
/* Disable automatic calibration. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_AUTO_CAL_CONFIG), EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_MEASURE_STALL, ENABLE),
|
||||||
|
EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_UPDATE_STALL, ENABLE),
|
||||||
|
EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_START, DISABLE));
|
||||||
|
|
||||||
|
/* Get whether digital delay locked loops are enabled. */
|
||||||
|
const bool has_dll = reg::HasValue(EMC_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, ENABLED));
|
||||||
|
if (has_dll) {
|
||||||
|
/* If they are, disable them. */
|
||||||
|
reg::ReadWrite(EMC_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the EMC timing. */
|
||||||
|
UpdateEmcTiming();
|
||||||
|
|
||||||
|
/* If dll was enabled, wait until both EMC0 and EMC1 have dll disabled. */
|
||||||
|
if (has_dll) {
|
||||||
|
while (!reg::HasValue(EMC0_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED))) { /* ... */ }
|
||||||
|
while (!reg::HasValue(EMC1_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED))) { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stall all reads and writes. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_REQ_CTRL), EMC_REG_BITS_VALUE(REQ_CTRL_STALL_ALL_READS, 1),
|
||||||
|
EMC_REG_BITS_VALUE(REQ_CTRL_STALL_ALL_WRITES, 1));
|
||||||
|
|
||||||
|
/* Wait until both EMC0 and EMC1 have no outstanding transactions. */
|
||||||
|
while (!reg::HasValue(EMC0_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_NO_OUTSTANDING_TRANSACTIONS, COMPLETED))) { /* ... */ }
|
||||||
|
while (!reg::HasValue(EMC1_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_NO_OUTSTANDING_TRANSACTIONS, COMPLETED))) { /* ... */ }
|
||||||
|
|
||||||
|
/* Enable self-refresh. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_SELF_REF), EMC_REG_BITS_ENUM(SELF_REF_SREF_DEV_SELECTN, BOTH),
|
||||||
|
EMC_REG_BITS_ENUM(SELF_REF_SELF_REF_CMD, ENABLED));
|
||||||
|
|
||||||
|
/* Wait until both EMC and EMC1 are in self-refresh. */
|
||||||
|
const auto desired = reg::HasValue(EMC_ADDRESS(EMC_ADR_CFG), EMC_REG_BITS_ENUM(ADR_CFG_EMEM_NUMDEV, N2)) ? EMC_REG_BITS_ENUM(EMC_STATUS_DRAM_IN_SELF_REFRESH, BOTH_ENABLED)
|
||||||
|
: EMC_REG_BITS_ENUM(EMC_STATUS_DRAM_DEV0_IN_SELF_REFRESH, ENABLED);
|
||||||
|
|
||||||
|
/* NOTE: Nintendo's sc7 entry firmware has a bug here. */
|
||||||
|
/* Instead of waiting for both EMCs to report self-refresh, they just read the EMC_STATUS for each EMC. */
|
||||||
|
/* This is incorrect, per documentation. */
|
||||||
|
while (!reg::HasValue(EMC0_ADDRESS(EMC_EMC_STATUS), desired)) { /* ... */ }
|
||||||
|
while (!reg::HasValue(EMC1_ADDRESS(EMC_EMC_STATUS), desired)) { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableEmcAllSegmentsRefresh() {
|
||||||
|
constexpr int MR17_PASR_Segment = 17;
|
||||||
|
|
||||||
|
/* Write zeros to MR17_PASR_Segment to enable refresh for all segments for dev0. */
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_MRW), EMC_REG_BITS_ENUM (MRW_DEV_SELECTN, DEV0),
|
||||||
|
EMC_REG_BITS_ENUM (MRW_CNT, EXT1),
|
||||||
|
EMC_REG_BITS_VALUE(MRW_MA, MR17_PASR_Segment),
|
||||||
|
EMC_REG_BITS_VALUE(MRW_OP, 0));
|
||||||
|
|
||||||
|
/* If dev1 exists, do the same for dev1. */
|
||||||
|
if (reg::HasValue(EMC_ADDRESS(EMC_ADR_CFG), EMC_REG_BITS_ENUM(ADR_CFG_EMEM_NUMDEV, N2))) {
|
||||||
|
reg::Write(EMC_ADDRESS(EMC_MRW), EMC_REG_BITS_ENUM (MRW_DEV_SELECTN, DEV1),
|
||||||
|
EMC_REG_BITS_ENUM (MRW_CNT, EXT1),
|
||||||
|
EMC_REG_BITS_VALUE(MRW_MA, MR17_PASR_Segment),
|
||||||
|
EMC_REG_BITS_VALUE(MRW_OP, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableDdrDeepPowerDown() {
|
||||||
|
/* Read and decode the parameters Nintendo stores in EMC_PMC_SCRATCH3. */
|
||||||
|
const u32 scratch3 = reg::Read(EMC_ADDRESS(EMC_PMC_SCRATCH3));
|
||||||
|
const bool weak_bias = (scratch3 & reg::EncodeMask(EMC_REG_BITS_MASK(PMC_SCRATCH3_WEAK_BIAS))) == reg::EncodeValue(EMC_REG_BITS_ENUM(PMC_SCRATCH3_WEAK_BIAS, ENABLED));
|
||||||
|
const u32 ddr_cntrl = (scratch3 & reg::EncodeMask(EMC_REG_BITS_MASK(PMC_SCRATCH3_DDR_CNTRL)));
|
||||||
|
|
||||||
|
/* Write the decoded value to PMC_DDR_CNTRL. */
|
||||||
|
reg::Write(PMC + APBDEV_PMC_DDR_CNTRL, ddr_cntrl);
|
||||||
|
|
||||||
|
/* If weak bias is enabled, set all VTT_E_WB bits in APBDEV_PMC_WEAK_BIAS. */
|
||||||
|
if (weak_bias) {
|
||||||
|
constexpr u32 WeakBiasVttEWbAll = 0x7FFF0000;
|
||||||
|
reg::Write(PMC + APBDEV_PMC_WEAK_BIAS, WeakBiasVttEWbAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request that DPD3 pads power down. */
|
||||||
|
constexpr u32 EristaDpd3Mask = 0x0FFFFFFF;
|
||||||
|
constexpr u32 MarikoDpd3Mask = 0x0FFF9FFF;
|
||||||
|
if (true /* TODO: IsErista */) {
|
||||||
|
RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD3_REQ, EristaDpd3Mask);
|
||||||
|
} else {
|
||||||
|
RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD3_REQ, MarikoDpd3Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request that DPD4 pads power down. */
|
||||||
|
constexpr u32 Dpd4Mask = 0x0FFF1FFF;
|
||||||
|
RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD4_REQ, Dpd4Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
exosphere2/program/sc7fw/source/sc7fw_dram.hpp
Normal file
26
exosphere2/program/sc7fw/source/sc7fw_dram.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::sc7fw {
|
||||||
|
|
||||||
|
void SaveEmcFsp();
|
||||||
|
void EnableSdramSelfRefresh();
|
||||||
|
void EnableEmcAllSegmentsRefresh();
|
||||||
|
void EnableDdrDeepPowerDown();
|
||||||
|
|
||||||
|
}
|
22
exosphere2/program/sc7fw/source/sc7fw_exception_vectors.s
Normal file
22
exosphere2/program/sc7fw/source/sc7fw_exception_vectors.s
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 .vectors, "ax", %progbits
|
||||||
|
.align 3
|
||||||
|
.global reset
|
||||||
|
reset:
|
||||||
|
b _start
|
||||||
|
b _ZN3ams5sc7fw16ExceptionHandlerEv
|
116
exosphere2/program/sc7fw/source/sc7fw_main.cpp
Normal file
116
exosphere2/program/sc7fw/source/sc7fw_main.cpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "sc7fw_util.hpp"
|
||||||
|
#include "sc7fw_dram.hpp"
|
||||||
|
|
||||||
|
namespace ams::sc7fw {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||||
|
|
||||||
|
void DisableCrail() {
|
||||||
|
/* Wait for CRAIL to be off. */
|
||||||
|
while (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, OFF))) { /* ... */ }
|
||||||
|
|
||||||
|
/* Set CRAIL to be clamped. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_SET_SW_CLAMP, PMC_REG_BITS_VALUE(SET_SW_CLAMP_CRAIL, 1));
|
||||||
|
|
||||||
|
/* Wait for CRAIL to be clamped. */
|
||||||
|
while (!reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, PMC_REG_BITS_ENUM(CLAMP_STATUS_CRAIL, ENABLE))) { /* ... */ }
|
||||||
|
|
||||||
|
/* Spin loop for a short while, to allow time for the clamp to take effect. */
|
||||||
|
sc7fw::SpinLoop(10);
|
||||||
|
|
||||||
|
/* Initialize i2c-5. */
|
||||||
|
i2c::Initialize(i2c::Port_5);
|
||||||
|
|
||||||
|
/* Disable the voltage to CPU. */
|
||||||
|
pmic::DisableVddCpu(fuse::GetRegulator());
|
||||||
|
|
||||||
|
/* Wait 700 microseconds to ensure voltage is disabled. */
|
||||||
|
util::WaitMicroSeconds(700);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableAllInterrupts() {
|
||||||
|
/* Disable all interrupts for bpmp in all interrupt controllers. */
|
||||||
|
reg::Write(PRI_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
reg::Write(SEC_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
reg::Write(TRI_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
reg::Write(QUAD_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
reg::Write(PENTA_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
reg::Write(HEXA_ICTLR(ICTLR_COP_IER_CLR), ~0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterSc7() {
|
||||||
|
/* Disable read buffering and write buffering in the BPMP cache. */
|
||||||
|
reg::ReadWrite(AVP_CACHE_ADDRESS(AVP_CACHE_CONFIG), AVP_CACHE_REG_BITS_ENUM(DISABLE_WB, TRUE),
|
||||||
|
AVP_CACHE_REG_BITS_ENUM(DISABLE_RB, TRUE));
|
||||||
|
|
||||||
|
/* Ensure the CPU Rail is turned off. */
|
||||||
|
DisableCrail();
|
||||||
|
|
||||||
|
/* Disable all interrupts. */
|
||||||
|
DisableAllInterrupts();
|
||||||
|
|
||||||
|
/* Save the EMC FSP */
|
||||||
|
SaveEmcFsp();
|
||||||
|
|
||||||
|
/* Enable self-refresh for DRAM */
|
||||||
|
EnableSdramSelfRefresh();
|
||||||
|
|
||||||
|
/* Enable refresh for all EMC devices. */
|
||||||
|
EnableEmcAllSegmentsRefresh();
|
||||||
|
|
||||||
|
/* Enable deep power-down for ddr. */
|
||||||
|
EnableDdrDeepPowerDown();
|
||||||
|
|
||||||
|
/* Enable pad sampling during deep sleep. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_DPD_SAMPLE, PMC_REG_BITS_ENUM(DPD_SAMPLE_ON, ENABLE));
|
||||||
|
reg::Read(PMC + APBDEV_PMC_DPD_SAMPLE);
|
||||||
|
|
||||||
|
/* Wait a while for pad sampling to be enabled. */
|
||||||
|
sc7fw::SpinLoop(0x128);
|
||||||
|
|
||||||
|
/* Enter deep sleep. */
|
||||||
|
reg::ReadWrite(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_ON, ENABLE));
|
||||||
|
|
||||||
|
/* Wait forever until we're asleep. */
|
||||||
|
while (true) { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Main() {
|
||||||
|
EnterSc7();
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void ExceptionHandler() {
|
||||||
|
/* Write enable to MAIN_RESET. */
|
||||||
|
reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
|
||||||
|
while (true) { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::diag {
|
||||||
|
|
||||||
|
void AbortImpl() {
|
||||||
|
sc7fw::ExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
exosphere2/program/sc7fw/source/sc7fw_start.s
Normal file
35
exosphere2/program/sc7fw/source/sc7fw_start.s
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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, "ax", %progbits
|
||||||
|
.align 3
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
/* Set CPSR_cf and CPSR_cf. */
|
||||||
|
msr cpsr_f, #0xC0
|
||||||
|
msr cpsr_cf, #0xD3
|
||||||
|
|
||||||
|
/* Set the stack pointer. */
|
||||||
|
ldr sp, =0x40005000
|
||||||
|
|
||||||
|
/* Set our link register to the exception handler. */
|
||||||
|
ldr lr, =_ZN3ams5sc7fw16ExceptionHandlerEv
|
||||||
|
|
||||||
|
/* Invoke main. */
|
||||||
|
bl _ZN3ams5sc7fw4MainEv
|
||||||
|
|
||||||
|
/* Infinite loop. */
|
||||||
|
1: b 1b
|
23
exosphere2/program/sc7fw/source/sc7fw_util.hpp
Normal file
23
exosphere2/program/sc7fw/source/sc7fw_util.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::sc7fw {
|
||||||
|
|
||||||
|
void SpinLoop(unsigned int num);
|
||||||
|
|
||||||
|
}
|
30
exosphere2/program/sc7fw/source/sc7fw_util_asm.s
Normal file
30
exosphere2/program/sc7fw/source/sc7fw_util_asm.s
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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._ZN3ams5sc7fw8SpinLoopEj, "ax", %progbits
|
||||||
|
.global _ZN3ams5sc7fw8SpinLoopEj
|
||||||
|
.thumb_func
|
||||||
|
.syntax unified
|
||||||
|
_ZN3ams5sc7fw8SpinLoopEj:
|
||||||
|
1:
|
||||||
|
/* Subtract one from the count. */
|
||||||
|
subs r0, r0, #1
|
||||||
|
|
||||||
|
/* If we aren't at zero, continue looping. */
|
||||||
|
bgt 1b
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
bx lr
|
25
exosphere2/program/source/boot/secmon_boot.hpp
Normal file
25
exosphere2/program/source/boot/secmon_boot.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
void MakePageTable();
|
||||||
|
|
||||||
|
void InitializeColdBoot();
|
||||||
|
|
||||||
|
}
|
22
exosphere2/program/source/boot/secmon_boot_cache.cpp
Normal file
22
exosphere2/program/source/boot/secmon_boot_cache.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
}
|
22
exosphere2/program/source/boot/secmon_boot_config.cpp
Normal file
22
exosphere2/program/source/boot/secmon_boot_config.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
}
|
26
exosphere2/program/source/boot/secmon_boot_functions.cpp
Normal file
26
exosphere2/program/source/boot/secmon_boot_functions.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_boot_functions.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
void ClearIram() {
|
||||||
|
/* Clear the boot code image from where it was loaded in IRAM. */
|
||||||
|
util::ClearMemory(MemoryRegionPhysicalIramBootCodeImage.GetPointer(), MemoryRegionPhysicalIramBootCodeImage.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
exosphere2/program/source/boot/secmon_boot_functions.hpp
Normal file
23
exosphere2/program/source/boot/secmon_boot_functions.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
void ClearIram();
|
||||||
|
|
||||||
|
}
|
337
exosphere2/program/source/boot/secmon_boot_setup.cpp
Normal file
337
exosphere2/program/source/boot/secmon_boot_setup.cpp
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_boot.hpp"
|
||||||
|
#include "../secmon_setup.hpp"
|
||||||
|
#include "../secmon_key_storage.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void ValidateSystemCounters() {
|
||||||
|
const uintptr_t sysctr0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
|
||||||
|
|
||||||
|
/* Validate the system counter frequency is as expected. */
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_CNTFID0) == 19'200'000u);
|
||||||
|
|
||||||
|
/* Validate the system counters are as expected. */
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 0)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 1)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 2)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 3)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 4)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 5)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 6)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 7)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 8)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 9)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(10)) == 0);
|
||||||
|
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(11)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupPmcRegisters() {
|
||||||
|
const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress();
|
||||||
|
|
||||||
|
/* Set the physical address of the warmboot binary to scratch 1. */
|
||||||
|
reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
|
||||||
|
|
||||||
|
/* Configure logging by setting bits 18-19 of scratch 20. */
|
||||||
|
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0));
|
||||||
|
|
||||||
|
/* Clear the wdt reset flag. */
|
||||||
|
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0));
|
||||||
|
|
||||||
|
/* Configure warmboot to set Set FUSE_PRIVATEKEYDISABLE to KEY_INVISIBLE. */
|
||||||
|
reg::ReadWrite(pmc + APBDEV_PMC_SECURE_SCRATCH21, REG_BITS_VALUE(4, 1, 1));
|
||||||
|
|
||||||
|
/* Write the warmboot key. */
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function derives the master kek and device keys using the tsec root key. */
|
||||||
|
/* NOTE: Exosphere does not use this in practice, and expects the bootloader to set up keys already. */
|
||||||
|
/* NOTE: This function is currently not implemented. If implemented, it will only be a reference implementation. */
|
||||||
|
[[maybe_unused]]
|
||||||
|
void DeriveMasterKekAndDeviceKey() {
|
||||||
|
/* TODO: Decide whether to implement this. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupRandomKey(int slot, se::KeySlotLockFlags flags) {
|
||||||
|
/* Create an aligned buffer to hold the key. */
|
||||||
|
constexpr size_t KeySize = se::AesBlockSize;
|
||||||
|
util::AlignedBuffer<hw::DataCacheLineSize, KeySize> key;
|
||||||
|
|
||||||
|
/* Ensure data is consistent before triggering the SE. */
|
||||||
|
hw::FlushDataCache(key, KeySize);
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Generate random bytes into the key. */
|
||||||
|
se::GenerateRandomBytes(key, KeySize);
|
||||||
|
|
||||||
|
/* Ensure that the CPU sees consistent data. */
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
hw::FlushDataCache(key, KeySize);
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Use the random bytes as a key source. */
|
||||||
|
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_DeviceMaster, key, KeySize);
|
||||||
|
|
||||||
|
/* Lock the keyslot. */
|
||||||
|
se::LockAesKeySlot(slot, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
constinit const u8 MasterKeyVectorsDev[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
|
||||||
|
{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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit const u8 MasterKeyVectorsProd[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
|
||||||
|
{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 TestKeyGeneration(int generation, bool is_prod) {
|
||||||
|
/* Decrypt the vector chain from generation to start. */
|
||||||
|
int slot = pkg1::AesKeySlot_Master;
|
||||||
|
for (int i = generation; i > 0; --i) {
|
||||||
|
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
|
||||||
|
slot = pkg1::AesKeySlot_Temporary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt the final vector. */
|
||||||
|
u8 test_vector[se::AesBlockSize];
|
||||||
|
se::DecryptAes128(test_vector, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[0] : MasterKeyVectorsDev[0], se::AesBlockSize);
|
||||||
|
|
||||||
|
constexpr u8 ZeroBlock[se::AesBlockSize] = {};
|
||||||
|
return crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DetermineKeyGeneration(bool is_prod) {
|
||||||
|
/* Test each generation in order. */
|
||||||
|
for (int generation = 0; generation < pkg1::KeyGeneration_Count; ++generation) {
|
||||||
|
if (TestKeyGeneration(generation, is_prod)) {
|
||||||
|
return generation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We must have found a correct key generation. */
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeriveAllMasterKeys(bool is_prod, u8 * const work_block) {
|
||||||
|
|
||||||
|
/* Determine the generation. */
|
||||||
|
const int generation = DetermineKeyGeneration(is_prod);
|
||||||
|
|
||||||
|
/* Set the global generation. */
|
||||||
|
::ams::secmon::impl::SetKeyGeneration(generation);
|
||||||
|
|
||||||
|
/* Derive all old keys. */
|
||||||
|
int slot = pkg1::AesKeySlot_Master;
|
||||||
|
for (int i = generation; i > 0; --i) {
|
||||||
|
/* Decrypt the old master key. */
|
||||||
|
se::DecryptAes128(work_block, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Set the old master key. */
|
||||||
|
SetMasterKey(generation - 1, work_block, se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Set the old master key into a temporary keyslot. */
|
||||||
|
se::SetAesKey(pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Perform the next decryption with the older master key. */
|
||||||
|
slot = pkg1::AesKeySlot_Temporary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constinit const u8 DeviceMasterKeySourceSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
|
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */
|
||||||
|
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */
|
||||||
|
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */
|
||||||
|
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */
|
||||||
|
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */
|
||||||
|
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */
|
||||||
|
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */
|
||||||
|
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
|
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */
|
||||||
|
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */
|
||||||
|
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */
|
||||||
|
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */
|
||||||
|
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */
|
||||||
|
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */
|
||||||
|
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */
|
||||||
|
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit const u8 DeviceMasterKekSourcesProd[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
|
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */
|
||||||
|
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */
|
||||||
|
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */
|
||||||
|
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */
|
||||||
|
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */
|
||||||
|
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */
|
||||||
|
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */
|
||||||
|
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */
|
||||||
|
};
|
||||||
|
|
||||||
|
void DeriveAllDeviceMasterKeys(bool is_prod, u8 * const work_block) {
|
||||||
|
/* Get the current key generation. */
|
||||||
|
const int current_generation = secmon::GetKeyGeneration();
|
||||||
|
|
||||||
|
/* Iterate for all generations. */
|
||||||
|
for (int i = 0; i < pkg1::OldDeviceMasterKeyCount; ++i) {
|
||||||
|
const int generation = pkg1::KeyGeneration_4_0_0 + i;
|
||||||
|
|
||||||
|
/* Load the first master key into the temporary keyslot keyslot. */
|
||||||
|
LoadMasterKey(pkg1::AesKeySlot_Temporary, pkg1::KeyGeneration_1_0_0);
|
||||||
|
|
||||||
|
/* Decrypt the device master kek for the generation. */
|
||||||
|
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, is_prod ? DeviceMasterKekSourcesProd[i] : DeviceMasterKekSourcesDev[i], se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Decrypt the device master key source into the work block. */
|
||||||
|
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_DeviceMasterKeySourceKek, DeviceMasterKeySourceSources[i], se::AesBlockSize);
|
||||||
|
|
||||||
|
/* If we're decrypting the current device master key, decrypt into the keyslot. */
|
||||||
|
if (generation == current_generation) {
|
||||||
|
se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
|
||||||
|
} else {
|
||||||
|
/* Otherwise, decrypt the work block into itself and set the old device master key. */
|
||||||
|
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Set the device master key. */
|
||||||
|
SetDeviceMasterKey(generation, work_block, se::AesBlockSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear and lock the Device Master Key Source Kek. */
|
||||||
|
se::ClearAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek);
|
||||||
|
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek, se::KeySlotLockFlags_AllLockKek);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeriveAllKeys() {
|
||||||
|
/* Determine whether we're prod. */
|
||||||
|
const bool is_prod = fuse::GetHardwareState() != fuse::HardwareState_Development;
|
||||||
|
|
||||||
|
/* Get the ephemeral work block. */
|
||||||
|
u8 * const work_block = se::GetEphemeralWorkBlock();
|
||||||
|
ON_SCOPE_EXIT { util::ClearMemory(work_block, se::AesBlockSize); };
|
||||||
|
|
||||||
|
/* Lock the master key as a key. */
|
||||||
|
se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKey);
|
||||||
|
|
||||||
|
/* Setup a random key to protect the old master and device master keys. */
|
||||||
|
SetupRandomKey(pkg1::AesKeySlot_RandomForKeyStorageWrap, se::KeySlotLockFlags_AllLockKey);
|
||||||
|
|
||||||
|
/* Derive the master keys. */
|
||||||
|
DeriveAllMasterKeys(is_prod, work_block);
|
||||||
|
|
||||||
|
/* Derive the device master keys. */
|
||||||
|
DeriveAllDeviceMasterKeys(is_prod, work_block);
|
||||||
|
|
||||||
|
/* Lock the device master key as a kek. */
|
||||||
|
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMaster, se::KeySlotLockFlags_AllLockKek);
|
||||||
|
|
||||||
|
/* Setup a random key to protect user keys. */
|
||||||
|
SetupRandomKey(pkg1::AesKeySlot_RandomForUserWrap, se::KeySlotLockFlags_AllLockKek);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeKeys() {
|
||||||
|
/* Read lock all aes keys. */
|
||||||
|
for (int i = 0; i < se::AesKeySlotCount; ++i) {
|
||||||
|
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllReadLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the secure monitor aes keys to be secmon only and non-readable. */
|
||||||
|
for (int i = pkg1::AesKeySlot_SecmonStart; i < pkg1::AesKeySlot_SecmonEnd; ++i) {
|
||||||
|
se::LockAesKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the unused keyslots entirely. */
|
||||||
|
static_assert(pkg1::AesKeySlot_UserEnd <= pkg1::AesKeySlot_SecmonStart);
|
||||||
|
for (int i = pkg1::AesKeySlot_UserEnd; i < pkg1::AesKeySlot_SecmonStart; ++i) {
|
||||||
|
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllLockKek);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read lock all rsa keys. */
|
||||||
|
for (int i = 0; i < se::RsaKeySlotCount; ++i) {
|
||||||
|
se::LockRsaKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey | se::KeySlotLockFlags_KeyRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the rng. */
|
||||||
|
se::InitializeRandom();
|
||||||
|
|
||||||
|
/* Derive the master kek and device key. */
|
||||||
|
if constexpr (false) {
|
||||||
|
DeriveMasterKekAndDeviceKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the device key as only usable as a kek. */
|
||||||
|
se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek);
|
||||||
|
|
||||||
|
/* Derive all keys. */
|
||||||
|
DeriveAllKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeColdBoot() {
|
||||||
|
/* Ensure that the system counters are valid. */
|
||||||
|
ValidateSystemCounters();
|
||||||
|
|
||||||
|
/* Set the security engine to Tzram Secure. */
|
||||||
|
se::SetTzramSecure();
|
||||||
|
|
||||||
|
/* Set the security engine to Per Key Secure. */
|
||||||
|
se::SetPerKeySecure();
|
||||||
|
|
||||||
|
/* Setup the PMC registers. */
|
||||||
|
SetupPmcRegisters();
|
||||||
|
|
||||||
|
/* Lockout the scratch that we've just written. */
|
||||||
|
/* pmc::LockSecureRegisters(1); */
|
||||||
|
|
||||||
|
/* Generate a random srk. */
|
||||||
|
se::GenerateSrk();
|
||||||
|
|
||||||
|
/* Initialize the SE keyslots. */
|
||||||
|
InitializeKeys();
|
||||||
|
|
||||||
|
/* Save a test vector for the SE keyslots. */
|
||||||
|
SaveSecurityEngineAesKeySlotTestVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
exosphere2/program/source/boot/secmon_crt0.s
Normal file
37
exosphere2/program/source/boot/secmon_crt0.s
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 .crt0.text.start, "ax", %progbits
|
||||||
|
.align 6
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
/* mask all interrupts */
|
||||||
|
msr daifset, #0xF
|
||||||
|
|
||||||
|
/* Set the stack pointer to a temporary location. */
|
||||||
|
ldr x20, =0x7C010800
|
||||||
|
mov sp, x20
|
||||||
|
|
||||||
|
/* Initialize all memory to expected state. */
|
||||||
|
ldr x0, =__bss_start__
|
||||||
|
ldr x1, =__bss_end__
|
||||||
|
ldr x2, =__boot_bss_start__
|
||||||
|
ldr x3, =__boot_bss_end__
|
||||||
|
bl _ZN3ams6secmon4boot10InitializeEmmmm
|
||||||
|
|
||||||
|
/* Jump to the first bit of virtual code. */
|
||||||
|
ldr x16, =_ZN3ams6secmon5StartEv
|
||||||
|
br x16
|
46
exosphere2/program/source/boot/secmon_crt0_cpp.cpp
Normal file
46
exosphere2/program/source/boot/secmon_crt0_cpp.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_boot.hpp"
|
||||||
|
#include "../secmon_setup.hpp"
|
||||||
|
|
||||||
|
extern "C" void __libc_init_array();
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
void Initialize(uintptr_t bss_start, size_t bss_end, uintptr_t boot_bss_start, uintptr_t boot_bss_end) {
|
||||||
|
/* Set our start time. */
|
||||||
|
auto &secmon_params = *MemoryRegionPhysicalDeviceBootloaderParams.GetPointer<pkg1::SecureMonitorParameters>();
|
||||||
|
secmon_params.secmon_start_time = *reinterpret_cast<volatile u32 *>(MemoryRegionPhysicalDeviceTimer.GetAddress() + 0x10);
|
||||||
|
|
||||||
|
/* Setup DMA controllers. */
|
||||||
|
SetupSocDmaControllers();
|
||||||
|
|
||||||
|
/* Make the page table. */
|
||||||
|
MakePageTable();
|
||||||
|
|
||||||
|
/* Setup memory controllers the MMU. */
|
||||||
|
SetupCpuMemoryControllersEnableMmu();
|
||||||
|
|
||||||
|
/* Clear bss. */
|
||||||
|
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
|
||||||
|
std::memset(reinterpret_cast<void *>(boot_bss_start), 0, boot_bss_end - boot_bss_start);
|
||||||
|
|
||||||
|
/* Call init array. */
|
||||||
|
__libc_init_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
exosphere2/program/source/boot/secmon_key_data.cpp
Normal file
22
exosphere2/program/source/boot/secmon_key_data.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
}
|
69
exosphere2/program/source/boot/secmon_main.cpp
Normal file
69
exosphere2/program/source/boot/secmon_main.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_boot.hpp"
|
||||||
|
#include "secmon_boot_functions.hpp"
|
||||||
|
#include "../secmon_setup.hpp"
|
||||||
|
#include "../secmon_misc.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
void Main() {
|
||||||
|
/* Set library register addresses. */
|
||||||
|
/* actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); */
|
||||||
|
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
|
||||||
|
/* flowctrl::SetRegisterAddress(); */
|
||||||
|
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
|
||||||
|
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
|
||||||
|
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
|
||||||
|
i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress());
|
||||||
|
/* pinmux::SetRegisterAddress(); */
|
||||||
|
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
|
||||||
|
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress());
|
||||||
|
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
|
||||||
|
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||||
|
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
|
||||||
|
|
||||||
|
/* Get the secure monitor parameters. */
|
||||||
|
auto &secmon_params = *reinterpret_cast<pkg1::SecureMonitorParameters *>(MemoryRegionVirtualDeviceBootloaderParams.GetAddress());
|
||||||
|
|
||||||
|
/* Perform initialization. */
|
||||||
|
{
|
||||||
|
/* Perform initial setup. */
|
||||||
|
/* This checks the security engine's validity, and configures common interrupts in the GIC. */
|
||||||
|
/* This also initializes the global configuration context. */
|
||||||
|
secmon::Setup1();
|
||||||
|
|
||||||
|
/* Save the boot info. */
|
||||||
|
secmon::SaveBootInfo(secmon_params);
|
||||||
|
|
||||||
|
/* Perform cold-boot specific init. */
|
||||||
|
secmon::boot::InitializeColdBoot();
|
||||||
|
|
||||||
|
/* Setup the SoC security measures. */
|
||||||
|
secmon::SetupSocSecurity();
|
||||||
|
|
||||||
|
/* TODO: More init. */
|
||||||
|
|
||||||
|
/* Clear the crt0 code that was present in iram. */
|
||||||
|
secmon::boot::ClearIram();
|
||||||
|
|
||||||
|
/* Alert the bootloader that we're initialized. */
|
||||||
|
secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
147
exosphere2/program/source/boot/secmon_make_page_table.cpp
Normal file
147
exosphere2/program/source/boot/secmon_make_page_table.cpp
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_setup.hpp"
|
||||||
|
#include "secmon_boot.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace ams::mmu;
|
||||||
|
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoCode, MemoryAttributeIndexNormal);
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwCode, MemoryAttributeIndexNormal);
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoData, MemoryAttributeIndexNormal);
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexNormal);
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexNormal);
|
||||||
|
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexDevice);
|
||||||
|
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexDevice);
|
||||||
|
|
||||||
|
|
||||||
|
constexpr void ClearMemory(volatile u64 *start, size_t size) {
|
||||||
|
volatile u64 * const end = start + (size / sizeof(u64));
|
||||||
|
|
||||||
|
for (volatile u64 *cur = start; cur < end; ++cur) {
|
||||||
|
*cur = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void MakePageTablesImpl(u64 *l1, u64 *l2, u64 *l3) {
|
||||||
|
/* Setup the L1 table. */
|
||||||
|
{
|
||||||
|
ClearMemory(l1, MemoryRegionPhysicalTzramL1PageTable.GetSize());
|
||||||
|
|
||||||
|
/* Create an L1 table entry for the physical region. */
|
||||||
|
SetL1TableEntry(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
|
||||||
|
static_assert(GetL1EntryIndex(MemoryRegionPhysical.GetAddress()) == 1);
|
||||||
|
|
||||||
|
/* Create an L1 mapping entry for dram. */
|
||||||
|
SetL1BlockEntry(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize(), MappingAttributesEl3NonSecureRwData);
|
||||||
|
|
||||||
|
/* Create an L1 table entry for the virtual region. */
|
||||||
|
SetL1TableEntry(l1, MemoryRegionVirtual.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the L2 table. */
|
||||||
|
{
|
||||||
|
ClearMemory(l2, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
|
||||||
|
|
||||||
|
/* Create an L2 table entry for the virtual region. */
|
||||||
|
SetL2TableEntry(l2, MemoryRegionVirtualL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
|
||||||
|
|
||||||
|
/* Create an L2 table entry for the physical iram region. */
|
||||||
|
SetL2TableEntry(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
|
||||||
|
|
||||||
|
/* Create an L2 table entry for the physical tzram region. */
|
||||||
|
SetL2TableEntry(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the L3 table. */
|
||||||
|
{
|
||||||
|
/* L2 and L3 share a page table. */
|
||||||
|
if (l2 != l3) {
|
||||||
|
ClearMemory(l3, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Identity-map TZRAM as rwx. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||||
|
|
||||||
|
/* Identity-map IRAM boot code as rwx. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||||
|
|
||||||
|
/* Map all devices. */
|
||||||
|
{
|
||||||
|
#define MAP_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualDevice##_NAME_.GetAddress(), MemoryRegionPhysicalDevice##_NAME_.GetAddress(), MemoryRegionVirtualDevice##_NAME_.GetSize(), _SECURE_ ? MappingAttributesEl3SecureDevice : MappingAttributesEl3NonSecureDevice);
|
||||||
|
|
||||||
|
AMS_SECMON_FOREACH_DEVICE_REGION(MAP_DEVICE_REGION);
|
||||||
|
|
||||||
|
#undef MAP_DEVICE_REGION
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the IRAM SC7 work region. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Work.GetAddress(), MemoryRegionPhysicalIramSc7Work.GetAddress(), MemoryRegionVirtualIramSc7Work.GetSize(), MappingAttributesEl3NonSecureDevice);
|
||||||
|
|
||||||
|
/* Map the IRAM SC7 firmware region. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Firmware.GetAddress(), MemoryRegionPhysicalIramSc7Firmware.GetAddress(), MemoryRegionVirtualIramSc7Firmware.GetSize(), MappingAttributesEl3NonSecureDevice);
|
||||||
|
|
||||||
|
/* Map the TZRAM ro alias region. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramReadOnlyAlias.GetAddress(), MemoryRegionPhysicalTzramReadOnlyAlias.GetAddress(), MemoryRegionVirtualTzramReadOnlyAlias.GetSize(), MappingAttributesEl3SecureRoData);
|
||||||
|
|
||||||
|
/* Map the DRAM secure data store region. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualDramSecureDataStore.GetAddress(), MemoryRegionPhysicalDramSecureDataStore.GetAddress(), MemoryRegionVirtualDramSecureDataStore.GetSize(), MappingAttributesEl3NonSecureDevice);
|
||||||
|
|
||||||
|
/* Map the program region as rwx. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramProgram.GetAddress(), MemoryRegionPhysicalTzramProgram.GetAddress(), MemoryRegionVirtualTzramProgram.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||||
|
|
||||||
|
/* Map the boot code region. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramBootCode.GetAddress(), MemoryRegionPhysicalTzramBootCode.GetAddress(), MemoryRegionVirtualTzramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
|
||||||
|
|
||||||
|
/* Map the volatile data regions regions. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileData.GetAddress(), MemoryRegionPhysicalTzramVolatileData.GetAddress(), MemoryRegionVirtualTzramVolatileData.GetSize(), MappingAttributesEl3SecureRwData);
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileStack.GetAddress(), MemoryRegionPhysicalTzramVolatileStack.GetAddress(), MemoryRegionVirtualTzramVolatileStack.GetSize(), MappingAttributesEl3SecureRwData);
|
||||||
|
|
||||||
|
/* Map the configuration data. */
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramConfigurationData.GetAddress(), MemoryRegionPhysicalTzramConfigurationData.GetAddress(), MemoryRegionVirtualTzramConfigurationData.GetSize(), MappingAttributesEl3SecureRwData);
|
||||||
|
|
||||||
|
/* Map the page tables. */
|
||||||
|
SetL3BlockEntry(l3, util::AlignDown(MemoryRegionVirtualTzramL1PageTable.GetAddress(), PageSize), util::AlignDown(MemoryRegionPhysicalTzramL1PageTable.GetAddress(), PageSize), PageSize, MappingAttributesEl3SecureDevice);
|
||||||
|
SetL3BlockEntry(l3, MemoryRegionVirtualTzramL2L3PageTable.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), MemoryRegionVirtualTzramL2L3PageTable.GetSize(), MappingAttributesEl3SecureRwData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool ValidateTzramPageTables() {
|
||||||
|
u64 l1_table[MemoryRegionPhysicalTzramL1PageTable.GetSize() / sizeof(u64)] = {};
|
||||||
|
u64 l2_l3_table[MemoryRegionPhysicalTzramL2L3PageTable.GetSize() / sizeof(u64)] = {};
|
||||||
|
|
||||||
|
MakePageTablesImpl(l1_table, l2_l3_table, l2_l3_table);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(ValidateTzramPageTables());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakePageTable() {
|
||||||
|
u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>();
|
||||||
|
u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer<u64>();
|
||||||
|
MakePageTablesImpl(l1, l2_l3, l2_l3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
exosphere2/program/source/boot/secmon_package2.cpp
Normal file
22
exosphere2/program/source/boot/secmon_package2.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::boot {
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
}
|
26
exosphere2/program/source/boot/secmon_size_data.s
Normal file
26
exosphere2/program/source/boot/secmon_size_data.s
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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 .metadata.sizes, "ax", %progbits
|
||||||
|
.align 6
|
||||||
|
.global __metadata__sizes
|
||||||
|
__metadata__sizes:
|
||||||
|
.quad 0xAAAAAAAAAAAAAAAA, 0xBBBBBBBBBBBBBBBB
|
||||||
|
.quad __glob_start__
|
||||||
|
.quad __bootcode_start__
|
||||||
|
.quad __bootcode_end__
|
||||||
|
.quad __program_start__
|
||||||
|
.quad 0xCCCCCCCCCCCCCCCC, 0xDDDDDDDDDDDDDDDD
|
22
exosphere2/program/source/secmon_cache.inc
Normal file
22
exosphere2/program/source/secmon_cache.inc
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FlushEntireDataCache();
|
||||||
|
void InvalidateEntireDataCache();
|
||||||
|
|
||||||
|
void EnsureMappingConsistency();
|
||||||
|
void EnsureMappingConsistency(uintptr_t address);
|
||||||
|
void EnsureInstructionConsistency();
|
132
exosphere2/program/source/secmon_cache_impl.inc
Normal file
132
exosphere2/program/source/secmon_cache_impl.inc
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
ALWAYS_INLINE int FloorLog2(int v) {
|
||||||
|
return BITSIZEOF(u32) - (hw::CountLeadingZeros(static_cast<u32>(v)) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int CeilLog2(int v) {
|
||||||
|
const int log = FloorLog2(v);
|
||||||
|
return ((1 << log) == v) ? log : log + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushDataCacheTo(int loc) {
|
||||||
|
for (int level = 0; level < loc; ++level) {
|
||||||
|
/* Set the selection register. */
|
||||||
|
{
|
||||||
|
util::BitPack32 csselr = {};
|
||||||
|
csselr.Set<hw::CsselrEl1::InD>(0);
|
||||||
|
csselr.Set<hw::CsselrEl1::Level>(level);
|
||||||
|
HW_CPU_SET_CSSELR_EL1(csselr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that reordering doesn't occur around this operation. */
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
|
||||||
|
/* Get ccsidr. */
|
||||||
|
util::BitPack32 ccsidr;
|
||||||
|
HW_CPU_GET_CCSIDR_EL1(ccsidr);
|
||||||
|
|
||||||
|
/* Get cache size id info. */
|
||||||
|
const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1;
|
||||||
|
const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1;
|
||||||
|
const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4;
|
||||||
|
|
||||||
|
const int way_shift = 32 - FloorLog2(num_ways);
|
||||||
|
const int set_shift = line_size;
|
||||||
|
|
||||||
|
for (int way = 0; way <= num_ways; way++) {
|
||||||
|
for (int set = 0; set <= num_sets; set++) {
|
||||||
|
const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1);
|
||||||
|
__asm__ __volatile__("dc cisw, %[value]" :: [value]"r"(value) : "memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidateDataCacheTo(int loc) {
|
||||||
|
for (int level = 0; level < loc; ++level) {
|
||||||
|
/* Set the selection register. */
|
||||||
|
{
|
||||||
|
util::BitPack32 csselr = {};
|
||||||
|
csselr.Set<hw::CsselrEl1::InD>(0);
|
||||||
|
csselr.Set<hw::CsselrEl1::Level>(level);
|
||||||
|
HW_CPU_SET_CSSELR_EL1(csselr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that reordering doesn't occur around this operation. */
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
|
||||||
|
/* Get ccsidr. */
|
||||||
|
util::BitPack32 ccsidr;
|
||||||
|
HW_CPU_GET_CCSIDR_EL1(ccsidr);
|
||||||
|
|
||||||
|
/* Get cache size id info. */
|
||||||
|
const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1;
|
||||||
|
const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1;
|
||||||
|
const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4;
|
||||||
|
|
||||||
|
const int way_shift = 32 - FloorLog2(num_ways);
|
||||||
|
const int set_shift = line_size;
|
||||||
|
|
||||||
|
for (int way = 0; way <= num_ways; way++) {
|
||||||
|
for (int set = 0; set <= num_sets; set++) {
|
||||||
|
const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1);
|
||||||
|
__asm__ __volatile__("dc isw, %[value]" :: [value]"r"(value) : "memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushEntireDataCache() {
|
||||||
|
util::BitPack32 clidr;
|
||||||
|
HW_CPU_GET_CLIDR_EL1(clidr);
|
||||||
|
FlushDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidateEntireDataCache() {
|
||||||
|
util::BitPack32 clidr;
|
||||||
|
HW_CPU_GET_CLIDR_EL1(clidr);
|
||||||
|
InvalidateDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureMappingConsistency() {
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
::ams::hw::InvalidateEntireTlb();
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
::ams::hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureMappingConsistency(uintptr_t address) {
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
::ams::hw::InvalidateTlb(address);
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
::ams::hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureInstructionConsistency() {
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
::ams::hw::InvalidateEntireInstructionCache();
|
||||||
|
::ams::hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
::ams::hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
192
exosphere2/program/source/secmon_cpu_context.cpp
Normal file
192
exosphere2/program/source/secmon_cpu_context.cpp
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_cpu_context.hpp"
|
||||||
|
#include "secmon_error.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct DebugRegisters {
|
||||||
|
u32 osdttrx_el1;
|
||||||
|
u32 osdtrtx_el1;
|
||||||
|
u32 mdscr_el1;
|
||||||
|
u32 oseccr_el1;
|
||||||
|
u32 mdccint_el1;
|
||||||
|
u32 dbgclaimclr_el1;
|
||||||
|
u32 dbgvcr32_el2;
|
||||||
|
u32 sder32_el3;
|
||||||
|
u32 mdcr_el2;
|
||||||
|
u32 mdcr_el3;
|
||||||
|
u32 spsr_el3;
|
||||||
|
u64 dbgbvcr_el1[12];
|
||||||
|
u64 dbgwvcr_el1[ 8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CoreContext {
|
||||||
|
EntryContext entry_context;
|
||||||
|
bool is_on;
|
||||||
|
bool is_reset_expected;
|
||||||
|
bool is_debug_registers_saved;
|
||||||
|
DebugRegisters debug_registers;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SaveDebugRegisters(DebugRegisters &dr) {
|
||||||
|
/* Set the OS lock; this will be unlocked by entry code. */
|
||||||
|
HW_CPU_SET_OSLAR_EL1(1);
|
||||||
|
|
||||||
|
/* Save general debug registers. */
|
||||||
|
HW_CPU_GET_OSDTRRX_EL1 (dr.osdttrx_el1);
|
||||||
|
HW_CPU_GET_OSDTRTX_EL1 (dr.osdtrtx_el1);
|
||||||
|
HW_CPU_GET_MDSCR_EL1 (dr.mdscr_el1);
|
||||||
|
HW_CPU_GET_OSECCR_EL1 (dr.oseccr_el1);
|
||||||
|
HW_CPU_GET_MDCCINT_EL1 (dr.mdccint_el1);
|
||||||
|
HW_CPU_GET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1);
|
||||||
|
HW_CPU_GET_DBGVCR32_EL2 (dr.dbgvcr32_el2);
|
||||||
|
HW_CPU_GET_SDER32_EL3 (dr.sder32_el3);
|
||||||
|
HW_CPU_GET_MDCR_EL2 (dr.mdcr_el2);
|
||||||
|
HW_CPU_GET_MDCR_EL3 (dr.mdcr_el3);
|
||||||
|
HW_CPU_GET_SPSR_EL3 (dr.spsr_el3);
|
||||||
|
|
||||||
|
/* Save debug breakpoints. */
|
||||||
|
HW_CPU_GET_DBGBVR0_EL1(dr.dbgbvcr_el1[ 0]);
|
||||||
|
HW_CPU_GET_DBGBCR0_EL1(dr.dbgbvcr_el1[ 1]);
|
||||||
|
HW_CPU_GET_DBGBVR1_EL1(dr.dbgbvcr_el1[ 2]);
|
||||||
|
HW_CPU_GET_DBGBCR1_EL1(dr.dbgbvcr_el1[ 3]);
|
||||||
|
HW_CPU_GET_DBGBVR2_EL1(dr.dbgbvcr_el1[ 4]);
|
||||||
|
HW_CPU_GET_DBGBCR2_EL1(dr.dbgbvcr_el1[ 5]);
|
||||||
|
HW_CPU_GET_DBGBVR3_EL1(dr.dbgbvcr_el1[ 6]);
|
||||||
|
HW_CPU_GET_DBGBCR3_EL1(dr.dbgbvcr_el1[ 7]);
|
||||||
|
HW_CPU_GET_DBGBVR4_EL1(dr.dbgbvcr_el1[ 8]);
|
||||||
|
HW_CPU_GET_DBGBCR4_EL1(dr.dbgbvcr_el1[ 9]);
|
||||||
|
HW_CPU_GET_DBGBVR5_EL1(dr.dbgbvcr_el1[10]);
|
||||||
|
HW_CPU_GET_DBGBCR5_EL1(dr.dbgbvcr_el1[11]);
|
||||||
|
|
||||||
|
/* Save debug watchpoints. */
|
||||||
|
HW_CPU_GET_DBGWVR0_EL1(dr.dbgwvcr_el1[0]);
|
||||||
|
HW_CPU_GET_DBGWCR0_EL1(dr.dbgwvcr_el1[1]);
|
||||||
|
HW_CPU_GET_DBGWVR1_EL1(dr.dbgwvcr_el1[2]);
|
||||||
|
HW_CPU_GET_DBGWCR1_EL1(dr.dbgwvcr_el1[3]);
|
||||||
|
HW_CPU_GET_DBGWVR2_EL1(dr.dbgwvcr_el1[4]);
|
||||||
|
HW_CPU_GET_DBGWCR2_EL1(dr.dbgwvcr_el1[5]);
|
||||||
|
HW_CPU_GET_DBGWVR3_EL1(dr.dbgwvcr_el1[6]);
|
||||||
|
HW_CPU_GET_DBGWCR3_EL1(dr.dbgwvcr_el1[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestoreDebugRegisters(const DebugRegisters &dr) {
|
||||||
|
/* Restore general debug registers. */
|
||||||
|
HW_CPU_SET_OSDTRRX_EL1 (dr.osdttrx_el1);
|
||||||
|
HW_CPU_SET_OSDTRTX_EL1 (dr.osdtrtx_el1);
|
||||||
|
HW_CPU_SET_MDSCR_EL1 (dr.mdscr_el1);
|
||||||
|
HW_CPU_SET_OSECCR_EL1 (dr.oseccr_el1);
|
||||||
|
HW_CPU_SET_MDCCINT_EL1 (dr.mdccint_el1);
|
||||||
|
HW_CPU_SET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1);
|
||||||
|
HW_CPU_SET_DBGVCR32_EL2 (dr.dbgvcr32_el2);
|
||||||
|
HW_CPU_SET_SDER32_EL3 (dr.sder32_el3);
|
||||||
|
HW_CPU_SET_MDCR_EL2 (dr.mdcr_el2);
|
||||||
|
HW_CPU_SET_MDCR_EL3 (dr.mdcr_el3);
|
||||||
|
HW_CPU_SET_SPSR_EL3 (dr.spsr_el3);
|
||||||
|
|
||||||
|
/* Restore debug breakpoints. */
|
||||||
|
HW_CPU_SET_DBGBVR0_EL1(dr.dbgbvcr_el1[ 0]);
|
||||||
|
HW_CPU_SET_DBGBCR0_EL1(dr.dbgbvcr_el1[ 1]);
|
||||||
|
HW_CPU_SET_DBGBVR1_EL1(dr.dbgbvcr_el1[ 2]);
|
||||||
|
HW_CPU_SET_DBGBCR1_EL1(dr.dbgbvcr_el1[ 3]);
|
||||||
|
HW_CPU_SET_DBGBVR2_EL1(dr.dbgbvcr_el1[ 4]);
|
||||||
|
HW_CPU_SET_DBGBCR2_EL1(dr.dbgbvcr_el1[ 5]);
|
||||||
|
HW_CPU_SET_DBGBVR3_EL1(dr.dbgbvcr_el1[ 6]);
|
||||||
|
HW_CPU_SET_DBGBCR3_EL1(dr.dbgbvcr_el1[ 7]);
|
||||||
|
HW_CPU_SET_DBGBVR4_EL1(dr.dbgbvcr_el1[ 8]);
|
||||||
|
HW_CPU_SET_DBGBCR4_EL1(dr.dbgbvcr_el1[ 9]);
|
||||||
|
HW_CPU_SET_DBGBVR5_EL1(dr.dbgbvcr_el1[10]);
|
||||||
|
HW_CPU_SET_DBGBCR5_EL1(dr.dbgbvcr_el1[11]);
|
||||||
|
|
||||||
|
/* Restore debug watchpoints. */
|
||||||
|
HW_CPU_SET_DBGWVR0_EL1(dr.dbgwvcr_el1[0]);
|
||||||
|
HW_CPU_SET_DBGWCR0_EL1(dr.dbgwvcr_el1[1]);
|
||||||
|
HW_CPU_SET_DBGWVR1_EL1(dr.dbgwvcr_el1[2]);
|
||||||
|
HW_CPU_SET_DBGWCR1_EL1(dr.dbgwvcr_el1[3]);
|
||||||
|
HW_CPU_SET_DBGWVR2_EL1(dr.dbgwvcr_el1[4]);
|
||||||
|
HW_CPU_SET_DBGWCR2_EL1(dr.dbgwvcr_el1[5]);
|
||||||
|
HW_CPU_SET_DBGWVR3_EL1(dr.dbgwvcr_el1[6]);
|
||||||
|
HW_CPU_SET_DBGWCR3_EL1(dr.dbgwvcr_el1[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
constinit CoreContext g_core_contexts[NumCores] = {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCoreOn(int core) {
|
||||||
|
return g_core_contexts[core].is_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCoreOff() {
|
||||||
|
g_core_contexts[hw::GetCurrentCoreId()].is_on = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsResetExpected() {
|
||||||
|
return g_core_contexts[hw::GetCurrentCoreId()].is_reset_expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetResetExpected(int core, bool expected) {
|
||||||
|
g_core_contexts[core].is_reset_expected = expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetResetExpected(bool expected) {
|
||||||
|
SetResetExpected(hw::GetCurrentCoreId(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEntryContext(int core, uintptr_t address, uintptr_t arg) {
|
||||||
|
g_core_contexts[core].entry_context.pc = address;
|
||||||
|
g_core_contexts[core].entry_context.x0 = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetEntryContext(EntryContext *out) {
|
||||||
|
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
|
||||||
|
|
||||||
|
const auto pc = ctx.entry_context.pc;
|
||||||
|
const auto x0 = ctx.entry_context.x0;
|
||||||
|
|
||||||
|
if (pc == 0 || ctx.is_on) {
|
||||||
|
SetError(pkg1::ErrorInfo_InvalidCoreContext);
|
||||||
|
AMS_ABORT("Invalid core context");
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.entry_context = {};
|
||||||
|
ctx.is_on = true;
|
||||||
|
|
||||||
|
out->pc = pc;
|
||||||
|
out->x0 = x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveDebugRegisters() {
|
||||||
|
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
|
||||||
|
|
||||||
|
SaveDebugRegisters(ctx.debug_registers);
|
||||||
|
ctx.is_debug_registers_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestoreDebugRegisters() {
|
||||||
|
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
|
||||||
|
|
||||||
|
if (ctx.is_debug_registers_saved) {
|
||||||
|
RestoreDebugRegisters(ctx.debug_registers);
|
||||||
|
ctx.is_debug_registers_saved = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
exosphere2/program/source/secmon_cpu_context.hpp
Normal file
41
exosphere2/program/source/secmon_cpu_context.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
constexpr inline int NumCores = 4;
|
||||||
|
|
||||||
|
struct EntryContext {
|
||||||
|
u64 x0;
|
||||||
|
u64 pc;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool IsCoreOn(int core);
|
||||||
|
void SetCoreOff();
|
||||||
|
|
||||||
|
bool IsResetExpected();
|
||||||
|
void SetResetExpected(int core, bool expected);
|
||||||
|
void SetResetExpected(bool expected);
|
||||||
|
|
||||||
|
void SetEntryContext(int core, uintptr_t address, uintptr_t arg);
|
||||||
|
void GetEntryContext(EntryContext *out);
|
||||||
|
|
||||||
|
void SaveDebugRegisters();
|
||||||
|
void RestoreDebugRegisters();
|
||||||
|
|
||||||
|
}
|
51
exosphere2/program/source/secmon_error.cpp
Normal file
51
exosphere2/program/source/secmon_error.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_error.hpp"
|
||||||
|
|
||||||
|
namespace ams::diag {
|
||||||
|
|
||||||
|
void AbortImpl() {
|
||||||
|
secmon::SetError(pkg1::ErrorInfo_UnknownAbort);
|
||||||
|
secmon::ErrorReboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
void SetError(pkg1::ErrorInfo info) {
|
||||||
|
const uintptr_t address = secmon::MemoryRegionVirtualDevicePmc.GetAddress() + PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH;
|
||||||
|
|
||||||
|
if (reg::Read(address) == pkg1::ErrorInfo_None) {
|
||||||
|
reg::Write(address, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void ErrorReboot() {
|
||||||
|
/* Lockout the security engine. */
|
||||||
|
se::Lockout();
|
||||||
|
|
||||||
|
/* TODO: Lockout fuses. */
|
||||||
|
|
||||||
|
/* TODO: Disable SE Crypto Operations. */
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
wdt::Reboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere2/program/source/secmon_error.hpp
Normal file
24
exosphere2/program/source/secmon_error.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
void SetError(pkg1::ErrorInfo info);
|
||||||
|
NORETURN void ErrorReboot();
|
||||||
|
|
||||||
|
}
|
326
exosphere2/program/source/secmon_exception_vectors.s
Normal file
326
exosphere2/program/source/secmon_exception_vectors.s
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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 Secure Monitor. */
|
||||||
|
.global _ZN3ams6secmon16ExceptionVectorsEv
|
||||||
|
vector_base _ZN3ams6secmon16ExceptionVectorsEv
|
||||||
|
|
||||||
|
/* Current EL, SP0 */
|
||||||
|
vector_entry synch_sp0
|
||||||
|
/* Branch to the exception handler. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
_ZN3ams6secmon26UnexpectedExceptionHandlerEv:
|
||||||
|
/* Load the ErrorInfo scratch. */
|
||||||
|
ldr x0, =0x1F004AC40
|
||||||
|
|
||||||
|
/* Write ErrorInfo_UnknownAbort to it. */
|
||||||
|
ldr w1, =0x07F00010
|
||||||
|
str w1, [x0]
|
||||||
|
|
||||||
|
/* Perform an error reboot. */
|
||||||
|
b _ZN3ams6secmon11ErrorRebootEv
|
||||||
|
|
||||||
|
vector_entry irq_sp0
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size irq_sp0
|
||||||
|
|
||||||
|
vector_entry fiq_sp0
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size fiq_sp0
|
||||||
|
|
||||||
|
vector_entry serror_sp0
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size serror_sp0
|
||||||
|
|
||||||
|
/* Current EL, SPx */
|
||||||
|
vector_entry synch_spx
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size synch_spx
|
||||||
|
|
||||||
|
vector_entry irq_spx
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size irq_spx
|
||||||
|
|
||||||
|
vector_entry fiq_spx
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size fiq_spx
|
||||||
|
|
||||||
|
vector_entry serror_spx
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size serror_spx
|
||||||
|
|
||||||
|
/* Lower EL, A64 */
|
||||||
|
vector_entry synch_a64
|
||||||
|
/* Check whether the exception is an SMC. If it's not, take the unexpected handler. */
|
||||||
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
mrs x30, esr_el3
|
||||||
|
lsr w29, w30, #26
|
||||||
|
cmp w29, #0x17
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
|
||||||
|
/* Save x29 and x30. */
|
||||||
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
|
||||||
|
/* Get the current core. */
|
||||||
|
mrs x29, mpidr_el1
|
||||||
|
and x29, x29, #3
|
||||||
|
|
||||||
|
/* If we're not on core 3, take the core0-2 handler. */
|
||||||
|
cmp x29, #3
|
||||||
|
b.ne _ZN3ams6secmon25HandleSmcExceptionCore012Ev
|
||||||
|
|
||||||
|
/* Handle the smc. */
|
||||||
|
bl _ZN3ams6secmon18HandleSmcExceptionEv
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
eret
|
||||||
|
check_vector_size synch_a64
|
||||||
|
|
||||||
|
vector_entry irq_a64
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size irq_a64
|
||||||
|
|
||||||
|
vector_entry fiq_a64
|
||||||
|
/* Save X29, X30. */
|
||||||
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
|
||||||
|
/* Get the current core ID, ensure it's core 3. */
|
||||||
|
mrs x29, mpidr_el1
|
||||||
|
and x29, x29, #3
|
||||||
|
cmp x29, #3
|
||||||
|
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
|
||||||
|
/* Save x26-x28, x18. */
|
||||||
|
stp x28, x18, [sp, #-0x10]!
|
||||||
|
stp x26, x27, [sp, #-0x10]!
|
||||||
|
|
||||||
|
/* Set x18 to the global data region. */
|
||||||
|
ldr x18, =0x1F01FA000
|
||||||
|
|
||||||
|
/* Handle the fiq exception. */
|
||||||
|
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
||||||
|
|
||||||
|
/* Restore registers. */
|
||||||
|
ldp x26, x27, [sp], #0x10
|
||||||
|
ldp x28, x18, [sp], #0x10
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
eret
|
||||||
|
check_vector_size fiq_a64
|
||||||
|
|
||||||
|
vector_entry serror_a64
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
_ZN3ams6secmon25HandleSmcExceptionCore012Ev:
|
||||||
|
/* Acquire exclusive access to the common smc stack. */
|
||||||
|
stp x4, x5, [sp, #-0x10]!
|
||||||
|
stp x2, x3, [sp, #-0x10]!
|
||||||
|
stp x0, x1, [sp, #-0x10]!
|
||||||
|
bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv
|
||||||
|
ldp x0, x1, [sp], #0x10
|
||||||
|
ldp x2, x3, [sp], #0x10
|
||||||
|
ldp x4, x5, [sp], #0x10
|
||||||
|
|
||||||
|
/* Pivot to use the common smc stack. */
|
||||||
|
mov x30, sp
|
||||||
|
ldr x29, =0x1F01F6E80
|
||||||
|
mov sp, x29
|
||||||
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
|
||||||
|
/* Handle the SMC. */
|
||||||
|
bl _ZN3ams6secmon18HandleSmcExceptionEv
|
||||||
|
|
||||||
|
/* Restore our core-specific stack. */
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
mov x30, sp
|
||||||
|
|
||||||
|
/* Release our exclusive access to the common smc stack. */
|
||||||
|
stp x0, x1, [sp, #-0x10]!
|
||||||
|
bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
|
||||||
|
ldp x0, x1, [sp], #0x10
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
eret
|
||||||
|
|
||||||
|
/* Lower EL, A32 */
|
||||||
|
vector_entry synch_a32
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size synch_a32
|
||||||
|
|
||||||
|
vector_entry irq_a32
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
_ZN3ams6secmon18HandleSmcExceptionEv:
|
||||||
|
/* Save registers. */
|
||||||
|
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]!
|
||||||
|
|
||||||
|
/* Set x18 to the global data region. */
|
||||||
|
ldr x18, =0x1F01FA000
|
||||||
|
|
||||||
|
/* Get esr. */
|
||||||
|
mrs x0, esr_el3
|
||||||
|
and x0, x0, #0xFFFF
|
||||||
|
|
||||||
|
/* Get the function arguments. */
|
||||||
|
mov x1, sp
|
||||||
|
|
||||||
|
/* Invoke the smc handler. */
|
||||||
|
bl _ZN3ams6secmon3smc9HandleSmcEiRNS1_12SmcArgumentsE
|
||||||
|
|
||||||
|
/* Restore registers. */
|
||||||
|
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
|
||||||
|
vector_entry fiq_a32
|
||||||
|
/* Handle fiq from a32 the same as fiq from a64. */
|
||||||
|
b fiq_a64
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
_ZN3ams6secmon18HandleFiqExceptionEv:
|
||||||
|
/* Save registers. */
|
||||||
|
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]!
|
||||||
|
|
||||||
|
/* Invoke the interrupt handler. */
|
||||||
|
bl _ZN3ams6secmon15HandleInterruptEv
|
||||||
|
|
||||||
|
/* Restore registers. */
|
||||||
|
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
|
||||||
|
/* An unexpected exception was taken. */
|
||||||
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
|
check_vector_size serror_a32
|
||||||
|
|
||||||
|
/* Instantiate the literal pool for the exception vectors. */
|
||||||
|
.ltorg
|
64
exosphere2/program/source/secmon_interrupt_handler.cpp
Normal file
64
exosphere2/program/source/secmon_interrupt_handler.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_interrupt_handler.hpp"
|
||||||
|
#include "secmon_error.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline int InterruptHandlersMax = 4;
|
||||||
|
|
||||||
|
constinit InterruptHandler g_handlers[InterruptHandlersMax] = {};
|
||||||
|
constinit int g_interrupt_ids[InterruptHandlersMax] = {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInterruptHandler(int interrupt_id, InterruptHandler handler) {
|
||||||
|
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||||
|
if (g_interrupt_ids[i] == 0) {
|
||||||
|
g_interrupt_ids[i] = interrupt_id;
|
||||||
|
g_handlers[i] = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AMS_ABORT("Failed to register interrupt handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleInterrupt() {
|
||||||
|
/* Get the interrupt id. */
|
||||||
|
const int interrupt_id = gic::GetInterruptRequestId();
|
||||||
|
if (interrupt_id >= gic::InterruptCount) {
|
||||||
|
/* Invalid interrupt number, just return. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check each handler. */
|
||||||
|
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||||
|
if (g_interrupt_ids[i] == interrupt_id) {
|
||||||
|
/* Invoke the handler. */
|
||||||
|
g_handlers[i]();
|
||||||
|
gic::SetEndOfInterrupt(interrupt_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AMS_ABORT("Failed to find interrupt handler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
exosphere2/program/source/secmon_interrupt_handler.hpp
Normal file
25
exosphere2/program/source/secmon_interrupt_handler.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
using InterruptHandler = void (*)();
|
||||||
|
|
||||||
|
void SetInterruptHandler(int interrupt_id, InterruptHandler handler);
|
||||||
|
|
||||||
|
}
|
103
exosphere2/program/source/secmon_key_storage.cpp
Normal file
103
exosphere2/program/source/secmon_key_storage.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_key_storage.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constinit u8 g_rsa_moduli[ImportRsaKey_Count][se::RsaSize] = {};
|
||||||
|
constinit bool g_rsa_modulus_committed[ImportRsaKey_Count] = {};
|
||||||
|
|
||||||
|
ALWAYS_INLINE u8 *GetRsaKeyModulus(ImportRsaKey which) {
|
||||||
|
return g_rsa_moduli[which];
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u8 *GetRsaKeyPrivateExponent(ImportRsaKey which) {
|
||||||
|
return ::ams::secmon::impl::GetRsaPrivateExponentStorage(static_cast<int>(which));
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE bool IsRsaKeyProvisional(ImportRsaKey which) {
|
||||||
|
return g_rsa_modulus_committed[which] == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearRsaKeyModulus(ImportRsaKey which) {
|
||||||
|
g_rsa_modulus_committed[which] = false;
|
||||||
|
std::memset(g_rsa_moduli[which], 0, se::RsaSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u8 *GetMasterKeyStorage(int index) {
|
||||||
|
return ::ams::secmon::impl::GetMasterKeyStorage(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int index) {
|
||||||
|
return ::ams::secmon::impl::GetDeviceMasterKeyStorage(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size) {
|
||||||
|
/* If we import an exponent, the modulus is not committed. */
|
||||||
|
ClearRsaKeyModulus(which);
|
||||||
|
|
||||||
|
/* Copy the exponent. */
|
||||||
|
std::memcpy(GetRsaKeyPrivateExponent(which), src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size) {
|
||||||
|
std::memcpy(GetRsaKeyModulus(which), src, std::min(static_cast<int>(size), se::RsaSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommitRsaKeyModulus(ImportRsaKey which) {
|
||||||
|
g_rsa_modulus_committed[which] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadRsaKey(int slot, ImportRsaKey which) {
|
||||||
|
/* If the key is still provisional, we can't load it. */
|
||||||
|
if (IsRsaKeyProvisional(which)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadProvisionalRsaKey(int slot, ImportRsaKey which) {
|
||||||
|
se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMasterKey(int generation, const void *src, size_t size) {
|
||||||
|
const int index = generation - pkg1::KeyGeneration_Min;
|
||||||
|
se::EncryptAes128(GetMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadMasterKey(int slot, int generation) {
|
||||||
|
const int index = std::min(0, generation - pkg1::KeyGeneration_Min);
|
||||||
|
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetMasterKeyStorage(index), se::AesBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDeviceMasterKey(int generation, const void *src, size_t size) {
|
||||||
|
const int index = generation - pkg1::KeyGeneration_4_0_0;
|
||||||
|
se::EncryptAes128(GetDeviceMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadDeviceMasterKey(int slot, int generation) {
|
||||||
|
const int index = std::min(0, generation - pkg1::KeyGeneration_4_0_0);
|
||||||
|
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetDeviceMasterKeyStorage(index), se::AesBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
exosphere2/program/source/secmon_key_storage.hpp
Normal file
44
exosphere2/program/source/secmon_key_storage.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
enum ImportRsaKey {
|
||||||
|
ImportRsaKey_EsDrmCert = 0,
|
||||||
|
ImportRsaKey_Lotus = 1,
|
||||||
|
ImportRsaKey_Ssl = 2,
|
||||||
|
ImportRsaKey_EsClientCert = 3,
|
||||||
|
|
||||||
|
ImportRsaKey_Count = 4,
|
||||||
|
};
|
||||||
|
static_assert(util::size(secmon::ConfigurationContext{}.rsa_private_exponents) == ImportRsaKey_Count);
|
||||||
|
|
||||||
|
void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size);
|
||||||
|
void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size);
|
||||||
|
void CommitRsaKeyModulus(ImportRsaKey which);
|
||||||
|
|
||||||
|
bool LoadRsaKey(int slot, ImportRsaKey which);
|
||||||
|
void LoadProvisionalRsaKey(int slot, ImportRsaKey which);
|
||||||
|
|
||||||
|
void SetMasterKey(int generation, const void *src, size_t size);
|
||||||
|
void LoadMasterKey(int slot, int generation);
|
||||||
|
|
||||||
|
void SetDeviceMasterKey(int generation, const void *src, size_t size);
|
||||||
|
void LoadDeviceMasterKey(int slot, int generation);
|
||||||
|
|
||||||
|
}
|
46
exosphere2/program/source/secmon_misc.cpp
Normal file
46
exosphere2/program/source/secmon_misc.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_misc.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
pkg1::BctParameters g_bct_params;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params) {
|
||||||
|
/* Save the BCT parameters. */
|
||||||
|
g_bct_params = secmon_params.bct_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRecoveryBoot() {
|
||||||
|
return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RecoveryBoot) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetRestrictedSmcMask() {
|
||||||
|
return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RestrictedSmcMask) >> pkg1::BootloaderAttribute_RestrictedSmcShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsJtagEnabled() {
|
||||||
|
util::BitPack32 dbg_auth;
|
||||||
|
HW_CPU_GET_DBGAUTHSTATUS_EL1(dbg_auth);
|
||||||
|
return dbg_auth.Get<hw::DbgAuthStatusEl1::Nsid>() == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
exosphere2/program/source/secmon_misc.hpp
Normal file
29
exosphere2/program/source/secmon_misc.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params);
|
||||||
|
|
||||||
|
bool IsRecoveryBoot();
|
||||||
|
|
||||||
|
u32 GetRestrictedSmcMask();
|
||||||
|
|
||||||
|
bool IsJtagEnabled();
|
||||||
|
|
||||||
|
}
|
750
exosphere2/program/source/secmon_setup.cpp
Normal file
750
exosphere2/program/source/secmon_setup.cpp
Normal file
|
@ -0,0 +1,750 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_setup.hpp"
|
||||||
|
#include "secmon_error.hpp"
|
||||||
|
#include "secmon_cpu_context.hpp"
|
||||||
|
#include "secmon_interrupt_handler.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const uintptr_t TIMER = secmon::MemoryRegionVirtualDeviceTimer.GetAddress();
|
||||||
|
constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress();
|
||||||
|
constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionVirtualDeviceFlowController.GetAddress();
|
||||||
|
constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc.GetAddress();
|
||||||
|
constexpr inline const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
|
||||||
|
|
||||||
|
alignas(8) constinit u8 g_se_aes_key_slot_test_vector[se::AesBlockSize] = {};
|
||||||
|
|
||||||
|
struct Carveout {
|
||||||
|
uintptr_t address;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit Carveout g_kernel_carveouts[KernelCarveoutCount] = {
|
||||||
|
{ secmon::MemoryRegionDramDefaultKernelCarveout.GetAddress(), secmon::MemoryRegionDramDefaultKernelCarveout.GetSize(), },
|
||||||
|
{ 0, 0, },
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit bool g_is_cold_boot = true;
|
||||||
|
|
||||||
|
constinit const se::StickyBits ExpectedSeStickyBits = {
|
||||||
|
.se_security = (1 << 0), /* SE_HARD_SETTING */
|
||||||
|
.tzram_security = 0,
|
||||||
|
.crypto_security_perkey = 0,
|
||||||
|
.crypto_keytable_access = {
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 6: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 7: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 14: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
|
||||||
|
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
|
||||||
|
},
|
||||||
|
.rsa_security_perkey = 0,
|
||||||
|
.rsa_keytable_access = {
|
||||||
|
(0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
|
||||||
|
(0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitializeConfigurationContext() {
|
||||||
|
/* Get the global context. */
|
||||||
|
auto &ctx = ::ams::secmon::impl::GetConfigurationContext();
|
||||||
|
|
||||||
|
/* Clear the context to zero. */
|
||||||
|
std::memset(std::addressof(ctx), 0, sizeof(ctx));
|
||||||
|
|
||||||
|
/* If the storage context is valid, we want to copy it to the global context. */
|
||||||
|
if (const auto &storage_ctx = *MemoryRegionPhysicalDramMonitorConfiguration.GetPointer<const SecureMonitorStorageConfiguration>(); storage_ctx.IsValid()) {
|
||||||
|
ctx.secmon_cfg.CopyFrom(storage_ctx);
|
||||||
|
ctx.emummc_cfg = storage_ctx.emummc_cfg;
|
||||||
|
} else {
|
||||||
|
/* If we don't have a valid storage context, we can just use the default one. */
|
||||||
|
ctx.secmon_cfg = DefaultSecureMonitorConfiguration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateSecurityEngineAesKeySlotTestVector(void *dst, size_t size) {
|
||||||
|
/* Clear the output. */
|
||||||
|
AMS_ABORT_UNLESS(size == se::AesBlockSize);
|
||||||
|
std::memset(dst, 0, se::AesBlockSize);
|
||||||
|
|
||||||
|
/* Ensure output is seen as cleared by the se. */
|
||||||
|
hw::FlushDataCache(dst, se::AesBlockSize);
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Declare a block. */
|
||||||
|
alignas(8) u8 empty_block[se::AesBlockSize];
|
||||||
|
|
||||||
|
/* Iteratively transform an empty block. */
|
||||||
|
#define TRANSFORM_WITH_KEY(key) \
|
||||||
|
__builtin_memset(empty_block, 0, sizeof(empty_block)); \
|
||||||
|
se::SetEncryptedAesKey256(pkg1::AesKeySlot_Temporary, key, empty_block, sizeof(empty_block)); \
|
||||||
|
se::DecryptAes128(dst, se::AesBlockSize, pkg1::AesKeySlot_Temporary, dst, se::AesBlockSize)
|
||||||
|
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
|
||||||
|
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
|
||||||
|
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
|
||||||
|
|
||||||
|
/* Ensure output is seen correctly by the cpu. */
|
||||||
|
hw::FlushDataCache(dst, se::AesBlockSize);
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Clear the temporary key slot. */
|
||||||
|
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifySecurityEngineStickyBits() {
|
||||||
|
if (!se::ValidateStickyBits(ExpectedSeStickyBits)) {
|
||||||
|
SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits);
|
||||||
|
AMS_ABORT("Invalid sticky bits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifySecurityEngineAesKeySlotTestVector() {
|
||||||
|
alignas(8) u8 test_vector[se::AesBlockSize];
|
||||||
|
GenerateSecurityEngineAesKeySlotTestVector(test_vector, sizeof(test_vector));
|
||||||
|
|
||||||
|
AMS_ABORT_UNLESS(crypto::IsSameBytes(g_se_aes_key_slot_test_vector, test_vector, se::AesBlockSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearAesKeySlots() {
|
||||||
|
/* Clear all non-secure monitor keys. */
|
||||||
|
for (int i = 0; i < pkg1::AesKeySlot_SecmonStart; ++i) {
|
||||||
|
se::ClearAesKeySlot(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the secure-monitor temporary keys. */
|
||||||
|
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
|
||||||
|
se::ClearAesKeySlot(pkg1::AesKeySlot_Smc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearRsaKeySlots() {
|
||||||
|
/* Clear all rsa keyslots. */
|
||||||
|
for (int i = 0; i < se::RsaKeySlotCount; ++i) {
|
||||||
|
se::ClearRsaKeySlot(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupKernelCarveouts() {
|
||||||
|
#define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE)
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess0 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, PTCR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0A),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0AB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0B),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0BB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0C),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0CB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, AFIR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHC),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHCB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, HDAR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, HOST1XDMAR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, HOST1XR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, NVENCSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBDMAR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess1 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, MPCORER),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, NVENCSWR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, AFIW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, HDAW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, HOST1XW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, MPCOREW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBDMAW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBSLVW));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess2 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess2_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, TSECSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(2, TSECSWR));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess3 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, APER),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, APEW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess3_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVDECSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVDECSWR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, APER),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, APEW),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess4 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(4, SESWR));
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess4_800 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(4, SESWR),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(4, TSECRDB),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(4, TSECWRB));
|
||||||
|
|
||||||
|
|
||||||
|
constexpr u32 ClientAccess4_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
|
||||||
|
MC_ENABLE_CLIENT_ACCESS(4, SESWR));
|
||||||
|
|
||||||
|
#undef MC_ENABLE_CLIENT_ACCESS
|
||||||
|
|
||||||
|
constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE));
|
||||||
|
constexpr u32 ForceInternalAccess0_100 = 0;
|
||||||
|
|
||||||
|
constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE));
|
||||||
|
constexpr u32 ForceInternalAccess1_100 = 0;
|
||||||
|
|
||||||
|
constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE));
|
||||||
|
|
||||||
|
constexpr u32 CarveoutConfig_100 = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE));
|
||||||
|
|
||||||
|
const u32 target_fw = GetTargetFirmware();
|
||||||
|
u32 client_access_2;
|
||||||
|
u32 client_access_3;
|
||||||
|
u32 client_access_4;
|
||||||
|
u32 carveout_config;
|
||||||
|
if (target_fw >= TargetFirmware_8_1_0) {
|
||||||
|
client_access_2 = ClientAccess2;
|
||||||
|
client_access_3 = ClientAccess3;
|
||||||
|
client_access_4 = ClientAccess4;
|
||||||
|
carveout_config = CarveoutConfig;
|
||||||
|
} else if (target_fw >= TargetFirmware_8_0_0) {
|
||||||
|
client_access_2 = ClientAccess2;
|
||||||
|
client_access_3 = ClientAccess3;
|
||||||
|
client_access_4 = ClientAccess4_800;
|
||||||
|
carveout_config = CarveoutConfig;
|
||||||
|
} else {
|
||||||
|
client_access_2 = ClientAccess2_100;
|
||||||
|
client_access_3 = ClientAccess3_100;
|
||||||
|
client_access_4 = ClientAccess4_100;
|
||||||
|
carveout_config = CarveoutConfig_100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure carveout 4. */
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, g_kernel_carveouts[0].address >> 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, g_kernel_carveouts[0].address >> 32);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, g_kernel_carveouts[0].size / 128_KB);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, ClientAccess0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, ClientAccess1);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, client_access_2);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, client_access_3);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, client_access_4);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess0 : ForceInternalAccess0_100);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess1 : ForceInternalAccess1_100);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, carveout_config);
|
||||||
|
|
||||||
|
/* Configure carveout 5. */
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM, g_kernel_carveouts[0].address >> 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM_HI, g_kernel_carveouts[0].address >> 32);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_SIZE_128KB, g_kernel_carveouts[0].size / 128_KB);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0, ClientAccess0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1, ClientAccess1);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2, client_access_2);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3, client_access_3);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4, client_access_4);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT5_CFG0, carveout_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureSlaveSecurity() {
|
||||||
|
u32 reg0, reg1, reg2;
|
||||||
|
if (GetTargetFirmware() > TargetFirmware_1_0_0) {
|
||||||
|
reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, SE, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE));
|
||||||
|
|
||||||
|
reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
|
||||||
|
|
||||||
|
reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC3, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(2, DP2, ENABLE));
|
||||||
|
|
||||||
|
const auto hw_type = fuse::GetHardwareType();
|
||||||
|
|
||||||
|
/* Switch Lite can't use HDMI, so set CEC to secure on hoag. */
|
||||||
|
if (hw_type == fuse::HardwareType_Hoag) {
|
||||||
|
reg0 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, CEC, ENABLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icosa, Iowa, and Five all set I2C4 to be secure. */
|
||||||
|
if (hw_type == fuse::HardwareType_Icosa && hw_type == fuse::HardwareType_Iowa && hw_type == fuse::HardwareType_Five) {
|
||||||
|
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, I2C4, ENABLE));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hoag additionally sets UART_B to secure. */
|
||||||
|
if (hw_type == fuse::HardwareType_Hoag) {
|
||||||
|
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copper and Calcio lack a lot of hardware, so set the corresponding registers to secure for them. */
|
||||||
|
if (hw_type == fuse::HardwareType_Calcio || hw_type == fuse::HardwareType_Copper) {
|
||||||
|
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, UART_C, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI4, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C2, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C3, ENABLE));
|
||||||
|
|
||||||
|
/* Copper/Calcio have no gamecard reader, and thus set SDMMC2 as secure. */
|
||||||
|
reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC2, ENABLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mariko hardware types (not Icosa or Copper) additionally set mariko-only mmio (SE2, PKA1, FEK) as secure. */
|
||||||
|
if (hw_type != fuse::HardwareType_Icosa && hw_type != fuse::HardwareType_Copper) {
|
||||||
|
reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SE2, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(2, PKA1, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(2, FEK, ENABLE));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE));
|
||||||
|
|
||||||
|
reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
|
||||||
|
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
|
||||||
|
|
||||||
|
reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE),
|
||||||
|
REG_BITS_VALUE(5, 1, 1), /* Note: Bit 5 is not documented in TRM. */
|
||||||
|
REG_BITS_VALUE(4, 1, 1)); /* Note: Bit 4 is not documented in TRM. */
|
||||||
|
}
|
||||||
|
|
||||||
|
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, reg0);
|
||||||
|
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, reg1);
|
||||||
|
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0, reg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSecureRegisters() {
|
||||||
|
/* Configure timers 5-8 and watchdog timers 0-3 as secure. */
|
||||||
|
reg::Write(TIMER + TIMER_SHARED_TIMER_SECURE_CFG, TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR5, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR6, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR7, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR8, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT0, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT1, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT2, ENABLE),
|
||||||
|
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT3, ENABLE));
|
||||||
|
|
||||||
|
/* Lock cluster switching, to prevent usage of the A53 cores. */
|
||||||
|
reg::Write(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER_LOCK, ENABLE),
|
||||||
|
FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_CLUSTER_SWITCH_ENABLE, DISABLE),
|
||||||
|
FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, FAST));
|
||||||
|
|
||||||
|
/* Enable flow controller debug qualifier for legacy FIQs. */
|
||||||
|
reg::Write(FLOW_CTLR + FLOW_CTLR_FLOW_DBG_QUAL, FLOW_REG_BITS_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, ENABLE));
|
||||||
|
|
||||||
|
/* Configure the PMC to disable deep power-down. */
|
||||||
|
reg::Write(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, DISABLE),
|
||||||
|
PMC_REG_BITS_ENUM(DPD_ENABLE_ON, DISABLE));
|
||||||
|
|
||||||
|
/* Configure the video protect region. */
|
||||||
|
reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_0, 1);
|
||||||
|
reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 0);
|
||||||
|
reg::Write(MC + MC_VIDEO_PROTECT_BOM, 0);
|
||||||
|
reg::Write(MC + MC_VIDEO_PROTECT_SIZE_MB, 0);
|
||||||
|
reg::Write(MC + MC_VIDEO_PROTECT_REG_CTRL, MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_ALLOW_TZ_WRITE, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_WRITE_ACCESS, DISABLED));
|
||||||
|
|
||||||
|
/* Configure the SEC carveout. */
|
||||||
|
reg::Write(MC + MC_SEC_CARVEOUT_BOM, 0);
|
||||||
|
reg::Write(MC + MC_SEC_CARVEOUT_SIZE_MB, 0);
|
||||||
|
reg::Write(MC + MC_SEC_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(SEC_CARVEOUT_REG_CTRL_SEC_CARVEOUT_WRITE_ACCESS, DISABLED));
|
||||||
|
|
||||||
|
/* Configure the MTS carveout. */
|
||||||
|
reg::Write(MC + MC_MTS_CARVEOUT_BOM, 0);
|
||||||
|
reg::Write(MC + MC_MTS_CARVEOUT_SIZE_MB, 0);
|
||||||
|
reg::Write(MC + MC_MTS_CARVEOUT_ADR_HI, 0);
|
||||||
|
reg::Write(MC + MC_MTS_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(MTS_CARVEOUT_REG_CTRL_MTS_CARVEOUT_WRITE_ACCESS, DISABLED));
|
||||||
|
|
||||||
|
/* Configure the security carveout. */
|
||||||
|
reg::Write(MC + MC_SECURITY_CFG0, MC_REG_BITS_VALUE(SECURITY_CFG0_SECURITY_BOM, 0));
|
||||||
|
reg::Write(MC + MC_SECURITY_CFG1, MC_REG_BITS_VALUE(SECURITY_CFG1_SECURITY_SIZE, 0));
|
||||||
|
reg::Write(MC + MC_SECURITY_CFG3, MC_REG_BITS_VALUE(SECURITY_CFG3_SECURITY_BOM_HI, 3));
|
||||||
|
|
||||||
|
/* Configure security carveout 1. */
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM_HI, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_SIZE_128KB, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT1_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE));
|
||||||
|
|
||||||
|
/* Security carveout 2 will be configured later by SetupGpuCarveout, after magic values are written to configure gpu/tsec. */
|
||||||
|
|
||||||
|
/* Configure carveout 3. */
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM_HI, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_SIZE_128KB, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2, MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD, ENABLE),
|
||||||
|
MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR, ENABLE));
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4, MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE),
|
||||||
|
MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE));
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
|
||||||
|
reg::Write(MC + MC_SECURITY_CARVEOUT3_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||||
|
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 3),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
|
||||||
|
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE));
|
||||||
|
|
||||||
|
/* Configure the two kernel carveouts. */
|
||||||
|
SetupKernelCarveouts();
|
||||||
|
|
||||||
|
/* Configure slave register security. */
|
||||||
|
ConfigureSlaveSecurity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSmmu() {
|
||||||
|
/* Turn on SMMU translation for all devices. */
|
||||||
|
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_0, ~0u);
|
||||||
|
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_1, ~0u);
|
||||||
|
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_2, ~0u);
|
||||||
|
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_3, ~0u);
|
||||||
|
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_4, ~0u);
|
||||||
|
|
||||||
|
/* Configure ASIDs 1-3 as secure, and all others as non-secure. */
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY, MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, SECURE),
|
||||||
|
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, SECURE),
|
||||||
|
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, SECURE));
|
||||||
|
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_1, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_2, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_3, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_4, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_5, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_6, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_ASID_SECURITY_7, 0);
|
||||||
|
|
||||||
|
/* Initialize the PTB registers to zero .*/
|
||||||
|
reg::Write(MC + MC_SMMU_PTB_ASID, 0);
|
||||||
|
reg::Write(MC + MC_SMMU_PTB_DATA, 0);
|
||||||
|
|
||||||
|
/* Configure the TLB and PTC, then read TLB_CONFIG to ensure configuration takes. */
|
||||||
|
reg::Write(MC + MC_SMMU_TLB_CONFIG, MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_HIT_UNDER_MISS, ENABLE),
|
||||||
|
MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_ROUND_ROBIN_ARBITRATION, ENABLE),
|
||||||
|
MC_REG_BITS_VALUE(SMMU_TLB_CONFIG_TLB_ACTIVE_LINES, 0x30));
|
||||||
|
|
||||||
|
reg::Write(MC + MC_SMMU_PTC_CONFIG, MC_REG_BITS_ENUM (SMMU_PTC_CONFIG_PTC_CACHE_ENABLE, ENABLE),
|
||||||
|
MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_REQ_LIMIT, 8),
|
||||||
|
MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_INDEX_MAP, 0x3F));
|
||||||
|
|
||||||
|
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||||
|
|
||||||
|
/* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
|
||||||
|
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
|
||||||
|
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||||
|
|
||||||
|
/* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
|
||||||
|
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
|
||||||
|
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||||
|
|
||||||
|
/* Enable the SMMU, and read TLB_CONFIG to ensure the enable takes. */
|
||||||
|
reg::Write(MC + MC_SMMU_CONFIG, MC_REG_BITS_ENUM (SMMU_CONFIG_SMMU_ENABLE, ENABLE));
|
||||||
|
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Setup1() {
|
||||||
|
/* Load the global configuration context. */
|
||||||
|
InitializeConfigurationContext();
|
||||||
|
|
||||||
|
/* Initialize uart for logging. */
|
||||||
|
log::Initialize();
|
||||||
|
|
||||||
|
/* Initialize the security engine. */
|
||||||
|
se::Initialize();
|
||||||
|
|
||||||
|
/* Initialize the gic. */
|
||||||
|
gic::InitializeCommon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSecurityEngineAesKeySlotTestVector() {
|
||||||
|
GenerateSecurityEngineAesKeySlotTestVector(g_se_aes_key_slot_test_vector, sizeof(g_se_aes_key_slot_test_vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSocSecurity() {
|
||||||
|
/* Set the fuse visibility. */
|
||||||
|
clkrst::SetFuseVisibility(true);
|
||||||
|
|
||||||
|
/* Set fuses as only secure-writable. */
|
||||||
|
fuse::SetWriteSecureOnly();
|
||||||
|
|
||||||
|
/* Lockout the fuses. */
|
||||||
|
fuse::Lockout();
|
||||||
|
|
||||||
|
/* Set the security engine to secure mode. */
|
||||||
|
se::SetSecure(true);
|
||||||
|
|
||||||
|
/* Verify the security engine's sticky bits. */
|
||||||
|
VerifySecurityEngineStickyBits();
|
||||||
|
|
||||||
|
/* Verify the security engine's Aes slots contain correct contents. */
|
||||||
|
VerifySecurityEngineAesKeySlotTestVector();
|
||||||
|
|
||||||
|
/* Clear aes keyslots. */
|
||||||
|
ClearAesKeySlots();
|
||||||
|
|
||||||
|
/* Clear rsa keyslots. */
|
||||||
|
ClearRsaKeySlots();
|
||||||
|
|
||||||
|
/* Overwrite keys that we want to be random with random contents. */
|
||||||
|
se::InitializeRandom();
|
||||||
|
se::SetRandomKey(pkg1::AesKeySlot_Temporary);
|
||||||
|
se::GenerateSrk();
|
||||||
|
se::SetRandomKey(pkg1::AesKeySlot_TzramSave);
|
||||||
|
|
||||||
|
/* Initialize pmc secure scratch. */
|
||||||
|
pmc::InitializeRandomScratch();
|
||||||
|
|
||||||
|
/* Setup secure registers. */
|
||||||
|
SetupSecureRegisters();
|
||||||
|
|
||||||
|
/* Setup the smmu. */
|
||||||
|
SetupSmmu();
|
||||||
|
|
||||||
|
/* Clear the cpu reset vector. */
|
||||||
|
reg::Write(secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress() + EVP_CPU_RESET_VECTOR, 0);
|
||||||
|
|
||||||
|
/* Configure the SB registers to our start address. */
|
||||||
|
constexpr u32 ResetVectorLow = static_cast<u32>((PhysicalTzramProgramResetVector >> 0));
|
||||||
|
constexpr u32 ResetVectorHigh = static_cast<u32>((PhysicalTzramProgramResetVector >> BITSIZEOF(u32)));
|
||||||
|
|
||||||
|
/* Write our reset vector to the secure boot registers. */
|
||||||
|
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_LOW, ResetVectorLow);
|
||||||
|
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_HIGH, ResetVectorHigh);
|
||||||
|
|
||||||
|
/* Disable non-secure writes to the reset vector. */
|
||||||
|
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR, SB_REG_BITS_ENUM(CSR_NS_RST_VEC_WR_DIS, DISABLE));
|
||||||
|
|
||||||
|
/* Read back SB_CSR to make sure our non-secure write disable takes. */
|
||||||
|
reg::Read(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR);
|
||||||
|
|
||||||
|
/* Write our reset vector to scratch registers used by warmboot, and lock those scratch registers. */
|
||||||
|
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH34, ResetVectorLow);
|
||||||
|
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH35, ResetVectorHigh);
|
||||||
|
pmc::LockSecureRegister(pmc::SecureRegister_ResetVector);
|
||||||
|
|
||||||
|
/* Setup the security engine interrupt. */
|
||||||
|
constexpr int SecurityEngineInterruptId = 90;
|
||||||
|
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
|
||||||
|
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
|
||||||
|
gic::SetEnable (SecurityEngineInterruptId, true);
|
||||||
|
gic::SetSpiTargetCpu (SecurityEngineInterruptId, (1 << 3));
|
||||||
|
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
|
||||||
|
|
||||||
|
/* Setup the activity monitor interrupt. */
|
||||||
|
constexpr int ActivityMonitorInterruptId = 77;
|
||||||
|
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
|
||||||
|
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
|
||||||
|
gic::SetEnable (ActivityMonitorInterruptId, true);
|
||||||
|
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, (1 << 3));
|
||||||
|
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
|
||||||
|
|
||||||
|
/* If we're coldboot, perform one-time setup. */
|
||||||
|
if (g_is_cold_boot) {
|
||||||
|
/* Register both interrupt handlers. */
|
||||||
|
SetInterruptHandler(SecurityEngineInterruptId, se::HandleInterrupt);
|
||||||
|
SetInterruptHandler(ActivityMonitorInterruptId, actmon::HandleInterrupt);
|
||||||
|
|
||||||
|
/* We're expecting the other cores to come out of reset. */
|
||||||
|
for (int i = 1; i < NumCores; ++i) {
|
||||||
|
SetResetExpected(i, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only coldboot once. */
|
||||||
|
g_is_cold_boot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSocProtections() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
exosphere2/program/source/secmon_setup.hpp
Normal file
36
exosphere2/program/source/secmon_setup.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
constexpr inline u64 MemoryAttributeIndexNormal = 0;
|
||||||
|
constexpr inline u64 MemoryAttributeIndexDevice = 1;
|
||||||
|
|
||||||
|
constexpr inline int KernelCarveoutCount = 2;
|
||||||
|
|
||||||
|
void SetupCpuMemoryControllersEnableMmu();
|
||||||
|
|
||||||
|
void SetupSocDmaControllers();
|
||||||
|
void SetupSocSecurity();
|
||||||
|
void SetupSocProtections();
|
||||||
|
|
||||||
|
void Setup1();
|
||||||
|
|
||||||
|
void SaveSecurityEngineAesKeySlotTestVector();
|
||||||
|
|
||||||
|
}
|
206
exosphere2/program/source/secmon_setup_warm.cpp
Normal file
206
exosphere2/program/source/secmon_setup_warm.cpp
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "secmon_setup.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace setup {
|
||||||
|
|
||||||
|
#include "secmon_cache_impl.inc"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace ams::mmu;
|
||||||
|
|
||||||
|
void SetupCpuCommonControllers() {
|
||||||
|
/* Set cpuactlr_el1. */
|
||||||
|
{
|
||||||
|
util::BitPack64 cpuactlr = {};
|
||||||
|
cpuactlr.Set<hw::CpuactlrEl1CortexA57::NonCacheableStreamingEnhancement>(1);
|
||||||
|
cpuactlr.Set<hw::CpuactlrEl1CortexA57::DisableLoadPassDmb>(1);
|
||||||
|
HW_CPU_SET_CPUACTLR_EL1(cpuactlr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set cpuectlr_el1. */
|
||||||
|
{
|
||||||
|
util::BitPack64 cpuectlr = {};
|
||||||
|
cpuectlr.Set<hw::CpuectlrEl1CortexA57::Smpen>(1);
|
||||||
|
cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2LoadStoreDataPrefetchDistance>(3);
|
||||||
|
cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2InstructionFetchPrefetchDistance>(3);
|
||||||
|
HW_CPU_SET_CPUECTLR_EL1(cpuectlr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent instruction reordering. */
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupCpuEl3Controllers() {
|
||||||
|
/* Set scr_el3. */
|
||||||
|
{
|
||||||
|
util::BitPack32 scr = {};
|
||||||
|
scr.Set<hw::ScrEl3::Ns >(1); /* Set EL0/EL1 as Non-Secure. */
|
||||||
|
scr.Set<hw::ScrEl3::Irq >(0); /* IRQs are taken in IRQ mode. */
|
||||||
|
scr.Set<hw::ScrEl3::Fiq >(1); /* FIQs are taken in Monitor mode. */
|
||||||
|
scr.Set<hw::ScrEl3::Ea >(1); /* External aborts are taken in Monitor mode. */
|
||||||
|
scr.Set<hw::ScrEl3::Fw >(1); /* CPSR.F is non-secure writable. */
|
||||||
|
scr.Set<hw::ScrEl3::Aw >(1); /* CPSR.A is non-secure writable. */
|
||||||
|
scr.Set<hw::ScrEl3::Net >(0); /* This bit is not implemented. */
|
||||||
|
scr.Set<hw::ScrEl3::Smd >(0); /* Secure Monitor Call is allowed. */
|
||||||
|
scr.Set<hw::ScrEl3::Hce >(0); /* Hypervisor Calls are disabled. */ /* TODO: Enable for thermosphere? */
|
||||||
|
scr.Set<hw::ScrEl3::Sif >(1); /* Secure mode cannot fetch instructions from non-secure memory. */
|
||||||
|
scr.Set<hw::ScrEl3::RwCortexA53>(1); /* Reserved bit. N probably sets it because on Cortex A53, this sets kernel as aarch64. */
|
||||||
|
scr.Set<hw::ScrEl3::StCortexA53>(0); /* Reserved bit. On Cortex A53, this sets secure registers to EL3 only. */
|
||||||
|
scr.Set<hw::ScrEl3::Twi >(0); /* WFI is not trapped. */
|
||||||
|
scr.Set<hw::ScrEl3::Twe >(0); /* WFE is not trapped. */
|
||||||
|
|
||||||
|
HW_CPU_SET_SCR_EL3(scr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set ttbr0_el3. */
|
||||||
|
{
|
||||||
|
constexpr u64 ttbr0 = MemoryRegionPhysicalTzramL1PageTable.GetAddress();
|
||||||
|
HW_CPU_SET_TTBR0_EL3(ttbr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set tcr_el3. */
|
||||||
|
{
|
||||||
|
util::BitPack32 tcr = { hw::TcrEl3::Res1 };
|
||||||
|
tcr.Set<hw::TcrEl3::T0sz >(31); /* Configure TTBR0 addressed size to be 64 GiB */
|
||||||
|
tcr.Set<hw::TcrEl3::Irgn0>(1); /* Configure PTE walks as inner write-back write-allocate cacheable */
|
||||||
|
tcr.Set<hw::TcrEl3::Orgn0>(1); /* Configure PTE walks as outer write-back write-allocate cacheable */
|
||||||
|
tcr.Set<hw::TcrEl3::Sh0 >(3); /* Configure PTE walks as inner shareable */
|
||||||
|
tcr.Set<hw::TcrEl3::Tg0 >(0); /* Set TTBR0_EL3 granule as 4 KiB */
|
||||||
|
tcr.Set<hw::TcrEl3::Ps >(1); /* Set the physical addrss size as 36-bit (64 GiB) */
|
||||||
|
tcr.Set<hw::TcrEl3::Tbi >(0); /* Top byte is not ignored in addrss calculations */
|
||||||
|
|
||||||
|
HW_CPU_SET_TCR_EL3(tcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear cptr_el3. */
|
||||||
|
{
|
||||||
|
util::BitPack32 cptr = {};
|
||||||
|
|
||||||
|
cptr.Set<hw::CptrEl3::Tfp >(0); /* FP/SIMD instructions don't trap. */
|
||||||
|
cptr.Set<hw::CptrEl3::Tta >(0); /* Reserved bit (no trace functionality present). */
|
||||||
|
cptr.Set<hw::CptrEl3::Tcpac>(0); /* Access to cpacr_El1 does not trap. */
|
||||||
|
|
||||||
|
HW_CPU_SET_CPTR_EL3(cptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set mair_el3. */
|
||||||
|
{
|
||||||
|
u64 mair = (MemoryRegionAttributes_Normal << (MemoryRegionAttributeWidth * MemoryAttributeIndexNormal)) |
|
||||||
|
(MemoryRegionAttributes_Device << (MemoryRegionAttributeWidth * MemoryAttributeIndexDevice));
|
||||||
|
HW_CPU_SET_MAIR_EL3(mair);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set vectors. */
|
||||||
|
{
|
||||||
|
constexpr u64 vectors = MemoryRegionVirtualTzramProgramExceptionVectors.GetAddress();
|
||||||
|
HW_CPU_SET_VBAR_EL3(vectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent instruction re-ordering around this point. */
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableMmu() {
|
||||||
|
/* Create sctlr value. */
|
||||||
|
util::BitPack32 sctlr = { hw::SctlrEl3::Res1 };
|
||||||
|
sctlr.Set<hw::SctlrEl3::M>(1); /* Globally enable the MMU. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::A>(0); /* Disable alignment fault checking. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::C>(1); /* Globally enable the data and unified caches. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::Sa>(0); /* Disable stack alignment checking. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::I>(1); /* Globally enable the instruction cache. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::Wxn>(0); /* Do not force writable pages to be ExecuteNever. */
|
||||||
|
sctlr.Set<hw::SctlrEl3::Ee>(0); /* Exceptions should be little endian. */
|
||||||
|
|
||||||
|
/* Ensure all writes are done before turning on the mmu. */
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
hw::InvalidateEntireTlb();
|
||||||
|
|
||||||
|
/* Ensure instruction consistency. */
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
|
||||||
|
/* Set sctlr_el3. */
|
||||||
|
HW_CPU_SET_SCTLR_EL3(sctlr);
|
||||||
|
hw::InstructionSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupCpuMemoryControllersEnableMmu() {
|
||||||
|
SetupCpuCommonControllers();
|
||||||
|
SetupCpuEl3Controllers();
|
||||||
|
EnableMmu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSocDmaControllers() {
|
||||||
|
/* Ensure that our caches are managed. */
|
||||||
|
setup::InvalidateEntireDataCache();
|
||||||
|
setup::EnsureInstructionConsistency();
|
||||||
|
|
||||||
|
/* Lock tsec. */
|
||||||
|
tsec::Lock();
|
||||||
|
|
||||||
|
/* Enable SWID[0] for all bits. */
|
||||||
|
reg::Write(AHB_ARBC(AHB_MASTER_SWID), ~0u);
|
||||||
|
|
||||||
|
/* Clear SWID1 for all bits. */
|
||||||
|
reg::Write(AHB_ARBC(AHB_MASTER_SWID_1), 0u);
|
||||||
|
|
||||||
|
/* Set MSELECT config to set WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||||
|
/* and clear ERR_RESP_EN_SLAVE1(PCIe) | ERR_RESP_EN_SLAVE2(GPU) */
|
||||||
|
{
|
||||||
|
auto mselect_cfg = reg::Read(MSELECT(MSELECT_CONFIG));
|
||||||
|
mselect_cfg &= ~(1u << 24); /* Clear ERR_RESP_EN_SLAVE1(PCIe) */
|
||||||
|
mselect_cfg &= ~(1u << 25); /* Clear ERR_RESP_EN_SLAVE2(GPU) */
|
||||||
|
mselect_cfg |= (1u << 27); /* Set WRAP_TO_INCR_SLAVE0(APC) */
|
||||||
|
mselect_cfg |= (1u << 28); /* Set WRAP_TO_INCR_SLAVE1(PCIe) */
|
||||||
|
mselect_cfg |= (1u << 29); /* Set WRAP_TO_INCR_SLAVE2(GPU) */
|
||||||
|
reg::Write(MSELECT(MSELECT_CONFIG), mselect_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable USB, USB2, AHB-DMA from arbitration. */
|
||||||
|
{
|
||||||
|
auto arb_dis = reg::Read(AHB_ARBC(AHB_ARBITRATION_DISABLE));
|
||||||
|
arb_dis |= (1u << 5); /* Disable AHB-DMA */
|
||||||
|
arb_dis |= (1u << 6); /* Disable USB */
|
||||||
|
arb_dis |= (1u << 18); /* Disable USB2 */
|
||||||
|
reg::Write(AHB_ARBC(AHB_ARBITRATION_DISABLE), arb_dis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select high priority group with priority 7. */
|
||||||
|
{
|
||||||
|
u32 priority_ctrl = {};
|
||||||
|
priority_ctrl |= (7u << 29); /* Set group 7. */
|
||||||
|
priority_ctrl |= (1u << 0); /* Set high priority. */
|
||||||
|
reg::Write(AHB_ARBC(AHB_ARBITRATION_PRIORITY_CTRL), priority_ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent splitting AHB writes to TZRAM. */
|
||||||
|
{
|
||||||
|
reg::Write(AHB_ARBC(AHB_GIZMO_TZRAM), (1u << 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
83
exosphere2/program/source/secmon_start_virtual.s
Normal file
83
exosphere2/program/source/secmon_start_virtual.s
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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._ZN3ams6secmon5StartEv, "ax", %progbits
|
||||||
|
.align 6
|
||||||
|
.global _ZN3ams6secmon5StartEv
|
||||||
|
_ZN3ams6secmon5StartEv:
|
||||||
|
/* Set SPSEL 1 stack pointer to the core 0 exception stack address. */
|
||||||
|
msr spsel, #1
|
||||||
|
ldr x20, =0x1F01F6F00
|
||||||
|
mov sp, x20
|
||||||
|
|
||||||
|
/* Set SPSEL 0 stack pointer to a temporary location in volatile memory. */
|
||||||
|
msr spsel, #1
|
||||||
|
ldr x20, =0x1F01C0800
|
||||||
|
mov sp, x20
|
||||||
|
|
||||||
|
/* Setup X18 to point to the global context. */
|
||||||
|
ldr x18, =0x1F01FA000
|
||||||
|
|
||||||
|
/* Invoke main. */
|
||||||
|
bl _ZN3ams6secmon4MainEv
|
||||||
|
|
||||||
|
/* Set the stack pointer to the core 3 exception stack address. */
|
||||||
|
ldr x20, =0x1F01FB000
|
||||||
|
mov sp, x20
|
||||||
|
|
||||||
|
/* TODO: JumpToLowerExceptionLevel */
|
||||||
|
1: b 1b
|
||||||
|
|
||||||
|
.section .text._ZN3ams6secmon25AcquireCommonSmcStackLockEv, "ax", %progbits
|
||||||
|
.align 4
|
||||||
|
.global _ZN3ams6secmon25AcquireCommonSmcStackLockEv
|
||||||
|
_ZN3ams6secmon25AcquireCommonSmcStackLockEv:
|
||||||
|
/* Get the address of the lock. */
|
||||||
|
ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE
|
||||||
|
|
||||||
|
/* Prepare to try to take the spinlock. */
|
||||||
|
mov w1, #1
|
||||||
|
sevl
|
||||||
|
prfm pstl1keep, [x0]
|
||||||
|
|
||||||
|
1: /* Repeatedly try to take the lock. */
|
||||||
|
wfe
|
||||||
|
ldaxr w2, [x0]
|
||||||
|
cbnz w2, 1b
|
||||||
|
stxr w2, w1, [x0]
|
||||||
|
cbnz w2, 1b
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
ret
|
||||||
|
|
||||||
|
.section .text._ZN3ams6secmon25ReleaseCommonSmcStackLockEv, "ax", %progbits
|
||||||
|
.align 4
|
||||||
|
.global _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
|
||||||
|
_ZN3ams6secmon25ReleaseCommonSmcStackLockEv:
|
||||||
|
/* Get the address of the lock. */
|
||||||
|
ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE
|
||||||
|
|
||||||
|
/* Release the spinlock. */
|
||||||
|
stlr wzr, [x0]
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
ret
|
||||||
|
|
||||||
|
.section .data._ZN3ams6secmon18CommonSmcStackLockE, "aw", %progbits
|
||||||
|
.global _ZN3ams6secmon18CommonSmcStackLockE
|
||||||
|
_ZN3ams6secmon18CommonSmcStackLockE:
|
||||||
|
/* Define storage for the global common smc stack spinlock. */
|
||||||
|
.word 0
|
52
exosphere2/program/source/smc/secmon_smc_aes.cpp
Normal file
52
exosphere2/program/source/smc/secmon_smc_aes.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_aes.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGenerateAesKek(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcLoadAesKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcComputeAes(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcGenerateSpecificAesKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcComputeCmac(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcLoadPreparedAesKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
exosphere2/program/source/smc/secmon_smc_aes.hpp
Normal file
29
exosphere2/program/source/smc/secmon_smc_aes.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGenerateAesKek(const SmcArguments &args);
|
||||||
|
SmcResult SmcLoadAesKey(const SmcArguments &args);
|
||||||
|
SmcResult SmcComputeAes(const SmcArguments &args);
|
||||||
|
SmcResult SmcGenerateSpecificAesKey(const SmcArguments &args);
|
||||||
|
SmcResult SmcComputeCmac(const SmcArguments &args);
|
||||||
|
SmcResult SmcLoadPreparedAesKey(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
27
exosphere2/program/source/smc/secmon_smc_carveout.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_carveout.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_carveout.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcSetKernelCarveoutRegion(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere2/program/source/smc/secmon_smc_carveout.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_carveout.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcSetKernelCarveoutRegion(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
45
exosphere2/program/source/smc/secmon_smc_common.hpp
Normal file
45
exosphere2/program/source/smc/secmon_smc_common.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
enum class SmcResult : u32 {
|
||||||
|
Success = 0,
|
||||||
|
NotImplemented = 1,
|
||||||
|
InvalidArgument = 2,
|
||||||
|
InProgress = 3,
|
||||||
|
NoAsyncOperation = 4,
|
||||||
|
InvalidAsyncOperation = 5,
|
||||||
|
NotPermitted = 6,
|
||||||
|
NotInitialized = 7,
|
||||||
|
|
||||||
|
PsciSuccess = 0,
|
||||||
|
PsciNotSupported = static_cast<u32>(-1),
|
||||||
|
PsciInvalidParameters = static_cast<u32>(-2),
|
||||||
|
PsciDenied = static_cast<u32>(-3),
|
||||||
|
PsciAlreadyOn = static_cast<u32>(-4),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SmcArguments {
|
||||||
|
u64 r[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline int SecurityEngineUserInterruptId = 44;
|
||||||
|
constexpr inline u64 InvalidAsyncKey = 0;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_device_unique_data.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcDecryptDeviceUniqueData(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcReencryptDeviceUniqueData(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Legacy APIs. */
|
||||||
|
SmcResult SmcDecryptAndImportEsDeviceKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcDecryptAndImportLotusKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcDecryptDeviceUniqueData(const SmcArguments &args);
|
||||||
|
SmcResult SmcReencryptDeviceUniqueData(const SmcArguments &args);
|
||||||
|
|
||||||
|
/* Legacy APIs. */
|
||||||
|
SmcResult SmcDecryptAndImportEsDeviceKey(const SmcArguments &args);
|
||||||
|
SmcResult SmcDecryptAndImportLotusKey(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
27
exosphere2/program/source/smc/secmon_smc_error.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_error.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_error.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcShowError(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere2/program/source/smc/secmon_smc_error.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_error.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcShowError(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
32
exosphere2/program/source/smc/secmon_smc_es.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_es.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_es.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcPrepareEsDeviceUniqueKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcPrepareEsCommonKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
exosphere2/program/source/smc/secmon_smc_es.hpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_es.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
enum EsKeyType {
|
||||||
|
EsKeyType_TitleKey = 0,
|
||||||
|
EsKeyType_ArchiveKey = 1,
|
||||||
|
|
||||||
|
EsKeyType_Count = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
SmcResult SmcPrepareEsDeviceUniqueKey(const SmcArguments &args);
|
||||||
|
SmcResult SmcPrepareEsCommonKey(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
233
exosphere2/program/source/smc/secmon_smc_handler.cpp
Normal file
233
exosphere2/program/source/smc/secmon_smc_handler.cpp
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "../secmon_misc.hpp"
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
#include "secmon_smc_handler.hpp"
|
||||||
|
#include "secmon_smc_aes.hpp"
|
||||||
|
#include "secmon_smc_carveout.hpp"
|
||||||
|
#include "secmon_smc_device_unique_data.hpp"
|
||||||
|
#include "secmon_smc_error.hpp"
|
||||||
|
#include "secmon_smc_es.hpp"
|
||||||
|
#include "secmon_smc_info.hpp"
|
||||||
|
#include "secmon_smc_memory_access.hpp"
|
||||||
|
#include "secmon_smc_power_management.hpp"
|
||||||
|
#include "secmon_smc_random.hpp"
|
||||||
|
#include "secmon_smc_register_access.hpp"
|
||||||
|
#include "secmon_smc_result.hpp"
|
||||||
|
#include "secmon_smc_rsa.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct HandlerInfo {
|
||||||
|
u32 function_id;
|
||||||
|
u32 restriction_mask;
|
||||||
|
SmcHandler handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HandlerTable {
|
||||||
|
const HandlerInfo *entries;
|
||||||
|
size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HandlerType : int {
|
||||||
|
HandlerType_User = 0,
|
||||||
|
HandlerType_Kern = 1,
|
||||||
|
HandlerType_Count = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Restriction {
|
||||||
|
Restriction_None = (0 << 0),
|
||||||
|
Restriction_Normal = (1 << 0),
|
||||||
|
Restriction_DeviceUniqueDataNotAllowed = (1 << 1),
|
||||||
|
Restriction_SafeModeNotAllowed = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SmcCallRange {
|
||||||
|
SmcCallRange_ArmArch = 0,
|
||||||
|
SmcCallRange_Cpu = 1,
|
||||||
|
SmcCallRange_Sip = 2,
|
||||||
|
SmcCallRange_Oem = 3,
|
||||||
|
SmcCallRange_Standard = 4,
|
||||||
|
|
||||||
|
SmcCallRange_TrustedApp = 0x30,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SmcArgumentType {
|
||||||
|
ArgumentType_Integer = 0,
|
||||||
|
ArgumentType_Pointer = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SmcConvention {
|
||||||
|
Convention_Smc32 = 0,
|
||||||
|
Convention_Smc64 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SmcCallType {
|
||||||
|
SmcCallType_YieldingCall = 0,
|
||||||
|
SmcCallType_FastCall = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SmcFunctionId {
|
||||||
|
using FunctionId = util::BitPack64::Field< 0, 8, u32>;
|
||||||
|
using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>;
|
||||||
|
using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>;
|
||||||
|
using Reserved = util::BitPack64::Field<16, 8, u32>;
|
||||||
|
using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>;
|
||||||
|
using Convention = util::BitPack64::Field<30, 1, SmcConvention>;
|
||||||
|
using CallType = util::BitPack64::Field<31, 1, SmcCallType>;
|
||||||
|
using Reserved2 = util::BitPack64::Field<32, 32, u32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit HandlerInfo g_user_handlers[] = {
|
||||||
|
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
|
||||||
|
{ 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig },
|
||||||
|
{ 0xC3000002, Restriction_Normal, SmcGetConfigUser },
|
||||||
|
{ 0xC3000003, Restriction_Normal, SmcGetResult },
|
||||||
|
{ 0xC3000404, Restriction_Normal, SmcGetResultData },
|
||||||
|
{ 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate },
|
||||||
|
{ 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes },
|
||||||
|
{ 0xC3000007, Restriction_Normal, SmcGenerateAesKek },
|
||||||
|
{ 0xC3000008, Restriction_Normal, SmcLoadAesKey },
|
||||||
|
{ 0xC3000009, Restriction_Normal, SmcComputeAes },
|
||||||
|
{ 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey },
|
||||||
|
{ 0xC300040B, Restriction_Normal, SmcComputeCmac },
|
||||||
|
{ 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData },
|
||||||
|
{ 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData },
|
||||||
|
{ 0xC300000E, Restriction_SafeModeNotAllowed, nullptr },
|
||||||
|
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
|
||||||
|
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
|
||||||
|
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
|
||||||
|
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonKey }
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit HandlerInfo g_kern_handlers[] = {
|
||||||
|
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
|
||||||
|
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
|
||||||
|
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
|
||||||
|
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
|
||||||
|
{ 0xC3000002, Restriction_Normal, SmcGetConfigKern },
|
||||||
|
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
|
||||||
|
{ 0xC3000006, Restriction_Normal, SmcShowError },
|
||||||
|
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
|
||||||
|
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit HandlerInfo g_ams_handlers[] = {
|
||||||
|
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
|
||||||
|
{ 0xF0000201, Restriction_None, SmcIramCopy },
|
||||||
|
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
|
||||||
|
{ 0xF0000003, Restriction_None, SmcWriteAddress },
|
||||||
|
{ 0xF0000003, Restriction_None, SmcGetEmummcConfig },
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit HandlerTable g_handler_tables[] = {
|
||||||
|
{ g_user_handlers, util::size(g_user_handlers) },
|
||||||
|
{ g_kern_handlers, util::size(g_kern_handlers) },
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit HandlerTable g_ams_handler_table = {
|
||||||
|
g_ams_handlers, util::size(g_ams_handlers)
|
||||||
|
};
|
||||||
|
|
||||||
|
NORETURN void InvalidSmcError(u64 id) {
|
||||||
|
SetError(pkg1::ErrorInfo_UnknownSmc);
|
||||||
|
AMS_ABORT("Invalid SMC: %lx", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HandlerTable &GetHandlerTable(HandlerType type, u64 id) {
|
||||||
|
/* Ensure we have a valid handler type. */
|
||||||
|
if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) {
|
||||||
|
InvalidSmcError(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're a user SMC. */
|
||||||
|
if (type == HandlerType_User) {
|
||||||
|
/* Nintendo uses OEM SMCs. */
|
||||||
|
/* We will assign Atmosphere extension SMCs the TrustedApplication range. */
|
||||||
|
if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) {
|
||||||
|
return g_ams_handler_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */
|
||||||
|
if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) {
|
||||||
|
InvalidSmcError(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_handler_tables[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
|
||||||
|
/* Get and check the index. */
|
||||||
|
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
|
||||||
|
if (AMS_UNLIKELY(index >= table.count)) {
|
||||||
|
InvalidSmcError(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get and check the handler info. */
|
||||||
|
const auto &handler_info = table.entries[index];
|
||||||
|
|
||||||
|
/* Check that the handler isn't null. */
|
||||||
|
if (AMS_UNLIKELY(handler_info.handler == nullptr)) {
|
||||||
|
InvalidSmcError(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the handler's id matches. */
|
||||||
|
if (AMS_UNLIKELY(handler_info.function_id != id)) {
|
||||||
|
InvalidSmcError(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsHandlerRestricted(const HandlerInfo &info) {
|
||||||
|
return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult InvokeSmcHandler(const HandlerInfo &info, const SmcArguments &args) {
|
||||||
|
/* Check if the smc is restricted. */
|
||||||
|
if (AMS_UNLIKELY(IsHandlerRestricted(info))) {
|
||||||
|
return SmcResult::NotPermitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invoke the smc. */
|
||||||
|
return info.handler(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSmc(int type, SmcArguments &args) {
|
||||||
|
/* Get the table. */
|
||||||
|
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);
|
||||||
|
|
||||||
|
/* Get the handler info. */
|
||||||
|
const auto &info = GetHandlerInfo(table, args.r[0]);
|
||||||
|
|
||||||
|
/* Set the invocation result. */
|
||||||
|
args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere2/program/source/smc/secmon_smc_handler.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_handler.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
using SmcHandler = SmcResult (*)(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
43
exosphere2/program/source/smc/secmon_smc_info.cpp
Normal file
43
exosphere2/program/source/smc/secmon_smc_info.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_info.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGetConfigUser(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcGetConfigKern(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcSetConfig(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is an atmosphere extension smc. */
|
||||||
|
SmcResult SmcGetEmummcConfig(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
exosphere2/program/source/smc/secmon_smc_info.hpp
Normal file
59
exosphere2/program/source/smc/secmon_smc_info.hpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
enum class ConfigItem : u32 {
|
||||||
|
/* Standard config items. */
|
||||||
|
DisableProgramVerification = 1,
|
||||||
|
DramId = 2,
|
||||||
|
SecurityEngineIrqNumber = 3,
|
||||||
|
FuseVersion = 4,
|
||||||
|
HardwareType = 5,
|
||||||
|
IsRetail = 6,
|
||||||
|
IsRecoveryBoot = 7,
|
||||||
|
DeviceId = 8,
|
||||||
|
BootReason = 9,
|
||||||
|
MemoryMode = 10,
|
||||||
|
IsDebugMode = 11,
|
||||||
|
KernelConfiguration = 12,
|
||||||
|
IsChargerHiZModeEnabled = 13,
|
||||||
|
IsQuest = 14,
|
||||||
|
RegulatorType = 15,
|
||||||
|
DeviceUniqueKeyGeneration = 16,
|
||||||
|
Package2Hash = 17,
|
||||||
|
|
||||||
|
/* Extension config items for exosphere. */
|
||||||
|
ExosphereApiVersion = 65000,
|
||||||
|
ExosphereNeedsReboot = 65001,
|
||||||
|
ExosphereNeedsShutdown = 65002,
|
||||||
|
ExosphereGitCommitHash = 65003,
|
||||||
|
ExosphereHasRcmBugPatch = 65004,
|
||||||
|
ExosphereBlankProdInfo = 65005,
|
||||||
|
ExosphereAllowCalWrites = 65006,
|
||||||
|
};
|
||||||
|
|
||||||
|
SmcResult SmcGetConfigUser(const SmcArguments &args);
|
||||||
|
SmcResult SmcGetConfigKern(const SmcArguments &args);
|
||||||
|
SmcResult SmcSetConfig(const SmcArguments &args);
|
||||||
|
|
||||||
|
/* This is an atmosphere extension smc. */
|
||||||
|
SmcResult SmcGetEmummcConfig(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
33
exosphere2/program/source/smc/secmon_smc_memory_access.cpp
Normal file
33
exosphere2/program/source/smc/secmon_smc_memory_access.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_memory_access.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
/* This is an atmosphere extension smc. */
|
||||||
|
SmcResult SmcIramCopy(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcWriteAddress(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
exosphere2/program/source/smc/secmon_smc_memory_access.hpp
Normal file
26
exosphere2/program/source/smc/secmon_smc_memory_access.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
/* This is an atmosphere extension smc. */
|
||||||
|
SmcResult SmcIramCopy(const SmcArguments &args);
|
||||||
|
SmcResult SmcWriteAddress(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_power_management.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcPowerOffCpu(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcPowerOnCpu(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcSuspendCpu(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcPowerOffCpu(const SmcArguments &args);
|
||||||
|
SmcResult SmcPowerOnCpu(const SmcArguments &args);
|
||||||
|
|
||||||
|
SmcResult SmcSuspendCpu(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
32
exosphere2/program/source/smc/secmon_smc_random.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_random.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_random.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGenerateRandomBytes(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcGenerateRandomBytesNonBlocking(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
exosphere2/program/source/smc/secmon_smc_random.hpp
Normal file
25
exosphere2/program/source/smc/secmon_smc_random.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGenerateRandomBytes(const SmcArguments &args);
|
||||||
|
SmcResult SmcGenerateRandomBytesNonBlocking(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
27
exosphere2/program/source/smc/secmon_smc_register_access.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_register_access.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_register_access.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcReadWriteRegister(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere2/program/source/smc/secmon_smc_register_access.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_register_access.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcReadWriteRegister(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
32
exosphere2/program/source/smc/secmon_smc_result.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_result.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_result.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcGetResult(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcGetResultData(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
exosphere2/program/source/smc/secmon_smc_result.hpp
Normal file
31
exosphere2/program/source/smc/secmon_smc_result.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
using GetResultHandler = SmcResult (*)(void *dst, size_t dst_size);
|
||||||
|
|
||||||
|
u64 BeginAsyncOperation(GetResultHandler handler);
|
||||||
|
void CancelAsyncOperation(u64 async_key);
|
||||||
|
void EndAsyncOperation();
|
||||||
|
|
||||||
|
SmcResult SmcGetResult(const SmcArguments &args);
|
||||||
|
SmcResult SmcGetResultData(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
32
exosphere2/program/source/smc/secmon_smc_rsa.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_rsa.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "../secmon_error.hpp"
|
||||||
|
#include "secmon_smc_rsa.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcModularExponentiate(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult SmcModularExponentiateByStorageKey(const SmcArguments &args) {
|
||||||
|
/* TODO */
|
||||||
|
return SmcResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
exosphere2/program/source/smc/secmon_smc_rsa.hpp
Normal file
25
exosphere2/program/source/smc/secmon_smc_rsa.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
#include "secmon_smc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
SmcResult SmcModularExponentiate(const SmcArguments &args);
|
||||||
|
SmcResult SmcModularExponentiateByStorageKey(const SmcArguments &args);
|
||||||
|
|
||||||
|
}
|
33
exosphere2/program/split_program.py
Normal file
33
exosphere2/program/split_program.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import sys, lz4
|
||||||
|
from struct import unpack as up
|
||||||
|
|
||||||
|
def lz4_compress(data):
|
||||||
|
return lz4.block.compress(data, 'high_compression', store_size=False)
|
||||||
|
|
||||||
|
def split_binary(data):
|
||||||
|
A, B, START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START, C, D = up('<QQQQQQQQ', data[:0x40])
|
||||||
|
assert A == 0xAAAAAAAAAAAAAAAA
|
||||||
|
assert B == 0xBBBBBBBBBBBBBBBB
|
||||||
|
assert C == 0xCCCCCCCCCCCCCCCC
|
||||||
|
assert D == 0xDDDDDDDDDDDDDDDD
|
||||||
|
data = data[0x40:]
|
||||||
|
|
||||||
|
boot_code = data[BOOT_CODE_START - START:BOOT_CODE_END - BOOT_CODE_START]
|
||||||
|
program = data[PROGRAM_START - START:]
|
||||||
|
return [('boot_code.lz4', lz4_compress(boot_code)), ('program.lz4', lz4_compress(program))]
|
||||||
|
|
||||||
|
def main(argc, argv):
|
||||||
|
if argc != 3:
|
||||||
|
print 'Usage: %s in outdir' % argv[0]
|
||||||
|
return 1
|
||||||
|
with open(argv[1], 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
assert len(data) >= 0x40
|
||||||
|
for (fn, fdata) in split_binary(data):
|
||||||
|
with open('%s/%s' % (argv[2], fn), 'wb') as f:
|
||||||
|
f.write(fdata)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(len(sys.argv), sys.argv))
|
11
libraries/config/arch/arm/arch.mk
Normal file
11
libraries/config/arch/arm/arch.mk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITPRO)/devkitARM/base_rules
|
||||||
|
|
||||||
|
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM
|
||||||
|
export ATMOSPHERE_SETTINGS +=
|
||||||
|
export ATMOSPHERE_CFLAGS +=
|
||||||
|
export ATMOSPHERE_CXXFLAGS +=
|
||||||
|
export ATMOSPHERE_ASFLAGS +=
|
5
libraries/config/arch/arm/cpu/arm7tdmi/cpu.mk
Normal file
5
libraries/config/arch/arm/cpu/arm7tdmi/cpu.mk
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_ARM7TDMI
|
||||||
|
export ATMOSPHERE_SETTINGS += -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||||
|
export ATMOSPHERE_CFLAGS +=
|
||||||
|
export ATMOSPHERE_CXXFLAGS +=
|
||||||
|
export ATMOSPHERE_ASFLAGS +=
|
5
libraries/config/board/nintendo/nx_bpmp/board.mk
Normal file
5
libraries/config/board/nintendo/nx_bpmp/board.mk
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__BPMP__
|
||||||
|
export ATMOSPHERE_SETTINGS +=
|
||||||
|
export ATMOSPHERE_CFLAGS +=
|
||||||
|
export ATMOSPHERE_CXXFLAGS +=
|
||||||
|
export ATMOSPHERE_ASFLAGS +=
|
|
@ -8,12 +8,13 @@ export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/..
|
||||||
|
|
||||||
ifeq ($(strip $(ATMOSPHERE_BOARD)),)
|
ifeq ($(strip $(ATMOSPHERE_BOARD)),)
|
||||||
export ATMOSPHERE_BOARD := nx-hac-001
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(ATMOSPHERE_CPU)),)
|
ifeq ($(strip $(ATMOSPHERE_CPU)),)
|
||||||
export ATMOSPHERE_CPU := arm-cortex-a57
|
export ATMOSPHERE_CPU := arm-cortex-a57
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
export ATMOSPHERE_DEFINES := -DATMOSPHERE
|
export ATMOSPHERE_DEFINES := -DATMOSPHERE
|
||||||
export ATMOSPHERE_SETTINGS := -fPIE -g
|
export ATMOSPHERE_SETTINGS := -fPIE -g
|
||||||
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
|
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
|
||||||
|
@ -23,6 +24,8 @@ export ATMOSPHERE_ASFLAGS :=
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
|
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
|
||||||
|
|
||||||
|
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
|
||||||
export ATMOSPHERE_ARCH_DIR := arch/arm64
|
export ATMOSPHERE_ARCH_DIR := arch/arm64
|
||||||
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx
|
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx
|
||||||
export ATMOSPHERE_OS_DIR := os/horizon
|
export ATMOSPHERE_OS_DIR := os/horizon
|
||||||
|
@ -30,6 +33,16 @@ export ATMOSPHERE_OS_DIR := os/horizon
|
||||||
export ATMOSPHERE_ARCH_NAME := arm64
|
export ATMOSPHERE_ARCH_NAME := arm64
|
||||||
export ATMOSPHERE_BOARD_NAME := nintendo_nx
|
export ATMOSPHERE_BOARD_NAME := nintendo_nx
|
||||||
export ATMOSPHERE_OS_NAME := horizon
|
export ATMOSPHERE_OS_NAME := horizon
|
||||||
|
else ifeq ($(ATMOSPHERE_CPU),arm7tdmi)
|
||||||
|
export ATMOSPHERE_ARCH_DIR := arch/arm
|
||||||
|
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx_bpmp
|
||||||
|
export ATMOSPHERE_OS_DIR := os/horizon
|
||||||
|
|
||||||
|
export ATMOSPHERE_ARCH_NAME := arm
|
||||||
|
export ATMOSPHERE_BOARD_NAME := nintendo_nx
|
||||||
|
export ATMOSPHERE_OS_NAME := horizon
|
||||||
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
|
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
|
||||||
|
@ -37,12 +50,20 @@ export ATMOSPHERE_CPU_DIR := arch/arm64/cpu/cortex_a57
|
||||||
export ATMOSPHERE_CPU_NAME := arm_cortex_a57
|
export ATMOSPHERE_CPU_NAME := arm_cortex_a57
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ATMOSPHERE_CPU),arm7tdmi)
|
||||||
|
export ATMOSPHERE_CPU_DIR := arch/arm/cpu/arm7tdmi
|
||||||
|
export ATMOSPHERE_CPU_NAME := arm7tdmi
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR)
|
export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR)
|
||||||
export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR)
|
export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR)
|
||||||
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR)
|
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR)
|
||||||
export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_CPU_DIR)
|
export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_CPU_DIR)
|
||||||
|
|
||||||
|
export ATMOSPHERE_LIBRARY_DIR := lib_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
|
||||||
|
export ATMOSPHERE_BUILD_DIR := build_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
|
||||||
|
|
||||||
include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk
|
include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk
|
||||||
include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk
|
include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk
|
||||||
include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk
|
include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk
|
||||||
|
|
46
libraries/config/templates/exosphere.mk
Normal file
46
libraries/config/templates/exosphere.mk
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
||||||
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions
|
||||||
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
|
else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
|
||||||
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions
|
||||||
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
|
||||||
|
|
||||||
|
export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
||||||
|
-Wl,--wrap,__cxa_throw \
|
||||||
|
-Wl,--wrap,__cxa_rethrow \
|
||||||
|
-Wl,--wrap,__cxa_allocate_exception \
|
||||||
|
-Wl,--wrap,__cxa_free_exception \
|
||||||
|
-Wl,--wrap,__cxa_begin_catch \
|
||||||
|
-Wl,--wrap,__cxa_end_catch \
|
||||||
|
-Wl,--wrap,__cxa_call_unexpected \
|
||||||
|
-Wl,--wrap,__cxa_call_terminate \
|
||||||
|
-Wl,--wrap,__gxx_personality_v0 \
|
||||||
|
-Wl,--wrap,_Unwind_Resume \
|
||||||
|
-Wl,--wrap,_ZSt19__throw_logic_errorPKc \
|
||||||
|
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
|
||||||
|
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
|
||||||
|
|
||||||
|
export LIBS := -lexosphere
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere
|
19
libraries/libexosphere/Makefile
Normal file
19
libraries/libexosphere/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.PHONY: all arm64 arm clean arm64-clean arm-clean
|
||||||
|
|
||||||
|
all: arm64 arm
|
||||||
|
|
||||||
|
arm64:
|
||||||
|
$(MAKE) -f arm64.mk
|
||||||
|
|
||||||
|
arm:
|
||||||
|
$(MAKE) -f arm.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
clean: arm64-clean arm-clean
|
||||||
|
|
||||||
|
arm64-clean:
|
||||||
|
$(MAKE) -f arm64.mk clean
|
||||||
|
|
||||||
|
arm-clean:
|
||||||
|
$(MAKE) -f arm.mk clean
|
142
libraries/libexosphere/arm.mk
Normal file
142
libraries/libexosphere/arm.mk
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Define the atmosphere board and cpu
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
|
export ATMOSPHERE_CPU := arm7tdmi
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions
|
||||||
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
|
|
||||||
|
SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source)
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.c))))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
|
||||||
|
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.cpp))))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
|
||||||
|
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.s))))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
|
||||||
|
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.
|
||||||
|
|
||||||
|
.PHONY: clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a
|
||||||
|
|
||||||
|
$(ATMOSPHERE_LIBRARY_DIR):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
$(ATMOSPHERE_BUILD_DIR):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a : $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES)
|
||||||
|
@$(MAKE) BUILD=$(ATMOSPHERE_BUILD_DIR) OUTPUT=$(CURDIR)/$@ \
|
||||||
|
DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \
|
||||||
|
--no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \
|
||||||
|
-f $(CURDIR)/arm.mk
|
||||||
|
|
||||||
|
dist-bin: all
|
||||||
|
@tar --exclude=*~ -cjf $(TARGET).tar.bz2 include $(ATMOSPHERE_LIBRARY_DIR)
|
||||||
|
|
||||||
|
dist-src:
|
||||||
|
@tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source arm.mk
|
||||||
|
|
||||||
|
dist: dist-src dist-bin
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(OUTPUT) : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES) : $(GCH_FILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
libc.o: CFLAGS += -fno-builtin
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%_bin.h %.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
|
143
libraries/libexosphere/arm64.mk
Normal file
143
libraries/libexosphere/arm64.mk
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Define the atmosphere board and cpu
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export ATMOSPHERE_BOARD := nx-hac-001
|
||||||
|
export ATMOSPHERE_CPU := arm-cortex-a57
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# pull in common atmosphere configuration
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions
|
||||||
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
|
|
||||||
|
SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source)
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.c))))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
|
||||||
|
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
|
||||||
|
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.cpp))))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
|
||||||
|
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
|
||||||
|
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
|
||||||
|
$(notdir $(wildcard $(dir)/*.s))))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
|
||||||
|
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
|
||||||
|
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.
|
||||||
|
|
||||||
|
.PHONY: clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a
|
||||||
|
|
||||||
|
$(ATMOSPHERE_LIBRARY_DIR):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
$(ATMOSPHERE_BUILD_DIR):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|
||||||
|
$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a : $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES)
|
||||||
|
@$(MAKE) BUILD=$(ATMOSPHERE_BUILD_DIR) OUTPUT=$(CURDIR)/$@ \
|
||||||
|
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
|
||||||
|
DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \
|
||||||
|
--no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \
|
||||||
|
-f $(CURDIR)/arm64.mk
|
||||||
|
|
||||||
|
dist-bin: all
|
||||||
|
@tar --exclude=*~ -cjf $(TARGET).tar.bz2 include $(ATMOSPHERE_LIBRARY_DIR)
|
||||||
|
|
||||||
|
dist-src:
|
||||||
|
@tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source arm64.mk
|
||||||
|
|
||||||
|
dist: dist-src dist-bin
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(OUTPUT) : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES) : $(GCH_FILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
libc.o: CFLAGS += -fno-builtin
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%_bin.h %.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
|
38
libraries/libexosphere/include/exosphere.hpp
Normal file
38
libraries/libexosphere/include/exosphere.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
#include <exosphere/common.hpp>
|
||||||
|
#include <exosphere/reg.hpp>
|
||||||
|
#include <exosphere/hw.hpp>
|
||||||
|
#include <exosphere/util.hpp>
|
||||||
|
#include <exosphere/mmu.hpp>
|
||||||
|
#include <exosphere/gic.hpp>
|
||||||
|
#include <exosphere/wdt.hpp>
|
||||||
|
#include <exosphere/pkg1.hpp>
|
||||||
|
#include <exosphere/tsec.hpp>
|
||||||
|
#include <exosphere/se.hpp>
|
||||||
|
#include <exosphere/fuse.hpp>
|
||||||
|
#include <exosphere/i2c.hpp>
|
||||||
|
#include <exosphere/uart.hpp>
|
||||||
|
#include <exosphere/pmic.hpp>
|
||||||
|
#include <exosphere/log.hpp>
|
||||||
|
#include <exosphere/clkrst.hpp>
|
||||||
|
#include <exosphere/actmon.hpp>
|
||||||
|
#include <exosphere/pmc.hpp>
|
||||||
|
#include <exosphere/secmon.hpp>
|
||||||
|
#include <exosphere/tegra.hpp>
|
30
libraries/libexosphere/include/exosphere/actmon.hpp
Normal file
30
libraries/libexosphere/include/exosphere/actmon.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::actmon {
|
||||||
|
|
||||||
|
using InterruptHandler = void(*)();
|
||||||
|
|
||||||
|
void SetRegisterAddress(uintptr_t address);
|
||||||
|
|
||||||
|
void HandleInterrupt();
|
||||||
|
|
||||||
|
void StartMonitoringBpmp(InterruptHandler handler);
|
||||||
|
void StopMonitoringBpmp();
|
||||||
|
|
||||||
|
}
|
29
libraries/libexosphere/include/exosphere/clkrst.hpp
Normal file
29
libraries/libexosphere/include/exosphere/clkrst.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::clkrst {
|
||||||
|
|
||||||
|
void SetRegisterAddress(uintptr_t address);
|
||||||
|
|
||||||
|
void SetFuseVisibility(bool visible);
|
||||||
|
|
||||||
|
void EnableUartAClock();
|
||||||
|
void EnableUartBClock();
|
||||||
|
void EnableUartCClock();
|
||||||
|
|
||||||
|
}
|
30
libraries/libexosphere/include/exosphere/common.hpp
Normal file
30
libraries/libexosphere/include/exosphere/common.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
|
||||||
|
#define EXOSPHERE_BUILD_FOR_AUDITING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(EXOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||||
|
#define EXOSPHERE_BUILD_FOR_DEBUGGING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXOSPHERE_BUILD_FOR_DEBUGGING
|
||||||
|
#define EXOSPHERE_ENABLE_ASSERTIONS
|
||||||
|
#define EXOSPHERE_ENABLE_DEBUG_PRINT
|
||||||
|
#endif
|
49
libraries/libexosphere/include/exosphere/fuse.hpp
Normal file
49
libraries/libexosphere/include/exosphere/fuse.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <exosphere/pmic.hpp>
|
||||||
|
|
||||||
|
namespace ams::fuse {
|
||||||
|
|
||||||
|
enum HardwareType {
|
||||||
|
HardwareType_Icosa = 0,
|
||||||
|
HardwareType_Copper = 1,
|
||||||
|
HardwareType_Hoag = 2,
|
||||||
|
HardwareType_Iowa = 3,
|
||||||
|
HardwareType_Calcio = 4,
|
||||||
|
HardwareType_Five = 5,
|
||||||
|
|
||||||
|
HardwareType_Undefined = 0xF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HardwareState {
|
||||||
|
HardwareState_Development = 0,
|
||||||
|
HardwareState_Production = 1,
|
||||||
|
HardwareState_Undefined = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetRegisterAddress(uintptr_t address);
|
||||||
|
void SetWriteSecureOnly();
|
||||||
|
void Lockout();
|
||||||
|
|
||||||
|
u32 GetOdmWord(int index);
|
||||||
|
|
||||||
|
HardwareType GetHardwareType();
|
||||||
|
HardwareState GetHardwareState();
|
||||||
|
pmic::Regulator GetRegulator();
|
||||||
|
|
||||||
|
}
|
42
libraries/libexosphere/include/exosphere/gic.hpp
Normal file
42
libraries/libexosphere/include/exosphere/gic.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::gic {
|
||||||
|
|
||||||
|
enum InterruptMode {
|
||||||
|
InterruptMode_Level = 0,
|
||||||
|
InterruptMode_Edge = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline s32 HighestPriority = 0;
|
||||||
|
constexpr inline s32 InterruptCount = 224;
|
||||||
|
|
||||||
|
void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address);
|
||||||
|
void InitializeCommon();
|
||||||
|
void InitializeCoreUnique();
|
||||||
|
|
||||||
|
void SetPriority(int interrupt_id, int priority);
|
||||||
|
void SetInterruptGroup(int interrupt_id, int group);
|
||||||
|
void SetEnable(int interrupt_id, bool enable);
|
||||||
|
void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask);
|
||||||
|
void SetSpiMode(int interrupt_id, InterruptMode mode);
|
||||||
|
|
||||||
|
int GetInterruptRequestId();
|
||||||
|
void SetEndOfInterrupt(int interrupt_id);
|
||||||
|
|
||||||
|
}
|
27
libraries/libexosphere/include/exosphere/hw.hpp
Normal file
27
libraries/libexosphere/include/exosphere/hw.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
|
#include <exosphere/hw/hw_arm64.hpp>
|
||||||
|
namespace ams::hw { using namespace ams::hw::arch::arm64; }
|
||||||
|
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||||
|
#include <exosphere/hw/hw_arm.hpp>
|
||||||
|
namespace ams::hw { using namespace ams::hw::arch::arm; }
|
||||||
|
#else
|
||||||
|
#error "Unknown architecture for hw!"
|
||||||
|
#endif
|
49
libraries/libexosphere/include/exosphere/hw/hw_arm.hpp
Normal file
49
libraries/libexosphere/include/exosphere/hw/hw_arm.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::hw::arch::arm {
|
||||||
|
|
||||||
|
#ifdef __BPMP__
|
||||||
|
constexpr inline size_t DataCacheLineSize = 0x1;
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataSynchronizationBarrier() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataMemoryBarrier() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InstructionSynchronizationBarrier() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FlushDataCache(const void *ptr, size_t size) {
|
||||||
|
AMS_UNUSED(ptr);
|
||||||
|
AMS_UNUSED(size);
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "Unknown ARM board for ams::hw"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
69
libraries/libexosphere/include/exosphere/hw/hw_arm64.hpp
Normal file
69
libraries/libexosphere/include/exosphere/hw/hw_arm64.hpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <exosphere/hw/hw_arm64_system_registers.hpp>
|
||||||
|
#include <exosphere/hw/hw_arm64_cache.hpp>
|
||||||
|
|
||||||
|
namespace ams::hw::arch::arm64 {
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataSynchronizationBarrier() {
|
||||||
|
__asm__ __volatile__("dsb sy" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() {
|
||||||
|
__asm__ __volatile__("dsb ish" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DataMemoryBarrier() {
|
||||||
|
__asm__ __volatile__("dmb sy" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InstructionSynchronizationBarrier() {
|
||||||
|
__asm__ __volatile__("isb" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void WaitForInterrupt() {
|
||||||
|
__asm__ __volatile__("wfi" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void WaitForEvent() {
|
||||||
|
__asm__ __volatile__("wfe" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void SendEvent() {
|
||||||
|
__asm__ __volatile__("sev" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int CountLeadingZeros(u64 v) {
|
||||||
|
u64 z;
|
||||||
|
__asm__ __volatile__("clz %[z], %[v]" : [z]"=r"(z) : [v]"r"(v));
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int CountLeadingZeros(u32 v) {
|
||||||
|
u32 z;
|
||||||
|
__asm__ __volatile__("clz %w[z], %w[v]" : [z]"=r"(z) : [v]"r"(v));
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int GetCurrentCoreId() {
|
||||||
|
u64 mpidr;
|
||||||
|
HW_CPU_GET_MPIDR_EL1(mpidr);
|
||||||
|
return mpidr & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::hw::arch::arm64 {
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_CPU_ARM_CORTEX_A57) || defined(ATMOSPHERE_CPU_ARM_CORTEX_A53)
|
||||||
|
constexpr inline size_t InstructionCacheLineSize = 0x40;
|
||||||
|
constexpr inline size_t DataCacheLineSize = 0x40;
|
||||||
|
constexpr inline size_t NumPerformanceCounters = 6;
|
||||||
|
#else
|
||||||
|
#error "Unknown CPU for cache line sizes"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateEntireTlb() {
|
||||||
|
__asm__ __volatile__("tlbi alle3is" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateDataCacheLine(void *ptr) {
|
||||||
|
__asm __volatile__("dc ivac, %[ptr]" :: [ptr]"r"(ptr) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FlushDataCacheLine(void *ptr) {
|
||||||
|
__asm __volatile__("dc civac, %[ptr]" :: [ptr]"r"(ptr) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateEntireInstructionCache() {
|
||||||
|
__asm__ __volatile__("ic iallu" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateTlb(uintptr_t address) {
|
||||||
|
__asm__ __volatile__("tlbi vae3is, %[address]" :: [address]"r"(address) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) {
|
||||||
|
__asm__ __volatile__("tlbi vale3is, %[address]" :: [address]"r"(address) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushDataCache(const void *ptr, size_t size);
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue