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:
Michael Scire 2020-05-04 23:33:16 -07:00 committed by SciresM
parent 71e0102f7a
commit f66b41c027
192 changed files with 15093 additions and 24 deletions

1
.gitignore vendored
View file

@ -31,6 +31,7 @@
# Executables
*.exe
*.lz4
*.out
*.app
*.i*86

38
exosphere2/Makefile Normal file
View 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)

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

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

View 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

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

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

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

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

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

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

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

View file

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

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

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

View 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

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

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

View 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

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

View 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

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

View 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

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

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

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

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

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

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

View 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

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

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

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

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

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

View 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

View 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();

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

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

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

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

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

View 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

View 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.");
}
}

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

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

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

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

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

View 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() {
}
}

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

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

View 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

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

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

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

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

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

View 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_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;
}
}

View 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 SmcDecryptDeviceUniqueData(const SmcArguments &args);
SmcResult SmcReencryptDeviceUniqueData(const SmcArguments &args);
/* Legacy APIs. */
SmcResult SmcDecryptAndImportEsDeviceKey(const SmcArguments &args);
SmcResult SmcDecryptAndImportLotusKey(const SmcArguments &args);
}

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

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

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

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

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

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

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

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

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

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

View 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/>.
*/
#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;
}
}

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

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

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

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

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

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

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

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

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

View 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))

View 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 +=

View 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 +=

View 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 +=

View file

@ -8,12 +8,13 @@ export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/..
ifeq ($(strip $(ATMOSPHERE_BOARD)),)
export ATMOSPHERE_BOARD := nx-hac-001
endif
ifeq ($(strip $(ATMOSPHERE_CPU)),)
export ATMOSPHERE_CPU := arm-cortex-a57
endif
endif
export ATMOSPHERE_DEFINES := -DATMOSPHERE
export ATMOSPHERE_SETTINGS := -fPIE -g
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_CPU),arm-cortex-a57)
export ATMOSPHERE_ARCH_DIR := arch/arm64
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx
export ATMOSPHERE_OS_DIR := os/horizon
@ -30,6 +33,16 @@ export ATMOSPHERE_OS_DIR := os/horizon
export ATMOSPHERE_ARCH_NAME := arm64
export ATMOSPHERE_BOARD_NAME := nintendo_nx
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
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
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_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_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_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_BOARD_MAKE_DIR)/board.mk
include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk

View 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

View 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

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

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

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

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

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

View 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

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

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

View 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

View 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
}

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

View file

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