diff --git a/exosphere2/Makefile b/exosphere2/Makefile
index 9b72ff1ec..20619aed9 100644
--- a/exosphere2/Makefile
+++ b/exosphere2/Makefile
@@ -11,6 +11,7 @@ clean: $(CLEAN_TARGETS)
exosphere.bin: program.lz4 boot_code.lz4
$(MAKE) -C loader_stub
@cp loader_stub/loader_stub.bin exosphere.bin
+ @printf LENY >> exosphere.bin
@echo "Built exosphere.bin..."
program.lz4: check_libexo
@@ -32,7 +33,6 @@ program-clean:
@rm -f program.lz4
boot_code-clean:
- $(MAKE) -C boot_code clean
@rm -f boot_code.lz4
.PHONY: all clean $(CLEAN_TARGETS)
diff --git a/exosphere2/program/Makefile b/exosphere2/program/Makefile
index 427061ca9..23b18af76 100644
--- a/exosphere2/program/Makefile
+++ b/exosphere2/program/Makefile
@@ -22,7 +22,8 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
- $(TOPDIR)/sc7fw
+ $(TOPDIR)/sc7fw \
+ $(TOPDIR)/rebootstub
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))))
@@ -42,7 +43,7 @@ SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATM
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 := sc7fw.bin
+BINFILES := sc7fw.bin rebootstub.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@@ -74,20 +75,22 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_L
#---------------------------------------------------------------------------------
all: $(BUILD) check_libexo
-$(BUILD): check_libexo check_sc7fw
+$(BUILD): check_libexo check_firmwares
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
check_libexo:
@$(MAKE) --no-print-directory -C ../../libraries/libexosphere arm64
-check_sc7fw:
+check_firmwares:
@$(MAKE) -C $(TOPDIR)/sc7fw all
+ @$(MAKE) -C $(TOPDIR)/rebootstub all
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@$(MAKE) -C $(TOPDIR)/sc7fw clean
+ @$(MAKE) -C $(TOPDIR)/rebootstub clean
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4
#---------------------------------------------------------------------------------
diff --git a/exosphere2/program/rebootstub/Makefile b/exosphere2/program/rebootstub/Makefile
new file mode 100644
index 000000000..31439e834
--- /dev/null
+++ b/exosphere2/program/rebootstub/Makefile
@@ -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
+#---------------------------------------------------------------------------------------
diff --git a/exosphere2/program/rebootstub/rebootstub.ld b/exosphere2/program/rebootstub/rebootstub.ld
new file mode 100644
index 000000000..c37c7555f
--- /dev/null
+++ b/exosphere2/program/rebootstub/rebootstub.ld
@@ -0,0 +1,183 @@
+OUTPUT_ARCH(arm)
+ENTRY(reset)
+
+MEMORY
+{
+ NULL : ORIGIN = 0, LENGTH = 4K
+ rebootstub : ORIGIN = 0x4003F000, LENGTH = 4K
+}
+
+
+SECTIONS
+{
+ /* =========== CODE section =========== */
+ PROVIDE(__start__ = ORIGIN(rebootstub));
+ . = __start__;
+ __code_start = . ;
+
+ .vectors :
+ {
+ KEEP (*(.vectors .vectors.*))
+ . = ALIGN(8);
+ } >rebootstub
+
+ .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);
+ } >rebootstub
+
+ .init :
+ {
+ KEEP( *(.init) )
+ . = ALIGN(8);
+ } >rebootstub
+
+ .plt :
+ {
+ *(.plt)
+ *(.iplt)
+ . = ALIGN(8);
+ } >rebootstub
+
+ .fini :
+ {
+ KEEP( *(.fini) )
+ . = ALIGN(8);
+ } >rebootstub
+
+
+ /* =========== RODATA section =========== */
+ . = ALIGN(8);
+ __rodata_start = . ;
+
+ .rodata :
+ {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ . = ALIGN(8);
+ } >rebootstub
+
+ .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >rebootstub
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >rebootstub
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >rebootstub
+ .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >rebootstub
+
+ .hash : { *(.hash) } >rebootstub
+
+ /* =========== DATA section =========== */
+ . = ALIGN(8);
+ __data_start = . ;
+
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >rebootstub
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >rebootstub
+ .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >rebootstub
+ .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >rebootstub
+
+ .preinit_array ALIGN(8) :
+ {
+ PROVIDE (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE (__preinit_array_end = .);
+ } >rebootstub
+
+ .init_array ALIGN(8) :
+ {
+ PROVIDE (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE (__init_array_end = .);
+ } >rebootstub
+
+ .fini_array ALIGN(8) :
+ {
+ PROVIDE (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE (__fini_array_end = .);
+ } >rebootstub
+
+ .ctors ALIGN(8) :
+ {
+ KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ } >rebootstub
+
+ .dtors ALIGN(8) :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ } >rebootstub
+
+ __got_start__ = .;
+
+ .got : { *(.got) *(.igot) } >rebootstub
+ .got.plt : { *(.got.plt) *(.igot.plt) } >rebootstub
+
+ __got_end__ = .;
+
+ .data ALIGN(8) :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ } >rebootstub
+
+ __bss_start__ = .;
+ .bss ALIGN(8) :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(16);
+ } >rebootstub
+ __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) }
+}
\ No newline at end of file
diff --git a/exosphere2/program/rebootstub/rebootstub.specs b/exosphere2/program/rebootstub/rebootstub.specs
new file mode 100644
index 000000000..4e41b1615
--- /dev/null
+++ b/exosphere2/program/rebootstub/rebootstub.specs
@@ -0,0 +1,7 @@
+%rename link old_link
+
+*link:
+%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
+
+*startfile:
+crti%O%s crtbegin%O%s
diff --git a/exosphere2/program/rebootstub/source/rebootstub_exception_vectors.s b/exosphere2/program/rebootstub/source/rebootstub_exception_vectors.s
new file mode 100644
index 000000000..eaf62f151
--- /dev/null
+++ b/exosphere2/program/rebootstub/source/rebootstub_exception_vectors.s
@@ -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 .
+ */
+
+.section .vectors, "ax", %progbits
+.align 3
+.global reset
+reset:
+ b _ZN3ams10rebootstub4MainEv
+
+.global _ZN3ams10rebootstub10RebootTypeE
+_ZN3ams10rebootstub10RebootTypeE:
+.word 0x00000001
\ No newline at end of file
diff --git a/exosphere2/program/rebootstub/source/rebootstub_main.s b/exosphere2/program/rebootstub/source/rebootstub_main.s
new file mode 100644
index 000000000..03e3ec618
--- /dev/null
+++ b/exosphere2/program/rebootstub/source/rebootstub_main.s
@@ -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 .
+ */
+
+.section .text._ZN3ams10rebootstub4MainEv, "ax", %progbits
+.align 3
+.global _ZN3ams10rebootstub4MainEv
+_ZN3ams10rebootstub4MainEv:
+ /* Get the reboot type. */
+ ldr r0, =_ZN3ams10rebootstub10RebootTypeE
+ ldr r0, [r0]
+
+ /* If the reboot type is power off, perform a power off. */
+ cmp r0, #0
+ beq _ZN3ams10rebootstub8PowerOffEv
+
+ /* Otherwise, clear all registers jump to the reboot payload in iram. */
+ ldr r0, =0x52425430 /* RBT0 */
+ mov r1, #0
+ mov r2, #0
+ mov r3, #0
+ mov r4, #0
+ mov r5, #0
+ mov r5, #0
+ mov r6, #0
+ mov r7, #0
+ mov r8, #0
+ mov r9, #0
+ mov r10, #0
+ mov r11, #0
+ mov r12, #0
+ mov r9, #0
+ mov lr, #0
+ ldr sp, =0x40010000
+ ldr pc, =0x40010000
+
+ /* Infinite loop. */
+ 1: b 1b
\ No newline at end of file
diff --git a/exosphere2/program/rebootstub/source/rebootstub_power_off.cpp b/exosphere2/program/rebootstub/source/rebootstub_power_off.cpp
new file mode 100644
index 000000000..97d0e210f
--- /dev/null
+++ b/exosphere2/program/rebootstub/source/rebootstub_power_off.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+namespace ams::rebootstub {
+
+ NORETURN void Halt() {
+ while (true) {
+ reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
+ FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED));
+ }
+
+ __builtin_unreachable();
+ }
+
+ NORETURN void PowerOff() {
+ /* Ensure that i2c5 is usable. */
+ clkrst::EnableI2c5Clock();
+
+ /* Initialize i2c5. */
+ i2c::Initialize(i2c::Port_5);
+
+ /* Stop rtc alarms. */
+ rtc::StopAlarm();
+
+ /* Perform a pmic power off. */
+ pmic::PowerOff();
+
+ /* Halt the bpmp. */
+ Halt();
+
+ /* This can never be reached. */
+ __builtin_unreachable();
+ }
+
+}
+
+namespace ams::diag {
+
+ void AbortImpl() {
+ /* Halt the bpmp. */
+ rebootstub::Halt();
+
+ /* This can never be reached. */
+ __builtin_unreachable();
+ }
+
+}
diff --git a/exosphere2/program/sc7fw/sc7fw.ld b/exosphere2/program/sc7fw/sc7fw.ld
index e8a097dbb..794edc3d3 100644
--- a/exosphere2/program/sc7fw/sc7fw.ld
+++ b/exosphere2/program/sc7fw/sc7fw.ld
@@ -1,5 +1,5 @@
OUTPUT_ARCH(arm)
-ENTRY(_start)
+ENTRY(reset)
MEMORY
{
diff --git a/exosphere2/program/source/secmon_map.cpp b/exosphere2/program/source/secmon_map.cpp
index 92100ad2f..96ccf84ed 100644
--- a/exosphere2/program/source/secmon_map.cpp
+++ b/exosphere2/program/source/secmon_map.cpp
@@ -171,6 +171,10 @@ namespace ams::secmon {
return;
}
+ /* Ensure that the page is no longer in cache. */
+ hw::FlushDataCache(MemoryRegionVirtualSmcUserPage.GetPointer(), MemoryRegionVirtualSmcUserPage.GetSize());
+ hw::DataSynchronizationBarrierInnerShareable();
+
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer();
UnmapSmcUserPageImpl(l2_l3);
@@ -218,6 +222,10 @@ namespace ams::secmon {
return;
}
+ /* Ensure that the page is no longer in cache. */
+ hw::FlushDataCache(MemoryRegionVirtualAtmosphereIramPage.GetPointer(), MemoryRegionVirtualAtmosphereIramPage.GetSize());
+ hw::DataSynchronizationBarrierInnerShareable();
+
/* Unmap the page. */
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer();
@@ -269,6 +277,10 @@ namespace ams::secmon {
return;
}
+ /* Ensure that the page is no longer in cache. */
+ hw::FlushDataCache(MemoryRegionVirtualAtmosphereUserPage.GetPointer(), MemoryRegionVirtualAtmosphereUserPage.GetSize());
+ hw::DataSynchronizationBarrierInnerShareable();
+
/* Unmap the page. */
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer();
diff --git a/exosphere2/program/source/smc/secmon_page_mapper.cpp b/exosphere2/program/source/secmon_page_mapper.cpp
similarity index 90%
rename from exosphere2/program/source/smc/secmon_page_mapper.cpp
rename to exosphere2/program/source/secmon_page_mapper.cpp
index 8d2008907..93452d4fe 100644
--- a/exosphere2/program/source/smc/secmon_page_mapper.cpp
+++ b/exosphere2/program/source/secmon_page_mapper.cpp
@@ -14,10 +14,10 @@
* along with this program. If not, see .
*/
#include
-#include "../secmon_map.hpp"
+#include "secmon_map.hpp"
#include "secmon_page_mapper.hpp"
-namespace ams::secmon::smc {
+namespace ams::secmon {
namespace impl {
@@ -35,7 +35,7 @@ namespace ams::secmon::smc {
return reinterpret_cast(phys + (this->virtual_address - this->physical_address));
}
- bool PageMapperImpl::CopyToUser(uintptr_t dst_phys, const void *src, size_t size) const {
+ bool PageMapperImpl::CopyToMapping(uintptr_t dst_phys, const void *src, size_t size) const {
void * const dst = this->GetPointerTo(dst_phys, size);
if (dst == nullptr) {
return false;
@@ -45,7 +45,7 @@ namespace ams::secmon::smc {
return true;
}
- bool PageMapperImpl::CopyFromUser(void *dst, uintptr_t src_phys, size_t size) const {
+ bool PageMapperImpl::CopyFromMapping(void *dst, uintptr_t src_phys, size_t size) const {
const void * const src = this->GetPointerTo(src_phys, size);
if (src == nullptr) {
return false;
diff --git a/exosphere2/program/source/smc/secmon_page_mapper.hpp b/exosphere2/program/source/secmon_page_mapper.hpp
similarity index 81%
rename from exosphere2/program/source/smc/secmon_page_mapper.hpp
rename to exosphere2/program/source/secmon_page_mapper.hpp
index a57f70812..1da95ebc3 100644
--- a/exosphere2/program/source/smc/secmon_page_mapper.hpp
+++ b/exosphere2/program/source/secmon_page_mapper.hpp
@@ -15,9 +15,8 @@
*/
#pragma once
#include
-#include "secmon_smc_common.hpp"
-namespace ams::secmon::smc {
+namespace ams::secmon {
namespace impl {
@@ -29,8 +28,12 @@ namespace ams::secmon::smc {
constexpr PageMapperImpl(uintptr_t phys) : physical_address(util::AlignDown(phys, 4_KB)), virtual_address() { /* ... */ }
void *GetPointerTo(uintptr_t phys, size_t size) const;
- bool CopyToUser(uintptr_t dst_phys, const void *src, size_t size) const;
- bool CopyFromUser(void *dst, uintptr_t src_phys, size_t size) const;
+
+ bool CopyToMapping(uintptr_t dst_phys, const void *src, size_t size) const;
+ bool CopyFromMapping(void *dst, uintptr_t src_phys, size_t size) const;
+
+ ALWAYS_INLINE bool CopyToUser(uintptr_t dst_phys, const void *src, size_t size) const { return CopyToMapping(dst_phys, src, size); }
+ ALWAYS_INLINE bool CopyFromUser(void *dst, uintptr_t src_phys, size_t size) const { return CopyFromMapping(dst, src_phys, size); }
template
bool MapImpl() {
diff --git a/exosphere2/program/source/secmon_user_power_management.cpp b/exosphere2/program/source/secmon_user_power_management.cpp
new file mode 100644
index 000000000..4fb063b96
--- /dev/null
+++ b/exosphere2/program/source/secmon_user_power_management.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "secmon_page_mapper.hpp"
+#include "secmon_user_power_management.hpp"
+
+#include "rebootstub_bin.h"
+
+namespace ams::secmon {
+
+ namespace {
+
+ constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
+
+ constexpr inline const u32 RebootStubPhysicalAddress = MemoryRegionPhysicalIramRebootStub.GetAddress();
+
+ enum RebootStubAction {
+ RebootStubAction_ShutDown = 0,
+ RebootStubAction_JumpToPayload = 1,
+ };
+
+ NORETURN void PerformPmcReboot() {
+ /* Write MAIN_RST. */
+ reg::Write(PMC + APBDEV_PMC_CNTRL, 0x10);
+
+ while (true) {
+ /* ... */
+ }
+ }
+
+ void LoadRebootStub(u32 action) {
+ /* Configure the bootrom to boot to warmboot payload. */
+ reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x1);
+
+ /* Patch the bootrom to perform an SVC immediately after the second spare write. */
+ reg::Write(PMC + APBDEV_PMC_SCRATCH45, 0x2E38DFFF);
+ reg::Write(PMC + APBDEV_PMC_SCRATCH46, 0x6001DC28);
+
+ /* Patch the bootrom to jump to the reboot stub we'll prepare in iram on SVC. */
+ reg::Write(PMC + APBDEV_PMC_SCRATCH33, RebootStubPhysicalAddress);
+ reg::Write(PMC + APBDEV_PMC_SCRATCH40, 0x6000F208);
+
+ {
+ /* Map the iram page. */
+ AtmosphereIramPageMapper mapper(RebootStubPhysicalAddress);
+ AMS_ABORT_UNLESS(mapper.Map());
+
+ /* Copy the reboot stub. */
+ AMS_ABORT_UNLESS(mapper.CopyToMapping(RebootStubPhysicalAddress, rebootstub_bin, rebootstub_bin_size));
+
+ /* Set the reboot type. */
+ AMS_ABORT_UNLESS(mapper.CopyToMapping(RebootStubPhysicalAddress + 4, std::addressof(action), sizeof(action)));
+ }
+ }
+
+ }
+
+ void PerformUserRebootToRcm() {
+ /* Configure the bootrom to boot to rcm. */
+ reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x2);
+
+ /* Reboot. */
+ PerformPmcReboot();
+ }
+
+ void PerformUserRebootToPayload() {
+ /* Load our reboot stub to iram. */
+ LoadRebootStub(RebootStubAction_JumpToPayload);
+
+ /* Reboot. */
+ PerformPmcReboot();
+ }
+
+ void PerformUserShutDown() {
+ /* Load our reboot stub to iram. */
+ LoadRebootStub(RebootStubAction_ShutDown);
+
+ /* Reboot. */
+ PerformPmcReboot();
+ }
+
+}
diff --git a/exosphere2/program/source/secmon_user_power_management.hpp b/exosphere2/program/source/secmon_user_power_management.hpp
new file mode 100644
index 000000000..9a50e8227
--- /dev/null
+++ b/exosphere2/program/source/secmon_user_power_management.hpp
@@ -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 .
+ */
+#pragma once
+#include
+
+namespace ams::secmon {
+
+ enum UserRebootType {
+ UserRebootType_None = 0,
+ UserRebootType_ToRcm = 1,
+ UserRebootType_ToPayload = 2,
+ };
+
+ void PerformUserRebootToRcm();
+ void PerformUserRebootToPayload();
+ void PerformUserShutDown();
+
+}
diff --git a/exosphere2/program/source/smc/secmon_smc_aes.cpp b/exosphere2/program/source/smc/secmon_smc_aes.cpp
index a3790c0fd..cfb992e33 100644
--- a/exosphere2/program/source/smc/secmon_smc_aes.cpp
+++ b/exosphere2/program/source/smc/secmon_smc_aes.cpp
@@ -17,10 +17,10 @@
#include "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
#include "../secmon_misc.hpp"
+#include "../secmon_page_mapper.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_se_lock.hpp"
-#include "secmon_page_mapper.hpp"
namespace ams::secmon::smc {
diff --git a/exosphere2/program/source/smc/secmon_smc_info.cpp b/exosphere2/program/source/smc/secmon_smc_info.cpp
index c36ef37b2..7cf50269d 100644
--- a/exosphere2/program/source/smc/secmon_smc_info.cpp
+++ b/exosphere2/program/source/smc/secmon_smc_info.cpp
@@ -16,7 +16,8 @@
#include
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
-#include "secmon_page_mapper.hpp"
+#include "../secmon_page_mapper.hpp"
+#include "../secmon_user_power_management.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_power_management.hpp"
@@ -269,17 +270,40 @@ namespace ams::secmon::smc {
}
SmcResult SetConfig(SmcArguments &args) {
+ const auto soc_type = GetSocType();
+
switch (static_cast(args.r[1])) {
case ConfigItem::IsChargerHiZModeEnabled:
/* Configure the HiZ mode. */
SetChargerHiZModeEnabled(static_cast(args.r[3]));
break;
case ConfigItem::ExosphereNeedsReboot:
- /* TODO */
- return SmcResult::NotImplemented;
+ if (soc_type == fuse::SocType_Erista) {
+ switch (static_cast(args.r[3])) {
+ case UserRebootType_None:
+ break;
+ case UserRebootType_ToRcm:
+ PerformUserRebootToRcm();
+ break;
+ case UserRebootType_ToPayload:
+ PerformUserRebootToPayload();
+ break;
+ default:
+ return SmcResult::InvalidArgument;
+ }
+ } else /* if (soc_type == fuse::SocType_Mariko) */ {
+ return SmcResult::NotImplemented;
+ }
+ break;
case ConfigItem::ExosphereNeedsShutdown:
- /* TODO */
- return SmcResult::NotImplemented;
+ if (soc_type == fuse::SocType_Erista) {
+ if (args.r[3] != 0) {
+ PerformUserShutDown();
+ }
+ } else /* if (soc_type == fuse::SocType_Mariko) */ {
+ return SmcResult::NotImplemented;
+ }
+ break;
default:
return SmcResult::InvalidArgument;
}
diff --git a/exosphere2/program/source/smc/secmon_smc_memory_access.cpp b/exosphere2/program/source/smc/secmon_smc_memory_access.cpp
index a4071a832..dba249ccf 100644
--- a/exosphere2/program/source/smc/secmon_smc_memory_access.cpp
+++ b/exosphere2/program/source/smc/secmon_smc_memory_access.cpp
@@ -15,14 +15,56 @@
*/
#include
#include "../secmon_error.hpp"
+#include "../secmon_page_mapper.hpp"
#include "secmon_smc_memory_access.hpp"
namespace ams::secmon::smc {
+ namespace {
+
+ enum IramCopyType {
+ IramCopyType_FromIramToDram = 0,
+ IramCopyType_FromDramToIram = 1,
+ IramCopyType_Count,
+ };
+
+ struct IramCopyOption {
+ using CopyType = util::BitPack32::Field<0, 1, IramCopyType>;
+ };
+
+ }
+
/* This is an atmosphere extension smc. */
SmcResult SmcIramCopy(SmcArguments &args) {
- /* TODO */
- return SmcResult::NotImplemented;
+ /* Decode arguments. */
+ const uintptr_t dram_address = args.r[1];
+ const uintptr_t iram_address = args.r[2];
+ const size_t size = args.r[3];
+ const util::BitPack32 option = { static_cast(args.r[4]) };
+
+ const auto copy_type = option.Get();
+
+ /* Validate arguments. */
+ SMC_R_UNLESS(copy_type < IramCopyType_Count, InvalidArgument);
+
+ {
+ /* Map the pages. */
+ AtmosphereUserPageMapper dram_mapper(dram_address);
+ AtmosphereIramPageMapper iram_mapper(iram_address);
+ SMC_R_UNLESS(dram_mapper.Map(), InvalidArgument);
+ SMC_R_UNLESS(iram_mapper.Map(), InvalidArgument);
+
+ /* Get the ranges we're copying. */
+ const void * const src = (copy_type == IramCopyType_FromIramToDram) ? iram_mapper.GetPointerTo(iram_address, size) : dram_mapper.GetPointerTo(dram_address, size);
+ void * const dst = (copy_type == IramCopyType_FromIramToDram) ? dram_mapper.GetPointerTo(dram_address, size) : iram_mapper.GetPointerTo(iram_address, size);
+ SMC_R_UNLESS(src != nullptr, InvalidArgument);
+ SMC_R_UNLESS(dst != nullptr, InvalidArgument);
+
+ /* Copy the data. */
+ std::memcpy(dst, src, size);
+ }
+
+ return SmcResult::Success;
}
SmcResult SmcWriteAddress(SmcArguments &args) {
diff --git a/exosphere2/program/source/smc/secmon_smc_result.cpp b/exosphere2/program/source/smc/secmon_smc_result.cpp
index 83fa1b404..246f50cd3 100644
--- a/exosphere2/program/source/smc/secmon_smc_result.cpp
+++ b/exosphere2/program/source/smc/secmon_smc_result.cpp
@@ -15,8 +15,8 @@
*/
#include
#include "../secmon_error.hpp"
+#include "../secmon_page_mapper.hpp"
#include "secmon_smc_result.hpp"
-#include "secmon_page_mapper.hpp"
namespace ams::secmon::smc {
diff --git a/exosphere2/program/source/smc/secmon_smc_rsa.cpp b/exosphere2/program/source/smc/secmon_smc_rsa.cpp
index 20b44711d..d84ce9b14 100644
--- a/exosphere2/program/source/smc/secmon_smc_rsa.cpp
+++ b/exosphere2/program/source/smc/secmon_smc_rsa.cpp
@@ -16,10 +16,10 @@
#include
#include "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
+#include "../secmon_page_mapper.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_rsa.hpp"
#include "secmon_smc_se_lock.hpp"
-#include "secmon_page_mapper.hpp"
namespace ams::secmon::smc {
diff --git a/libraries/libexosphere/arm.mk b/libraries/libexosphere/arm.mk
index 7a653f53b..5819d270c 100644
--- a/libraries/libexosphere/arm.mk
+++ b/libraries/libexosphere/arm.mk
@@ -14,7 +14,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
-SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions
+SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -flto -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
@@ -125,7 +125,7 @@ $(OFILES) : $(GCH_FILES)
$(OFILES_SRC) : $(HFILES_BIN)
-libc.o: CFLAGS += -fno-builtin
+libc.o: CFLAGS += -fno-builtin -fno-lto
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
diff --git a/libraries/libexosphere/arm64.mk b/libraries/libexosphere/arm64.mk
index 35492a4c9..1ad716a3e 100644
--- a/libraries/libexosphere/arm64.mk
+++ b/libraries/libexosphere/arm64.mk
@@ -126,7 +126,7 @@ $(OFILES) : $(GCH_FILES)
$(OFILES_SRC) : $(HFILES_BIN)
-libc.o: CFLAGS += -fno-builtin
+libc.o: CFLAGS += -fno-builtin -fno-lto
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
diff --git a/libraries/libexosphere/include/exosphere.hpp b/libraries/libexosphere/include/exosphere.hpp
index e93e8b8fa..d7403cbf5 100644
--- a/libraries/libexosphere/include/exosphere.hpp
+++ b/libraries/libexosphere/include/exosphere.hpp
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libraries/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp b/libraries/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp
index ac534fe14..547014f4f 100644
--- a/libraries/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp
+++ b/libraries/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp
@@ -43,11 +43,13 @@ namespace ams::hw::arch::arm64 {
}
ALWAYS_INLINE void InvalidateTlb(uintptr_t address) {
- __asm__ __volatile__("tlbi vae3is, %[address]" :: [address]"r"(address) : "memory");
+ const uintptr_t page_index = address / 4_KB;
+ __asm__ __volatile__("tlbi vae3is, %[page_index]" :: [page_index]"r"(page_index) : "memory");
}
ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) {
- __asm__ __volatile__("tlbi vale3is, %[address]" :: [address]"r"(address) : "memory");
+ const uintptr_t page_index = address / 4_KB;
+ __asm__ __volatile__("tlbi vale3is, %[page_index]" :: [page_index]"r"(page_index) : "memory");
}
void FlushDataCache(const void *ptr, size_t size);
diff --git a/libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp b/libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp
index 07fea9c43..d4d0c970f 100644
--- a/libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp
+++ b/libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp
@@ -140,7 +140,7 @@ namespace ams::mmu::arch::arm64 {
constexpr inline u64 MemoryRegionAttributeWidth = 8;
- constexpr PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) {
+ constexpr ALWAYS_INLINE PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) {
return static_cast(attr | (static_cast::type>(index) << 2));
}
@@ -169,35 +169,35 @@ namespace ams::mmu::arch::arm64 {
constexpr inline u64 EntryBlock = 0x1ul;
constexpr inline u64 EntryPage = 0x3ul;
- constexpr u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) {
+ constexpr ALWAYS_INLINE u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) {
return address | static_cast(attr) | 0x3ul;
}
- constexpr u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) {
return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul;
}
- constexpr u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) {
return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul;
}
- constexpr u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) {
return address | static_cast(attr) | static_cast(PageTableMappingAttribute_AccessFlagAccessed) | 0x3ul;
}
- constexpr uintptr_t GetL2Offset(uintptr_t address) {
+ constexpr ALWAYS_INLINE uintptr_t GetL2Offset(uintptr_t address) {
return address & ((1ul << L2EntryShift) - 1);
}
- constexpr u64 GetL1EntryIndex(uintptr_t address) {
+ constexpr ALWAYS_INLINE u64 GetL1EntryIndex(uintptr_t address) {
return ((address >> L1EntryShift) & TableEntryIndexMask);
}
- constexpr u64 GetL2EntryIndex(uintptr_t address) {
+ constexpr ALWAYS_INLINE u64 GetL2EntryIndex(uintptr_t address) {
return ((address >> L2EntryShift) & TableEntryIndexMask);
}
- constexpr u64 GetL3EntryIndex(uintptr_t address) {
+ constexpr ALWAYS_INLINE u64 GetL3EntryIndex(uintptr_t address) {
return ((address >> L3EntryShift) & TableEntryIndexMask);
}
@@ -218,15 +218,15 @@ namespace ams::mmu::arch::arm64 {
SetTableEntryImpl(table, index, value);
}
- constexpr void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
+ constexpr ALWAYS_INLINE void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
SetTableEntry(table, GetL1EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr));
}
- constexpr void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
+ constexpr ALWAYS_INLINE void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
SetTableEntry(table, GetL2EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr));
}
- constexpr void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
const u64 start = GetL1EntryIndex(virt_addr);
const u64 count = (size >> L1EntryShift);
@@ -235,7 +235,7 @@ namespace ams::mmu::arch::arm64 {
}
}
- constexpr void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
const u64 start = GetL2EntryIndex(virt_addr);
const u64 count = (size >> L2EntryShift);
@@ -244,7 +244,7 @@ namespace ams::mmu::arch::arm64 {
}
}
- constexpr void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
+ constexpr ALWAYS_INLINE void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
const u64 start = GetL3EntryIndex(virt_addr);
const u64 count = (size >> L3EntryShift);
@@ -253,7 +253,7 @@ namespace ams::mmu::arch::arm64 {
}
}
- constexpr void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
+ constexpr ALWAYS_INLINE void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
const u64 start = GetL1EntryIndex(virt_addr);
const u64 count = (size >> L1EntryShift);
const u64 end = start + count;
@@ -263,7 +263,7 @@ namespace ams::mmu::arch::arm64 {
}
}
- constexpr void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
+ constexpr ALWAYS_INLINE void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
const u64 start = GetL2EntryIndex(virt_addr);
const u64 count = (size >> L2EntryShift);
const u64 end = start + count;
@@ -273,7 +273,7 @@ namespace ams::mmu::arch::arm64 {
}
}
- constexpr void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
+ constexpr ALWAYS_INLINE void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
const u64 start = GetL3EntryIndex(virt_addr);
const u64 count = (size >> L3EntryShift);
const u64 end = start + count;
diff --git a/libraries/libexosphere/include/exosphere/pmic.hpp b/libraries/libexosphere/include/exosphere/pmic.hpp
index 1d01eb811..29122bce2 100644
--- a/libraries/libexosphere/include/exosphere/pmic.hpp
+++ b/libraries/libexosphere/include/exosphere/pmic.hpp
@@ -30,6 +30,7 @@ namespace ams::pmic {
void EnableVddCpu(Regulator regulator);
void DisableVddCpu(Regulator regulator);
void EnableSleep();
+ void PowerOff();
bool IsAcOk();
}
\ No newline at end of file
diff --git a/libraries/libexosphere/include/exosphere/rtc.hpp b/libraries/libexosphere/include/exosphere/rtc.hpp
new file mode 100644
index 000000000..bacf1b9f1
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/rtc.hpp
@@ -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 .
+ */
+#pragma once
+#include
+
+namespace ams::rtc {
+
+ void StopAlarm();
+
+}
diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
index 38e6452bf..c6ec12b37 100644
--- a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
+++ b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
@@ -287,4 +287,6 @@ namespace ams::secmon {
constexpr inline const MemoryRegion MemoryRegionPhysicalIramWarmbootBin = MemoryRegion(UINT64_C(0x4003E000), 0x17F0);
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400);
+ constexpr inline const MemoryRegion MemoryRegionPhysicalIramRebootStub = MemoryRegion(UINT64_C(0x4003F000), 0x1000);
+
}
diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp
index f64f500f5..da1c6d053 100644
--- a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp
+++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp
@@ -44,6 +44,8 @@
#define APBDEV_PMC_CRYPTO_OP (0x0F4)
#define APBDEV_PMC_SCRATCH31 (0x118)
#define APBDEV_PMC_SCRATCH32 (0x11C)
+#define APBDEV_PMC_SCRATCH33 (0x120)
+#define APBDEV_PMC_SCRATCH40 (0x13C)
#define APBDEV_PMC_WAKE2_MASK (0x160)
#define APBDEV_PMC_WAKE2_LVL (0x164)
#define APBDEV_PMC_WAKE2_STATUS (0x168)
@@ -54,6 +56,8 @@
#define APBDEV_PMC_IO_DPD2_REQ (0x1C0)
#define APBDEV_PMC_IO_DPD2_STATUS (0x1C4)
#define APBDEV_PMC_SEL_DPD_TIM (0x1C8)
+#define APBDEV_PMC_SCRATCH45 (0x234)
+#define APBDEV_PMC_SCRATCH46 (0x238)
#define APBDEV_PMC_TSC_MULT (0x2B4)
#define APBDEV_PMC_WEAK_BIAS (0x2C8)
#define APBDEV_PMC_GPU_RG_CNTRL (0x2D4)
diff --git a/libraries/libexosphere/source/pmic/pmic_api.cpp b/libraries/libexosphere/source/pmic/pmic_api.cpp
index 96847f898..bf1515d7c 100644
--- a/libraries/libexosphere/source/pmic/pmic_api.cpp
+++ b/libraries/libexosphere/source/pmic/pmic_api.cpp
@@ -145,12 +145,17 @@ namespace ams::pmic {
u8 cnfg = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1);
/* Set SlpEn. */
- cnfg |= (1 << 2);
+ cnfg |= MAX77620_ONOFFCNFG1_SLPEN;
/* Write the new cfg. */
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, cnfg);
}
+ void PowerOff() {
+ /* Write power-off to onoff cfg. */
+ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, MAX77620_ONOFFCNFG1_PWR_OFF);
+ }
+
bool IsAcOk() {
return (GetPmicOnOffStat() & (1 << 1)) != 0;
}
diff --git a/libraries/libexosphere/source/rtc/max77620-rtc.h b/libraries/libexosphere/source/rtc/max77620-rtc.h
new file mode 100644
index 000000000..2d38487cc
--- /dev/null
+++ b/libraries/libexosphere/source/rtc/max77620-rtc.h
@@ -0,0 +1,60 @@
+/*
+ * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
+ *
+ * Copyright (c) 2018 CTCaer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef _MFD_MAX77620_RTC_H_
+#define _MFD_MAX77620_RTC_H_
+
+#define MAX77620_RTC_I2C_ADDR 0x68
+
+#define MAX77620_RTC_NR_TIME_REGS 7
+
+#define MAX77620_RTC_CONTROLM_REG 0x02
+#define MAX77620_RTC_CONTROL_REG 0x03
+#define MAX77620_RTC_BIN_FORMAT (1 << 0)
+#define MAX77620_RTC_24H (1 << 1)
+
+#define MAX77620_RTC_UPDATE0_REG 0x04
+#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
+#define MAX77620_RTC_READ_UPDATE (1 << 4)
+
+#define MAX77620_RTC_SEC_REG 0x07
+#define MAX77620_RTC_MIN_REG 0x08
+#define MAX77620_RTC_HOUR_REG 0x09
+#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
+#define MAX77620_RTC_WEEKDAY_REG 0x0A
+#define MAX77620_RTC_MONTH_REG 0x0B
+#define MAX77620_RTC_YEAR_REG 0x0C
+#define MAX77620_RTC_DATE_REG 0x0D
+
+#define MAX77620_ALARM1_SEC_REG 0x0E
+#define MAX77620_ALARM1_MIN_REG 0x0F
+#define MAX77620_ALARM1_HOUR_REG 0x10
+#define MAX77620_ALARM1_WEEKDAY_REG 0x11
+#define MAX77620_ALARM1_MONTH_REG 0x12
+#define MAX77620_ALARM1_YEAR_REG 0x13
+#define MAX77620_ALARM1_DATE_REG 0x14
+#define MAX77620_ALARM2_SEC_REG 0x15
+#define MAX77620_ALARM2_MIN_REG 0x16
+#define MAX77620_ALARM2_HOUR_REG 0x17
+#define MAX77620_ALARM2_WEEKDAY_REG 0x18
+#define MAX77620_ALARM2_MONTH_REG 0x19
+#define MAX77620_ALARM2_YEAR_REG 0x1A
+#define MAX77620_ALARM2_DATE_REG 0x1B
+#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
+
+#endif /* _MFD_MAX77620_RTC_H_ */
diff --git a/libraries/libexosphere/source/rtc/rtc_api.cpp b/libraries/libexosphere/source/rtc/rtc_api.cpp
new file mode 100644
index 000000000..dcf8480ee
--- /dev/null
+++ b/libraries/libexosphere/source/rtc/rtc_api.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "max77620-rtc.h"
+
+namespace ams::rtc {
+
+ namespace {
+
+ constexpr inline int I2cAddressMax77620Rtc = 0x68;
+
+ /* TODO: Find datasheet, link to it instead. */
+ /* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */
+ constexpr inline int Max77620RtcRegisterUpdate0 = 0x04;
+
+ constexpr inline int Max77620RtcRegisterAlarmStart = 0x0E;
+
+ constexpr inline int Max77620RtcRegisterAlarm1Sec = 0x0E;
+ constexpr inline int Max77620RtcRegisterAlarm1Min = 0x0F;
+ constexpr inline int Max77620RtcRegisterAlarm1Hour = 0x10;
+ constexpr inline int Max77620RtcRegisterAlarm1Weekday = 0x11;
+ constexpr inline int Max77620RtcRegisterAlarm1Month = 0x12;
+ constexpr inline int Max77620RtcRegisterAlarm1Year = 0x13;
+ constexpr inline int Max77620RtcRegisterAlarm1Date = 0x14;
+ constexpr inline int Max77620RtcRegisterAlarm2Sec = 0x15;
+ constexpr inline int Max77620RtcRegisterAlarm2Min = 0x16;
+ constexpr inline int Max77620RtcRegisterAlarm2Hour = 0x17;
+ constexpr inline int Max77620RtcRegisterAlarm2Weekday = 0x18;
+ constexpr inline int Max77620RtcRegisterAlarm2Month = 0x19;
+ constexpr inline int Max77620RtcRegisterAlarm2Year = 0x1A;
+ constexpr inline int Max77620RtcRegisterAlarm2Date = 0x1B;
+
+ constexpr inline int Max77620RtcRegisterAlarmLast = 0x1B;
+
+ }
+
+ void StopAlarm() {
+ /* Begin update. */
+ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_READ_UPDATE);
+
+ /* Clear ALARM_EN for all alarm registers. */
+ for (auto reg = Max77620RtcRegisterAlarmStart; reg <= Max77620RtcRegisterAlarmLast; ++reg) {
+ u8 val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Rtc, reg);
+ val &= ~MAX77620_RTC_ALARM_EN_MASK;
+ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, reg, val);
+ }
+
+ /* End update. */
+ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_WRITE_UPDATE);
+ }
+
+}