exo: implement start of mariko fatal handler

This commit is contained in:
Michael Scire 2020-11-15 12:58:13 -08:00 committed by SciresM
parent 123ed80dc7
commit 7bcd5c6e3b
28 changed files with 1138 additions and 24 deletions

View file

@ -24,7 +24,6 @@ namespace ams::secmon::loader {
/* 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);

View file

@ -0,0 +1,138 @@
#---------------------------------------------------------------------------------
# Define the atmosphere board and cpu
#---------------------------------------------------------------------------------
export ATMOSPHERE_BOARD := nx-hac-001
export ATMOSPHERE_CPU := arm-cortex-a57
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
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 ($(__RECURSIVE__),1)
#---------------------------------------------------------------------------------
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),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)/$(ATMOSPHERE_LIBRARY_DIR))
export TOPDIR := $(CURRENT_DIRECTORY)
OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR))
#---------------------------------------------------------------------------------
ATMOSPHERE_BUILD_CONFIGS :=
all: release
define ATMOSPHERE_ADD_TARGET
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1)
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
LIBEXOSPHERE_NAME=exosphere$(strip $2) \
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
-f $$(THIS_MAKEFILE)
check_libexo_$(strip $1):
@$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1)
clean-$(strip $1):
@echo clean $(strip $1) ...
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf
endef
$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \
ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \
))
$(ATMOSPHERE_BUILD_DIR)/%:
@[ -d $@ ] || mkdir -p $@
#---------------------------------------------------------------------------------
clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config))
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).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,227 @@
OUTPUT_ARCH(aarch64)
ENTRY(_start)
MEMORY
{
NULL : ORIGIN = 0, LENGTH = 4K
mariko_tzram : ORIGIN = 0x1F00D0000, LENGTH = 128K
}
SECTIONS
{
/* =========== CODE section =========== */
PROVIDE(__start__ = ORIGIN(mariko_tzram));
. = __start__;
__code_start = . ;
.crt0 :
{
KEEP (*(.crt0 .crt0.*))
KEEP (fatal_crt0_cpp.o(.text*))
*(.crt0.rodata*)
fatal_crt0_cpp.o(.rodata*)
*(.crt0.data*)
fatal_crt0_cpp.o(.data*)
. = ALIGN(8);
} >mariko_tzram
.preinit_array ALIGN(8) :
{
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
} >mariko_tzram
.init_array ALIGN(8) :
{
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
} >mariko_tzram
.fini_array ALIGN(8) :
{
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
} >mariko_tzram
.ctors ALIGN(8) :
{
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >mariko_tzram
.dtors ALIGN(8) :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >mariko_tzram
.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);
} >mariko_tzram
.init :
{
KEEP( *(.init) )
. = ALIGN(8);
} >mariko_tzram
.plt :
{
*(.plt)
*(.iplt)
. = ALIGN(8);
} >mariko_tzram
.fini :
{
KEEP( *(.fini) )
. = ALIGN(8);
} >mariko_tzram
/* =========== RODATA section =========== */
. = ALIGN(8);
__rodata_start = . ;
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(8);
} >mariko_tzram
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >mariko_tzram
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >mariko_tzram
.hash : { *(.hash) } >mariko_tzram
/* =========== DATA section =========== */
. = ALIGN(8);
__data_start = . ;
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >mariko_tzram
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >mariko_tzram
.preinit_array ALIGN(8) :
{
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
} >mariko_tzram
.init_array ALIGN(8) :
{
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
} >mariko_tzram
.fini_array ALIGN(8) :
{
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
} >mariko_tzram
.ctors ALIGN(8) :
{
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >mariko_tzram
.dtors ALIGN(8) :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >mariko_tzram
__got_start__ = .;
.got : { *(.got) *(.igot) } >mariko_tzram
.got.plt : { *(.got.plt) *(.igot.plt) } >mariko_tzram
__got_end__ = .;
.data ALIGN(8) :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
} >mariko_tzram
__bss_start__ = .;
.bss ALIGN(8) :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(16);
} >mariko_tzram
__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 /mariko_fatal.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

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/>.
*/
#include <exosphere.hpp>
namespace ams::diag {
void AbortImpl() {
AMS_SECMON_LOG("AbortImpl was called\n");
/* TODO: Reboot */
AMS_INFINITE_LOOP();
}
#include <exosphere/diag/diag_detailed_assertion_impl.inc>
}

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/>.
*/
.section .crt0.text.start, "ax", %progbits
.align 6
.global _start
_start:
/* Set the stack pointer to a temporary location. */
ldr x20, =0x1F00FC000
mov sp, x20
/* Initialize all memory to expected state. */
ldr x0, =__bss_start__
ldr x1, =__bss_end__
bl _ZN3ams6secmon5fatal10InitializeEmm
/* Jump to the fatal program. */
ldr x16, =_ZN3ams6secmon5fatal4MainEv
br x16

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/>.
*/
#include <exosphere.hpp>
extern "C" void __libc_init_array();
namespace ams::secmon::fatal {
void Initialize(uintptr_t bss_start, size_t bss_end) {
/* Clear bss. */
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
/* Call init array. */
__libc_init_array();
}
}

