From 293c213bf299ad2453da0ae23b5c1f57681518c1 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 11 Jun 2020 01:30:30 -0700 Subject: [PATCH] exo2: implement warmboot firmware --- exosphere2/warmboot/Makefile | 122 ++++++++++ .../source/warmboot_bootrom_workaround.cpp | 99 ++++++++ .../source/warmboot_bootrom_workaround.hpp | 23 ++ .../warmboot/source/warmboot_clkrst.cpp | 46 ++++ .../warmboot/source/warmboot_clkrst.hpp | 23 ++ .../warmboot/source/warmboot_cpu_cluster.cpp | 219 ++++++++++++++++++ .../warmboot/source/warmboot_cpu_cluster.hpp | 24 ++ exosphere2/warmboot/source/warmboot_dram.cpp | 130 +++++++++++ exosphere2/warmboot/source/warmboot_dram.hpp | 25 ++ .../source/warmboot_exception_vectors.s | 63 +++++ exosphere2/warmboot/source/warmboot_main.cpp | 105 +++++++++ exosphere2/warmboot/source/warmboot_main.hpp | 31 +++ exosphere2/warmboot/source/warmboot_misc.cpp | 56 +++++ exosphere2/warmboot/source/warmboot_misc.hpp | 23 ++ .../source/warmboot_secure_monitor.cpp | 130 +++++++++++ .../source/warmboot_secure_monitor.hpp | 23 ++ exosphere2/warmboot/source/warmboot_start.s | 36 +++ exosphere2/warmboot/source/warmboot_util.hpp | 23 ++ .../warmboot/source/warmboot_util_asm.s | 30 +++ exosphere2/warmboot/warmboot.ld | 189 +++++++++++++++ exosphere2/warmboot/warmboot.specs | 7 + .../libexosphere/include/exosphere/fuse.hpp | 3 + .../libexosphere/include/exosphere/pmic.hpp | 1 + .../libexosphere/include/exosphere/reg.hpp | 4 + .../include/exosphere/se/se_aes.hpp | 3 + .../libexosphere/include/exosphere/tegra.hpp | 2 + .../exosphere/tegra/tegra_apb_misc.hpp | 32 ++- .../include/exosphere/tegra/tegra_clkrst.hpp | 158 ++++++++++++- .../include/exosphere/tegra/tegra_emc.hpp | 55 +++-- .../exosphere/tegra/tegra_flow_ctlr.hpp | 5 +- .../include/exosphere/tegra/tegra_mselect.hpp | 17 ++ .../include/exosphere/tegra/tegra_pg_up.hpp | 23 ++ .../include/exosphere/tegra/tegra_pinmux.hpp | 68 ++++++ .../include/exosphere/tegra/tegra_pmc.hpp | 11 + .../include/exosphere/tegra/tegra_sb.hpp | 6 + .../include/exosphere/tegra/tegra_timer.hpp | 5 +- .../libexosphere/source/fuse/fuse_api.cpp | 58 ++++- .../source/fuse/fuse_registers.hpp | 9 +- .../libexosphere/source/pinmux/pinmux_api.cpp | 1 - .../source/pinmux/pinmux_registers.hpp | 65 ------ .../libexosphere/source/pmic/pmic_api.cpp | 20 ++ libraries/libexosphere/source/se/se_aes.cpp | 68 ++++++ .../crypto/crypto_memory_compare.arch.arm.cpp | 58 +++++ 43 files changed, 1996 insertions(+), 103 deletions(-) create mode 100644 exosphere2/warmboot/Makefile create mode 100644 exosphere2/warmboot/source/warmboot_bootrom_workaround.cpp create mode 100644 exosphere2/warmboot/source/warmboot_bootrom_workaround.hpp create mode 100644 exosphere2/warmboot/source/warmboot_clkrst.cpp create mode 100644 exosphere2/warmboot/source/warmboot_clkrst.hpp create mode 100644 exosphere2/warmboot/source/warmboot_cpu_cluster.cpp create mode 100644 exosphere2/warmboot/source/warmboot_cpu_cluster.hpp create mode 100644 exosphere2/warmboot/source/warmboot_dram.cpp create mode 100644 exosphere2/warmboot/source/warmboot_dram.hpp create mode 100644 exosphere2/warmboot/source/warmboot_exception_vectors.s create mode 100644 exosphere2/warmboot/source/warmboot_main.cpp create mode 100644 exosphere2/warmboot/source/warmboot_main.hpp create mode 100644 exosphere2/warmboot/source/warmboot_misc.cpp create mode 100644 exosphere2/warmboot/source/warmboot_misc.hpp create mode 100644 exosphere2/warmboot/source/warmboot_secure_monitor.cpp create mode 100644 exosphere2/warmboot/source/warmboot_secure_monitor.hpp create mode 100644 exosphere2/warmboot/source/warmboot_start.s create mode 100644 exosphere2/warmboot/source/warmboot_util.hpp create mode 100644 exosphere2/warmboot/source/warmboot_util_asm.s create mode 100644 exosphere2/warmboot/warmboot.ld create mode 100644 exosphere2/warmboot/warmboot.specs create mode 100644 libraries/libexosphere/include/exosphere/tegra/tegra_pg_up.hpp create mode 100644 libraries/libexosphere/include/exosphere/tegra/tegra_pinmux.hpp delete mode 100644 libraries/libexosphere/source/pinmux/pinmux_registers.hpp create mode 100644 libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm.cpp diff --git a/exosphere2/warmboot/Makefile b/exosphere2/warmboot/Makefile new file mode 100644 index 000000000..2288e2717 --- /dev/null +++ b/exosphere2/warmboot/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/warmboot/source/warmboot_bootrom_workaround.cpp b/exosphere2/warmboot/source/warmboot_bootrom_workaround.cpp new file mode 100644 index 000000000..f49bf2429 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_bootrom_workaround.cpp @@ -0,0 +1,99 @@ +/* + * 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 "warmboot_clkrst.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); + constexpr inline const uintptr_t EMC = EMC_ADDRESS(0); + + } + + void ApplyMbistWorkaround() { + /* Clear all LVL2 clock gate overrides to zero. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA, 0); + reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB, 0); + reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC, 0); + reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, 0); + reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE, 0); + + /* Clear clock enable for all but a select few devices. */ + auto devices_to_clear_l = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L); + reg::ClearBits(static_cast(devices_to_clear_l), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_RTC ), + CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_TMR ), + CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_GPIO ), + CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_CACHE2)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, devices_to_clear_l); + + auto devices_to_clear_h = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H); + reg::ClearBits(static_cast(devices_to_clear_h), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_MEM ), + CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_PMC ), + CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_FUSE), + CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_EMC )); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, devices_to_clear_h); + + auto devices_to_clear_u = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U); + reg::ClearBits(static_cast(devices_to_clear_u), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CSITE), + CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMA), + CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMB), + CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMC), + CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMD), + CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CRAM2)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_CLR, devices_to_clear_u); + + auto devices_to_clear_v = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V); + reg::ClearBits(static_cast(devices_to_clear_v), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_MSELECT ), + CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SPDIF_DOUBLER), + CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_TZRAM ), + CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SE )); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_CLR, devices_to_clear_v); + + auto devices_to_clear_w = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W); + reg::ClearBits(static_cast(devices_to_clear_w), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX0), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX1), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX2), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX3), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX4), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX5), + CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_ENTROPY)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, devices_to_clear_w); + + auto devices_to_clear_x = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X); + reg::ClearBits(static_cast(devices_to_clear_x), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CAPA ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CBPA ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CPU ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_BBC ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_EMC_DLL ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_GPU ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_DBGAPB ), + CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_PLLG_REF)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_CLR, devices_to_clear_x); + + auto devices_to_clear_y = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y); + reg::ClearBits(static_cast(devices_to_clear_y), CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CCPA), + CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CDPA)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_CLR, devices_to_clear_y); + + /* If CH1 is enabled, enable clock to MC1. */ + if (reg::HasValue(EMC + EMC_FBIO_CFG7, EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE))) { + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE)); + } + } + +} diff --git a/exosphere2/warmboot/source/warmboot_bootrom_workaround.hpp b/exosphere2/warmboot/source/warmboot_bootrom_workaround.hpp new file mode 100644 index 000000000..039c3df20 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_bootrom_workaround.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::warmboot { + + void ApplyMbistWorkaround(); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_clkrst.cpp b/exosphere2/warmboot/source/warmboot_clkrst.cpp new file mode 100644 index 000000000..258b3b398 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_clkrst.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "warmboot_clkrst.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); + constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + constexpr inline const uintptr_t TIMER = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); + + } + + void ConfigureOscillators() { + /* Enable the crystal oscillator, and copy the drive strength from pmc. */ + const auto xofs = reg::GetValue(PMC + APBDEV_PMC_OSC_EDPD_OVER, PMC_REG_BITS_MASK(OSC_EDPD_OVER_XOFS)); + + reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_OSC_CTRL, CLK_RST_REG_BITS_ENUM (OSC_CTRL_XOE, ENABLE), + CLK_RST_REG_BITS_VALUE(OSC_CTRL_XOFS, xofs)); + + /* Configure CLK_M_DIVISOR to 2. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0, CLK_RST_REG_BITS_ENUM(SPARE_REG0_CLK_M_DIVISOR, CLK_M_DIVISOR2)); + reg::Read(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0); + + /* Restore TIMERUS config to 19.2 MHz. */ + reg::Write(TIMER + TIMERUS_USEC_CFG, TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVIDEND, 5 - 1), + TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVISOR, 96 - 1)); + + } + +} diff --git a/exosphere2/warmboot/source/warmboot_clkrst.hpp b/exosphere2/warmboot/source/warmboot_clkrst.hpp new file mode 100644 index 000000000..327f82512 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_clkrst.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::warmboot { + + void ConfigureOscillators(); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_cpu_cluster.cpp b/exosphere2/warmboot/source/warmboot_cpu_cluster.cpp new file mode 100644 index 000000000..34983e02c --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_cpu_cluster.cpp @@ -0,0 +1,219 @@ +/* + * 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 "warmboot_clkrst.hpp" +#include "warmboot_util.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); + constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); + constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); + constexpr inline const uintptr_t GPIO = secmon::MemoryRegionPhysicalDeviceGpio.GetAddress(); + constexpr inline const uintptr_t MSELECT = MSELECT(0); + constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress(); + + ALWAYS_INLINE void EnableClusterPartition(const reg::BitsValue value, APBDEV_PMC_PWRGATE_TOGGLE_PARTID part_id) { + /* Toggle the partitions if necessary. */ + if (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) { + reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE), + PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, part_id)); + } + + /* Wait for the toggle to complete. */ + while (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) { /* ... */ } + + /* Remove clamping. */ + reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, value); + + /* Wait for clamping to be removed. */ + while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, value)) { /* ... */ } + } + + } + + void InitializeCpuCluster() { + /* Set CoreSight reset. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_U_SET_SET_CSITE_RST, ENABLE)); + + /* Restore PROD setting to CPU_SOFTRST_CTRL2 by clearing CAR2PMC_CPU_ACK_WIDTH. */ + reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2, CLK_RST_REG_BITS_VALUE(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0)); + + /* Restore the CPU reset vector from PMC scratch. */ + reg::Write(SYSTEM + SB_AA64_RESET_LOW, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH34) | 1); + reg::Write(SYSTEM + SB_AA64_RESET_HIGH, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH35)); + + /* Configure SUPER_CCLKG_DIVIDER. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKG_DIVIDER_SUPER_CDIV_ENB, ENABLE), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT), + CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0), + CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0)); + + /* Configure SUPER_CCLKLP_DIVIDER. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKLP_DIVIDER_SUPER_CDIV_ENB, ENABLE), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT), + CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT), + CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0), + CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0)); + + /* Enable CoreSight clock. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_SET_SET_CLK_ENB_CSITE, ENABLE)); + + /* Clear CoreSight reset. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_U_CLR_CLR_CSITE_RST, ENABLE)); + + /* Select MSELECT clock source as PLLP_OUT0 with divider of 4. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_MSELECT_MSELECT_CLK_SRC, PLLP_OUT0), + CLK_RST_REG_BITS_VALUE(CLK_SOURCE_MSELECT_MSELECT_CLK_DIVISOR, 6)); + + /* Enable clock to MSELECT. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_MSELECT, ENABLE)); + + /* Wait two microseconds, then take MSELECT out of reset. */ + util::WaitMicroSeconds(2); + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_V_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_V_CLR_CLR_MSELECT_RST, ENABLE)); + + /* Workaround bug by disabling MSELECT error mechanism and enabling WRAP type conversion. */ + reg::ReadWrite(MSELECT + MSELECT_CONFIG, MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE1, DISABLE), + MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE2, DISABLE), + MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE0, ENABLE), + MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE1, ENABLE), + MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE2, ENABLE)); + + /* Disable PLLX. */ + reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, CLK_RST_REG_BITS_ENUM(PLLX_BASE_PLLX_ENABLE, DISABLE)); + + /* Clear bit 0 of PMC Scratch 190. */ + reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0)); + + /* Clear PMC_DPD_SAMPLE, and wait 10 us for clear to take effect. */ + reg::Write(PMC + APBDEV_PMC_DPD_SAMPLE, 0); + util::WaitMicroSeconds(10); + + /* Configure UART2_RTS low (GPIO controller 2 G). */ + reg::ReadWrite(GPIO + 0x108, REG_BITS_VALUE(2, 1, 1)); /* GPIO_CNF */ + reg::ReadWrite(GPIO + 0x118, REG_BITS_VALUE(2, 1, 1)); /* GPIO_OE */ + reg::ReadWrite(GPIO + 0x128, REG_BITS_VALUE(2, 1, 0)); /* GPIO_OUT */ + + /* Tristate CLDVFS PWN. */ + reg::Write(APB_MISC + PINMUX_AUX_DVFS_PWM, PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), + PINMUX_REG_BITS_ENUM(AUX_DVFS_PWM_PM, CLDVFS)); + reg::Read(APB_MISC + PINMUX_AUX_DVFS_PWM); + + /* Restore PWR_I2C E_INPUT. */ + reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); + reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); + + /* Enable CLDVFS clock. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DVFS, ENABLE)); + + /* Set CLDVFS clock source/divider. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_REF_DVFS_REF_CLK_SRC, PLLP_OUT0), + CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_REF_DVFS_REF_DIVISOR, 14)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_SOC_DVFS_SOC_CLK_SRC, PLLP_OUT0), + CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_SOC_DVFS_SOC_DIVISOR, 14)); + + /* Enable PWR_I2C controller (I2C5). */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_I2C5, ENABLE)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE)); + util::WaitMicroSeconds(5); + + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_I2C5_I2C5_CLK_SRC, PLLP_OUT0), + CLK_RST_REG_BITS_VALUE(CLK_SOURCE_I2C5_I2C5_CLK_DIVISOR, 4)); + + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_I2C5_RST, ENABLE)); + + /* Set the EN bit in pmic regulator. */ + pmic::SetEnBit(fuse::GetRegulator()); + + /* Wait 2ms. */ + util::WaitMicroSeconds(2'000); + + /* Enable power to the CRAIL partition. */ + EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CRAIL); + + /* Remove software clamp to CRAIL. */ + reg::Write(PMC + APBDEV_PMC_SET_SW_CLAMP, 0); + reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, PMC_REG_BITS_ENUM(REMOVE_CLAMPING_COMMAND_CRAIL, ENABLE)); + while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, PMC_REG_BITS_ENUM(CLAMP_STATUS_CRAIL, ENABLE))) { /* ... */ } + + /* Spinloop 8 times, to add a little delay. */ + SpinLoop(8); + + /* Disable PWR_I2C controller (I2C5). */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_I2C5, ENABLE)); + + /* Disable CLDVFS clock. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLR_CLR_CLK_ENB_DVFS, ENABLE)); + + /* Perform fast cluster RAM repair if needed. */ + if (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, SLOW))) { + reg::Write(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_REQ, ENABLE)); + + while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_STS, DONE))) { + /* ... */ + } + } + + /* Enable power to the non-cpu partition. */ + EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_C0NC, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_C0NC); + + /* Enable clock to PLLP_OUT_CPU. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_SET_SET_CLK_ENB_PLLP_OUT_CPU, ENABLE)); + util::WaitMicroSeconds(2); + + /* Enable clock to the cpu complex. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_CPU, ENABLE)); + reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_CPUG, ENABLE)); + util::WaitMicroSeconds(10); + + /* Select cpu complex clock source. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKG_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN)); + + reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0), + CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN)); + util::WaitMicroSeconds(10); + + /* Wake non-cpu out of reset. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, ENABLE)); + } + + void PowerOnCpu() { + /* Enable power to the CE0 partition. */ + EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CE0, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0); + + /* Clear CPU reset. */ + reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET0, ENABLE), + CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET0, ENABLE)); + } + +} diff --git a/exosphere2/warmboot/source/warmboot_cpu_cluster.hpp b/exosphere2/warmboot/source/warmboot_cpu_cluster.hpp new file mode 100644 index 000000000..6b2e3c8be --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_cpu_cluster.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::warmboot { + + void InitializeCpuCluster(); + void PowerOnCpu(); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_dram.cpp b/exosphere2/warmboot/source/warmboot_dram.cpp new file mode 100644 index 000000000..10999644d --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_dram.cpp @@ -0,0 +1,130 @@ +/* + * 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 "warmboot_dram.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); + constexpr inline const uintptr_t EMC = EMC_ADDRESS(0); + constexpr inline const uintptr_t EMC0 = EMC0_ADDRESS(0); + constexpr inline const uintptr_t EMC1 = EMC1_ADDRESS(0); + constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); + constexpr inline const uintptr_t MC0 = secmon::MemoryRegionPhysicalDeviceMemoryController0.GetAddress(); + constexpr inline const uintptr_t MC1 = secmon::MemoryRegionPhysicalDeviceMemoryController1.GetAddress(); + + } + + void RestrictBpmpAccessToMainMemory() { + /* Bpmp memory access is restricted by forcing internal access to an invalid carveout. */ + constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE)); + constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE)); + + constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), + MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), + MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE)); + + /* Specify a 128KB carveout at NULL with no clients allowed access, and bpmp forced to access. */ + reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, 1); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, ForceInternalAccess0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, ForceInternalAccess1); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4, 0); + reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, CarveoutConfig); + } + + void RestoreRamSvop() { + reg::ReadWrite(APB_MISC + APB_MISC_GP_ASDBGREG, APB_MISC_REG_BITS_VALUE(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 2)); + } + + void ConfigureEmcPmacroTraining() { + /* Disable writes to BYTE0-7. */ + reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, ENABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE)); + + /* Set E_WRPTR on Channel 0. */ + reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_0, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_ENABLED, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_TRAIN_QPOP, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_RX_E_DIRECT_ZI, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_E_WRPTR, ENABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_DRV_DQS, DISABLED)); + + /* Set E_WRPTR on Channel 1. */ + reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_1, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_ENABLED, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_TRAIN_QPOP, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_RX_E_DIRECT_ZI, DISABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_E_WRPTR, ENABLED), + EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_DRV_DQS, DISABLED)); + + /* Re-enable writes to BYTE0-7. */ + reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE), + EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE)); + } + +} diff --git a/exosphere2/warmboot/source/warmboot_dram.hpp b/exosphere2/warmboot/source/warmboot_dram.hpp new file mode 100644 index 000000000..0e8cbaa88 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_dram.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::warmboot { + + void RestrictBpmpAccessToMainMemory(); + void RestoreRamSvop(); + void ConfigureEmcPmacroTraining(); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_exception_vectors.s b/exosphere2/warmboot/source/warmboot_exception_vectors.s new file mode 100644 index 000000000..7bac9ac54 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_exception_vectors.s @@ -0,0 +1,63 @@ +/* + * 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 warmboot_header +warmboot_header: + /* TODO: If Mariko warmboothax ever happens, generate a mariko header? */ + /* Warmboot header. */ + .word __total_size__ + .rept 3 + .word 0x00000000 + .endr + + /* RSA modulus. */ + .rept 0x40 + .word 0xFFFFFFFF + .endr + + /* Padding */ + .rept 4 + .word 0x00000000 + .endr + + /* RSA signature */ + .rept 0x40 + .word 0xFFFFFFFF + .endr + + /* Padding */ + .rept 4 + .word 0x00000000 + .endr + + /* Firmware metadata. */ + .word __total_size__ + .word _reset + .word _reset + .word __executable_size__ + +.global _reset +_reset: + b _ZN3ams8warmboot5StartEv + +.global _metadata +_metadata: + .ascii "WBT0" /* Magic number */ + .word 0x00000000 /* Target firmware. */ + .word 0x00000000 /* Reserved */ + .word 0x00000000 /* Reserved */ \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_main.cpp b/exosphere2/warmboot/source/warmboot_main.cpp new file mode 100644 index 000000000..933b17e37 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_main.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "warmboot_bootrom_workaround.hpp" +#include "warmboot_clkrst.hpp" +#include "warmboot_cpu_cluster.hpp" +#include "warmboot_dram.hpp" +#include "warmboot_main.hpp" +#include "warmboot_misc.hpp" +#include "warmboot_secure_monitor.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); + + constexpr inline const uintptr_t ExpectedMetadataAddress = 0x40010244; + + } + + void Main(const Metadata *metadata) { + /* Ensure that we're running under vaguely sane conditions. */ + AMS_ABORT_UNLESS(metadata->magic == Metadata::Magic); + AMS_ABORT_UNLESS(metadata->target_firmware <= ams::TargetFirmware_Max); + + /* Restrict the bpmp's access to dram. */ + if (metadata->target_firmware >= TargetFirmware_4_0_0) { + RestrictBpmpAccessToMainMemory(); + } + + /* Configure rtck-daisychaining/jtag. */ + ConfigureMiscSystemDebug(); + + /* NOTE: Here, Nintendo checks that the number of burnt anti-downgrade fuses is valid. */ + + /* NOTE: Here, Nintendo validates that APBDEV_PMC_SECURE_SCRATCH32 contains the correct magic number for the current warmboot firmware revision. */ + + /* Validate that we're executing at the correct address. */ + AMS_ABORT_UNLESS(reinterpret_cast(metadata) == ExpectedMetadataAddress); + + /* Validate that we're executing on the bpmp. */ + AMS_ABORT_UNLESS(reg::Read(PG_UP(PG_UP_TAG)) == PG_UP_TAG_PID_COP); + + /* Configure fuse bypass. */ + fuse::ConfigureFuseBypass(); + + /* Configure system oscillators. */ + ConfigureOscillators(); + + /* Restore DRAM configuration. */ + RestoreRamSvop(); + ConfigureEmcPmacroTraining(); + + /* If on Erista, work around the bootrom mbist issue. */ + if (fuse::GetSocType() == fuse::SocType_Erista) { + ApplyMbistWorkaround(); + } + + /* Initialize the cpu cluster. */ + InitializeCpuCluster(); + + /* Restore the secure monitor to tzram. */ + RestoreSecureMonitorToTzram(metadata->target_firmware); + + /* Power on the cpu. */ + PowerOnCpu(); + + /* Halt ourselves. */ + const bool disable_jtag = metadata->target_firmware >= TargetFirmware_4_0_0; + 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_SEL(HALT_COP_EVENTS_JTAG, disable_jtag, DISABLED, ENABLED)); + } + } + + NORETURN void ExceptionHandler() { + /* Write enable to MAIN_RESET. */ + reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE)); + while (true) { /* ... */ } + } + +} + +namespace ams::diag { + + void AbortImpl() { + warmboot::ExceptionHandler(); + } + +} diff --git a/exosphere2/warmboot/source/warmboot_main.hpp b/exosphere2/warmboot/source/warmboot_main.hpp new file mode 100644 index 000000000..f71a89b1a --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_main.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::warmboot { + + struct Metadata { + static constexpr u32 Magic = util::FourCC<'W','B','T','0'>::Code; + + u32 magic; + ams::TargetFirmware target_firmware; + u32 reserved[2]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(Metadata) == 0x10); + +} diff --git a/exosphere2/warmboot/source/warmboot_misc.cpp b/exosphere2/warmboot/source/warmboot_misc.cpp new file mode 100644 index 000000000..eeb5932f2 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_misc.cpp @@ -0,0 +1,56 @@ +/* + * 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 "warmboot_misc.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); + constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress(); + + } + + void ConfigureMiscSystemDebug() { + /* Enable RTCK daisy-chaining. */ + reg::Write(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM(PP_CONFIG_CTL_TBE, ENABLE)); + + /* If we're in production mode, perform JTAG configuration. */ + /* NOTE: While this is what NVidia's code does, this is almost certainly a logic error. */ + /* They intend to configure JTAG only when *not* in production mode. */ + /* However, here we will do what they do, and not what they intend. */ + const bool production_mode = fuse::IsOdmProductionMode(); + if (production_mode) { + const bool jtag_sts = reg::HasValue(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM(STICKY_BITS_JTAG_STS, ENABLE)); + + reg::ReadWrite(SYSTEM + SB_PFCFG, SB_REG_BITS_ENUM_SEL(PFCFG_DBGEN, jtag_sts, ENABLE, DISABLE), + SB_REG_BITS_ENUM_SEL(PFCFG_NIDEN, jtag_sts, ENABLE, DISABLE), + SB_REG_BITS_ENUM_SEL(PFCFG_SPNIDEN, jtag_sts, ENABLE, DISABLE), + SB_REG_BITS_ENUM (PFCFG_SPIDEN, DISABLE)); + + reg::ReadWrite(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM_SEL(PP_CONFIG_CTL_JTAG, jtag_sts, ENABLE, DISABLE)); + } + + /* Configure HDA codec disable. */ + reg::ReadWrite(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM_SEL(STICKY_BITS_HDA_LPBK_DIS, production_mode, ENABLE, DISABLE)); + + /* Set E_INPUT in PINMUX_AUX_GPIO_PA6 (needed by the XUSB and SATA controllers). */ + reg::ReadWrite(APB_MISC + PINMUX_AUX_GPIO_PA6, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); + } + +} diff --git a/exosphere2/warmboot/source/warmboot_misc.hpp b/exosphere2/warmboot/source/warmboot_misc.hpp new file mode 100644 index 000000000..4cfeeab20 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_misc.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::warmboot { + + void ConfigureMiscSystemDebug(); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_secure_monitor.cpp b/exosphere2/warmboot/source/warmboot_secure_monitor.cpp new file mode 100644 index 000000000..40b7b84c3 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_secure_monitor.cpp @@ -0,0 +1,130 @@ +/* + * 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 "warmboot_secure_monitor.hpp" + +namespace ams::warmboot { + + namespace { + + constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + + constexpr inline const pkg1::AesKeySlot SavedAesKeySlots[] = { + pkg1::AesKeySlot_TzramSaveKek, + pkg1::AesKeySlot_RandomForUserWrap, + pkg1::AesKeySlot_RandomForKeyStorageWrap, + pkg1::AesKeySlot_DeviceMaster, + pkg1::AesKeySlot_Master, + pkg1::AesKeySlot_Device, + }; + + constexpr ALWAYS_INLINE bool IsSavedAesKeySlot(int slot) { + for (const auto SavedSlot : SavedAesKeySlots) { + if (slot == SavedSlot) { + return true; + } + } + + return false; + } + + void ClearUnsavedSecurityEngineKeySlots() { + /* Clear unsaved aes keys and all ivs. */ + for (int slot = 0; slot < se::AesKeySlotCount; ++slot) { + if (!IsSavedAesKeySlot(slot)) { + se::ClearAesKeySlot(slot); + } + se::ClearAesKeyIv(slot); + } + + /* Clear all rsa keys. */ + for (int slot = 0; slot < se::RsaKeySlotCount; ++slot) { + se::ClearRsaKeySlot(slot); + } + } + + void RestoreEncryptedTzram(void * const tzram_dst, const void * const tzram_src, size_t tzram_size) { + /* Derive the save key from the save kek. */ + const u32 key_source[se::AesBlockSize / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27)}; + se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); + se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, sizeof(key_source)); + + /* Decrypt tzram. */ + const u8 tzram_iv[se::AesBlockSize] = {}; + se::DecryptAes256Cbc(tzram_dst, tzram_size, pkg1::AesKeySlot_TzramSaveKey, tzram_src, tzram_size, tzram_iv, sizeof(tzram_iv)); + + /* Calculate the cmac of decrypted tzram. */ + u8 tzram_mac[se::AesBlockSize] = {}; + se::ComputeAes256Cmac(tzram_mac, sizeof(tzram_mac), pkg1::AesKeySlot_TzramSaveKey, tzram_dst, tzram_size); + + /* Get the expected mac from pmc scratch. */ + const u32 expected_mac[sizeof(tzram_mac) / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115)}; + + /* Validate that the calculated mac is correct. */ + AMS_ABORT_UNLESS(crypto::IsSameBytes(tzram_mac, expected_mac, sizeof(tzram_mac))); + } + + void RestoreSecureMonitorToTzramErista(const TargetFirmware target_fw) { + /* Clear all unsaved security engine keyslots. */ + ClearUnsavedSecurityEngineKeySlots(); + + /* Restore encrypted tzram contents. */ + void * const tzram_src = secmon::MemoryRegionPhysicalDramSecureDataStoreTzram.GetPointer(); + void * const tzram_dst = secmon::MemoryRegionPhysicalTzramNonVolatile.GetPointer(); + const size_t tzram_size = secmon::MemoryRegionPhysicalTzramNonVolatile.GetSize(); + RestoreEncryptedTzram(tzram_dst, tzram_src, tzram_size); + + /* Clear the tzram kek registers. */ + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, 0); + + /* Clear the tzram cmac registers. */ + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, 0); + reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, 0); + + /* Clear the keydata used to protect tzram. */ + se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKek); + se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); + + /* Clear the encrypted copy of tzram in dram. */ + /* NOTE: This does not actually clear the encrypted copy, because BPMP access to main memory has been restricted. */ + /* Nintendo seems to not realize this, though, so we'll do the same. */ + std::memset(tzram_src, 0, tzram_size); + + /* Set Tzram to secure-world only. */ + se::SetTzramSecure(); + } + + } + + void RestoreSecureMonitorToTzram(const TargetFirmware target_fw) { + /* If erista, perform restoration procedure. */ + if (fuse::GetSocType() == fuse::SocType_Erista) { + RestoreSecureMonitorToTzramErista(target_fw); + } + + /* Lock secure scratch. */ + pmc::LockSecureRegister(static_cast(pmc::SecureRegister_DramParameters | pmc::SecureRegister_Other)); + + /* Lockout fuses. */ + fuse::Lockout(); + } + +} diff --git a/exosphere2/warmboot/source/warmboot_secure_monitor.hpp b/exosphere2/warmboot/source/warmboot_secure_monitor.hpp new file mode 100644 index 000000000..499d125c6 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_secure_monitor.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::warmboot { + + void RestoreSecureMonitorToTzram(const TargetFirmware target_fw); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_start.s b/exosphere2/warmboot/source/warmboot_start.s new file mode 100644 index 000000000..18070e04a --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_start.s @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +.section .text._ZN3ams8warmboot5StartEv, "ax", %progbits +.align 3 +.global _ZN3ams8warmboot5StartEv +_ZN3ams8warmboot5StartEv: + /* Set CPSR_cf and CPSR_cf. */ + msr cpsr_f, #0xC0 + msr cpsr_cf, #0xD3 + + /* Set the stack pointer. */ + ldr sp, =__stack_top__ + + /* Set our link register to the exception handler. */ + ldr lr, =_ZN3ams8warmboot16ExceptionHandlerEv + + /* Invoke main. */ + ldr r0, =_metadata + bl _ZN3ams8warmboot4MainEPKNS0_8MetadataE + + /* Infinite loop. */ + 1: b 1b \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_util.hpp b/exosphere2/warmboot/source/warmboot_util.hpp new file mode 100644 index 000000000..5ca4402e6 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_util.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::warmboot { + + void SpinLoop(unsigned int num); + +} \ No newline at end of file diff --git a/exosphere2/warmboot/source/warmboot_util_asm.s b/exosphere2/warmboot/source/warmboot_util_asm.s new file mode 100644 index 000000000..c23d7f307 --- /dev/null +++ b/exosphere2/warmboot/source/warmboot_util_asm.s @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +.section .text._ZN3ams8warmboot8SpinLoopEj, "ax", %progbits +.global _ZN3ams8warmboot8SpinLoopEj +.thumb_func +.syntax unified +_ZN3ams8warmboot8SpinLoopEj: + 1: + /* Subtract one from the count. */ + subs r0, r0, #1 + + /* If we aren't at zero, continue looping. */ + bgt 1b + + /* Return. */ + bx lr \ No newline at end of file diff --git a/exosphere2/warmboot/warmboot.ld b/exosphere2/warmboot/warmboot.ld new file mode 100644 index 000000000..0e3d4482f --- /dev/null +++ b/exosphere2/warmboot/warmboot.ld @@ -0,0 +1,189 @@ +OUTPUT_ARCH(arm) +ENTRY(_reset) + +MEMORY +{ + NULL : ORIGIN = 0, LENGTH = 4K + lp0fw : ORIGIN = 0x40010000, LENGTH = 16K +} + + +SECTIONS +{ + /* =========== CODE section =========== */ + PROVIDE(__start__ = ORIGIN(lp0fw)); + . = __start__; + __code_start = . ; + + .vectors : + { + KEEP (*(.vectors .vectors.*)) + . = ALIGN(8); + } >lp0fw + + .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); + } >lp0fw + + .init : + { + KEEP( *(.init) ) + . = ALIGN(8); + } >lp0fw + + .plt : + { + *(.plt) + *(.iplt) + . = ALIGN(8); + } >lp0fw + + .fini : + { + KEEP( *(.fini) ) + . = ALIGN(8); + } >lp0fw + + + /* =========== RODATA section =========== */ + . = ALIGN(8); + __rodata_start = . ; + + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + . = ALIGN(8); + } >lp0fw + + .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >lp0fw + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >lp0fw + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >lp0fw + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >lp0fw + + .hash : { *(.hash) } >lp0fw + + /* =========== DATA section =========== */ + . = ALIGN(8); + __data_start = . ; + + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >lp0fw + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >lp0fw + .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >lp0fw + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >lp0fw + + .preinit_array ALIGN(8) : + { + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + } >lp0fw + + .init_array ALIGN(8) : + { + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + } >lp0fw + + .fini_array ALIGN(8) : + { + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } >lp0fw + + .ctors ALIGN(8) : + { + KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >lp0fw + + .dtors ALIGN(8) : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >lp0fw + + __got_start__ = .; + + .got : { *(.got) *(.igot) } >lp0fw + .got.plt : { *(.got.plt) *(.igot.plt) } >lp0fw + + __got_end__ = .; + + .data ALIGN(8) : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } >lp0fw + + __bss_start__ = .; + .bss ALIGN(8) : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(16); + } >lp0fw + __bss_end__ = .; + + __end__ = ABSOLUTE(.) ; + + __total_size__ = (__end__ - __start__); + __executable_size__ = (__end__ - _reset); + + __stack_top__ = 0x40013000; + __stack_bottom__ = 0x40012000; + + /* ================== + ==== 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/warmboot/warmboot.specs b/exosphere2/warmboot/warmboot.specs new file mode 100644 index 000000000..45d00560d --- /dev/null +++ b/exosphere2/warmboot/warmboot.specs @@ -0,0 +1,7 @@ +%rename link old_link + +*link: +%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic -nostdlib -nostartfiles + +*startfile: +crti%O%s crtbegin%O%s diff --git a/libraries/libexosphere/include/exosphere/fuse.hpp b/libraries/libexosphere/include/exosphere/fuse.hpp index eef79fed7..19b58dca7 100644 --- a/libraries/libexosphere/include/exosphere/fuse.hpp +++ b/libraries/libexosphere/include/exosphere/fuse.hpp @@ -109,4 +109,7 @@ namespace ams::fuse { int GetExpectedFuseVersion(TargetFirmware target_fw); bool HasRcmVulnerabilityPatch(); + bool IsOdmProductionMode(); + void ConfigureFuseBypass(); + } \ No newline at end of file diff --git a/libraries/libexosphere/include/exosphere/pmic.hpp b/libraries/libexosphere/include/exosphere/pmic.hpp index 29122bce2..fc43715b8 100644 --- a/libraries/libexosphere/include/exosphere/pmic.hpp +++ b/libraries/libexosphere/include/exosphere/pmic.hpp @@ -27,6 +27,7 @@ namespace ams::pmic { Regulator_Mariko_Max77812_B = 2, /* Device code 0x3A000006 */ }; + void SetEnBit(Regulator regulator); void EnableVddCpu(Regulator regulator); void DisableVddCpu(Regulator regulator); void EnableSleep(); diff --git a/libraries/libexosphere/include/exosphere/reg.hpp b/libraries/libexosphere/include/exosphere/reg.hpp index aa0de0831..1ac314110 100644 --- a/libraries/libexosphere/include/exosphere/reg.hpp +++ b/libraries/libexosphere/include/exosphere/reg.hpp @@ -87,6 +87,10 @@ namespace ams::reg { template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) ALWAYS_INLINE bool HasValue(uintptr_t reg, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); } + ALWAYS_INLINE u32 GetValue(volatile u32 *reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); } + ALWAYS_INLINE u32 GetValue(volatile u32 ®, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); } + ALWAYS_INLINE u32 GetValue(uintptr_t reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); } + ALWAYS_INLINE void ReadWrite(volatile u32 *reg, u32 val, u32 mask) { *reg = (*reg & (~mask)) | (val & mask); } ALWAYS_INLINE void ReadWrite(volatile u32 ®, u32 val, u32 mask) { reg = ( reg & (~mask)) | (val & mask); } ALWAYS_INLINE void ReadWrite(uintptr_t reg, u32 val, u32 mask) { ReadWrite(reinterpret_cast(reg), val, mask); } diff --git a/libraries/libexosphere/include/exosphere/se/se_aes.hpp b/libraries/libexosphere/include/exosphere/se/se_aes.hpp index bd8c46ced..d3f18d20c 100644 --- a/libraries/libexosphere/include/exosphere/se/se_aes.hpp +++ b/libraries/libexosphere/include/exosphere/se/se_aes.hpp @@ -23,6 +23,7 @@ namespace ams::se { constexpr inline size_t AesBlockSize = crypto::AesEncryptor128::BlockSize; void ClearAesKeySlot(int slot); + void ClearAesKeyIv(int slot); void LockAesKeySlot(int slot, u32 flags); void SetAesKey(int slot, const void *key, size_t key_size); @@ -40,6 +41,8 @@ namespace ams::se { void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); + void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); + void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler); void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler); diff --git a/libraries/libexosphere/include/exosphere/tegra.hpp b/libraries/libexosphere/include/exosphere/tegra.hpp index a6c8a0dda..7f988871f 100644 --- a/libraries/libexosphere/include/exosphere/tegra.hpp +++ b/libraries/libexosphere/include/exosphere/tegra.hpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp index af05f3658..4ad9de8ba 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp @@ -16,22 +16,32 @@ #pragma once #include +#define APB_MISC_PP_CONFIG_CTL (0x024) + +#define APB_MISC_GP_ASDBGREG (0x810) + +#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 (0xc00) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 (0xc00) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 (0xc04) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 (0xc08) -#define AHB_MISC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (AHB_MISC, NAME) -#define AHB_MISC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (AHB_MISC, NAME, VALUE) -#define AHB_MISC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (AHB_MISC, NAME, ENUM) -#define AHB_MISC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(AHB_MISC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) +#define APB_MISC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (APB_MISC, NAME) +#define APB_MISC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (APB_MISC, NAME, VALUE) +#define APB_MISC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (APB_MISC, NAME, ENUM) +#define APB_MISC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(APB_MISC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) -#define DEFINE_AHB_MISC_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (AHB_MISC, NAME, __OFFSET__, __WIDTH__) -#define DEFINE_AHB_MISC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (AHB_MISC, NAME, __OFFSET__, ZERO, ONE) -#define DEFINE_AHB_MISC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (AHB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) -#define DEFINE_AHB_MISC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(AHB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) -#define DEFINE_AHB_MISC_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (AHB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) +#define DEFINE_APB_MISC_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (APB_MISC, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_APB_MISC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (APB_MISC, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_APB_MISC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (APB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_APB_MISC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(APB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_APB_MISC_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (APB_MISC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) -#define DEFINE_SLAVE_SECURITY_REG(RINDEX, INDEX, NAME) DEFINE_AHB_MISC_REG_BIT_ENUM(SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG##RINDEX##_##NAME##_SECURITY_EN, INDEX, DISABLE, ENABLE) +DEFINE_APB_MISC_REG_BIT_ENUM(PP_CONFIG_CTL_JTAG, 6, DISABLE, ENABLE); +DEFINE_APB_MISC_REG_BIT_ENUM(PP_CONFIG_CTL_TBE, 7, DISABLE, ENABLE); + +DEFINE_APB_MISC_REG(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 24, 2); + +#define DEFINE_SLAVE_SECURITY_REG(RINDEX, INDEX, NAME) DEFINE_APB_MISC_REG_BIT_ENUM(SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG##RINDEX##_##NAME##_SECURITY_EN, INDEX, DISABLE, ENABLE) DEFINE_SLAVE_SECURITY_REG(0, 29, STM); DEFINE_SLAVE_SECURITY_REG(0, 24, CEC); @@ -96,4 +106,4 @@ DEFINE_SLAVE_SECURITY_REG(2, 0, SDMMC1); #undef DEFINE_SLAVE_SECURITY_REG -#define SLAVE_SECURITY_REG_BITS_ENUM(RINDEX, NAME, ENUM) AHB_MISC_REG_BITS_ENUM(SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG##RINDEX##_##NAME##_SECURITY_EN, ENUM) +#define SLAVE_SECURITY_REG_BITS_ENUM(RINDEX, NAME, ENUM) APB_MISC_REG_BITS_ENUM(SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG##RINDEX##_##NAME##_SECURITY_EN, ENUM) diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp index fc2253c27..649ed3f04 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp @@ -29,14 +29,51 @@ #define DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (CLK_RST_CONTROLLER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) -#define CLK_RST_CONTROLLER_RST_SOURCE (0x000) +#define CLK_RST_CONTROLLER_RST_SOURCE (0x000) -#define CLK_RST_CONTROLLER_MISC_CLK_ENB (0x048) +#define CLK_RST_CONTROLLER_MISC_CLK_ENB (0x048) +#define CLK_RST_CONTROLLER_OSC_CTRL (0x050) +#define CLK_RST_CONTROLLER_PLLX_BASE (0x0E0) +#define CLK_RST_CONTROLLER_CCLKG_BURST_POLICY (0x368) +#define CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER (0x36C) +#define CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY (0x370) +#define CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER (0x374) +#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 (0x388) +#define CLK_RST_CONTROLLER_SPARE_REG0 (0x55C) +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA (0x0F8) +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB (0x0FC) +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC (0x3A0) #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD (0x3A4) +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE (0x554) DEFINE_CLK_RST_REG(MISC_CLK_ENB_CFG_ALL_VISIBLE, 28, 1); +DEFINE_CLK_RST_REG_BIT_ENUM(OSC_CTRL_XOE, 0, DISABLE, ENABLE); +DEFINE_CLK_RST_REG(OSC_CTRL_XOFS, 4, 6); + +DEFINE_CLK_RST_REG_BIT_ENUM(PLLX_BASE_PLLX_ENABLE, 30, DISABLE, ENABLE); + +DEFINE_CLK_RST_REG(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0, 8); +DEFINE_CLK_RST_REG(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 8, 8); +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, 24, NO_IMPACT, DISABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, 25, NO_IMPACT, DISABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, 26, NO_IMPACT, DISABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, 27, NO_IMPACT, DISABLE); + +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLKG_DIVIDER_SUPER_CDIV_ENB, 31, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(SUPER_CCLKLP_DIVIDER_SUPER_CDIV_ENB, 31, DISABLE, ENABLE); + +DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, 0, CLKM, RSVD1, CLKS, RSVD3, PLLP_OUT0, PLLP_OUT4, RSVD6, RSVD7, PLLX_OUT0_LJ, DVFS_CPU_CLK, RSVD10, RSVD11, RSVD12, RSVD13, PLLX_OUT0, DVFS_CPU_CLK_LJ); +DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, 4, CLKM, RSVD1, CLKS, RSVD3, PLLP_OUT0, PLLP_OUT4, RSVD6, RSVD7, PLLX_OUT0_LJ, DVFS_CPU_CLK, RSVD10, RSVD11, RSVD12, RSVD13, PLLX_OUT0, DVFS_CPU_CLK_LJ); +DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, 8, CLKM, RSVD1, CLKS, RSVD3, PLLP_OUT0, PLLP_OUT4, RSVD6, RSVD7, PLLX_OUT0_LJ, DVFS_CPU_CLK, RSVD10, RSVD11, RSVD12, RSVD13, PLLX_OUT0, DVFS_CPU_CLK_LJ); +DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, 12, CLKM, RSVD1, CLKS, RSVD3, PLLP_OUT0, PLLP_OUT4, RSVD6, RSVD7, PLLX_OUT0_LJ, DVFS_CPU_CLK, RSVD10, RSVD11, RSVD12, RSVD13, PLLX_OUT0, DVFS_CPU_CLK_LJ); +DEFINE_CLK_RST_REG_FOUR_BIT_ENUM(CCLK_BURST_POLICY_CPU_STATE, 28, STDBY, IDLE, RUN, RSVD3, IRQ, RSVD5, RSVD6, RSVD7, FIQ, RSVD9, RSVD10, RSVD11, RSVD12, RSVD13, RSVD14, RSVD15); + +DEFINE_CLK_RST_REG(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0, 12); + +DEFINE_CLK_RST_REG_TWO_BIT_ENUM(SPARE_REG0_CLK_M_DIVISOR, 2, CLK_M_DIVISOR1, CLK_M_DIVISOR2, CLK_M_DIVISOR3, CLK_M_DIVISOR4); + /* RST_DEVICES */ #define CLK_RST_CONTROLLER_RST_DEVICES_L (0x004) #define CLK_RST_CONTROLLER_RST_DEVICES_H (0x008) @@ -56,18 +93,45 @@ DEFINE_CLK_RST_REG(MISC_CLK_ENB_CFG_ALL_VISIBLE, 28, 1); #define CLK_RST_CONTROLLER_CLK_OUT_ENB_W (0x364) /* CLK_SOURCE */ -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 (0x124) -#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 (0x128) -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA (0x178) -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB (0x17C) -#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0) -#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8) +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 (0x124) +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 (0x128) +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA (0x178) +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB (0x17C) +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0) +#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT (0x3B4) +#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8) +#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF (0x62C) +#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC (0x630) /* RST_DEV_*_SET */ #define CLK_RST_CONTROLLER_RST_DEV_L_SET (0x300) +#define CLK_RST_CONTROLLER_RST_DEV_H_SET (0x308) +#define CLK_RST_CONTROLLER_RST_DEV_U_SET (0x310) +#define CLK_RST_CONTROLLER_RST_DEV_V_SET (0x430) /* RST_DEV_*_CLR */ #define CLK_RST_CONTROLLER_RST_DEV_L_CLR (0x304) +#define CLK_RST_CONTROLLER_RST_DEV_H_CLR (0x30C) +#define CLK_RST_CONTROLLER_RST_DEV_U_CLR (0x314) +#define CLK_RST_CONTROLLER_RST_DEV_V_CLR (0x434) + +/* CLK_ENB_*_SET */ +#define CLK_RST_CONTROLLER_CLK_ENB_L_SET (0x320) +#define CLK_RST_CONTROLLER_CLK_ENB_H_SET (0x328) +#define CLK_RST_CONTROLLER_CLK_ENB_U_SET (0x330) +#define CLK_RST_CONTROLLER_CLK_ENB_V_SET (0x440) +#define CLK_RST_CONTROLLER_CLK_ENB_W_SET (0x448) +#define CLK_RST_CONTROLLER_CLK_ENB_X_SET (0x284) +#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET (0x29C) + +/* CLK_ENB_*_CLR */ +#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR (0x324) +#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR (0x32C) +#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR (0x334) +#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR (0x288) +#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR (0x2A0) +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR (0x444) +#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR (0x44C) /* CLK_ENB_*_INDEX */ #define CLK_RST_CONTROLLER_CLK_ENB_I2C1_INDEX (0x0C) @@ -95,14 +159,92 @@ DEFINE_CLK_RST_REG_BIT_ENUM(LVL2_CLK_GATE_OVRD_SDMMC3_LEGACY_TMCLK_OVR_ON, 30, O DEFINE_CLK_RST_REG_BIT_ENUM(LVL2_CLK_GATE_OVRD_SDMMC4_LEGACY_TMCLK_OVR_ON, 31, OFF, ON); DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_I2C1_I2C1_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); +DEFINE_CLK_RST_REG(CLK_SOURCE_I2C1_I2C1_CLK_DIVISOR, 0, 8); DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_I2C5_I2C5_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); +DEFINE_CLK_RST_REG(CLK_SOURCE_I2C5_I2C5_CLK_DIVISOR, 0, 8); DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTA_UARTA_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTB_UARTB_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTC_UARTC_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); +DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_MSELECT_MSELECT_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT2, PLLC4_OUT1, CLK_S, CLK_M, PLLC4_OUT0); +DEFINE_CLK_RST_REG(CLK_SOURCE_MSELECT_MSELECT_CLK_DIVISOR, 0, 8); + DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_ACTMON_ACTMON_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, CLK_S, PLLC4_OUT1, CLK_M, PLLC4_OUT2); +DEFINE_CLK_RST_REG(CLK_SOURCE_DVFS_REF_DVFS_REF_DIVISOR, 0, 8); +DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_DVFS_REF_DVFS_REF_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); + +DEFINE_CLK_RST_REG(CLK_SOURCE_DVFS_SOC_DVFS_SOC_DIVISOR, 0, 8); +DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_DVFS_SOC_DVFS_SOC_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2); + DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_SET_SET_COP_RST, 1, DISABLE, ENABLE); DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_CLR_CLR_COP_RST, 1, DISABLE, ENABLE); + +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET0, 0, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET1, 1, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET2, 2, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET3, 3, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET0, 16, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET1, 17, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET2, 18, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET3, 19, DISABLE, ENABLE); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, 29, DISABLE, ENABLE); + +/* TODO: Actually include all devices. */ +#define CLK_RST_FOREACH_DEVICE(HANDLER) \ + HANDLER(L, CPU, 0, 0) \ + HANDLER(L, RTC, 0, 4) \ + HANDLER(L, TMR, 0, 5) \ + HANDLER(L, GPIO, 0, 8) \ + HANDLER(L, CACHE2, 0, 31) \ + HANDLER(H, MEM, 1, 0) \ + HANDLER(H, PMC, 1, 6) \ + HANDLER(H, FUSE, 1, 7) \ + HANDLER(H, I2C5, 1, 15) \ + HANDLER(H, EMC, 1, 25) \ + HANDLER(U, CSITE, 2, 9) \ + HANDLER(U, IRAMA, 2, 20) \ + HANDLER(U, IRAMB, 2, 21) \ + HANDLER(U, IRAMC, 2, 22) \ + HANDLER(U, IRAMD, 2, 23) \ + HANDLER(U, CRAM2, 2, 24) \ + HANDLER(V, CPUG, 3, 0) \ + HANDLER(V, MSELECT, 3, 3) \ + HANDLER(V, SPDIF_DOUBLER, 3, 22) \ + HANDLER(V, TZRAM, 3, 30) \ + HANDLER(V, SE, 3, 31) \ + HANDLER(W, PCIERX0, 4, 2) \ + HANDLER(W, PCIERX1, 4, 3) \ + HANDLER(W, PCIERX2, 4, 4) \ + HANDLER(W, PCIERX3, 4, 5) \ + HANDLER(W, PCIERX4, 4, 6) \ + HANDLER(W, PCIERX5, 4, 7) \ + HANDLER(W, ENTROPY, 4, 21) \ + HANDLER(W, DVFS, 4, 27) \ + HANDLER(W, MC1, 4, 30) \ + HANDLER(X, MC_CAPA, 5, 7) \ + HANDLER(X, MC_CBPA, 5, 8) \ + HANDLER(X, MC_CPU, 5, 9) \ + HANDLER(X, MC_BBC, 5, 10) \ + HANDLER(X, EMC_DLL, 5, 14) \ + HANDLER(X, GPU, 5, 24) \ + HANDLER(X, DBGAPB, 5, 25) \ + HANDLER(X, PLLG_REF, 5, 29) \ + HANDLER(Y, MC_CCPA, 6, 8) \ + HANDLER(Y, MC_CDPA, 6, 9) \ + HANDLER(Y, PLLP_OUT_CPU, 6, 31) + +#define CLK_RST_DEFINE_SET_CLR_REG(REGISTER, DEVICE, REGISTER_INDEX, DEVICE_INDEX) \ + DEFINE_CLK_RST_REG_BIT_ENUM(CLK_ENB_##REGISTER##_SET_SET_CLK_ENB_##DEVICE, DEVICE_INDEX, DISABLE, ENABLE); \ + DEFINE_CLK_RST_REG_BIT_ENUM(CLK_ENB_##REGISTER##_CLR_CLR_CLK_ENB_##DEVICE, DEVICE_INDEX, DISABLE, ENABLE); \ + DEFINE_CLK_RST_REG_BIT_ENUM(CLK_ENB_##REGISTER##_CLK_ENB_##DEVICE, DEVICE_INDEX, DISABLE, ENABLE); \ + DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_##REGISTER##_SET_SET_##DEVICE##_RST, DEVICE_INDEX, DISABLE, ENABLE); \ + DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_##REGISTER##_CLR_CLR_##DEVICE##_RST, DEVICE_INDEX, DISABLE, ENABLE); \ + DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_##REGISTER##_##DEVICE##_RST, DEVICE_INDEX, DISABLE, ENABLE); + +CLK_RST_FOREACH_DEVICE(CLK_RST_DEFINE_SET_CLR_REG) + +#undef CLK_RST_DEFINE_SET_CLR_REG + diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_emc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_emc.hpp index f072b0196..7078ea199 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_emc.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_emc.hpp @@ -20,20 +20,23 @@ #define EMC0_ADDRESS(x) (0x7001E000 + x) #define EMC1_ADDRESS(x) (0x7001F000 + x) -#define EMC_CFG (0x00C) -#define EMC_ADR_CFG (0x010) -#define EMC_TIMING_CONTROL (0x028) -#define EMC_SELF_REF (0x0E0) -#define EMC_MRW (0x0E8) -#define EMC_FBIO_CFG5 (0x104) -#define EMC_MRW3 (0x138) -#define EMC_AUTO_CAL_CONFIG (0x2A4) -#define EMC_REQ_CTRL (0x2B0) -#define EMC_EMC_STATUS (0x2B4) -#define EMC_CFG_DIG_DLL (0x2BC) -#define EMC_ZCAL_INTERVAL (0x2E0) -#define EMC_PMC_SCRATCH3 (0x448) -#define EMC_FBIO_CFG7 (0x584) +#define EMC_CFG (0x00C) +#define EMC_ADR_CFG (0x010) +#define EMC_TIMING_CONTROL (0x028) +#define EMC_SELF_REF (0x0E0) +#define EMC_MRW (0x0E8) +#define EMC_FBIO_CFG5 (0x104) +#define EMC_MRW3 (0x138) +#define EMC_AUTO_CAL_CONFIG (0x2A4) +#define EMC_REQ_CTRL (0x2B0) +#define EMC_EMC_STATUS (0x2B4) +#define EMC_CFG_DIG_DLL (0x2BC) +#define EMC_ZCAL_INTERVAL (0x2E0) +#define EMC_PMC_SCRATCH3 (0x448) +#define EMC_FBIO_CFG7 (0x584) +#define EMC_PMACRO_CFG_PM_GLOBAL_0 (0xC30) +#define EMC_PMACRO_TRAINING_CTRL_0 (0xCF8) +#define EMC_PMACRO_TRAINING_CTRL_1 (0xCFC) #define EMC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (EMC, NAME) #define EMC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (EMC, NAME, VALUE) @@ -88,3 +91,27 @@ DEFINE_EMC_REG_BIT_ENUM(PMC_SCRATCH3_WEAK_BIAS, 30, DISABLED, ENABLED); DEFINE_EMC_REG_BIT_ENUM(FBIO_CFG7_CH1_ENABLE, 2, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, 16, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, 17, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, 18, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, 19, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, 20, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, 21, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, 22, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, 23, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, 24, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, 25, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, 26, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, 27, DISABLE, ENABLE); + +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_ENABLED, 0, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_TRAIN_QPOP, 1, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_RX_E_DIRECT_ZI, 2, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_E_WRPTR, 3, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_DRV_DQS, 4, DISABLED, ENABLED); + +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_ENABLED, 0, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_TRAIN_QPOP, 1, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_RX_E_DIRECT_ZI, 2, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_E_WRPTR, 3, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_DRV_DQS, 4, DISABLED, ENABLED); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp index eebdcc400..ef74c7f78 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp @@ -16,7 +16,7 @@ #pragma once #include - +#define FLOW_CTLR_RAM_REPAIR (0x040) #define FLOW_CTLR_FLOW_DBG_QUAL (0x050) #define FLOW_CTLR_L2FLUSH_CONTROL (0x094) #define FLOW_CTLR_BPMP_CLUSTER_CONTROL (0x098) @@ -66,6 +66,9 @@ DEFINE_FLOW_REG_THREE_BIT_ENUM(HALT_COP_EVENTS_MODE, 29, FLOW_MODE_NONE, FLOW_MO DEFINE_FLOW_REG_BIT_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, 28, DISABLE, ENABLE); +DEFINE_FLOW_REG_BIT_ENUM(RAM_REPAIR_REQ, 0, DISABLE, ENABLE); +DEFINE_FLOW_REG_BIT_ENUM(RAM_REPAIR_STS, 1, REQUESTED, DONE); + DEFINE_FLOW_REG_BIT_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, 0, FAST, SLOW); DEFINE_FLOW_REG_BIT_ENUM(BPMP_CLUSTER_CONTROL_CLUSTER_SWITCH_ENABLE, 1, DISABLE, ENABLE); DEFINE_FLOW_REG_BIT_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER_LOCK, 2, DISABLE, ENABLE); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_mselect.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_mselect.hpp index 20c5530df..6f0c5137b 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_mselect.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_mselect.hpp @@ -20,3 +20,20 @@ #define MSELECT_CONFIG (0x000) +#define MSELECT_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (MSELECT, NAME) +#define MSELECT_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (MSELECT, NAME, VALUE) +#define MSELECT_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (MSELECT, NAME, ENUM) +#define MSELECT_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(MSELECT, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_MSELECT_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (MSELECT, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_MSELECT_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (MSELECT, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_MSELECT_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (MSELECT, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_MSELECT_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(MSELECT, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_MSELECT_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (MSELECT, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_ERR_RESP_EN_SLAVE1, 24, DISABLE, ENABLE); +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_ERR_RESP_EN_SLAVE2, 25, DISABLE, ENABLE); +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_WRAP_TO_INCR_SLAVE0, 27, DISABLE, ENABLE); +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_WRAP_TO_INCR_SLAVE1, 28, DISABLE, ENABLE); +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_WRAP_TO_INCR_SLAVE2, 29, DISABLE, ENABLE); +DEFINE_MSELECT_REG_BIT_ENUM(CONFIG_WRAP_TO_INCR_SLAVE3, 30, DISABLE, ENABLE); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pg_up.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pg_up.hpp new file mode 100644 index 000000000..a461d28d2 --- /dev/null +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pg_up.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 + +#define PG_UP(x) (0x60000000 + x) + +#define PG_UP_TAG (0x000) + +#define PG_UP_TAG_PID_COP 0xAAAAAAAA diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pinmux.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pinmux.hpp new file mode 100644 index 000000000..8e5424880 --- /dev/null +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pinmux.hpp @@ -0,0 +1,68 @@ +/* + * 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 + +#define PINMUX_AUX_GEN1_I2C_SCL (0x30BC) +#define PINMUX_AUX_GEN1_I2C_SDA (0x30C0) +#define PINMUX_AUX_PWR_I2C_SCL (0x30DC) +#define PINMUX_AUX_PWR_I2C_SDA (0x30E0) + +#define PINMUX_AUX_UART1_TX (0x30E4) +#define PINMUX_AUX_UART1_RX (0x30E8) +#define PINMUX_AUX_UART1_RTS (0x30EC) +#define PINMUX_AUX_UART1_CTS (0x30F0) +#define PINMUX_AUX_UART2_TX (0x30F4) +#define PINMUX_AUX_UART2_RX (0x30F8) +#define PINMUX_AUX_UART2_RTS (0x30FC) +#define PINMUX_AUX_UART2_CTS (0x3100) +#define PINMUX_AUX_UART3_TX (0x3104) +#define PINMUX_AUX_UART3_RX (0x3108) +#define PINMUX_AUX_UART3_RTS (0x310C) +#define PINMUX_AUX_UART3_CTS (0x3110) +#define PINMUX_AUX_DVFS_PWM (0x3184) +#define PINMUX_AUX_GPIO_PA6 (0x3244) + +#define PINMUX_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (PINMUX, NAME) +#define PINMUX_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (PINMUX, NAME, VALUE) +#define PINMUX_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (PINMUX, NAME, ENUM) +#define PINMUX_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(PINMUX, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_PINMUX_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (PINMUX, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_PINMUX_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_PINMUX_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_PINMUX_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_PINMUX_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_PUPD, 2, NONE, PULL_DOWN, PULL_UP, RSVD); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_TRISTATE, 4, PASSTHROUGH, TRISTATE); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_PARK, 5, NORMAL, PARKED); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_INPUT, 6, DISABLE, ENABLE); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_LOCK, 7, DISABLE, ENABLE); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_LPDR, 8, DISABLE, ENABLE); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_OD, 11, DISABLE, ENABLE); +DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_SCHMT, 12, DISABLE, ENABLE); + +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_GEN1_I2C_PM, 0, I2C1, RSVD1, RSVD2, RSVD3); +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_PWR_I2C_PM, 0, I2CPMU, RSVD1, RSVD2, RSVD3); + +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART1_PM, 0, UARTA, RSVD1, RSVD2, RSVD3); +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART2_PM, 0, UARTB, I2S4A, RSVD2, UART); +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART3_PM, 0, UARTC, SPI4, RSVD2, RSVD3); + +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_DVFS_PWM_PM, 0, RSVD0, CLDVFS, SPI3, RSVD3); + +DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_GPIO_PA6_PM, 0, SATA, RSVD1, RSVD2, RSVD3); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp index da1c6d053..6934c8ccb 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp @@ -50,6 +50,7 @@ #define APBDEV_PMC_WAKE2_LVL (0x164) #define APBDEV_PMC_WAKE2_STATUS (0x168) #define APBDEV_PMC_AUTO_WAKE2_LVL_MASK (0x170) +#define APBDEV_PMC_OSC_EDPD_OVER (0x1A4) #define APBDEV_PMC_CLK_OUT_CNTRL (0x1A8) #define APBDEV_PMC_IO_DPD_REQ (0x1B8) #define APBDEV_PMC_IO_DPD_STATUS (0x1BC) @@ -59,6 +60,7 @@ #define APBDEV_PMC_SCRATCH45 (0x234) #define APBDEV_PMC_SCRATCH46 (0x238) #define APBDEV_PMC_TSC_MULT (0x2B4) +#define APBDEV_PMC_STICKY_BITS (0x2C0) #define APBDEV_PMC_WEAK_BIAS (0x2C8) #define APBDEV_PMC_GPU_RG_CNTRL (0x2D4) #define APBDEV_PMC_CNTRL2 (0x440) @@ -162,6 +164,8 @@ enum APBDEV_PMC_PWRGATE_TOGGLE_PARTID : u8 { APBDEV_PMC_PWRGATE_TOGGLE_PARTID_VE2 = 29, }; +DEFINE_PMC_REG_BIT_ENUM(REMOVE_CLAMPING_COMMAND_CRAIL, 0, DISABLE, ENABLE); + enum APBDEV_PMC_PWRGATE_STATUS_STATUS { APBDEV_PMC_PWRGATE_STATUS_STATUS_OFF = 0, APBDEV_PMC_PWRGATE_STATUS_STATUS_ON = 1, @@ -221,4 +225,11 @@ DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBC, 22, DISABLE, ENABLE); DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VIC, 23, DISABLE, ENABLE); DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_IRAM, 24, DISABLE, ENABLE); +DEFINE_PMC_REG(OSC_EDPD_OVER_XOFS, 1, 6); + +DEFINE_PMC_REG_BIT_ENUM(STICKY_BITS_HDA_LPBK_DIS, 0, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(STICKY_BITS_JTAG_STS, 6, ENABLE, DISABLE); + DEFINE_PMC_REG_BIT_ENUM(CNTRL2_WAKE_DET_EN, 9, DISABLE, ENABLE); + +DEFINE_PMC_REG_BIT_ENUM(SEC_DISABLE2_WRITE21, 26, OFF, ON); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_sb.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_sb.hpp index d6827adeb..83ea3f677 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_sb.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_sb.hpp @@ -17,6 +17,7 @@ #include #define SB_CSR (0x200) +#define SB_PFCFG (0x208) #define SB_AA64_RESET_LOW (0x230) #define SB_AA64_RESET_HIGH (0x234) @@ -39,3 +40,8 @@ DEFINE_SB_REG_BIT_ENUM(CSR_HANG, 6, DISABLE, ENABLE); DEFINE_SB_REG_BIT_ENUM(CSR_SWDM_ENABLE, 7, DISABLE, ENABLE); DEFINE_SB_REG(CSR_SWDM_FAIL_COUNT, 8, 4); DEFINE_SB_REG(CSR_COT_FAIL_COUNT, 12, 4); + +DEFINE_SB_REG_BIT_ENUM(PFCFG_SPNIDEN, 0, DISABLE, ENABLE); +DEFINE_SB_REG_BIT_ENUM(PFCFG_SPIDEN, 1, DISABLE, ENABLE); +DEFINE_SB_REG_BIT_ENUM(PFCFG_NIDEN, 2, DISABLE, ENABLE); +DEFINE_SB_REG_BIT_ENUM(PFCFG_DBGEN, 3, DISABLE, ENABLE); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_timer.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_timer.hpp index 93a7c8b66..ee3fe3dd1 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_timer.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_timer.hpp @@ -16,7 +16,7 @@ #pragma once #include - +#define TIMERUS_USEC_CFG (0x014) #define TIMER_SHARED_TIMER_SECURE_CFG (0x1A4) #define TIMER_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (TIMER, NAME) @@ -30,6 +30,9 @@ #define DEFINE_TIMER_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(TIMER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) #define DEFINE_TIMER_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (TIMER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) +DEFINE_TIMER_REG(USEC_CFG_USEC_DIVISOR, 0, 8); +DEFINE_TIMER_REG(USEC_CFG_USEC_DIVIDEND, 8, 8); + DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_TMR5, 5, DISABLE, ENABLE); DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_TMR6, 6, DISABLE, ENABLE); DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_TMR7, 7, DISABLE, ENABLE); diff --git a/libraries/libexosphere/source/fuse/fuse_api.cpp b/libraries/libexosphere/source/fuse/fuse_api.cpp index 920976f9e..7265e42d9 100644 --- a/libraries/libexosphere/source/fuse/fuse_api.cpp +++ b/libraries/libexosphere/source/fuse/fuse_api.cpp @@ -20,6 +20,11 @@ namespace ams::fuse { namespace { + struct BypassEntry { + u32 offset; + u32 value; + }; + struct OdmWord2 { using DeviceUniqueKeyGeneration = util::BitPack32::Field<0, 5, int>; using Reserved = util::BitPack32::Field<5, 27, int>; @@ -135,6 +140,12 @@ namespace ams::fuse { constexpr inline int NumFuseIncrements = util::size(FuseVersionIncrementFirmwares); + constexpr const BypassEntry FuseBypassEntries[] = { + /* Don't configure any fuse bypass entries. */ + }; + + constexpr inline int NumFuseBypassEntries = util::size(FuseBypassEntries); + /* Verify that the fuse version increment list is sorted. */ static_assert([] { for (size_t i = 0; i < util::size(FuseVersionIncrementFirmwares) - 1; ++i) { @@ -169,7 +180,7 @@ namespace ams::fuse { } void Lockout() { - reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_DISABLEREGPROGRAM_VAL, ENABLE)); + reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, ENABLE)); } u32 ReadWord(int address) { @@ -367,4 +378,49 @@ namespace ams::fuse { return g_has_rcm_bug_patch; } + bool IsOdmProductionMode() { + return reg::HasValue(GetChipRegisters().FUSE_SECURITY_MODE, FUSE_REG_BITS_ENUM(SECURITY_MODE_SECURITY_MODE, ENABLED)); + } + + void ConfigureFuseBypass() { + /* Make the fuse registers visible. */ + clkrst::SetFuseVisibility(true); + + /* Only perform bypass configuration if fuse programming is allowed. */ + if (!reg::HasValue(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE))) { + return; + } + + /* Enable software writes to fuses. */ + reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READWRITE), + FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_STATUS, WRITE)); + + /* Enable fuse bypass. */ + reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE)); + + /* Override fuses. */ + for (const auto &entry : FuseBypassEntries) { + reg::Write(g_register_address + entry.offset, entry.value); + } + + /* Disable software writes to fuses. */ + reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READONLY)); + + /* NOTE: Here, NVidia almost certainly intends to *disable* fuse bypass, but they write enable instead... */ + reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE)); + + /* NOTE: Here, NVidia intends to disable fuse programming. However, they fuck up -- and *clear* the disable bit. */ + /* It should be noted that this is a sticky bit, and thus software clears have no effect. */ + reg::ReadWrite(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE)); + + /* Configure FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT. */ + constexpr const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + const bool key_invisible = reg::HasValue(PMC + APBDEV_PMC_SECURE_SCRATCH21, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE)); + + reg::ReadWrite(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM_SEL(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, key_invisible, KEY_INVISIBLE, KEY_VISIBLE)); + + /* Write-lock PMC_SECURE_SCRATCH21. */ + reg::ReadWrite(PMC + APBDEV_PMC_SEC_DISABLE2, PMC_REG_BITS_ENUM(SEC_DISABLE2_WRITE21, ON)); + } + } diff --git a/libraries/libexosphere/source/fuse/fuse_registers.hpp b/libraries/libexosphere/source/fuse/fuse_registers.hpp index ff0fcc571..3d729c9b6 100644 --- a/libraries/libexosphere/source/fuse/fuse_registers.hpp +++ b/libraries/libexosphere/source/fuse/fuse_registers.hpp @@ -241,6 +241,13 @@ namespace ams::fuse { DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, 4, KEY_VISIBLE, KEY_INVISIBLE); DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_PRIVATEKEYDISABLE_VAL_KEY, 0, VISIBLE, INVISIBLE); - DEFINE_FUSE_REG_BIT_ENUM(DISABLEREGPROGRAM_DISABLEREGPROGRAM_VAL, 0, DISABLE, ENABLE); + DEFINE_FUSE_REG_BIT_ENUM(FUSEBYPASS_VAL, 0, DISABLE, ENABLE); + + DEFINE_FUSE_REG_BIT_ENUM(DISABLEREGPROGRAM_VAL, 0, DISABLE, ENABLE); + + DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_CTRL, 0, READWRITE, READONLY); + DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_STATUS, 16, NOWRITE, WRITE); + + DEFINE_FUSE_REG_BIT_ENUM(SECURITY_MODE_SECURITY_MODE, 0, DISABLED, ENABLED); } diff --git a/libraries/libexosphere/source/pinmux/pinmux_api.cpp b/libraries/libexosphere/source/pinmux/pinmux_api.cpp index 513797dfb..276c9c8b8 100644 --- a/libraries/libexosphere/source/pinmux/pinmux_api.cpp +++ b/libraries/libexosphere/source/pinmux/pinmux_api.cpp @@ -14,7 +14,6 @@ * along with this program. If not, see . */ #include -#include "pinmux_registers.hpp" namespace ams::pinmux { diff --git a/libraries/libexosphere/source/pinmux/pinmux_registers.hpp b/libraries/libexosphere/source/pinmux/pinmux_registers.hpp deleted file mode 100644 index 4fd1c4d51..000000000 --- a/libraries/libexosphere/source/pinmux/pinmux_registers.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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::pinmux { - - #define PINMUX_AUX_GEN1_I2C_SCL (0x30BC) - #define PINMUX_AUX_GEN1_I2C_SDA (0x30C0) - #define PINMUX_AUX_PWR_I2C_SCL (0x30DC) - #define PINMUX_AUX_PWR_I2C_SDA (0x30E0) - - #define PINMUX_AUX_UART1_TX (0x30E4) - #define PINMUX_AUX_UART1_RX (0x30E8) - #define PINMUX_AUX_UART1_RTS (0x30EC) - #define PINMUX_AUX_UART1_CTS (0x30F0) - #define PINMUX_AUX_UART2_TX (0x30F4) - #define PINMUX_AUX_UART2_RX (0x30F8) - #define PINMUX_AUX_UART2_RTS (0x30FC) - #define PINMUX_AUX_UART2_CTS (0x3100) - #define PINMUX_AUX_UART3_TX (0x3104) - #define PINMUX_AUX_UART3_RX (0x3108) - #define PINMUX_AUX_UART3_RTS (0x310C) - #define PINMUX_AUX_UART3_CTS (0x3110) - - #define PINMUX_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (PINMUX, NAME) - #define PINMUX_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (PINMUX, NAME, VALUE) - #define PINMUX_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (PINMUX, NAME, ENUM) - #define PINMUX_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(PINMUX, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) - - #define DEFINE_PINMUX_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (PINMUX, NAME, __OFFSET__, __WIDTH__) - #define DEFINE_PINMUX_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE) - #define DEFINE_PINMUX_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) - #define DEFINE_PINMUX_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) - #define DEFINE_PINMUX_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (PINMUX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) - - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_PUPD, 2, NONE, PULL_DOWN, PULL_UP, RSVD); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_TRISTATE, 4, PASSTHROUGH, TRISTATE); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_PARK, 5, NORMAL, PARKED); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_INPUT, 6, DISABLE, ENABLE); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_LOCK, 7, DISABLE, ENABLE); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_LPDR, 8, DISABLE, ENABLE); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_OD, 11, DISABLE, ENABLE); - DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_SCHMT, 12, DISABLE, ENABLE); - - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_GEN1_I2C_PM, 0, I2C1, RSVD1, RSVD2, RSVD3); - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_PWR_I2C_PM, 0, I2CPMU, RSVD1, RSVD2, RSVD3); - - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART1_PM, 0, UARTA, RSVD1, RSVD2, RSVD3); - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART2_PM, 0, UARTB, I2S4A, RSVD2, UART); - DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_UART3_PM, 0, UARTC, SPI4, RSVD2, RSVD3); - -} diff --git a/libraries/libexosphere/source/pmic/pmic_api.cpp b/libraries/libexosphere/source/pmic/pmic_api.cpp index bf1515d7c..808d465d0 100644 --- a/libraries/libexosphere/source/pmic/pmic_api.cpp +++ b/libraries/libexosphere/source/pmic/pmic_api.cpp @@ -60,6 +60,10 @@ namespace ams::pmic { i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77620RegisterGpio0 + gpio, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); } + void SetEnBitErista() { + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE); + } + void EnableVddCpuErista() { /* Enable GPIO 5. */ /* TODO: What does this control? */ @@ -87,6 +91,11 @@ namespace ams::pmic { } } + void SetEnBitMariko(Regulator regulator) { + /* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */ + i2c::SendByte(i2c::Port_5, GetI2cAddressForMarikoMax77812(regulator), Max77812RegisterEnCtrl, 0x40); + } + void EnableVddCpuMariko(Regulator regulator) { const int address = GetI2cAddressForMarikoMax77812(regulator); @@ -118,6 +127,17 @@ namespace ams::pmic { } + void SetEnBit(Regulator regulator) { + switch (regulator) { + case Regulator_Erista_Max77621: + return SetEnBitErista(); + case Regulator_Mariko_Max77812_A: + case Regulator_Mariko_Max77812_B: + return SetEnBitMariko(regulator); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + void EnableVddCpu(Regulator regulator) { switch (regulator) { case Regulator_Erista_Max77621: diff --git a/libraries/libexosphere/source/se/se_aes.cpp b/libraries/libexosphere/source/se/se_aes.cpp index 5ded61a13..00105f71d 100644 --- a/libraries/libexosphere/source/se/se_aes.cpp +++ b/libraries/libexosphere/source/se/se_aes.cpp @@ -308,6 +308,37 @@ namespace ams::se { ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size); } + void DecryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) { + /* If nothing to decrypt, succeed. */ + if (src_size == 0) { return; } + + /* Validate input. */ + AMS_ABORT_UNLESS(iv_size == AesBlockSize); + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Determine extents. */ + const size_t num_blocks = src_size / AesBlockSize; + const size_t aligned_size = num_blocks * AesBlockSize; + AMS_ABORT_UNLESS(src_size == aligned_size); + + /* Configure for aes-cbc encryption. */ + SetConfig(SE, false, SE_CONFIG_DST_MEMORY); + SetAesConfig(SE, slot, false, AesConfigCbcDecrypt); + UpdateAesMode(SE, mode); + + /* Set the iv. */ + SetAesKeyIv(SE, slot, iv, iv_size); + + /* Set the block count. */ + SetBlockCount(SE, num_blocks); + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size); + } + void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) { /* If nothing to decrypt, succeed. */ if (size == 0) { return; } @@ -349,6 +380,35 @@ namespace ams::se { } } + void ClearAesKeyIv(int slot) { + /* Validate the key slot. */ + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Set each iv word in order. */ + for (int i = 0; i < 4; ++i) { + /* Select the keyslot original iv. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), + SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), + SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV), + SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); + + /* Set the iv word. */ + SE->SE_CRYPTO_KEYTABLE_DATA = 0; + + /* Select the keyslot updated iv. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), + SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), + SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, UPDATED_IV), + SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); + + /* Set the iv word. */ + SE->SE_CRYPTO_KEYTABLE_DATA = 0; + } + } + void LockAesKeySlot(int slot, u32 flags) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); @@ -487,6 +547,14 @@ namespace ams::se { return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256); } + void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { + return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128); + } + + void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { + return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256); + } + void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) { /* Validate the iv. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); diff --git a/libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm.cpp b/libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm.cpp new file mode 100644 index 000000000..340a2fe52 --- /dev/null +++ b/libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm.cpp @@ -0,0 +1,58 @@ +/* + * 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::crypto { + + bool IsSameBytes(const void *lhs, const void *rhs, size_t size) { + bool result; + u8 xor_acc, ltmp, rtmp; + size_t index; + + __asm__ __volatile__( + /* Clear registers and prepare for comparison. */ + " movs %[xor_acc], #0\n" + " movs %[index], #0\n" + " b 1f\n" + + /* Compare one byte in constant time. */ + "0:\n" + " ldrb %[ltmp], [%[lhs]]\n" + " ldrb %[rtmp], [%[rhs]]\n" + " adds %[lhs], #1\n" + " adds %[rhs], #1\n" + " eors %[ltmp], %[ltmp], %[rtmp]\n" + " orrs %[xor_acc], %[xor_acc], %[ltmp]\n" + " adds %[index], #1\n" + + /* Check if there is still data to compare. */ + "1:\n" + " cmp %[index], %[size]\n" + " bcc 0b\n" + + /* We're done, set result. */ + " cmp %[xor_acc], #0\n" + " moveq %[result], #1\n" + " movne %[result], #0\n" + : [result]"=r"(result), [lhs]"+r"(lhs), [rhs]"+r"(rhs), [xor_acc]"=&r"(xor_acc), [index]"=&r"(index), [ltmp]"=&r"(ltmp), [rtmp]"=&r"(rtmp) + : [size]"r"(size) + : "cc" + ); + + return result; + } + +} \ No newline at end of file