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