View file

@ -0,0 +1,307 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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::fatal {
namespace {
/* Definitions. */
constexpr size_t PageDirectorySize = mmu::PageSize;
constexpr size_t PageTableSize = mmu::PageSize;
static_assert(PageDirectorySize == mmu::PageSize);
using DeviceVirtualAddress = u64;
constexpr size_t AsidCount = 0x80;
constexpr size_t PhysicalAddressBits = 34;
constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul;
constexpr size_t DeviceVirtualAddressBits = 34;
constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul;
constexpr size_t DevicePageBits = 12;
constexpr size_t DevicePageSize = (1ul << DevicePageBits);
static_assert(DevicePageSize == mmu::PageSize);
constexpr size_t DeviceLargePageBits = 22;
constexpr size_t DeviceLargePageSize = (1ul << DeviceLargePageBits);
static_assert(DeviceLargePageSize % DevicePageSize == 0);
constexpr size_t DeviceRegionBits = 32;
constexpr size_t DeviceRegionSize = (1ul << DeviceRegionBits);
static_assert(DeviceRegionSize % DeviceLargePageSize == 0);
constexpr const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
constexpr size_t TableCount = (1ul << DeviceVirtualAddressBits) / DeviceRegionSize;
constexpr u8 SdmmcAsid = 1;
constexpr u32 SdmmcAsidRegisterValue = [] {
u32 value = 0x80000000u;
for (size_t t = 0; t < TableCount; t++) {
value |= (SdmmcAsid << (BITSIZEOF(u8) * t));
}
return value;
}();
constexpr dd::PhysicalAddress SdmmcL0PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L0DevicePageTable.GetAddress();
constexpr dd::PhysicalAddress SdmmcL1PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L1DevicePageTable.GetAddress();
/* Types. */
class EntryBase {
protected:
enum Bit : u32 {
Bit_Table = 28,
Bit_NonSecure = 29,
Bit_Writeable = 30,
Bit_Readable = 31,
};
private:
u32 value;
protected:
constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const {
return (this->value & (1u << n));
}
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
return this->SelectBit(n) != 0;
}
static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) {
return en ? (1u << n) : 0;
}
static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, dd::PhysicalAddress addr, bool t) {
return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast<u32>(addr >> DevicePageBits);
}
ALWAYS_INLINE void SetValue(u32 v) {
/* Prevent re-ordering around entry modifications. */
__asm__ __volatile__("" ::: "memory");
this->value = v;
__asm__ __volatile__("" ::: "memory");
}
public:
static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(dd::PhysicalAddress addr) {
return EncodeValue(true, true, true, addr, false);
}
public:
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); }
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(this->value) << DevicePageBits) & PhysicalAddressMask; }
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
};
class PageDirectoryEntry : public EntryBase {
public:
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); }
ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
this->SetValue(EncodeValue(r, w, ns, addr, true));
}
ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
AMS_ASSERT(util::IsAligned(addr, DeviceLargePageSize));
this->SetValue(EncodeValue(r, w, ns, addr, false));
}
};
class PageTableEntry : public EntryBase {
public:
ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, dd::PhysicalAddress addr) {
AMS_ASSERT(util::IsAligned(addr, DevicePageSize));
this->SetValue(EncodeValue(r, w, ns, addr, true));
}
};
/* Memory controller access functionality. */
void WriteMcRegister(size_t offset, u32 value) {
reg::Write(MC + offset, value);
}
u32 ReadMcRegister(size_t offset) {
return reg::Read(MC + offset);
}
/* Memory controller utilities. */
void SmmuSynchronizationBarrier() {
ReadMcRegister(MC_SMMU_CONFIG);
}
void InvalidatePtc() {
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0);
}
void InvalidatePtc(dd::PhysicalAddress address) {
WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(address) >> 32));
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (address & 0xFFFFFFF0u) | 1u);
}
enum TlbFlushVaMatch : u32 {
TlbFlushVaMatch_All = 0,
TlbFlushVaMatch_Section = 2,
TlbFlushVaMatch_Group = 3,
};
static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, dd::PhysicalAddress address, TlbFlushVaMatch match) {
return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match);
}
void InvalidateTlb() {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All));
}
void InvalidateTlb(u8 asid) {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All));
}
void InvalidateTlbSection(u8 asid, dd::PhysicalAddress address) {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section));
}
void SetTable(u8 asid, dd::PhysicalAddress address) {
/* Write the table address. */
{
WriteMcRegister(MC_SMMU_PTB_ASID, asid);
WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address));
SmmuSynchronizationBarrier();
}
/* Ensure consistency. */
InvalidatePtc();
InvalidateTlb(asid);
SmmuSynchronizationBarrier();
}
void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address) {
/* Cache permissions. */
const bool read = true;
const bool write = true;
/* Walk the directory. */
u64 remaining = size;
while (remaining > 0) {
const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize;
const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize;
/* Get and validate l1. */
PageDirectoryEntry *l1 = static_cast<PageDirectoryEntry *>(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>());
AMS_ASSERT(l1 != nullptr);
/* Setup an l1 table/entry, if needed. */
if (!l1[l1_index].IsTable()) {
/* Check that an entry doesn't already exist. */
AMS_ASSERT(!l1[l1_index].IsValid());
/* If we can make an l1 entry, do so. */
if (l2_index == 0 && util::IsAligned(phys_addr, DeviceLargePageSize) && remaining >= DeviceLargePageSize) {
/* Set the large page. */
l1[l1_index].SetLargePage(read, write, true, phys_addr);
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
/* Synchronize. */
InvalidatePtc(SdmmcL1PageTablePhysical);
InvalidateTlbSection(SdmmcAsid, address);
SmmuSynchronizationBarrier();
/* Advance. */
phys_addr += DeviceLargePageSize;
address += DeviceLargePageSize;
remaining -= DeviceLargePageSize;
continue;
} else {
/* Make an l1 table. */
std::memset(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>(), mmu::PageSize);
/* Set the l1 table. */
l1[l1_index].SetTable(true, true, true, SdmmcL1PageTablePhysical);
hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
/* Synchronize. */
InvalidatePtc(SdmmcL1PageTablePhysical);
InvalidateTlbSection(SdmmcAsid, address);
SmmuSynchronizationBarrier();
}
}
/* If we get to this point, l1 must be a table. */
AMS_ASSERT(l1[l1_index].IsTable());
/* Map l2 entries. */
{
PageTableEntry *l2 = static_cast<PageTableEntry *>(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>());
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
/* Set the entries. */
for (size_t i = 0; i < map_count; ++i) {
AMS_ASSERT(!l2[l2_index + i].IsValid());
l2[l2_index + i].SetPage(read, write, true, phys_addr + DevicePageSize * i);
}
hw::FlushDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
/* Invalidate the page table cache. */
for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) {
InvalidatePtc(SdmmcL1PageTablePhysical + i * sizeof(PageTableEntry));
}
/* Synchronize. */
InvalidateTlbSection(SdmmcAsid, address);
SmmuSynchronizationBarrier();
/* Advance. */
phys_addr += map_count * DevicePageSize;
address += map_count * DevicePageSize;
remaining -= map_count * DevicePageSize;
}
}
}
}
void InitializeDevicePageTableForSdmmc1() {
/* Configure sdmmc to use our new page table. */
WriteMcRegister(MC_SMMU_SDMMC1A_ASID, SdmmcAsidRegisterValue);
SmmuSynchronizationBarrier();
/* Ensure consistency. */
InvalidatePtc();
InvalidateTlb();
SmmuSynchronizationBarrier();
/* Clear the L0 Page Table. */
std::memset(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize);
hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), mmu::PageSize);
/* Set the page table for the sdmmc asid. */
SetTable(SdmmcAsid, SdmmcL0PageTablePhysical);
/* Map the appropriate region into the asid. */
MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress());
}
}

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::fatal {
void InitializeDevicePageTableForSdmmc1();
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 "fatal_sdmmc.hpp"
namespace ams::secmon::fatal {
void Main() {
/* Set library register addresses. */
actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress());
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
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(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress());
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress(), MemoryRegionVirtualDeviceSecurityEngine2.GetAddress());
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
/* Ensure that the log library is initialized. */
log::Initialize();
AMS_SECMON_LOG("%s\n", "Fatal start.");
/* Initialize the sdmmc driver. */
Result result = InitializeSdCard();
AMS_SECMON_LOG("InitializeSdCard: %08x\n", result.GetValue());
/* TODO */
AMS_INFINITE_LOOP();
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 "fatal_device_page_table.hpp"
namespace ams::secmon::fatal {
namespace {
constexpr inline auto Port = sdmmc::Port_SdCard0;
ALWAYS_INLINE u8 *GetSdCardWorkBuffer() {
return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>() + MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize;
}
}
Result InitializeSdCard() {
/* Map main memory for the sdmmc device. */
AMS_SECMON_LOG("%s\n", "Initializing Device Page Table.");
InitializeDevicePageTableForSdmmc1();
AMS_SECMON_LOG("%s\n", "Initialized Device Page Table.");
/* Initialize sdmmc library. */
sdmmc::Initialize(Port);
AMS_SECMON_LOG("%s\n", "Initialized Sdmmc Port.");
sdmmc::SetSdCardWorkBuffer(Port, GetSdCardWorkBuffer(), sdmmc::SdCardWorkBufferSize);
AMS_SECMON_LOG("%s\n", "Set SD Card Work Buffer.");
R_TRY(sdmmc::Activate(Port));
AMS_SECMON_LOG("%s\n", "Activated.");
return ResultSuccess();
}
}

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::fatal {
Result InitializeSdCard();
}

View file

@ -106,6 +106,17 @@ SECTIONS
.debug_code : {
KEEP (*(.text._ZN3ams3log6PrintfEPKcz .text._ZN3ams3log7VPrintfEPKcSt9__va_list .text._ZN3ams3log4DumpEPKvm))
KEEP (*(.text._ZN3ams4util10TVSNPrintfEPcmPKcSt9__va_list .text._ZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_list .text._ZZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_listENKUlbmE3_clEbm))
KEEP(secmon_exception_handler.o(.text*))
secmon_exception_handler.o(.rodata*)
secmon_exception_handler.o(.data*)
} >debug_code AT>glob
.debug_code.bss_fill :
{
FILL(0x00000000);
secmon_exception_handler.o(.bss* COMMON)
. = ORIGIN(debug_code) + LENGTH(debug_code) - 1;
BYTE(0x00);
} >debug_code AT>glob
__bootcode_end__ = ABSOLUTE(.) - ORIGIN(debug_code) + 0x40034000;
@ -138,8 +149,9 @@ SECTIONS
. = ALIGN(8);
} >tzram_boot AT>glob
.tzram_boot_code.bss :
.tzram_boot_code.bss_fill :
{
FILL(0x00000000);
__boot_bss_start__ = ABSOLUTE(.);
secmon_main.o(.bss* COMMON)
secmon_boot_functions.o(.bss* COMMON)
@ -149,11 +161,6 @@ SECTIONS
secmon_boot_rsa.o(.bss* COMMON)
secmon_package2.o(.bss* COMMON)
__boot_bss_end__ = ABSOLUTE(.);
} >tzram_boot AT>glob
.tzram_boot_code.fill :
{
FILL(0x00000000);
. = ORIGIN(tzram_boot) + LENGTH(tzram_boot) - 1;
BYTE(0x00);
} > tzram_boot AT>glob

View file

@ -188,7 +188,7 @@ namespace ams::secmon::boot {
const u8 key_generation = meta.GetKeyGeneration();
/* Decrypt or load each payload in order. */
for (int i = 0; i < pkg2::PayloadCount; ++i) {
AMS_SECMON_LOG("pkg2 payload[%d]: %09lx -> %09lx size=%08x\n", i, dst + meta.payload_offsets[i], src, meta.payload_sizes[i]);
AMS_SECMON_LOG("pkg2 payload[%d]: %09lx -> %09lx size=%08x\n", i, src, dst + meta.payload_offsets[i], meta.payload_sizes[i]);
if (encrypted) {
DecryptPayload(dst + meta.payload_offsets[i], src, meta.payload_sizes[i], meta.payload_ivs[i], sizeof(meta.payload_ivs[i]), key_generation);

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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::secmon {
namespace {
constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
constinit std::atomic_bool g_is_locked = false;
}
void ExceptionHandlerImpl(uintptr_t lr, uintptr_t sp) {
/* Ensure that previous logs have been flushed. */
AMS_LOG_FLUSH();
/* Get system registers. */
uintptr_t far_el1, far_el3, elr_el3;
util::BitPack32 esr_el3;
HW_CPU_GET_FAR_EL1(far_el1);
HW_CPU_GET_FAR_EL3(far_el3);
HW_CPU_GET_ELR_EL3(elr_el3);
HW_CPU_GET_ESR_EL3(esr_el3);
/* Print some whitespace before the exception handler. */
AMS_LOG("\n\n");
AMS_SECMON_LOG("ExceptionHandler\n");
AMS_SECMON_LOG("----------------\n");
AMS_SECMON_LOG("esr: 0x%08X\n", esr_el3.value);
AMS_SECMON_LOG(" Exception Class: 0x%02X\n", esr_el3.Get<hw::EsrEl3::Ec>());
AMS_SECMON_LOG(" Instruction Length: %d\n", esr_el3.Get<hw::EsrEl3::Il>() ? 32 : 16);
AMS_SECMON_LOG(" Instruction Specific Syndrome: 0x%07X\n", esr_el3.Get<hw::EsrEl3::Iss>());
AMS_SECMON_LOG("far_el1: 0x%016lX\n", far_el1);
AMS_SECMON_LOG("far_el3: 0x%016lX\n", far_el3);
AMS_SECMON_LOG("elr_el3: 0x%016lX\n", elr_el3);
AMS_SECMON_LOG("lr: 0x%016lX\n", lr);
AMS_SECMON_LOG("sp: 0x%016lX\n", sp);
AMS_DUMP(reinterpret_cast<void *>(sp), util::AlignUp(sp, mmu::PageSize) - sp);
AMS_LOG_FLUSH();
}
NORETURN void ExceptionHandler() {
/* Get link register and stack pointer. */
u64 lr, sp;
{
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
__asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory");
}
/* Acquire exclusive access to exception handling logic. */
if (g_is_locked.exchange(true)) {
/* Invoke the exception handler impl. */
ExceptionHandlerImpl(lr, sp);
/* Lockout the security engine. */
se::Lockout();
/* Lockout fuses. */
fuse::Lockout();
/* Disable crypto operations after reboot. */
reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0);
/* Perform an error reboot. */
secmon::SetError(pkg1::ErrorInfo_UnknownAbort);
secmon::ErrorReboot();
} else {
/* Wait forever while the first core prints the exception and reboots. */
while (true) {
util::WaitMicroSeconds(1000);
}
}
}
}

View file

@ -76,6 +76,11 @@ vector_entry synch_sp0
.endfunc
.cfi_endproc
_ZN3ams6secmon26UnexpectedExceptionHandlerEv:
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
/* Jump to the debug exception handler. */
ldr x16, =_ZN3ams6secmon16ExceptionHandlerEv
br x16
#else
/* Load the ErrorInfo scratch. */
ldr x0, =0x1F004AC40
@ -85,6 +90,7 @@ _ZN3ams6secmon26UnexpectedExceptionHandlerEv:
/* Perform an error reboot. */
b _ZN3ams6secmon11ErrorRebootEv
#endif
vector_entry irq_sp0
/* An unexpected exception was taken. */

View file

@ -84,6 +84,26 @@ namespace ams::secmon {
PerformPmcReboot();
}
void PerformUserRebootToFatalError() {
if (fuse::GetSocType() == fuse::SocType_Erista) {
/* On Erista, we reboot to fatal error by jumping to fusee primary's handler. */
return PerformUserRebootToPayload();
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
/* TODO: Send a SGI FIQ to the other CPUs, so that user code stops executing. */
/* TODO: On cores other than 3, halt/wfi. */
AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal.");
AMS_LOG_FLUSH();
/* Jump to the mariko fatal program. */
reinterpret_cast<void (*)()>(secmon::MemoryRegionVirtualTzramMarikoProgram.GetAddress())();
/* The mariko fatal program never returns. */
__builtin_unreachable();
}
}
void PerformUserShutDown() {
/* Load our reboot stub to iram. */
LoadRebootStub(RebootStubAction_ShutDown);

View file

@ -19,13 +19,15 @@
namespace ams::secmon {
enum UserRebootType {
UserRebootType_None = 0,
UserRebootType_ToRcm = 1,
UserRebootType_ToPayload = 2,
UserRebootType_None = 0,
UserRebootType_ToRcm = 1,
UserRebootType_ToPayload = 2,
UserRebootType_ToFatalError = 3,
};
void PerformUserRebootToRcm();
void PerformUserRebootToPayload();
void PerformUserRebootToFatalError();
void PerformUserShutDown();
}

View file

@ -304,11 +304,20 @@ namespace ams::secmon::smc {
case UserRebootType_ToPayload:
PerformUserRebootToPayload();
break;
case UserRebootType_ToFatalError:
PerformUserRebootToFatalError();
break;
default:
return SmcResult::InvalidArgument;
}
} else /* if (soc_type == fuse::SocType_Mariko) */ {
return SmcResult::NotImplemented;
switch (static_cast<UserRebootType>(args.r[3])) {
case UserRebootType_ToFatalError:
PerformUserRebootToFatalError();
break;
default:
return SmcResult::InvalidArgument;
}
}
break;
case ConfigItem::ExosphereNeedsShutdown:

View file

@ -43,6 +43,15 @@ namespace ams::hw::arch::arm64 {
#define HW_CPU_GET_VBAR_EL3(value) HW_CPU_GET_SYSREG(vbar_el3, value)
#define HW_CPU_SET_VBAR_EL3(value) HW_CPU_SET_SYSREG(vbar_el3, value)
#define HW_CPU_GET_ELR_EL3(value) HW_CPU_GET_SYSREG(elr_el3, value)
#define HW_CPU_SET_ELR_EL3(value) HW_CPU_SET_SYSREG(elr_el3, value)
#define HW_CPU_GET_FAR_EL3(value) HW_CPU_GET_SYSREG(far_el3, value)
#define HW_CPU_SET_FAR_EL3(value) HW_CPU_SET_SYSREG(far_el3, value)
#define HW_CPU_GET_ESR_EL3(value) HW_CPU_GET_SYSREG(esr_el3, value)
#define HW_CPU_SET_ESR_EL3(value) HW_CPU_SET_SYSREG(esr_el3, value)
#define HW_CPU_GET_CLIDR_EL1(value) HW_CPU_GET_SYSREG(clidr_el1, value)
#define HW_CPU_SET_CLIDR_EL1(value) HW_CPU_SET_SYSREG(clidr_el1, value)
@ -84,6 +93,9 @@ namespace ams::hw::arch::arm64 {
#define HW_CPU_GET_DBGCLAIMCLR_EL1(value) HW_CPU_GET_SYSREG(dbgclaimclr_el1, value)
#define HW_CPU_SET_DBGCLAIMCLR_EL1(value) HW_CPU_SET_SYSREG(dbgclaimclr_el1, value)
#define HW_CPU_GET_FAR_EL1(value) HW_CPU_GET_SYSREG(far_el1, value)
#define HW_CPU_SET_FAR_EL1(value) HW_CPU_SET_SYSREG(far_el1, value)
#define HW_CPU_GET_DBGVCR32_EL2(value) HW_CPU_GET_SYSREG(dbgvcr32_el2, value)
#define HW_CPU_SET_DBGVCR32_EL2(value) HW_CPU_SET_SYSREG(dbgvcr32_el2, value)
@ -327,4 +339,10 @@ namespace ams::hw::arch::arm64 {
using Rw = util::BitPack64::Field<31, 1>;
};
struct EsrEl3 {
using Iss = util::BitPack32::Field< 0, 25>;
using Il = util::BitPack32::Field<25, 1>;
using Ec = util::BitPack32::Field<26, 6>;
};
}

View file

@ -143,7 +143,8 @@ namespace ams::secmon {
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__)
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__)
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \
@ -258,6 +259,15 @@ namespace ams::secmon {
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore));
static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore));
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L0DevicePageTable = MemoryRegion(UINT64_C(0x1F010F000), 0x1000);
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L0DevicePageTable = MemoryRegion( UINT64_C(0x8001F000), 0x1000);
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L1DevicePageTable = MemoryRegion(UINT64_C(0x1F010E000), 0x1000);
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L1DevicePageTable = MemoryRegion( UINT64_C(0x8001E000), 0x1000);
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmcMappedData = MemoryRegion(UINT64_C(0x1F0100000), 0xE000);
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmcMappedData = MemoryRegion(UINT64_C(0x80010000), 0xE000);
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x1F0100000), 0xE000);
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x1F010E000), 0x17C0);
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x1F010F7C0), 0x0840);

View file

@ -23,6 +23,7 @@ namespace ams::exosphere {
void ForceRebootToRcm();
void ForceRebootToIramPayload();
void ForceRebootToFatalError();
void ForceShutdown();
bool IsRcmBugPatched();

View file

@ -36,6 +36,10 @@ namespace ams::exosphere {
R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 2)));
}
void ForceRebootToFatalError() {
R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 3)));
}
void ForceShutdown() {
R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::SetConfig(spl::ConfigItem::ExosphereNeedsShutdown, 1)));
}

View file

@ -28,9 +28,20 @@ namespace ams::dd {
uintptr_t QueryIoMapping(dd::PhysicalAddress phys_addr, size_t size) {
#if defined(ATMOSPHERE_IS_EXOSPHERE)
#if defined(ATMOSPHERE_ARCH_ARM64)
/* TODO: Secure Monitor translation? */
AMS_UNUSED(size);
return static_cast<uintptr_t>(phys_addr);
/* TODO: Do this in a less shitty way. */
if (secmon::MemoryRegionPhysicalDeviceClkRst.Contains(phys_addr, size)) {
return secmon::MemoryRegionVirtualDeviceClkRst.GetAddress() + phys_addr - secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
} else if (secmon::MemoryRegionPhysicalDeviceGpio.Contains(phys_addr, size)) {
return secmon::MemoryRegionVirtualDeviceGpio.GetAddress() + phys_addr - secmon::MemoryRegionPhysicalDeviceGpio.GetAddress();
} else if (secmon::MemoryRegionPhysicalDeviceApbMisc.Contains(phys_addr, size)) {
return secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress() + phys_addr - secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress();
} else if (secmon::MemoryRegionPhysicalDeviceSdmmc.Contains(phys_addr, size)) {
return secmon::MemoryRegionVirtualDeviceSdmmc.GetAddress() + phys_addr - secmon::MemoryRegionPhysicalDeviceSdmmc.GetAddress();
} else {
AMS_UNUSED(size);
return static_cast<uintptr_t>(phys_addr);
}
#elif defined(ATMOSPHERE_ARCH_ARM)
/* TODO: BPMP translation? */
AMS_UNUSED(size);

View file

@ -143,9 +143,9 @@ namespace ams::sdmmc::impl {
virtual void SetWorkBuffer(void *wb, size_t wb_size) = 0;
virtual Result Startup(BusPower bus_power, BusWidth bus_width, SpeedMode speed_mode, bool power_saving_enable) = 0;
virtual void Shutdown();
virtual void PutToSleep();
virtual Result Awaken();
virtual void Shutdown() = 0;
virtual void PutToSleep() = 0;
virtual Result Awaken() = 0;
virtual Result SwitchToSdr12();

View file

@ -68,7 +68,7 @@ namespace ams::mitm::bpc {
exosphere::CopyToIram(IramPayloadBase + IramFatalErrorContextOffset, g_work_page, sizeof(g_work_page));
}
exosphere::ForceRebootToIramPayload();
exosphere::ForceRebootToFatalError();
}
}

View file

@ -216,6 +216,8 @@ int main(int argc, char **argv)
boot::CheckBatteryCharge();
}
AMS_ABORT_UNLESS(spl::GetSocType() != spl::SocType_Mariko);
/* Configure pinmux + drive pads. */
boot::SetInitialPinmuxConfiguration();

View file

@ -43,7 +43,20 @@ namespace ams::boot {
}
}
void DoRebootToPayload(ams::FatalErrorContext *ctx) {
void DoRebootToPayload() {
/* Ensure clean IRAM state. */
ClearIram();
/* Copy in payload. */
for (size_t ofs = 0; ofs < fusee_primary_bin_size; ofs += sizeof(g_work_page)) {
std::memcpy(g_work_page, &fusee_primary_bin[ofs], std::min(static_cast<size_t>(fusee_primary_bin_size - ofs), sizeof(g_work_page)));
exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, sizeof(g_work_page));
}
exosphere::ForceRebootToIramPayload();
}
void DoRebootToFatalError(ams::FatalErrorContext *ctx) {
/* Ensure clean IRAM state. */
ClearIram();
@ -61,14 +74,14 @@ namespace ams::boot {
exosphere::CopyToIram(IramPayloadBase + IramFatalErrorContextOffset, g_work_page, sizeof(g_work_page));
}
exosphere::ForceRebootToIramPayload();
exosphere::ForceRebootToFatalError();
}
}
void RebootSystem() {
if (spl::GetSocType() == spl::SocType_Erista) {
DoRebootToPayload(nullptr);
DoRebootToPayload();
} else {
/* On Mariko, we can't reboot to payload, so we should just do a reboot. */
PmicDriver().RebootSystem();
@ -84,7 +97,7 @@ namespace ams::boot {
}
void RebootForFatalError(ams::FatalErrorContext *ctx) {
DoRebootToPayload(ctx);
DoRebootToFatalError(ctx);
}
}