From bc653fa85503594b870badaea7a807052c7bbd03 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 4 May 2020 23:33:16 -0700 Subject: [PATCH] exo2: Initial work on the exosphere rewrite. exo2: Implement uncompressor stub and boot code up to Main(). exo2: implement some more init (uart/gic) exo2: implement more of init exo2: improve reg api, add keyslot flag setters exo2: implement se aes decryption/enc exo2: fix bugs in loader stub/mmu mappings exo2: start skeletoning bootconfig/global context types arch: fix makefile flags exo2: implement through master key derivation exo2: implement device master keygen exo2: more init through start of SetupSocSecurity exo2: implement pmc secure scratch management se: implement sticky bit validation libexosphere: fix building for arm32 libexo: fix makefile flags libexo: support building for arm64/arm sc7fw: skeleton binary sc7fw: skeleton a little more sc7fw: implement all non-dram functionality exo2: fix DivideUp error sc7fw: implement more dram code, fix reg library errors sc7fw: complete sc7fw impl. exo2: skeleton the rest of SetupSocSecurity exo2: implement fiq interrupt handler exo2: implement all exception handlers exo2: skeleton the entire smc api, implement the svc invoker exo2: implement rest of SetupSocSecurity exo2: correct slave security errors exo2: fix register definition exo2: minor fixes --- config/arch/arm/arch.mk | 11 + config/arch/arm/cpu/arm7tdmi/cpu.mk | 5 + config/board/nintendo/nx_bpmp/board.mk | 5 + config/common.mk | 23 +- config/templates/exosphere.mk | 46 + libexosphere/Makefile | 19 + libexosphere/arm.mk | 142 ++ libexosphere/arm64.mk | 143 +++ libexosphere/include/exosphere.hpp | 38 + libexosphere/include/exosphere/actmon.hpp | 30 + libexosphere/include/exosphere/clkrst.hpp | 29 + libexosphere/include/exosphere/common.hpp | 30 + libexosphere/include/exosphere/fuse.hpp | 49 + libexosphere/include/exosphere/gic.hpp | 42 + libexosphere/include/exosphere/hw.hpp | 27 + libexosphere/include/exosphere/hw/hw_arm.hpp | 49 + .../include/exosphere/hw/hw_arm64.hpp | 69 + .../include/exosphere/hw/hw_arm64_cache.hpp | 55 + .../hw/hw_arm64_system_registers.hpp | 245 ++++ libexosphere/include/exosphere/i2c.hpp | 46 + libexosphere/include/exosphere/log.hpp | 23 + libexosphere/include/exosphere/mmu.hpp | 18 + .../exosphere/mmu/mmu_api.arch.arm.hpp | 43 + .../exosphere/mmu/mmu_api.arch.arm64.hpp | 279 ++++ .../include/exosphere/mmu/mmu_api.hpp | 37 + libexosphere/include/exosphere/pkg1.hpp | 22 + .../exosphere/pkg1/pkg1_boot_config.hpp | 133 ++ .../pkg1/pkg1_bootloader_parameters.hpp | 68 + .../exosphere/pkg1/pkg1_error_types.hpp | 108 ++ .../exosphere/pkg1/pkg1_key_generation.hpp | 47 + .../exosphere/pkg1/pkg1_se_key_slots.hpp | 56 + libexosphere/include/exosphere/pmc.hpp | 50 + libexosphere/include/exosphere/pmic.hpp | 33 + libexosphere/include/exosphere/reg.hpp | 205 +++ libexosphere/include/exosphere/se.hpp | 24 + libexosphere/include/exosphere/se/se_aes.hpp | 36 + .../include/exosphere/se/se_common.hpp | 53 + .../include/exosphere/se/se_management.hpp | 33 + libexosphere/include/exosphere/se/se_rng.hpp | 28 + libexosphere/include/exosphere/se/se_rsa.hpp | 29 + .../include/exosphere/se/se_suspend.hpp | 55 + libexosphere/include/exosphere/secmon.hpp | 20 + ...ecmon_configuration_context.arch.arm64.hpp | 99 ++ .../secmon/secmon_configuration_context.hpp | 25 + .../secmon/secmon_emummc_context.hpp | 73 ++ .../exosphere/secmon/secmon_memory_layout.hpp | 277 ++++ .../secmon/secmon_monitor_context.hpp | 77 ++ .../secmon/secmon_volatile_context.hpp | 62 + libexosphere/include/exosphere/tegra.hpp | 31 + .../exosphere/tegra/tegra_ahb_arbc.hpp | 26 + .../exosphere/tegra/tegra_apb_misc.hpp | 99 ++ .../exosphere/tegra/tegra_avp_cache.hpp | 35 + .../include/exosphere/tegra/tegra_emc.hpp | 90 ++ .../include/exosphere/tegra/tegra_evp.hpp | 19 + .../exosphere/tegra/tegra_flow_ctlr.hpp | 38 + .../include/exosphere/tegra/tegra_ictlr.hpp | 27 + .../include/exosphere/tegra/tegra_mc.hpp | 329 +++++ .../include/exosphere/tegra/tegra_mselect.hpp | 22 + .../include/exosphere/tegra/tegra_pmc.hpp | 156 +++ .../include/exosphere/tegra/tegra_sb.hpp | 41 + .../include/exosphere/tegra/tegra_sysctr0.hpp | 36 + .../include/exosphere/tegra/tegra_timer.hpp | 41 + libexosphere/include/exosphere/tsec.hpp | 23 + libexosphere/include/exosphere/uart.hpp | 42 + libexosphere/include/exosphere/util.hpp | 33 + libexosphere/include/exosphere/wdt.hpp | 24 + libexosphere/source/actmon/actmon_api.cpp | 42 + libexosphere/source/clkrst/clkrst_api.cpp | 98 ++ .../source/clkrst/clkrst_registers.hpp | 71 + libexosphere/source/fuse/fuse_api.cpp | 121 ++ libexosphere/source/fuse/fuse_registers.hpp | 221 ++++ libexosphere/source/gic/gic_api.cpp | 217 ++++ .../source/hw/hw_cache.arch.arm64.cpp | 29 + libexosphere/source/i2c/i2c_api.cpp | 202 +++ libexosphere/source/i2c/i2c_registers.hpp | 77 ++ libexosphere/source/libc/libc.c | 1141 +++++++++++++++++ libexosphere/source/log/log_api.cpp | 53 + libexosphere/source/pmc/pmc_api.cpp | 275 ++++ .../source/pmc/pmc_secure_scratch_test.inc | 100 ++ libexosphere/source/pmic/max77620.h | 340 +++++ libexosphere/source/pmic/max7762x.h | 109 ++ libexosphere/source/pmic/pmic_api.cpp | 135 ++ libexosphere/source/se/se_aes.cpp | 209 +++ libexosphere/source/se/se_execute.cpp | 138 ++ libexosphere/source/se/se_execute.hpp | 28 + libexosphere/source/se/se_management.cpp | 114 ++ libexosphere/source/se/se_registers.hpp | 249 ++++ libexosphere/source/se/se_rng.cpp | 146 +++ libexosphere/source/se/se_rsa.cpp | 125 ++ libexosphere/source/se/se_suspend.cpp | 59 + libexosphere/source/tsec/tsec_api.cpp | 35 + libexosphere/source/uart/uart_api.cpp | 113 ++ libexosphere/source/uart/uart_registers.hpp | 180 +++ libexosphere/source/util/util_api.cpp | 50 + libexosphere/source/wdt/wdt_api.cpp | 99 ++ .../source/diag/diag_assertion_impl.cpp | 4 + libvapours/include/vapours/assert.hpp | 3 +- .../crypto/impl/crypto_ctr_mode_impl.hpp | 2 +- libvapours/include/vapours/defines.hpp | 2 + libvapours/include/vapours/literals.hpp | 12 +- .../svc/arch/arm/svc_thread_local_region.hpp | 38 + .../svc/svc_select_thread_local_region.hpp | 8 + .../include/vapours/svc/svc_types_common.hpp | 19 +- libvapours/include/vapours/types.hpp | 9 +- libvapours/include/vapours/util.hpp | 1 + .../vapours/util/util_aligned_buffer.hpp | 35 + .../include/vapours/util/util_bitpack.hpp | 2 +- .../include/vapours/util/util_endian.hpp | 8 +- .../include/vapours/util/util_tinymt.hpp | 2 +- 109 files changed, 9129 insertions(+), 20 deletions(-) create mode 100644 config/arch/arm/arch.mk create mode 100644 config/arch/arm/cpu/arm7tdmi/cpu.mk create mode 100644 config/board/nintendo/nx_bpmp/board.mk create mode 100644 config/templates/exosphere.mk create mode 100644 libexosphere/Makefile create mode 100644 libexosphere/arm.mk create mode 100644 libexosphere/arm64.mk create mode 100644 libexosphere/include/exosphere.hpp create mode 100644 libexosphere/include/exosphere/actmon.hpp create mode 100644 libexosphere/include/exosphere/clkrst.hpp create mode 100644 libexosphere/include/exosphere/common.hpp create mode 100644 libexosphere/include/exosphere/fuse.hpp create mode 100644 libexosphere/include/exosphere/gic.hpp create mode 100644 libexosphere/include/exosphere/hw.hpp create mode 100644 libexosphere/include/exosphere/hw/hw_arm.hpp create mode 100644 libexosphere/include/exosphere/hw/hw_arm64.hpp create mode 100644 libexosphere/include/exosphere/hw/hw_arm64_cache.hpp create mode 100644 libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp create mode 100644 libexosphere/include/exosphere/i2c.hpp create mode 100644 libexosphere/include/exosphere/log.hpp create mode 100644 libexosphere/include/exosphere/mmu.hpp create mode 100644 libexosphere/include/exosphere/mmu/mmu_api.arch.arm.hpp create mode 100644 libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp create mode 100644 libexosphere/include/exosphere/mmu/mmu_api.hpp create mode 100644 libexosphere/include/exosphere/pkg1.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_bootloader_parameters.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_error_types.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_se_key_slots.hpp create mode 100644 libexosphere/include/exosphere/pmc.hpp create mode 100644 libexosphere/include/exosphere/pmic.hpp create mode 100644 libexosphere/include/exosphere/reg.hpp create mode 100644 libexosphere/include/exosphere/se.hpp create mode 100644 libexosphere/include/exosphere/se/se_aes.hpp create mode 100644 libexosphere/include/exosphere/se/se_common.hpp create mode 100644 libexosphere/include/exosphere/se/se_management.hpp create mode 100644 libexosphere/include/exosphere/se/se_rng.hpp create mode 100644 libexosphere/include/exosphere/se/se_rsa.hpp create mode 100644 libexosphere/include/exosphere/se/se_suspend.hpp create mode 100644 libexosphere/include/exosphere/secmon.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_configuration_context.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp create mode 100644 libexosphere/include/exosphere/secmon/secmon_volatile_context.hpp create mode 100644 libexosphere/include/exosphere/tegra.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_ahb_arbc.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_avp_cache.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_emc.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_evp.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_ictlr.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_mc.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_mselect.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_pmc.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_sb.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp create mode 100644 libexosphere/include/exosphere/tegra/tegra_timer.hpp create mode 100644 libexosphere/include/exosphere/tsec.hpp create mode 100644 libexosphere/include/exosphere/uart.hpp create mode 100644 libexosphere/include/exosphere/util.hpp create mode 100644 libexosphere/include/exosphere/wdt.hpp create mode 100644 libexosphere/source/actmon/actmon_api.cpp create mode 100644 libexosphere/source/clkrst/clkrst_api.cpp create mode 100644 libexosphere/source/clkrst/clkrst_registers.hpp create mode 100644 libexosphere/source/fuse/fuse_api.cpp create mode 100644 libexosphere/source/fuse/fuse_registers.hpp create mode 100644 libexosphere/source/gic/gic_api.cpp create mode 100644 libexosphere/source/hw/hw_cache.arch.arm64.cpp create mode 100644 libexosphere/source/i2c/i2c_api.cpp create mode 100644 libexosphere/source/i2c/i2c_registers.hpp create mode 100644 libexosphere/source/libc/libc.c create mode 100644 libexosphere/source/log/log_api.cpp create mode 100644 libexosphere/source/pmc/pmc_api.cpp create mode 100644 libexosphere/source/pmc/pmc_secure_scratch_test.inc create mode 100644 libexosphere/source/pmic/max77620.h create mode 100644 libexosphere/source/pmic/max7762x.h create mode 100644 libexosphere/source/pmic/pmic_api.cpp create mode 100644 libexosphere/source/se/se_aes.cpp create mode 100644 libexosphere/source/se/se_execute.cpp create mode 100644 libexosphere/source/se/se_execute.hpp create mode 100644 libexosphere/source/se/se_management.cpp create mode 100644 libexosphere/source/se/se_registers.hpp create mode 100644 libexosphere/source/se/se_rng.cpp create mode 100644 libexosphere/source/se/se_rsa.cpp create mode 100644 libexosphere/source/se/se_suspend.cpp create mode 100644 libexosphere/source/tsec/tsec_api.cpp create mode 100644 libexosphere/source/uart/uart_api.cpp create mode 100644 libexosphere/source/uart/uart_registers.hpp create mode 100644 libexosphere/source/util/util_api.cpp create mode 100644 libexosphere/source/wdt/wdt_api.cpp create mode 100644 libvapours/include/vapours/svc/arch/arm/svc_thread_local_region.hpp create mode 100644 libvapours/include/vapours/util/util_aligned_buffer.hpp diff --git a/config/arch/arm/arch.mk b/config/arch/arm/arch.mk new file mode 100644 index 00000000..f629bb39 --- /dev/null +++ b/config/arch/arm/arch.mk @@ -0,0 +1,11 @@ +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +include $(DEVKITPRO)/devkitARM/base_rules + +export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM +export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += diff --git a/config/arch/arm/cpu/arm7tdmi/cpu.mk b/config/arch/arm/cpu/arm7tdmi/cpu.mk new file mode 100644 index 00000000..d50dd060 --- /dev/null +++ b/config/arch/arm/cpu/arm7tdmi/cpu.mk @@ -0,0 +1,5 @@ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_ARM7TDMI +export ATMOSPHERE_SETTINGS += -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += \ No newline at end of file diff --git a/config/board/nintendo/nx_bpmp/board.mk b/config/board/nintendo/nx_bpmp/board.mk new file mode 100644 index 00000000..e267e24d --- /dev/null +++ b/config/board/nintendo/nx_bpmp/board.mk @@ -0,0 +1,5 @@ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__BPMP__ +export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += \ No newline at end of file diff --git a/config/common.mk b/config/common.mk index 4d68b232..e3a12dd7 100644 --- a/config/common.mk +++ b/config/common.mk @@ -8,12 +8,13 @@ export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/.. ifeq ($(strip $(ATMOSPHERE_BOARD)),) export ATMOSPHERE_BOARD := nx-hac-001 -endif ifeq ($(strip $(ATMOSPHERE_CPU)),) export ATMOSPHERE_CPU := arm-cortex-a57 endif +endif + export ATMOSPHERE_DEFINES := -DATMOSPHERE export ATMOSPHERE_SETTINGS := -fPIE -g export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \ @@ -23,6 +24,8 @@ export ATMOSPHERE_ASFLAGS := ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) + +ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) export ATMOSPHERE_ARCH_DIR := arch/arm64 export ATMOSPHERE_BOARD_DIR := board/nintendo/nx export ATMOSPHERE_OS_DIR := os/horizon @@ -30,6 +33,16 @@ export ATMOSPHERE_OS_DIR := os/horizon export ATMOSPHERE_ARCH_NAME := arm64 export ATMOSPHERE_BOARD_NAME := nintendo_nx export ATMOSPHERE_OS_NAME := horizon +else ifeq ($(ATMOSPHERE_CPU),arm7tdmi) +export ATMOSPHERE_ARCH_DIR := arch/arm +export ATMOSPHERE_BOARD_DIR := board/nintendo/nx_bpmp +export ATMOSPHERE_OS_DIR := os/horizon + +export ATMOSPHERE_ARCH_NAME := arm +export ATMOSPHERE_BOARD_NAME := nintendo_nx +export ATMOSPHERE_OS_NAME := horizon +endif + endif ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) @@ -37,12 +50,20 @@ export ATMOSPHERE_CPU_DIR := arch/arm64/cpu/cortex_a57 export ATMOSPHERE_CPU_NAME := arm_cortex_a57 endif +ifeq ($(ATMOSPHERE_CPU),arm7tdmi) +export ATMOSPHERE_CPU_DIR := arch/arm/cpu/arm7tdmi +export ATMOSPHERE_CPU_NAME := arm7tdmi +endif + export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR) export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR) export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR) export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_CPU_DIR) +export ATMOSPHERE_LIBRARY_DIR := lib_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME) +export ATMOSPHERE_BUILD_DIR := build_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME) + include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk diff --git a/config/templates/exosphere.mk b/config/templates/exosphere.mk new file mode 100644 index 00000000..16362665 --- /dev/null +++ b/config/templates/exosphere.mk @@ -0,0 +1,46 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE +SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions +CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) +else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm) +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE +SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions +CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) +endif + +export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now + +export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ + -Wl,--wrap,__cxa_throw \ + -Wl,--wrap,__cxa_rethrow \ + -Wl,--wrap,__cxa_allocate_exception \ + -Wl,--wrap,__cxa_free_exception \ + -Wl,--wrap,__cxa_begin_catch \ + -Wl,--wrap,__cxa_end_catch \ + -Wl,--wrap,__cxa_call_unexpected \ + -Wl,--wrap,__cxa_call_terminate \ + -Wl,--wrap,__gxx_personality_v0 \ + -Wl,--wrap,_Unwind_Resume \ + -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ + -Wl,--wrap,_ZSt20__throw_length_errorPKc \ + -Wl,--wrap,_ZNSt11logic_errorC2EPKc + +export LIBS := -lexosphere + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere diff --git a/libexosphere/Makefile b/libexosphere/Makefile new file mode 100644 index 00000000..97b463c6 --- /dev/null +++ b/libexosphere/Makefile @@ -0,0 +1,19 @@ +.PHONY: all arm64 arm clean arm64-clean arm-clean + +all: arm64 arm + +arm64: + $(MAKE) -f arm64.mk + +arm: + $(MAKE) -f arm.mk + +#--------------------------------------------------------------------------------- + +clean: arm64-clean arm-clean + +arm64-clean: + $(MAKE) -f arm64.mk clean + +arm-clean: + $(MAKE) -f arm.mk clean diff --git a/libexosphere/arm.mk b/libexosphere/arm.mk new file mode 100644 index 00000000..7a653f53 --- /dev/null +++ b/libexosphere/arm.mk @@ -0,0 +1,142 @@ +#--------------------------------------------------------------------------------- +# Define the atmosphere board and cpu +#--------------------------------------------------------------------------------- +export ATMOSPHERE_BOARD := nx-hac-001 +export ATMOSPHERE_CPU := arm7tdmi + +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE +SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions +CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) + +SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) + +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \ + $(notdir $(wildcard $(dir)/*.c)))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c))) + +CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \ + $(notdir $(wildcard $(dir)/*.cpp)))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp))) + +SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \ + $(notdir $(wildcard $(dir)/*.s)))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr))) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +.PHONY: clean all + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a + +$(ATMOSPHERE_LIBRARY_DIR): + @[ -d $@ ] || mkdir -p $@ + +$(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a : $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) + @$(MAKE) BUILD=$(ATMOSPHERE_BUILD_DIR) OUTPUT=$(CURDIR)/$@ \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(CURDIR)/arm.mk + +dist-bin: all + @tar --exclude=*~ -cjf $(TARGET).tar.bz2 include $(ATMOSPHERE_LIBRARY_DIR) + +dist-src: + @tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source arm.mk + +dist: dist-src dist-bin + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2 + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +$(OFILES) : $(GCH_FILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +libc.o: CFLAGS += -fno-builtin + +#--------------------------------------------------------------------------------- +%_bin.h %.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- + diff --git a/libexosphere/arm64.mk b/libexosphere/arm64.mk new file mode 100644 index 00000000..c9a17e60 --- /dev/null +++ b/libexosphere/arm64.mk @@ -0,0 +1,143 @@ +#--------------------------------------------------------------------------------- +# Define the atmosphere board and cpu +#--------------------------------------------------------------------------------- +export ATMOSPHERE_BOARD := nx-hac-001 +export ATMOSPHERE_CPU := arm-cortex-a57 + +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE +SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions +CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) + +SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) + +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \ + $(notdir $(wildcard $(dir)/*.c)))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c))) + +CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \ + $(notdir $(wildcard $(dir)/*.cpp)))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp))) + +SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \ + $(notdir $(wildcard $(dir)/*.s)))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr))) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +.PHONY: clean all + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a + +$(ATMOSPHERE_LIBRARY_DIR): + @[ -d $@ ] || mkdir -p $@ + +$(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a : $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) + @$(MAKE) BUILD=$(ATMOSPHERE_BUILD_DIR) OUTPUT=$(CURDIR)/$@ \ + BUILD_CFLAGS="-DNDEBUG=1 -O2" \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(CURDIR)/arm64.mk + +dist-bin: all + @tar --exclude=*~ -cjf $(TARGET).tar.bz2 include $(ATMOSPHERE_LIBRARY_DIR) + +dist-src: + @tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source arm64.mk + +dist: dist-src dist-bin + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2 + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +$(OFILES) : $(GCH_FILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +libc.o: CFLAGS += -fno-builtin + +#--------------------------------------------------------------------------------- +%_bin.h %.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- + diff --git a/libexosphere/include/exosphere.hpp b/libexosphere/include/exosphere.hpp new file mode 100644 index 00000000..db9b2cb2 --- /dev/null +++ b/libexosphere/include/exosphere.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/libexosphere/include/exosphere/actmon.hpp b/libexosphere/include/exosphere/actmon.hpp new file mode 100644 index 00000000..929b3284 --- /dev/null +++ b/libexosphere/include/exosphere/actmon.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::actmon { + + using InterruptHandler = void(*)(); + + void SetRegisterAddress(uintptr_t address); + + void HandleInterrupt(); + + void StartMonitoringBpmp(InterruptHandler handler); + void StopMonitoringBpmp(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/clkrst.hpp b/libexosphere/include/exosphere/clkrst.hpp new file mode 100644 index 00000000..c26dfb11 --- /dev/null +++ b/libexosphere/include/exosphere/clkrst.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::clkrst { + + void SetRegisterAddress(uintptr_t address); + + void SetFuseVisibility(bool visible); + + void EnableUartAClock(); + void EnableUartBClock(); + void EnableUartCClock(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/common.hpp b/libexosphere/include/exosphere/common.hpp new file mode 100644 index 00000000..c0f4e4b7 --- /dev/null +++ b/libexosphere/include/exosphere/common.hpp @@ -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 . + */ +#pragma once +#include + +#if 1 || defined(AMS_BUILD_FOR_AUDITING) +#define EXOSPHERE_BUILD_FOR_AUDITING +#endif + +#if defined(EXOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) +#define EXOSPHERE_BUILD_FOR_DEBUGGING +#endif + +#ifdef EXOSPHERE_BUILD_FOR_DEBUGGING +#define EXOSPHERE_ENABLE_ASSERTIONS +#define EXOSPHERE_ENABLE_DEBUG_PRINT +#endif diff --git a/libexosphere/include/exosphere/fuse.hpp b/libexosphere/include/exosphere/fuse.hpp new file mode 100644 index 00000000..3df44b8a --- /dev/null +++ b/libexosphere/include/exosphere/fuse.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::fuse { + + enum HardwareType { + HardwareType_Icosa = 0, + HardwareType_Copper = 1, + HardwareType_Hoag = 2, + HardwareType_Iowa = 3, + HardwareType_Calcio = 4, + HardwareType_Five = 5, + + HardwareType_Undefined = 0xF, + }; + + enum HardwareState { + HardwareState_Development = 0, + HardwareState_Production = 1, + HardwareState_Undefined = 2, + }; + + void SetRegisterAddress(uintptr_t address); + void SetWriteSecureOnly(); + void Lockout(); + + u32 GetOdmWord(int index); + + HardwareType GetHardwareType(); + HardwareState GetHardwareState(); + pmic::Regulator GetRegulator(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/gic.hpp b/libexosphere/include/exosphere/gic.hpp new file mode 100644 index 00000000..72e30432 --- /dev/null +++ b/libexosphere/include/exosphere/gic.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::gic { + + enum InterruptMode { + InterruptMode_Level = 0, + InterruptMode_Edge = 1, + }; + + constexpr inline s32 HighestPriority = 0; + constexpr inline s32 InterruptCount = 224; + + void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address); + void InitializeCommon(); + void InitializeCoreUnique(); + + void SetPriority(int interrupt_id, int priority); + void SetInterruptGroup(int interrupt_id, int group); + void SetEnable(int interrupt_id, bool enable); + void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask); + void SetSpiMode(int interrupt_id, InterruptMode mode); + + int GetInterruptRequestId(); + void SetEndOfInterrupt(int interrupt_id); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/hw.hpp b/libexosphere/include/exosphere/hw.hpp new file mode 100644 index 00000000..73c68b05 --- /dev/null +++ b/libexosphere/include/exosphere/hw.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#if defined(ATMOSPHERE_ARCH_ARM64) + #include + namespace ams::hw { using namespace ams::hw::arch::arm64; } +#elif defined(ATMOSPHERE_ARCH_ARM) + #include + namespace ams::hw { using namespace ams::hw::arch::arm; } +#else + #error "Unknown architecture for hw!" +#endif \ No newline at end of file diff --git a/libexosphere/include/exosphere/hw/hw_arm.hpp b/libexosphere/include/exosphere/hw/hw_arm.hpp new file mode 100644 index 00000000..344e3072 --- /dev/null +++ b/libexosphere/include/exosphere/hw/hw_arm.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::hw::arch::arm { + +#ifdef __BPMP__ + constexpr inline size_t DataCacheLineSize = 0x1; + + ALWAYS_INLINE void DataSynchronizationBarrier() { + /* ... */ + } + + ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() { + /* ... */ + } + + ALWAYS_INLINE void DataMemoryBarrier() { + /* ... */ + } + + ALWAYS_INLINE void InstructionSynchronizationBarrier() { + /* ... */ + } + + ALWAYS_INLINE void FlushDataCache(const void *ptr, size_t size) { + AMS_UNUSED(ptr); + AMS_UNUSED(size); + /* ... */ + } +#else + #error "Unknown ARM board for ams::hw" +#endif + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/hw/hw_arm64.hpp b/libexosphere/include/exosphere/hw/hw_arm64.hpp new file mode 100644 index 00000000..404a3c5b --- /dev/null +++ b/libexosphere/include/exosphere/hw/hw_arm64.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include + +namespace ams::hw::arch::arm64 { + + ALWAYS_INLINE void DataSynchronizationBarrier() { + __asm__ __volatile__("dsb sy" ::: "memory"); + } + + ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() { + __asm__ __volatile__("dsb ish" ::: "memory"); + } + + ALWAYS_INLINE void DataMemoryBarrier() { + __asm__ __volatile__("dmb sy" ::: "memory"); + } + + ALWAYS_INLINE void InstructionSynchronizationBarrier() { + __asm__ __volatile__("isb" ::: "memory"); + } + + ALWAYS_INLINE void WaitForInterrupt() { + __asm__ __volatile__("wfi" ::: "memory"); + } + + ALWAYS_INLINE void WaitForEvent() { + __asm__ __volatile__("wfe" ::: "memory"); + } + + ALWAYS_INLINE void SendEvent() { + __asm__ __volatile__("sev" ::: "memory"); + } + + ALWAYS_INLINE int CountLeadingZeros(u64 v) { + u64 z; + __asm__ __volatile__("clz %[z], %[v]" : [z]"=r"(z) : [v]"r"(v)); + return z; + } + + ALWAYS_INLINE int CountLeadingZeros(u32 v) { + u32 z; + __asm__ __volatile__("clz %w[z], %w[v]" : [z]"=r"(z) : [v]"r"(v)); + return z; + } + + ALWAYS_INLINE int GetCurrentCoreId() { + u64 mpidr; + HW_CPU_GET_MPIDR_EL1(mpidr); + return mpidr & 0xFF; + } + +} diff --git a/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp b/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp new file mode 100644 index 00000000..ac534fe1 --- /dev/null +++ b/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::hw::arch::arm64 { + +#if defined(ATMOSPHERE_CPU_ARM_CORTEX_A57) || defined(ATMOSPHERE_CPU_ARM_CORTEX_A53) + constexpr inline size_t InstructionCacheLineSize = 0x40; + constexpr inline size_t DataCacheLineSize = 0x40; + constexpr inline size_t NumPerformanceCounters = 6; +#else + #error "Unknown CPU for cache line sizes" +#endif + + ALWAYS_INLINE void InvalidateEntireTlb() { + __asm__ __volatile__("tlbi alle3is" ::: "memory"); + } + + ALWAYS_INLINE void InvalidateDataCacheLine(void *ptr) { + __asm __volatile__("dc ivac, %[ptr]" :: [ptr]"r"(ptr) : "memory"); + } + + ALWAYS_INLINE void FlushDataCacheLine(void *ptr) { + __asm __volatile__("dc civac, %[ptr]" :: [ptr]"r"(ptr) : "memory"); + } + + ALWAYS_INLINE void InvalidateEntireInstructionCache() { + __asm__ __volatile__("ic iallu" ::: "memory"); + } + + ALWAYS_INLINE void InvalidateTlb(uintptr_t address) { + __asm__ __volatile__("tlbi vae3is, %[address]" :: [address]"r"(address) : "memory"); + } + + ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) { + __asm__ __volatile__("tlbi vale3is, %[address]" :: [address]"r"(address) : "memory"); + } + + void FlushDataCache(const void *ptr, size_t size); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp b/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp new file mode 100644 index 00000000..637f3c02 --- /dev/null +++ b/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp @@ -0,0 +1,245 @@ +/* + * 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::hw::arch::arm64 { + + #define HW_CPU_GET_SYSREG(name, value) __asm__ __volatile__("mrs %0, " #name "" : "=&r"(value) :: "memory"); + + #define HW_CPU_SET_SYSREG(name, value) __asm__ __volatile__("msr " #name ", %0" :: "r"(value) : "memory", "cc") + + #define HW_CPU_GET_SCTLR_EL3(value) HW_CPU_GET_SYSREG(sctlr_el3, value) + #define HW_CPU_SET_SCTLR_EL3(value) HW_CPU_SET_SYSREG(sctlr_el3, value) + + #define HW_CPU_GET_SCR_EL3(value) HW_CPU_GET_SYSREG(scr_el3, value) + #define HW_CPU_SET_SCR_EL3(value) HW_CPU_SET_SYSREG(scr_el3, value) + + #define HW_CPU_GET_CPTR_EL3(value) HW_CPU_GET_SYSREG(cptr_el3, value) + #define HW_CPU_SET_CPTR_EL3(value) HW_CPU_SET_SYSREG(cptr_el3, value) + + #define HW_CPU_GET_TTBR0_EL3(value) HW_CPU_GET_SYSREG(ttbr0_el3, value) + #define HW_CPU_SET_TTBR0_EL3(value) HW_CPU_SET_SYSREG(ttbr0_el3, value) + + #define HW_CPU_GET_TCR_EL3(value) HW_CPU_GET_SYSREG(tcr_el3, value) + #define HW_CPU_SET_TCR_EL3(value) HW_CPU_SET_SYSREG(tcr_el3, value) + + #define HW_CPU_GET_MAIR_EL3(value) HW_CPU_GET_SYSREG(mair_el3, value) + #define HW_CPU_SET_MAIR_EL3(value) HW_CPU_SET_SYSREG(mair_el3, value) + + #define HW_CPU_GET_VBAR_EL3(value) HW_CPU_GET_SYSREG(vbar_el3, value) + #define HW_CPU_SET_VBAR_EL3(value) HW_CPU_SET_SYSREG(vbar_el3, value) + + #define HW_CPU_GET_CLIDR_EL1(value) HW_CPU_GET_SYSREG(clidr_el1, value) + #define HW_CPU_SET_CLIDR_EL1(value) HW_CPU_SET_SYSREG(clidr_el1, value) + + #define HW_CPU_GET_CCSIDR_EL1(value) HW_CPU_GET_SYSREG(ccsidr_el1, value) + #define HW_CPU_SET_CCSIDR_EL1(value) HW_CPU_SET_SYSREG(ccsidr_el1, value) + + #define HW_CPU_GET_CSSELR_EL1(value) HW_CPU_GET_SYSREG(csselr_el1, value) + #define HW_CPU_SET_CSSELR_EL1(value) HW_CPU_SET_SYSREG(csselr_el1, value) + + #define HW_CPU_GET_CPUACTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_0, value) + #define HW_CPU_SET_CPUACTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_0, value) + + #define HW_CPU_GET_CPUECTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_1, value) + #define HW_CPU_SET_CPUECTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_1, value) + + #define HW_CPU_GET_DBGAUTHSTATUS_EL1(value) HW_CPU_GET_SYSREG(dbgauthstatus_el1, value) + #define HW_CPU_SET_DBGAUTHSTATUS_EL1(value) HW_CPU_SET_SYSREG(dbgauthstatus_el1, value) + + #define HW_CPU_GET_MPIDR_EL1(value) HW_CPU_GET_SYSREG(mpidr_el1, value) + + #define HW_CPU_GET_OSLAR_EL1(value) HW_CPU_GET_SYSREG(oslar_el1, value) + #define HW_CPU_SET_OSLAR_EL1(value) HW_CPU_SET_SYSREG(oslar_el1, value) + + #define HW_CPU_GET_OSDTRRX_EL1(value) HW_CPU_GET_SYSREG(osdtrrx_el1, value) + #define HW_CPU_SET_OSDTRRX_EL1(value) HW_CPU_SET_SYSREG(osdtrrx_el1, value) + + #define HW_CPU_GET_OSDTRTX_EL1(value) HW_CPU_GET_SYSREG(osdtrtx_el1, value) + #define HW_CPU_SET_OSDTRTX_EL1(value) HW_CPU_SET_SYSREG(osdtrtx_el1, value) + + #define HW_CPU_GET_MDSCR_EL1(value) HW_CPU_GET_SYSREG(mdscr_el1, value) + #define HW_CPU_SET_MDSCR_EL1(value) HW_CPU_SET_SYSREG(mdscr_el1, value) + + #define HW_CPU_GET_OSECCR_EL1(value) HW_CPU_GET_SYSREG(oseccr_el1, value) + #define HW_CPU_SET_OSECCR_EL1(value) HW_CPU_SET_SYSREG(oseccr_el1, value) + + #define HW_CPU_GET_MDCCINT_EL1(value) HW_CPU_GET_SYSREG(mdccint_el1, value) + #define HW_CPU_SET_MDCCINT_EL1(value) HW_CPU_SET_SYSREG(mdccint_el1, value) + + #define HW_CPU_GET_DBGCLAIMCLR_EL1(value) HW_CPU_GET_SYSREG(dbgclaimclr_el1, value) + #define HW_CPU_SET_DBGCLAIMCLR_EL1(value) HW_CPU_SET_SYSREG(dbgclaimclr_el1, value) + + #define HW_CPU_GET_DBGVCR32_EL2(value) HW_CPU_GET_SYSREG(dbgvcr32_el2, value) + #define HW_CPU_SET_DBGVCR32_EL2(value) HW_CPU_SET_SYSREG(dbgvcr32_el2, value) + + #define HW_CPU_GET_SDER32_EL3(value) HW_CPU_GET_SYSREG(sder32_el3, value) + #define HW_CPU_SET_SDER32_EL3(value) HW_CPU_SET_SYSREG(sder32_el3, value) + + #define HW_CPU_GET_MDCR_EL2(value) HW_CPU_GET_SYSREG(mdcr_el2, value) + #define HW_CPU_SET_MDCR_EL2(value) HW_CPU_SET_SYSREG(mdcr_el2, value) + + #define HW_CPU_GET_MDCR_EL3(value) HW_CPU_GET_SYSREG(mdcr_el3, value) + #define HW_CPU_SET_MDCR_EL3(value) HW_CPU_SET_SYSREG(mdcr_el3, value) + + #define HW_CPU_GET_SPSR_EL3(value) HW_CPU_GET_SYSREG(spsr_el3, value) + #define HW_CPU_SET_SPSR_EL3(value) HW_CPU_SET_SYSREG(spsr_el3, value) + + #define HW_CPU_GET_DBGBVR0_EL1(value) HW_CPU_GET_SYSREG(dbgbvr0_el1, value) + #define HW_CPU_SET_DBGBVR0_EL1(value) HW_CPU_SET_SYSREG(dbgbvr0_el1, value) + #define HW_CPU_GET_DBGBCR0_EL1(value) HW_CPU_GET_SYSREG(dbgbcr0_el1, value) + #define HW_CPU_SET_DBGBCR0_EL1(value) HW_CPU_SET_SYSREG(dbgbcr0_el1, value) + #define HW_CPU_GET_DBGBVR1_EL1(value) HW_CPU_GET_SYSREG(dbgbvr1_el1, value) + #define HW_CPU_SET_DBGBVR1_EL1(value) HW_CPU_SET_SYSREG(dbgbvr1_el1, value) + #define HW_CPU_GET_DBGBCR1_EL1(value) HW_CPU_GET_SYSREG(dbgbcr1_el1, value) + #define HW_CPU_SET_DBGBCR1_EL1(value) HW_CPU_SET_SYSREG(dbgbcr1_el1, value) + #define HW_CPU_GET_DBGBVR2_EL1(value) HW_CPU_GET_SYSREG(dbgbvr2_el1, value) + #define HW_CPU_SET_DBGBVR2_EL1(value) HW_CPU_SET_SYSREG(dbgbvr2_el1, value) + #define HW_CPU_GET_DBGBCR2_EL1(value) HW_CPU_GET_SYSREG(dbgbcr2_el1, value) + #define HW_CPU_SET_DBGBCR2_EL1(value) HW_CPU_SET_SYSREG(dbgbcr2_el1, value) + #define HW_CPU_GET_DBGBVR3_EL1(value) HW_CPU_GET_SYSREG(dbgbvr3_el1, value) + #define HW_CPU_SET_DBGBVR3_EL1(value) HW_CPU_SET_SYSREG(dbgbvr3_el1, value) + #define HW_CPU_GET_DBGBCR3_EL1(value) HW_CPU_GET_SYSREG(dbgbcr3_el1, value) + #define HW_CPU_SET_DBGBCR3_EL1(value) HW_CPU_SET_SYSREG(dbgbcr3_el1, value) + #define HW_CPU_GET_DBGBVR4_EL1(value) HW_CPU_GET_SYSREG(dbgbvr4_el1, value) + #define HW_CPU_SET_DBGBVR4_EL1(value) HW_CPU_SET_SYSREG(dbgbvr4_el1, value) + #define HW_CPU_GET_DBGBCR4_EL1(value) HW_CPU_GET_SYSREG(dbgbcr4_el1, value) + #define HW_CPU_SET_DBGBCR4_EL1(value) HW_CPU_SET_SYSREG(dbgbcr4_el1, value) + #define HW_CPU_GET_DBGBVR5_EL1(value) HW_CPU_GET_SYSREG(dbgbvr5_el1, value) + #define HW_CPU_SET_DBGBVR5_EL1(value) HW_CPU_SET_SYSREG(dbgbvr5_el1, value) + #define HW_CPU_GET_DBGBCR5_EL1(value) HW_CPU_GET_SYSREG(dbgbcr5_el1, value) + #define HW_CPU_SET_DBGBCR5_EL1(value) HW_CPU_SET_SYSREG(dbgbcr5_el1, value) + + #define HW_CPU_GET_DBGWVR0_EL1(value) HW_CPU_GET_SYSREG(dbgwvr0_el1, value) + #define HW_CPU_SET_DBGWVR0_EL1(value) HW_CPU_SET_SYSREG(dbgwvr0_el1, value) + #define HW_CPU_GET_DBGWCR0_EL1(value) HW_CPU_GET_SYSREG(dbgwcr0_el1, value) + #define HW_CPU_SET_DBGWCR0_EL1(value) HW_CPU_SET_SYSREG(dbgwcr0_el1, value) + #define HW_CPU_GET_DBGWVR1_EL1(value) HW_CPU_GET_SYSREG(dbgwvr1_el1, value) + #define HW_CPU_SET_DBGWVR1_EL1(value) HW_CPU_SET_SYSREG(dbgwvr1_el1, value) + #define HW_CPU_GET_DBGWCR1_EL1(value) HW_CPU_GET_SYSREG(dbgwcr1_el1, value) + #define HW_CPU_SET_DBGWCR1_EL1(value) HW_CPU_SET_SYSREG(dbgwcr1_el1, value) + #define HW_CPU_GET_DBGWVR2_EL1(value) HW_CPU_GET_SYSREG(dbgwvr2_el1, value) + #define HW_CPU_SET_DBGWVR2_EL1(value) HW_CPU_SET_SYSREG(dbgwvr2_el1, value) + #define HW_CPU_GET_DBGWCR2_EL1(value) HW_CPU_GET_SYSREG(dbgwcr2_el1, value) + #define HW_CPU_SET_DBGWCR2_EL1(value) HW_CPU_SET_SYSREG(dbgwcr2_el1, value) + #define HW_CPU_GET_DBGWVR3_EL1(value) HW_CPU_GET_SYSREG(dbgwvr3_el1, value) + #define HW_CPU_SET_DBGWVR3_EL1(value) HW_CPU_SET_SYSREG(dbgwvr3_el1, value) + #define HW_CPU_GET_DBGWCR3_EL1(value) HW_CPU_GET_SYSREG(dbgwcr3_el1, value) + #define HW_CPU_SET_DBGWCR3_EL1(value) HW_CPU_SET_SYSREG(dbgwcr3_el1, value) + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el3 */ + struct SctlrEl3 { + using M = util::BitPack32::Field< 0, 1>; + using A = util::BitPack32::Field< 1, 1>; + using C = util::BitPack32::Field< 2, 1>; + using Sa = util::BitPack32::Field< 3, 1>; + using I = util::BitPack32::Field<12, 1>; + using Wxn = util::BitPack32::Field<19, 1>; + using Ee = util::BitPack32::Field<25, 1>; + + static constexpr u32 Res1 = 0x30C50830; + }; + + /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABGIHHJ.html */ + struct ScrEl3 { + using Ns = util::BitPack32::Field< 0, 1>; + using Irq = util::BitPack32::Field< 1, 1>; + using Fiq = util::BitPack32::Field< 2, 1>; + using Ea = util::BitPack32::Field< 3, 1>; + using Fw = util::BitPack32::Field< 4, 1>; + using Aw = util::BitPack32::Field< 5, 1>; + using Net = util::BitPack32::Field< 6, 1>; + using Smd = util::BitPack32::Field< 7, 1>; + using Hce = util::BitPack32::Field< 8, 1>; + using Sif = util::BitPack32::Field< 9, 1>; + using RwCortexA53 = util::BitPack32::Field<10, 1>; + using StCortexA53 = util::BitPack32::Field<11, 1>; + using Twi = util::BitPack32::Field<12, 1>; + using Twe = util::BitPack32::Field<13, 1>; + }; + + /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/CIHDEBIG.html */ + struct CptrEl3 { + using Tfp = util::BitPack32::Field<10, 1>; + using Tta = util::BitPack32::Field<20, 1>; + using Tcpac = util::BitPack32::Field<31, 1>; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/translation-control-register-el3 */ + struct TcrEl3 { + using T0sz = util::BitPack32::Field< 0, 6>; + using Irgn0 = util::BitPack32::Field< 8, 2>; + using Orgn0 = util::BitPack32::Field<10, 2>; + using Sh0 = util::BitPack32::Field<12, 2>; + using Tg0 = util::BitPack32::Field<14, 2>; + using Ps = util::BitPack32::Field<16, 3>; + using Tbi = util::BitPack32::Field<20, 1>; + + static constexpr u32 Res1 = 0x80800000; + }; + + struct ClidrEl1 { + using Ctype1 = util::BitPack32::Field< 0, 3>; + using Ctype2 = util::BitPack32::Field< 3, 3>; + using Ctype3 = util::BitPack32::Field< 6, 3>; + using Louis = util::BitPack32::Field<21, 3>; + using Loc = util::BitPack32::Field<24, 3>; + using Louu = util::BitPack32::Field<27, 3>; + }; + + struct CcsidrEl1 { + using LineSize = util::BitPack32::Field< 0, 3>; + using Associativity = util::BitPack32::Field< 3, 10>; + using NumSets = util::BitPack32::Field<13, 15>; + using Wa = util::BitPack32::Field<28, 1>; + using Ra = util::BitPack32::Field<29, 1>; + using Wb = util::BitPack32::Field<30, 1>; + using Wt = util::BitPack32::Field<31, 1>; + }; + + struct CsselrEl1 { + using InD = util::BitPack32::Field<0, 1>; + using Level = util::BitPack32::Field<1, 3>; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-auxiliary-control-register-el1 */ + struct CpuactlrEl1CortexA57 { + /* TODO: Other bits */ + using NonCacheableStreamingEnhancement = util::BitPack64::Field<24, 1>; + /* TODO: Other bits */ + using DisableLoadPassDmb = util::BitPack64::Field<59, 1>; + using ForceProcessorRcgEnablesActive = util::BitPack64::Field<63, 1>; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-extended-control-register-el1 */ + struct CpuectlrEl1CortexA57 { + using ProcessorDynamicRetentionControl = util::BitPack64::Field< 0, 2>; + using Smpen = util::BitPack64::Field< 6, 1>; + using L2LoadStoreDataPrefetchDistance = util::BitPack64::Field<32, 2>; + using L2InstructionFetchPrefetchDistance = util::BitPack64::Field<35, 2>; + using DisableTableWalkDescriptorAccessPrefetch = util::BitPack64::Field<38, 1>; + }; + + /* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/dbgauthstatus_el1 */ + struct DbgAuthStatusEl1 { + using Nsid = util::BitPack32::Field<0, 2>; + using Nsnid = util::BitPack32::Field<2, 2>; + using Sid = util::BitPack32::Field<4, 2>; + using Snid = util::BitPack32::Field<6, 2>; + }; + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/i2c.hpp b/libexosphere/include/exosphere/i2c.hpp new file mode 100644 index 00000000..fd3b10d2 --- /dev/null +++ b/libexosphere/include/exosphere/i2c.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::i2c { + + enum Port { + Port_1 = 0, + /* TODO: Support other ports? */ + Port_5 = 4, + + Port_Count = 5, + }; + + void SetRegisterAddress(Port port, uintptr_t address); + + void Initialize(Port port); + + bool Query(void *dst, size_t dst_size, Port port, int address, int r); + bool Send(Port port, int address, int r, const void *src, size_t src_size); + + inline u8 QueryByte(Port port, int address, int r) { + u8 byte; + Query(std::addressof(byte), sizeof(byte), port, address, r); + return byte; + } + + inline void SendByte(Port port, int address, int r, u8 byte) { + Send(port, address, r, std::addressof(byte), sizeof(byte)); + } + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/log.hpp b/libexosphere/include/exosphere/log.hpp new file mode 100644 index 00000000..2f1cca8c --- /dev/null +++ b/libexosphere/include/exosphere/log.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::log { + + void Initialize(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/mmu.hpp b/libexosphere/include/exosphere/mmu.hpp new file mode 100644 index 00000000..c3b888e1 --- /dev/null +++ b/libexosphere/include/exosphere/mmu.hpp @@ -0,0 +1,18 @@ +/* + * 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 +#include \ No newline at end of file diff --git a/libexosphere/include/exosphere/mmu/mmu_api.arch.arm.hpp b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm.hpp new file mode 100644 index 00000000..bedce5af --- /dev/null +++ b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::mmu::arch::arm { + + /* NOTE: mmu is not supported by libexosphere-on-arm. */ + /* However, we want the memory layout to be parseable, so we will include some arm64 mmu definitions. */ + constexpr inline u64 L1EntryShift = 30; + constexpr inline u64 L2EntryShift = 21; + constexpr inline u64 L3EntryShift = 12; + + constexpr inline u64 L1EntrySize = 1_GB; + constexpr inline u64 L2EntrySize = 2_MB; + constexpr inline u64 L3EntrySize = 4_KB; + + constexpr inline u64 PageSize = L3EntrySize; + + constexpr inline u64 L1EntryMask = ((static_cast(1) << (48 - L1EntryShift)) - 1) << L1EntryShift; + constexpr inline u64 L2EntryMask = ((static_cast(1) << (48 - L2EntryShift)) - 1) << L2EntryShift; + constexpr inline u64 L3EntryMask = ((static_cast(1) << (48 - L3EntryShift)) - 1) << L3EntryShift; + + constexpr inline u64 TableEntryMask = L3EntryMask; + + static_assert(L1EntryMask == 0x0000FFFFC0000000ul); + static_assert(L2EntryMask == 0x0000FFFFFFE00000ul); + static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul); + +} diff --git a/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp new file mode 100644 index 00000000..d18e2b4f --- /dev/null +++ b/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp @@ -0,0 +1,279 @@ +/* + * 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::mmu::arch::arm64 { + + enum PageTableTableAttribute : u64 { + PageTableTableAttribute_None = (0ul << 0), + PageTableTableAttribute_PrivilegedExecuteNever = (1ul << 59), + PageTableTableAttribute_ExecuteNever = (1ul << 60), + PageTableTableAttribute_NonSecure = (1ul << 63), + + PageTableTableAttributes_El3SecureCode = PageTableTableAttribute_None, + PageTableTableAttributes_El3SecureData = PageTableTableAttribute_ExecuteNever, + PageTableTableAttributes_El3NonSecureCode = PageTableTableAttributes_El3SecureCode | PageTableTableAttribute_NonSecure, + PageTableTableAttributes_El3NonSecureData = PageTableTableAttributes_El3SecureData | PageTableTableAttribute_NonSecure, + }; + + enum PageTableMappingAttribute : u64{ + /* Security. */ + PageTableMappingAttribute_NonSecure = (1ul << 5), + + /* El1 Access. */ + PageTableMappingAttribute_El1NotAllowed = (0ul << 6), + PageTableMappingAttribute_El1Allowed = (1ul << 6), + + /* RW Permission. */ + PageTableMappingAttribute_PermissionReadWrite = (0ul << 7), + PageTableMappingAttribute_PermissionReadOnly = (1ul << 7), + + /* Shareability. */ + PageTableMappingAttribute_ShareabilityNonShareable = (0ul << 8), + PageTableMappingAttribute_ShareabiltiyOuterShareable = (2ul << 8), + PageTableMappingAttribute_ShareabilityInnerShareable = (3ul << 8), + + /* Access flag. */ + PageTableMappingAttribute_AccessFlagNotAccessed = (0ul << 10), + PageTableMappingAttribute_AccessFlagAccessed = (1ul << 10), + + /* Global. */ + PageTableMappingAttribute_Global = (0ul << 11), + PageTableMappingAttribute_NonGlobal = (1ul << 11), + + /* Contiguous */ + PageTableMappingAttribute_NonContiguous = (0ul << 52), + PageTableMappingAttribute_Contiguous = (1ul << 52), + + /* Privileged Execute Never */ + PageTableMappingAttribute_PrivilegedExecuteNever = (1ul << 53), + + /* Execute Never */ + PageTableMappingAttribute_ExecuteNever = (1ul << 54), + + + /* Useful definitions. */ + PageTableMappingAttributes_El3SecureRwCode = ( + PageTableMappingAttribute_PermissionReadWrite | + PageTableMappingAttribute_ShareabilityInnerShareable + ), + + PageTableMappingAttributes_El3SecureRoCode = ( + PageTableMappingAttribute_PermissionReadOnly | + PageTableMappingAttribute_ShareabilityInnerShareable + ), + + PageTableMappingAttributes_El3SecureRoData = ( + PageTableMappingAttribute_PermissionReadOnly | + PageTableMappingAttribute_ShareabilityInnerShareable | + PageTableMappingAttribute_ExecuteNever + ), + + PageTableMappingAttributes_El3SecureRwData = ( + PageTableMappingAttribute_PermissionReadWrite | + PageTableMappingAttribute_ShareabilityInnerShareable | + PageTableMappingAttribute_ExecuteNever + ), + + PageTableMappingAttributes_El3NonSecureRwCode = PageTableMappingAttributes_El3SecureRwCode | PageTableMappingAttribute_NonSecure, + PageTableMappingAttributes_El3NonSecureRoCode = PageTableMappingAttributes_El3SecureRoCode | PageTableMappingAttribute_NonSecure, + PageTableMappingAttributes_El3NonSecureRoData = PageTableMappingAttributes_El3SecureRoData | PageTableMappingAttribute_NonSecure, + PageTableMappingAttributes_El3NonSecureRwData = PageTableMappingAttributes_El3SecureRwData | PageTableMappingAttribute_NonSecure, + + + PageTableMappingAttributes_El3SecureDevice = PageTableMappingAttributes_El3SecureRwData, + PageTableMappingAttributes_El3NonSecureDevice = PageTableMappingAttributes_El3NonSecureRwData, + }; + + enum MemoryRegionAttribute : u64 { + MemoryRegionAttribute_Device_nGnRnE = (0ul << 2), + MemoryRegionAttribute_Device_nGnRE = (1ul << 2), + MemoryRegionAttribute_NormalMemory = (2ul << 2), + MemoryRegionAttribute_NormalMemoryNotCacheable = (3ul << 2), + + MemoryRegionAttribute_NormalInnerShift = 0, + MemoryRegionAttribute_NormalOuterShift = 4, + + #define AMS_MRA_DEFINE_NORMAL_ATTR(__NAME__, __VAL__) \ + MemoryRegionAttribute_NormalInner##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalInnerShift), \ + MemoryRegionAttribute_NormalOuter##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalOuterShift) + + AMS_MRA_DEFINE_NORMAL_ATTR(NonCacheable, 4), + + AMS_MRA_DEFINE_NORMAL_ATTR(WriteAllocate, (1ul << 0)), + AMS_MRA_DEFINE_NORMAL_ATTR(ReadAllocate, (1ul << 1)), + + AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughTransient, (0ul << 2)), + AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackTransient, (1ul << 2)), + AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughNonTransient, (2ul << 2)), + AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackNonTransient, (3ul << 2)), + + #undef AMS_MRA_DEFINE_NORMAL_ATTR + + MemoryRegionAttributes_Normal = ( + MemoryRegionAttribute_NormalInnerReadAllocate | + MemoryRegionAttribute_NormalOuterReadAllocate | + MemoryRegionAttribute_NormalInnerWriteAllocate | + MemoryRegionAttribute_NormalOuterWriteAllocate | + MemoryRegionAttribute_NormalInnerWriteBackNonTransient | + MemoryRegionAttribute_NormalOuterWriteBackNonTransient + ), + + MemoryRegionAttributes_Device = ( + MemoryRegionAttribute_Device_nGnRE + ), + }; + + constexpr inline u64 MemoryRegionAttributeWidth = 8; + + constexpr PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) { + return static_cast(attr | (static_cast::type>(index) << 2)); + } + + constexpr inline u64 L1EntryShift = 30; + constexpr inline u64 L2EntryShift = 21; + constexpr inline u64 L3EntryShift = 12; + + constexpr inline u64 L1EntrySize = 1_GB; + constexpr inline u64 L2EntrySize = 2_MB; + constexpr inline u64 L3EntrySize = 4_KB; + + constexpr inline u64 PageSize = L3EntrySize; + + constexpr inline u64 L1EntryMask = ((1ul << (48 - L1EntryShift)) - 1) << L1EntryShift; + constexpr inline u64 L2EntryMask = ((1ul << (48 - L2EntryShift)) - 1) << L2EntryShift; + constexpr inline u64 L3EntryMask = ((1ul << (48 - L3EntryShift)) - 1) << L3EntryShift; + + constexpr inline u64 TableEntryMask = L3EntryMask; + + static_assert(L1EntryMask == 0x0000FFFFC0000000ul); + static_assert(L2EntryMask == 0x0000FFFFFFE00000ul); + static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul); + + constexpr inline u64 TableEntryIndexMask = 0x1FF; + + constexpr inline u64 EntryBlock = 0x1ul; + constexpr inline u64 EntryPage = 0x3ul; + + constexpr u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) { + return address | static_cast(attr) | 0x3ul; + } + + constexpr u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) { + return address | static_cast(attr) | 0x1ul; + } + + constexpr u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) { + return address | static_cast(attr) | 0x1ul; + } + + constexpr u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) { + return address | static_cast(attr) | 0x3ul; + } + + constexpr uintptr_t GetL2Offset(uintptr_t address) { + return address & ((1ul << L2EntryShift) - 1); + } + + constexpr u64 GetL1EntryIndex(uintptr_t address) { + return ((address >> L1EntryShift) & TableEntryIndexMask); + } + + constexpr u64 GetL2EntryIndex(uintptr_t address) { + return ((address >> L2EntryShift) & TableEntryIndexMask); + } + + constexpr u64 GetL3EntryIndex(uintptr_t address) { + return ((address >> L3EntryShift) & TableEntryIndexMask); + } + + constexpr ALWAYS_INLINE void SetTableImpl(u64 *table, u64 index, u64 value) { + /* Ensure (for constexpr validation purposes) that the entry we set is clear. */ + if (table[index]) { + __builtin_unreachable(); + } + + /* Set the value. */ + table[index] = value; + } + + constexpr void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { + SetTableImpl(table, GetL1EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); + } + + constexpr void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { + SetTableImpl(table, GetL2EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); + } + + constexpr void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + const u64 start = GetL1EntryIndex(virt_addr); + const u64 count = (size >> L1EntryShift); + + for (u64 i = 0; i < count; ++i) { + SetTableImpl(table, start + i, MakeL1BlockEntry((phys_addr & L1EntryMask) + (i << L1EntryShift), attr)); + } + } + + constexpr void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + const u64 start = GetL2EntryIndex(virt_addr); + const u64 count = (size >> L2EntryShift); + + for (u64 i = 0; i < count; ++i) { + SetTableImpl(table, start + i, MakeL2BlockEntry((phys_addr & L2EntryMask) + (i << L2EntryShift), attr)); + } + } + + constexpr void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { + const u64 start = GetL3EntryIndex(virt_addr); + const u64 count = (size >> L3EntryShift); + + for (u64 i = 0; i < count; ++i) { + SetTableImpl(table, start + i, MakeL3BlockEntry((phys_addr & L3EntryMask) + (i << L3EntryShift), attr)); + } + } + + constexpr void InvalidateL1Entries(u64 *table, uintptr_t virt_addr, size_t size) { + const u64 start = GetL1EntryIndex(virt_addr); + const u64 count = (size >> L1EntryShift); + const u64 end = start + count; + + for (u64 i = start; i < end; ++i) { + table[i] = 0; + } + } + + constexpr void InvalidateL2Entries(u64 *table, uintptr_t virt_addr, size_t size) { + const u64 start = GetL2EntryIndex(virt_addr); + const u64 count = (size >> L2EntryShift); + const u64 end = start + count; + + for (u64 i = start; i < end; ++i) { + table[i] = 0; + } + } + + constexpr void InvalidateL3Entries(u64 *table, uintptr_t virt_addr, size_t size) { + const u64 start = GetL3EntryIndex(virt_addr); + const u64 count = (size >> L3EntryShift); + const u64 end = start + count; + + for (u64 i = start; i < end; ++i) { + table[i] = 0; + } + } + +} diff --git a/libexosphere/include/exosphere/mmu/mmu_api.hpp b/libexosphere/include/exosphere/mmu/mmu_api.hpp new file mode 100644 index 00000000..1c0e0280 --- /dev/null +++ b/libexosphere/include/exosphere/mmu/mmu_api.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#if defined(ATMOSPHERE_ARCH_ARM64) + #include +#elif defined(ATMOSPHERE_ARCH_ARM) + #include +#else + #error "Unknown architecture for mmu!" +#endif + +namespace ams::mmu { + + #if defined(ATMOSPHERE_ARCH_ARM64) + using namespace ams::mmu::arch::arm64; + #elif defined(ATMOSPHERE_ARCH_ARM) + using namespace ams::mmu::arch::arm; + #else + #error "Unknown architecture for mmu!" + #endif + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/pkg1.hpp b/libexosphere/include/exosphere/pkg1.hpp new file mode 100644 index 00000000..d7dbad6a --- /dev/null +++ b/libexosphere/include/exosphere/pkg1.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include +#include +#include diff --git a/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp b/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp new file mode 100644 index 00000000..da73f011 --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp @@ -0,0 +1,133 @@ +/* + * 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::pkg1 { + + enum MemorySize { + MemorySize_4GB = 0, + MemorySize_6GB = 1, + MemorySize_8GB = 2, + }; + + enum MemoryArrange { + MemoryArrange_Normal = 1, + MemoryArrange_AppletDev = 2, + MemoryArrange_SystemDev = 2, + }; + + enum MemoryMode { + MemoryMode_SizeShift = 4, + MemoryMode_SizeMask = 0x30, + + MemoryMode_ArrangeMask = 0x0F, + + MemoryMode_Auto = 0x00, + + MemoryMode_4GB = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), + MemoryMode_4GBAppletDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)), + MemoryMode_4GBSystemDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_SystemDev)), + + MemoryMode_6GB = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), + MemoryMode_6GBAppletDev = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)), + + MemoryMode_8GB = ((MemorySize_8GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), + }; + + constexpr ALWAYS_INLINE MemorySize GetMemorySize(MemoryMode mode) { + return static_cast(mode >> MemoryMode_SizeShift); + } + + constexpr ALWAYS_INLINE MemoryArrange GetMemoryArrange(MemoryMode mode) { + return static_cast(mode & MemoryMode_ArrangeMask); + } + + constexpr ALWAYS_INLINE MemoryMode MakeMemoryMode(MemorySize size, MemoryArrange arrange) { + return static_cast((size << MemoryMode_SizeShift) | (arrange)); + } + + struct BootConfigData { + u32 version; + u32 reserved_04; + u32 reserved_08; + u32 reserved_0C; + u8 flags1[0x10]; + u8 flags0[0x10]; + u64 initial_tsc_value; + u8 padding_38[0x200 - 0x38]; + + constexpr bool IsDevelopmentFunctionEnabled() const { + return (this->flags1[0] & (1 << 1)) != 0; + } + + constexpr bool IsSErrorDebugEnabled() const { + return (this->flags1[0] & (1 << 2)) != 0; + } + + constexpr u8 GetKernelFlags0() const { + return this->flags0[1]; + } + + constexpr u8 GetKernelFlags1() const { + return this->flags1[0]; + } + + constexpr MemoryMode GetMemoryMode() const { + return static_cast(this->flags0[3]); + } + + bool IsTscInitialValueValid() const { + return (this->flags0[4] & (1 << 0)) != 0; + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(BootConfigData) == 0x200); + + struct BootConfigSignedData { + u32 version; + u32 reserved_04; + u8 flags; + u8 reserved_09[0x10 - 9]; + u8 ecid[0x10]; + u8 flags1[0x10]; + u8 flags0[0x10]; + u8 padding_40[0x100 - 0x40]; + + constexpr bool IsPackage2EncryptionDisabled() const { + return (this->flags & (1 << 0)) != 0; + } + + constexpr bool IsPackage2SignatureVerificationDisabled() const { + return (this->flags & (1 << 1)) != 0; + } + + constexpr bool IsProgramVerificationDisabled() const { + return (this->flags1[0] & (1 << 0)) != 0; + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(BootConfigSignedData) == 0x100); + + struct BootConfig { + BootConfigData data; + u8 signature[0x100]; + BootConfigSignedData signed_data; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(BootConfig) == 0x400); + +} diff --git a/libexosphere/include/exosphere/pkg1/pkg1_bootloader_parameters.hpp b/libexosphere/include/exosphere/pkg1/pkg1_bootloader_parameters.hpp new file mode 100644 index 00000000..93f70df1 --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_bootloader_parameters.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 + +namespace ams::pkg1 { + + enum BootloaderState { + BootloaderState_Start = 0, + BootloaderState_LoadedBootConfig = 1, + BootloaderState_InitializedDram = 2, + BootloaderState_LoadedPackage2 = 3, + BootloaderState_Done = 4, + }; + + enum SecureMonitorState { + SecureMonitorState_Start = 0, + SecureMonitorState_Initialized = 1, + }; + + struct BctParameters { + u32 bootloader_version; + u32 bootloader_start_block; + u32 bootloader_start_page; + u32 bootloader_attributes; + }; + static_assert(util::is_pod::value && sizeof(BctParameters) == 0x10); + + struct SecureMonitorParameters { + u32 bootloader_start_time; + u32 bootloader_end_time; + u32 secmon_start_time; + u32 secmon_end_time; + BctParameters bct_params; + u8 reserved[0xD8]; + u32 bootloader_state; + u32 secmon_state; + u8 reserved2[0x100]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(SecureMonitorParameters) == 0x200); + + static_assert(offsetof(SecureMonitorParameters, bct_params) == 0x10); + static_assert(offsetof(SecureMonitorParameters, bootloader_state) == 0xF8); + static_assert(offsetof(SecureMonitorParameters, secmon_state) == 0xFC); + + enum BootloaderAttribute { + BootloaderAttribute_None = (0u << 0), + BootloaderAttribute_RecoveryBoot = (1u << 0), + + BootloaderAttribute_RestrictedSmcShift = 1, + BootloaderAttribute_RestrictedSmcMask = (0xFu << BootloaderAttribute_RestrictedSmcShift), + }; + +} diff --git a/libexosphere/include/exosphere/pkg1/pkg1_error_types.hpp b/libexosphere/include/exosphere/pkg1/pkg1_error_types.hpp new file mode 100644 index 00000000..76331434 --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_error_types.hpp @@ -0,0 +1,108 @@ +/* + * 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::pkg1 { + + enum ErrorReason { + ErrorReason_None = 0, + ErrorReason_InvalidPackage2Signature = 1, + ErrorReason_InvalidPackage2Meta = 2, + ErrorReason_InvalidPackage2Version = 3, + ErrorReason_InvalidPackage2Payload = 4, + ErrorReason_UnknownSmc = 5, + ErrorReason_UnknownAbort = 6, + ErrorReason_InvalidCoreContext = 7, + ErrorReason_InvalidSecurityEngineStickyBits = 8, + ErrorReason_UnexpectedReset = 9, + + ErrorReason_Exception = 0x10, + + ErrorReason_TransitionToSafeMode = 0x20, + ErrorReason_SecureInitializerReboot = 0x21, + + ErrorReason_SdmmcError = 0x30, + ErrorReason_InvalidDramId = 0x31, + ErrorReason_InvalidPackage2 = 0x32, + ErrorReason_InvalidBct = 0x33, + ErrorReason_InvalidGpt = 0x34, + ErrorReason_FailedToTransitionToSafeMode = 0x35, + ErrorReason_ActivityMonitorInterrupt = 0x36, + + ErrorReason_KernelPanic = 0x40, + }; + + enum ErrorColor { + ErrorColor_Black = 0x000, + + ErrorColor_Red = 0x00F, + ErrorColor_Yellow = 0x0FF, + ErrorColor_Orange = 0x07F, + ErrorColor_Blue = 0xF00, + ErrorColor_LightBlue = 0xFF0, + ErrorColor_Pink = 0xF7F, + ErrorColor_Purple = 0xF0A, + }; + + enum ErrorInfo { + ErrorInfo_ReasonMask = 0xFF, + ErrorInfo_ColorShift = 20, + + #define MAKE_ERROR_INFO(_COLOR_, _DESC_) ((static_cast(ErrorColor_##_COLOR_) << ErrorInfo_ColorShift) | (ErrorReason_##_DESC_)) + + ErrorInfo_None = MAKE_ERROR_INFO(Black, None), + + ErrorInfo_InvalidPackage2Signature = MAKE_ERROR_INFO(Blue, InvalidPackage2Signature), + ErrorInfo_InvalidPackage2Meta = MAKE_ERROR_INFO(Blue, InvalidPackage2Meta), + ErrorInfo_InvalidPackage2Version = MAKE_ERROR_INFO(Blue, InvalidPackage2Version), + ErrorInfo_InvalidPackage2Payload = MAKE_ERROR_INFO(Blue, InvalidPackage2Payload), + + ErrorInfo_UnknownSmc = MAKE_ERROR_INFO(LightBlue, UnknownSmc), + + ErrorInfo_UnknownAbort = MAKE_ERROR_INFO(Yellow, UnknownAbort), + + ErrorInfo_InvalidCoreContext = MAKE_ERROR_INFO(Pink, InvalidCoreContext), + ErrorInfo_InvalidSecurityEngineStickyBits = MAKE_ERROR_INFO(Pink, InvalidSecurityEngineStickyBits), + ErrorInfo_UnexpectedReset = MAKE_ERROR_INFO(Pink, UnexpectedReset), + + ErrorInfo_Exception = MAKE_ERROR_INFO(Orange, Exception), + + ErrorInfo_TransitionToSafeMode = MAKE_ERROR_INFO(Black, TransitionToSafeMode), + ErrorInfo_SecureInitializerReboot = MAKE_ERROR_INFO(Black, SecureInitializerReboot), + + ErrorInfo_SdmmcError = MAKE_ERROR_INFO(Purple, SdmmcError), + ErrorInfo_InvalidDramId = MAKE_ERROR_INFO(Purple, InvalidDramId), + ErrorInfo_InvalidPackage2 = MAKE_ERROR_INFO(Purple, InvalidPackage2), + ErrorInfo_InvalidBct = MAKE_ERROR_INFO(Purple, InvalidBct), + ErrorInfo_InvalidGpt = MAKE_ERROR_INFO(Purple, InvalidGpt), + ErrorInfo_FailedToTransitionToSafeMode = MAKE_ERROR_INFO(Purple, FailedToTransitionToSafeMode), + ErrorInfo_ActivityMonitorInterrupt = MAKE_ERROR_INFO(Purple, ActivityMonitorInterrupt), + + #undef MAKE_ERROR_INFO + }; + + constexpr inline ErrorReason GetErrorReason(u32 info) { + return static_cast(info & ErrorInfo_ReasonMask); + } + + constexpr inline ErrorInfo MakeKernelPanicResetInfo(u32 color) { + return static_cast((color << ErrorInfo_ColorShift) | (ErrorReason_KernelPanic)); + } + + #define PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH (0x840) + +} diff --git a/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp b/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp new file mode 100644 index 00000000..711f36ba --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::pkg1 { + + enum KeyGeneration : int { + + KeyGeneration_1_0_0 = 0x00, + KeyGeneration_3_0_0 = 0x01, + KeyGeneration_3_0_1 = 0x02, + KeyGeneration_4_0_0 = 0x03, + KeyGeneration_5_0_0 = 0x04, + KeyGeneration_6_0_0 = 0x05, + KeyGeneration_6_2_0 = 0x06, + KeyGeneration_7_0_0 = 0x07, + KeyGeneration_8_1_0 = 0x08, + KeyGeneration_9_0_0 = 0x09, + KeyGeneration_9_1_0 = 0x0A, + + KeyGeneration_Count, + + KeyGeneration_Current = KeyGeneration_Count - 1, + + KeyGeneration_Min = 0x00, + KeyGeneration_Max = 0x20, + }; + static_assert(KeyGeneration_Count <= KeyGeneration_Max); + + constexpr inline const int OldMasterKeyCount = KeyGeneration_Count - 1; + constexpr inline const int OldDeviceMasterKeyCount = KeyGeneration_Count - KeyGeneration_4_0_0; + +} diff --git a/libexosphere/include/exosphere/pkg1/pkg1_se_key_slots.hpp b/libexosphere/include/exosphere/pkg1/pkg1_se_key_slots.hpp new file mode 100644 index 00000000..614aa5a3 --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_se_key_slots.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::pkg1 { + + enum AesKeySlot { + AesKeySlot_UserStart = 0, + + AesKeySlot_TzramSave = 2, + + AesKeySlot_UserLast = 5, + AesKeySlot_UserEnd = AesKeySlot_UserLast + 1, + + AesKeySlot_SecmonStart = 8, + + AesKeySlot_Temporary = 8, + AesKeySlot_Smc = 9, + AesKeySlot_RandomForUserWrap = 10, + AesKeySlot_RandomForKeyStorageWrap = 11, + AesKeySlot_DeviceMaster = 12, + AesKeySlot_Master = 13, + AesKeySlot_Device = 15, + + AesKeySlot_SecmonEnd = 16, + + /* Used only during boot. */ + AesKeySlot_Tsec = 12, + AesKeySlot_TsecRoot = 13, + AesKeySlot_SecureBoot = 14, + AesKeySlot_SecureStorage = 15, + + AesKeySlot_MasterKek = 13, + AesKeySlot_DeviceMasterKeySourceKek = 14, + }; + + enum RsaKeySlot { + RsaKeySlot_Temporary = 0, + RsaKeySlot_PrivateKey = 1, + }; + +} diff --git a/libexosphere/include/exosphere/pmc.hpp b/libexosphere/include/exosphere/pmc.hpp new file mode 100644 index 00000000..d1e2091b --- /dev/null +++ b/libexosphere/include/exosphere/pmc.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::pmc { + + enum SecureRegister { + SecureRegister_Other = (1 << 0), + SecureRegister_DramParameters = (1 << 1), + SecureRegister_ResetVector = (1 << 2), + SecureRegister_Carveout = (1 << 3), + SecureRegister_CmacWrite = (1 << 4), + SecureRegister_CmacRead = (1 << 5), + SecureRegister_KeySourceWrite = (1 << 6), + SecureRegister_KeySourceRead = (1 << 7), + SecureRegister_Srk = (1 << 8), + + SecureRegister_CmacReadWrite = SecureRegister_CmacRead | SecureRegister_CmacWrite, + SecureRegister_KeySourceReadWrite = SecureRegister_KeySourceRead | SecureRegister_KeySourceWrite, + }; + + void SetRegisterAddress(uintptr_t address); + + void InitializeRandomScratch(); + + void LockSecureRegister(SecureRegister reg); + + enum class LockState { + Locked = 0, + NotLocked = 1, + PartiallyLocked = 2, + }; + + LockState GetSecureRegisterLockState(SecureRegister reg); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/pmic.hpp b/libexosphere/include/exosphere/pmic.hpp new file mode 100644 index 00000000..46b10372 --- /dev/null +++ b/libexosphere/include/exosphere/pmic.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::pmic { + + enum Regulator { + /* Erista regulators. */ + Regulator_Erista_Max77621 = 0, /* Device code 0x3A000001 */ + + /* Mariko regulators. */ + Regulator_Mariko_Max77812_A = 1, /* Device code 0x3A000002 */ + Regulator_Mariko_Max77812_B = 2, /* Device code 0x3A000006 */ + }; + + void EnableVddCpu(Regulator regulator); + void DisableVddCpu(Regulator regulator); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/reg.hpp b/libexosphere/include/exosphere/reg.hpp new file mode 100644 index 00000000..a16d6619 --- /dev/null +++ b/libexosphere/include/exosphere/reg.hpp @@ -0,0 +1,205 @@ +/* + * 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::reg { + + using BitsValue = std::tuple; + using BitsMask = std::tuple; + + constexpr ALWAYS_INLINE u32 GetOffset(const BitsMask v) { return std::get<0>(v); } + constexpr ALWAYS_INLINE u32 GetOffset(const BitsValue v) { return std::get<0>(v); } + constexpr ALWAYS_INLINE u32 GetWidth(const BitsMask v) { return std::get<1>(v); } + constexpr ALWAYS_INLINE u32 GetWidth(const BitsValue v) { return std::get<1>(v); } + constexpr ALWAYS_INLINE u32 GetValue(const BitsValue v) { return std::get<2>(v); } + + constexpr ALWAYS_INLINE u32 EncodeMask(const BitsMask v) { + return (~0u >> (BITSIZEOF(u32) - GetWidth(v))) << GetOffset(v); + } + + constexpr ALWAYS_INLINE u32 EncodeMask(const BitsValue v) { + return (~0u >> (BITSIZEOF(u32) - GetWidth(v))) << GetOffset(v); + } + + constexpr ALWAYS_INLINE u32 EncodeValue(const BitsValue v) { + return ((GetValue(v) << GetOffset(v)) & EncodeMask(v)); + } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + constexpr ALWAYS_INLINE u32 Encode(const Values... values) { + return (EncodeValue(values) | ...); + } + + ALWAYS_INLINE void Write(volatile u32 *reg, u32 val) { *reg = val; } + ALWAYS_INLINE void Write(volatile u32 ®, u32 val) { reg = val; } + ALWAYS_INLINE void Write(uintptr_t reg, u32 val) { Write(reinterpret_cast(reg), val); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void Write(volatile u32 *reg, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void Write(volatile u32 ®, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void Write(uintptr_t reg, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); } + + ALWAYS_INLINE u32 Read(volatile u32 *reg) { return *reg; } + ALWAYS_INLINE u32 Read(volatile u32 ®) { return reg; } + ALWAYS_INLINE u32 Read(uintptr_t reg) { return Read(reinterpret_cast(reg)); } + + ALWAYS_INLINE u32 Read(volatile u32 *reg, u32 mask) { return *reg & mask; } + ALWAYS_INLINE u32 Read(volatile u32 ®, u32 mask) { return reg & mask; } + ALWAYS_INLINE u32 Read(uintptr_t reg, u32 mask) { return Read(reinterpret_cast(reg), mask); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE u32 Read(volatile u32 *reg, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE u32 Read(volatile u32 ®, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE u32 Read(uintptr_t reg, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE bool HasValue(volatile u32 *reg, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE bool HasValue(volatile u32 ®, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); } + + 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 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); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ReadWrite(volatile u32 *reg, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ReadWrite(volatile u32 ®, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); } + + template requires ((sizeof...(Values) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ReadWrite(uintptr_t reg, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); } + + ALWAYS_INLINE void SetBits(volatile u32 *reg, u32 mask) { *reg = *reg | mask; } + ALWAYS_INLINE void SetBits(volatile u32 ®, u32 mask) { reg = reg | mask; } + ALWAYS_INLINE void SetBits(uintptr_t reg, u32 mask) { SetBits(reinterpret_cast(reg), mask); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void SetBits(volatile u32 *reg, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void SetBits(volatile u32 ®, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void SetBits(uintptr_t reg, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); } + + ALWAYS_INLINE void ClearBits(volatile u32 *reg, u32 mask) { *reg = *reg & ~mask; } + ALWAYS_INLINE void ClearBits(volatile u32 ®, u32 mask) { reg = reg & ~mask; } + ALWAYS_INLINE void ClearBits(uintptr_t reg, u32 mask) { ClearBits(reinterpret_cast(reg), mask); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ClearBits(volatile u32 *reg, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ClearBits(volatile u32 ®, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void ClearBits(uintptr_t reg, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); } + + ALWAYS_INLINE void MaskBits(volatile u32 *reg, u32 mask) { *reg = *reg & mask; } + ALWAYS_INLINE void MaskBits(volatile u32 ®, u32 mask) { reg = reg & mask; } + ALWAYS_INLINE void MaskBits(uintptr_t reg, u32 mask) { MaskBits(reinterpret_cast(reg), mask); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void MaskBits(volatile u32 *reg, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void MaskBits(volatile u32 ®, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); } + + template requires ((sizeof...(Masks) > 0) && (std::is_same::value && ...)) + ALWAYS_INLINE void MaskBits(uintptr_t reg, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); } + + #define REG_BITS_MASK(OFFSET, WIDTH) ::ams::reg::BitsMask{OFFSET, WIDTH} + #define REG_BITS_VALUE(OFFSET, WIDTH, VALUE) ::ams::reg::BitsValue{OFFSET, WIDTH, VALUE} + + #define REG_NAMED_BITS_MASK(PREFIX, NAME) REG_BITS_MASK(PREFIX##_##NAME##_OFFSET, PREFIX##_##NAME##_WIDTH) + #define REG_NAMED_BITS_VALUE(PREFIX, NAME, VALUE) REG_BITS_VALUE(PREFIX##_##NAME##_OFFSET, PREFIX##_##NAME##_WIDTH, VALUE) + #define REG_NAMED_BITS_ENUM(PREFIX, NAME, ENUM) REG_BITS_VALUE(PREFIX##_##NAME##_OFFSET, PREFIX##_##NAME##_WIDTH, PREFIX##_##NAME##_##ENUM) + + #define REG_NAMED_BITS_ENUM_SEL(PREFIX, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_BITS_VALUE(PREFIX##_##NAME##_OFFSET, PREFIX##_##NAME##_WIDTH, (__COND__) ? PREFIX##_##NAME##_##TRUE_ENUM : PREFIX##_##NAME##_##FALSE_ENUM) + + #define REG_DEFINE_NAMED_REG(PREFIX, NAME, __OFFSET__, __WIDTH__) \ + constexpr inline u32 PREFIX##_##NAME##_OFFSET = __OFFSET__; \ + constexpr inline u32 PREFIX##_##NAME##_WIDTH = __WIDTH__ + + #define REG_DEFINE_NAMED_BIT_ENUM(PREFIX, NAME, __OFFSET__, ZERO, ONE) \ + REG_DEFINE_NAMED_REG(PREFIX, NAME, __OFFSET__, 1); \ + \ + enum PREFIX##_##NAME { \ + PREFIX##_##NAME##_##ZERO = 0, \ + PREFIX##_##NAME##_##ONE = 1, \ + }; + + #define REG_DEFINE_NAMED_TWO_BIT_ENUM(PREFIX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) \ + REG_DEFINE_NAMED_REG(PREFIX, NAME, __OFFSET__, 2); \ + \ + enum PREFIX##_##NAME { \ + PREFIX##_##NAME##_##ZERO = 0, \ + PREFIX##_##NAME##_##ONE = 1, \ + PREFIX##_##NAME##_##TWO = 2, \ + PREFIX##_##NAME##_##THREE = 3, \ + }; + + #define REG_DEFINE_NAMED_THREE_BIT_ENUM(PREFIX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) \ + REG_DEFINE_NAMED_REG(PREFIX, NAME, __OFFSET__, 3); \ + \ + enum PREFIX##_##NAME { \ + PREFIX##_##NAME##_##ZERO = 0, \ + PREFIX##_##NAME##_##ONE = 1, \ + PREFIX##_##NAME##_##TWO = 2, \ + PREFIX##_##NAME##_##THREE = 3, \ + PREFIX##_##NAME##_##FOUR = 4, \ + PREFIX##_##NAME##_##FIVE = 5, \ + PREFIX##_##NAME##_##SIX = 6, \ + PREFIX##_##NAME##_##SEVEN = 7, \ + }; + + #define REG_DEFINE_NAMED_FOUR_BIT_ENUM(PREFIX, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) \ + REG_DEFINE_NAMED_REG(PREFIX, NAME, __OFFSET__, 4); \ + \ + enum PREFIX##_##NAME { \ + PREFIX##_##NAME##_##ZERO = 0, \ + PREFIX##_##NAME##_##ONE = 1, \ + PREFIX##_##NAME##_##TWO = 2, \ + PREFIX##_##NAME##_##THREE = 3, \ + PREFIX##_##NAME##_##FOUR = 4, \ + PREFIX##_##NAME##_##FIVE = 5, \ + PREFIX##_##NAME##_##SIX = 6, \ + PREFIX##_##NAME##_##SEVEN = 7, \ + PREFIX##_##NAME##_##EIGHT = 8, \ + PREFIX##_##NAME##_##NINE = 9, \ + PREFIX##_##NAME##_##TEN = 10, \ + PREFIX##_##NAME##_##ELEVEN = 11, \ + PREFIX##_##NAME##_##TWELVE = 12, \ + PREFIX##_##NAME##_##THIRTEEN = 13, \ + PREFIX##_##NAME##_##FOURTEEN = 14, \ + PREFIX##_##NAME##_##FIFTEEN = 15, \ + }; + +} diff --git a/libexosphere/include/exosphere/se.hpp b/libexosphere/include/exosphere/se.hpp new file mode 100644 index 00000000..ad9abd63 --- /dev/null +++ b/libexosphere/include/exosphere/se.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 + +#include +#include +#include +#include +#include +#include diff --git a/libexosphere/include/exosphere/se/se_aes.hpp b/libexosphere/include/exosphere/se/se_aes.hpp new file mode 100644 index 00000000..c2873f11 --- /dev/null +++ b/libexosphere/include/exosphere/se/se_aes.hpp @@ -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 . + */ +#pragma once +#include +#include + +namespace ams::se { + + constexpr inline int AesKeySlotCount = 16; + constexpr inline size_t AesBlockSize = crypto::AesEncryptor128::BlockSize; + + void ClearAesKeySlot(int slot); + void LockAesKeySlot(int slot, u32 flags); + + void SetAesKey(int slot, const void *key, size_t key_size); + + void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size); + void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size); + + void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); + void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/se/se_common.hpp b/libexosphere/include/exosphere/se/se_common.hpp new file mode 100644 index 00000000..4a87d642 --- /dev/null +++ b/libexosphere/include/exosphere/se/se_common.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::secmon { + + u8 *GetSecurityEngineEphemeralWorkBlock(); + +} + +namespace ams::se { + + using DoneHandler = void(*)(); + + enum KeySlotLockFlags { + KeySlotLockFlags_None = 0, + KeySlotLockFlags_KeyRead = (1u << 0), + KeySlotLockFlags_KeyWrite = (1u << 1), + KeySlotLockFlags_OriginalIvRead = (1u << 2), + KeySlotLockFlags_OriginalIvWrite = (1u << 3), + KeySlotLockFlags_UpdatedIvRead = (1u << 4), + KeySlotLockFlags_UpdatedIvWrite = (1u << 5), + KeySlotLockFlags_KeyUse = (1u << 6), + KeySlotLockFlags_DstKeyTableOnly = (1u << 7), + KeySlotLockFlags_PerKey = (1u << 8), + + KeySlotLockFlags_AllReadLock = (KeySlotLockFlags_KeyRead | KeySlotLockFlags_OriginalIvRead | KeySlotLockFlags_UpdatedIvRead), + KeySlotLockFlags_AllLockKek = 0x1FF, + KeySlotLockFlags_AllLockKey = (KeySlotLockFlags_AllLockKek & ~KeySlotLockFlags_DstKeyTableOnly), + + KeySlotLockFlags_EristaMask = 0x7F, + KeySlotLockFlags_MarikoMask = 0xFF, + }; + + ALWAYS_INLINE u8 *GetEphemeralWorkBlock() { + return ::ams::secmon::GetSecurityEngineEphemeralWorkBlock(); + } + +} diff --git a/libexosphere/include/exosphere/se/se_management.hpp b/libexosphere/include/exosphere/se/se_management.hpp new file mode 100644 index 00000000..f5a8e6be --- /dev/null +++ b/libexosphere/include/exosphere/se/se_management.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::se { + + void SetRegisterAddress(uintptr_t address); + + void Initialize(); + + void SetSecure(bool secure); + void SetTzramSecure(); + void SetPerKeySecure(); + + void Lockout(); + + void HandleInterrupt(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/se/se_rng.hpp b/libexosphere/include/exosphere/se/se_rng.hpp new file mode 100644 index 00000000..3fa33936 --- /dev/null +++ b/libexosphere/include/exosphere/se/se_rng.hpp @@ -0,0 +1,28 @@ +/* + * 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::se { + + void InitializeRandom(); + + void GenerateRandomBytes(void *dst, size_t size); + void SetRandomKey(int slot); + + void GenerateSrk(); + +} diff --git a/libexosphere/include/exosphere/se/se_rsa.hpp b/libexosphere/include/exosphere/se/se_rsa.hpp new file mode 100644 index 00000000..e16b99c6 --- /dev/null +++ b/libexosphere/include/exosphere/se/se_rsa.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::se { + + constexpr inline int RsaKeySlotCount = 2; + constexpr inline int RsaSize = 0x100; + + void ClearRsaKeySlot(int slot); + void LockRsaKeySlot(int slot, u32 flags); + + void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size); + +} diff --git a/libexosphere/include/exosphere/se/se_suspend.hpp b/libexosphere/include/exosphere/se/se_suspend.hpp new file mode 100644 index 00000000..9f16924b --- /dev/null +++ b/libexosphere/include/exosphere/se/se_suspend.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include + +namespace ams::se { + + /* 256-bit AES keyslots are two 128-bit keys. */ + constexpr inline int AesKeySlotPartCount = 2; + + /* RSA keys are both a modulus and an exponent. */ + constexpr inline int RsaKeySlotPartCount = 2; + + constexpr inline size_t StickyBitContextSize = 2 * AesBlockSize; + + struct Context { + u8 random[AesBlockSize]; + u8 sticky_bits[StickyBitContextSize / AesBlockSize][AesBlockSize]; + u8 aes_key[AesKeySlotCount][AesKeySlotPartCount][AesBlockSize]; + u8 aes_oiv[AesKeySlotCount][AesBlockSize]; + u8 aes_uiv[AesKeySlotCount][AesBlockSize]; + u8 rsa_key[RsaKeySlotCount][RsaKeySlotPartCount][RsaSize / AesBlockSize][AesBlockSize]; + u8 fixed_pattern[AesBlockSize]; + }; + static_assert(sizeof(Context) == 0x840); + static_assert(util::is_pod::value); + + struct StickyBits { + u8 se_security; + u8 tzram_security; + u16 crypto_security_perkey; + u8 crypto_keytable_access[AesKeySlotCount]; + u8 rsa_security_perkey; + u8 rsa_keytable_access[RsaKeySlotCount]; + }; + static_assert(util::is_pod::value); + + bool ValidateStickyBits(const StickyBits &bits); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/secmon.hpp b/libexosphere/include/exosphere/secmon.hpp new file mode 100644 index 00000000..1b476e0f --- /dev/null +++ b/libexosphere/include/exosphere/secmon.hpp @@ -0,0 +1,20 @@ +/* + * 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 +#include +#include +#include \ No newline at end of file diff --git a/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp new file mode 100644 index 00000000..7f094a14 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -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 . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::secmon { + + struct ConfigurationContext { + union { + SecureMonitorConfiguration secmon_cfg; + u8 _raw_exosphere_config[0x80]; + }; + union { + EmummcConfiguration emummc_cfg; + u8 _raw_emummc_config[0x120]; + }; + union { + u8 _misc_data[0x400 - sizeof(_raw_exosphere_config) - sizeof(_raw_emummc_config)]; + }; + u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; + u8 sealed_master_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; + pkg1::BootConfig boot_config; + u8 rsa_private_exponents[4][se::RsaSize]; + }; + static_assert(sizeof(ConfigurationContext) == 0x1000); + static_assert(util::is_pod::value); + static_assert(offsetof(ConfigurationContext, sealed_device_keys) == 0x400); + + namespace impl { + + ALWAYS_INLINE uintptr_t GetConfigurationContextAddress() { + register uintptr_t x18 asm("x18"); + __asm__ __volatile__("" : [x18]"=r"(x18)); + return x18; + } + + ALWAYS_INLINE ConfigurationContext &GetConfigurationContext() { + return *reinterpret_cast(GetConfigurationContextAddress()); + } + + ALWAYS_INLINE u8 *GetMasterKeyStorage(int generation) { + return GetConfigurationContext().sealed_master_keys[generation]; + } + + ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int generation) { + return GetConfigurationContext().sealed_device_keys[generation]; + } + + ALWAYS_INLINE u8 *GetRsaPrivateExponentStorage(int which) { + return GetConfigurationContext().rsa_private_exponents[which]; + } + + ALWAYS_INLINE void SetKeyGeneration(int generation) { + GetConfigurationContext().secmon_cfg.key_generation = generation; + } + + } + + ALWAYS_INLINE const ConfigurationContext &GetConfigurationContext() { + return *reinterpret_cast(impl::GetConfigurationContextAddress()); + } + + ALWAYS_INLINE const SecureMonitorConfiguration &GetSecmonConfiguration() { + return GetConfigurationContext().secmon_cfg; + } + + ALWAYS_INLINE const EmummcConfiguration &GetEmummcConfiguration() { + return GetConfigurationContext().emummc_cfg; + } + + ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() { + return GetConfigurationContext().boot_config; + } + + ALWAYS_INLINE ams::TargetFirmware GetTargetFirmware() { + return GetSecmonConfiguration().GetTargetFirmware(); + } + + ALWAYS_INLINE int GetKeyGeneration() { + return GetSecmonConfiguration().GetKeyGeneration(); + } + +} diff --git a/libexosphere/include/exosphere/secmon/secmon_configuration_context.hpp b/libexosphere/include/exosphere/secmon/secmon_configuration_context.hpp new file mode 100644 index 00000000..c66816d5 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_configuration_context.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 + +#if defined(ATMOSPHERE_ARCH_ARM64) + #include +#elif defined(ATMOSPHERE_ARCH_ARM) + /* Nothing to include. */ +#else + #error "Unknown architecture for secmon::ConfigurationContext.hpp" +#endif diff --git a/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp b/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp new file mode 100644 index 00000000..044420e8 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::secmon { + + enum EmummcType : u32 { + EmummcType_None = 0, + EmummcType_Partition = 1, + EmummcType_File = 2, + }; + + enum EmummcMmc { + EmummcMmc_Nand = 0, + EmummcMmc_Sd = 1, + EmummcMmc_Gc = 2, + }; + + constexpr inline size_t EmummcFilePathLengthMax = 0x80; + + struct EmummcFilePath { + char str[EmummcFilePathLengthMax]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcFilePath) == EmummcFilePathLengthMax); + + struct EmummcBaseConfiguration { + static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code; + + u32 magic; + EmummcType type; + u32 id; + u32 fs_version; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcBaseConfiguration) == 0x10); + + struct EmummcPartitionConfiguration { + u64 start_sector; + }; + static_assert(util::is_pod::value); + + struct EmummcFileConfiguration { + EmummcFilePath path; + }; + static_assert(util::is_pod::value); + + struct EmummcConfiguration { + EmummcBaseConfiguration base_cfg; + union { + EmummcPartitionConfiguration partition_cfg; + EmummcFileConfiguration file_cfg; + }; + EmummcFilePath emu_dir_path; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcConfiguration) <= 0x200); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp new file mode 100644 index 00000000..c40368a3 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -0,0 +1,277 @@ +/* + * 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 +#include + +namespace ams::secmon { + + using Address = u64; + + struct MemoryRegion { + Address start_address; + Address end_address; + + constexpr MemoryRegion(Address address, size_t size) : start_address(address), end_address(address + size) { + if (end_address < start_address) { + __builtin_unreachable(); + } + } + + constexpr Address GetStartAddress() const { + return this->start_address; + } + + constexpr Address GetAddress() const { + return this->GetStartAddress(); + } + + constexpr Address GetEndAddress() const { + return this->end_address; + } + + constexpr Address GetLastAddress() const { + return this->end_address - 1; + } + + constexpr size_t GetSize() const { + return this->end_address - this->start_address; + } + + constexpr bool Contains(Address address, size_t size) const { + return this->start_address <= address && (address + size - 1) <= this->GetLastAddress(); + } + + constexpr bool Contains(const MemoryRegion &rhs) const { + return this->Contains(rhs.GetStartAddress(), rhs.GetSize()); + } + + template requires (std::is_same::value || util::is_pod::value) + ALWAYS_INLINE T *GetPointer() const { + return reinterpret_cast(this->GetAddress()); + } + + template requires (std::is_same::value || util::is_pod::value) + ALWAYS_INLINE T *GetEndPointer() const { + return reinterpret_cast(this->GetEndAddress()); + } + }; + + constexpr inline const MemoryRegion MemoryRegionVirtual = MemoryRegion(UINT64_C(0x1F0000000), 2_MB); + constexpr inline const MemoryRegion MemoryRegionPhysical = MemoryRegion(UINT64_C( 0x40000000), 1_GB); + constexpr inline const MemoryRegion MemoryRegionDram = MemoryRegion(UINT64_C( 0x80000000), 2_GB); + + constexpr inline const MemoryRegion MemoryRegionDramDefaultKernelCarveout = MemoryRegion(UINT64_C(0x80060000), UINT64_C(0x1FFE0000)); + static_assert(MemoryRegionDram.Contains(MemoryRegionDramDefaultKernelCarveout)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalIram = MemoryRegion(UINT64_C(0x40000000), 0x40000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzram = MemoryRegion(UINT64_C(0x7C010000), 0x10000); + static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalIram)); + static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalTzram)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatile(UINT64_C(0x7C010000), 0x2000); + static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramVolatile)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramNonVolatile(UINT64_C(0x7C012000), 0xE000); + static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramNonVolatile)); + + static_assert(MemoryRegionPhysicalTzram.GetSize() == MemoryRegionPhysicalTzramNonVolatile.GetSize() + MemoryRegionPhysicalTzramVolatile.GetSize()); + + constexpr inline const MemoryRegion MemoryRegionVirtualL1 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize); + constexpr inline const MemoryRegion MemoryRegionPhysicalL1 = MemoryRegion(util::AlignDown(MemoryRegionPhysical.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize); + static_assert(MemoryRegionVirtualL1.Contains(MemoryRegionVirtual)); + static_assert(MemoryRegionPhysicalL1.Contains(MemoryRegionPhysical)); + + constexpr inline const MemoryRegion MemoryRegionVirtualL2 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalIram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalTzram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); + static_assert(MemoryRegionVirtualL2.Contains(MemoryRegionVirtual)); + static_assert(MemoryRegionPhysicalIramL2.Contains(MemoryRegionPhysicalIram)); + static_assert(MemoryRegionPhysicalTzramL2.Contains(MemoryRegionPhysicalTzram)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000); + static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000)); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0); + + #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \ + HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ + HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \ + HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \ + HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ + HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ + HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(FuseKFuse, MemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \ + HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) + + #define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \ + constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \ + constexpr inline const MemoryRegion MemoryRegionPhysicalDevice##_NAME_ = MemoryRegion(_ADDRESS_, _SIZE_); \ + static_assert(MemoryRegionVirtualDevice.Contains(MemoryRegionVirtualDevice##_NAME_)); \ + static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalDevice##_NAME_)); + + AMS_SECMON_FOREACH_DEVICE_REGION(DEFINE_DEVICE_REGION) + + #undef DEFINE_DEVICE_REGION + + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceFuses = MemoryRegion(MemoryRegionVirtualDeviceFuseKFuse.GetAddress() + 0x800, 0x400); + constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceFuses = MemoryRegion(MemoryRegionPhysicalDeviceFuseKFuse.GetAddress() + 0x800, 0x400); + static_assert(MemoryRegionVirtualDeviceFuseKFuse.Contains(MemoryRegionVirtualDeviceFuses)); + static_assert(MemoryRegionPhysicalDeviceFuseKFuse.Contains(MemoryRegionPhysicalDeviceFuses)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceActivityMonitor = MemoryRegion(MemoryRegionVirtualDeviceSystem.GetAddress() + 0x800, 0x400); + constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceActivityMonitor = MemoryRegion(MemoryRegionPhysicalDeviceSystem.GetAddress() + 0x800, 0x400); + static_assert(MemoryRegionVirtualDeviceSystem.Contains(MemoryRegionVirtualDeviceActivityMonitor)); + static_assert(MemoryRegionPhysicalDeviceSystem.Contains(MemoryRegionPhysicalDeviceActivityMonitor)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartA = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x000, 0x040); + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartB = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x040, 0x040); + constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartC = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x200, 0x100); + static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartA)); + static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartB)); + static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartC)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartA = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x000, 0x040); + constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartB = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x040, 0x040); + constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartC = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x200, 0x100); + static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartA)); + static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartB)); + static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartC)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDevicePmc = MemoryRegion(MemoryRegionVirtualDeviceRtcPmc.GetAddress() + 0x400, 0xC00); + constexpr inline const MemoryRegion MemoryRegionPhysicalDevicePmc = MemoryRegion(MemoryRegionPhysicalDeviceRtcPmc.GetAddress() + 0x400, 0xC00); + static_assert(MemoryRegionVirtualDeviceRtcPmc.Contains(MemoryRegionVirtualDevicePmc)); + static_assert(MemoryRegionPhysicalDeviceRtcPmc.Contains(MemoryRegionPhysicalDevicePmc)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramReadOnlyAlias = MemoryRegion(UINT64_C(0x1F00A0000), MemoryRegionPhysicalTzram.GetSize()); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramReadOnlyAlias = MemoryRegion(MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize()); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramReadOnlyAlias)); + static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramReadOnlyAlias)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgram(UINT64_C(0x1F00C0000), 0xC000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramProgram)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramExceptionVectors(UINT64_C(0x1F00C0000), 0x800); + static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramExceptionVectors)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramMain(UINT64_C(0x1F00C0800), 0xB800); + static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramMain)); + + static_assert(MemoryRegionVirtualTzramProgram.GetSize() == MemoryRegionVirtualTzramProgramExceptionVectors.GetSize() + MemoryRegionVirtualTzramProgramMain.GetSize()); + + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramProgram(UINT64_C(0x7C012000), 0xC000); + static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramProgram)); + + constexpr inline const Address PhysicalTzramProgramResetVector = MemoryRegionPhysicalTzramProgram.GetAddress() + MemoryRegionVirtualTzramProgramExceptionVectors.GetSize(); + static_assert(static_cast(PhysicalTzramProgramResetVector) == PhysicalTzramProgramResetVector); + + constexpr uintptr_t GetPhysicalTzramProgramAddress(uintptr_t virtual_address) { + return virtual_address - MemoryRegionVirtualTzramProgram.GetStartAddress() + MemoryRegionPhysicalTzramNonVolatile.GetStartAddress(); + } + + constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Work = MemoryRegion(UINT64_C(0x1F0120000), MemoryRegionPhysicalTzram.GetSize()); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Work = MemoryRegion( UINT64_C(0x40020000), MemoryRegionPhysicalTzram.GetSize()); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Work)); + static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Work)); + + constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Firmware = MemoryRegion(UINT64_C(0x1F0140000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Firmware = MemoryRegion( UINT64_C(0x40003000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Firmware)); + static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Firmware)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDebug = MemoryRegion(UINT64_C(0x1F0160000), 0x10000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Firmware)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramBootCode = MemoryRegion(UINT64_C(0x1F01C0000), 0x2000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramBootCode = MemoryRegion( UINT64_C(0x7C010000), 0x2000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramBootCode)); + static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramBootCode)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalDramMonitorConfiguration = MemoryRegion( UINT64_C(0x8000F000), 0x1000); + + constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStore = MemoryRegion(UINT64_C(0x1F0100000), 0x10000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStore = MemoryRegion( UINT64_C(0x80010000), 0x10000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore)); + static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore)); + + constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x1F0100000), 0xE000); + constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x1F010E000), 0x17C0); + constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x1F010F7C0), 0x0840); + static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreTzram)); + static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware)); + static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x80010000), 0xE000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x8001E000), 0x17C0); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x8001F7C0), 0x0840); + static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreTzram)); + static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware)); + static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState)); + + constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereIramPage = MemoryRegion(UINT64_C(0x1F01F0000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereIramPage)); + + constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereUserPage = MemoryRegion(UINT64_C(0x1F01F2000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereUserPage)); + + constexpr inline const MemoryRegion MemoryRegionVirtualSmcUserPage = MemoryRegion(UINT64_C(0x1F01F4000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualSmcUserPage)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileData = MemoryRegion(UINT64_C(0x1F01F6000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileData = MemoryRegion( UINT64_C(0x7C010000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileData)); + static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileData)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileStack = MemoryRegion(UINT64_C(0x1F01F8000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileStack = MemoryRegion( UINT64_C(0x7C011000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileStack)); + static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileStack)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramConfigurationData = MemoryRegion(UINT64_C(0x1F01FA000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramConfigurationData = MemoryRegion( UINT64_C(0x7C01E000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramConfigurationData)); + static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramConfigurationData)); + + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramL1PageTable = MemoryRegion(UINT64_C(0x1F01FCFC0), 0x40); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL1PageTable = MemoryRegion( UINT64_C(0x7C01EFC0), 0x40); + static_assert(MemoryRegionPhysicalTzramConfigurationData.Contains(MemoryRegionPhysicalTzramL1PageTable)); + + constexpr inline const MemoryRegion MemoryRegionVirtualTzramL2L3PageTable = MemoryRegion(UINT64_C(0x1F01FE000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2L3PageTable = MemoryRegion( UINT64_C(0x7C01F000), 0x1000); + static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramL2L3PageTable)); + static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable)); + + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(0x7C010800, 0xD800); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(0x40032000, 0xC000); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp b/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp new file mode 100644 index 00000000..1aa0b679 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp @@ -0,0 +1,77 @@ +/* + * 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 +#include + +namespace ams::secmon { + + enum SecureMonitorConfigurationFlag : u32 { + SecureMonitorConfigurationFlag_None = (0u << 0), + SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel = (1u << 1), + SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser = (1u << 2), + SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers = (1u << 3), + SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4), + SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5), + SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6), + + SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel, + }; + + struct SecureMonitorStorageConfiguration { + static constexpr u32 Magic = util::FourCC<'E','X','O','0'>::Code; + + u32 magic; + ams::TargetFirmware target_firmware; + u32 flags; + u32 reserved[5]; + EmummcConfiguration emummc_cfg; + + constexpr bool IsValid() const { return this->magic == Magic; } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x130); + + struct SecureMonitorConfiguration { + ams::TargetFirmware target_firmware; + s32 key_generation; + u32 flags; + u32 reserved[(0x80 - 0x0C) / sizeof(u32)]; + + constexpr void CopyFrom(const SecureMonitorStorageConfiguration &storage) { + this->target_firmware = storage.target_firmware; + this->flags = storage.flags; + } + + constexpr ams::TargetFirmware GetTargetFirmware() const { return this->target_firmware; } + constexpr int GetKeyGeneration() const { return this->key_generation; } + + constexpr bool IsDevelopmentFunctionEnabledForKernel() const { return (this->flags & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel) != 0; } + constexpr bool IsDevelopmentFunctionEnabledForUser() const { return (this->flags & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser) != 0; } + constexpr bool DisableUserModeExceptionHandlers() const { return (this->flags & SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers) != 0; } + constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; } + constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; } + constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(SecureMonitorConfiguration) == 0x80); + + constexpr inline const SecureMonitorConfiguration DefaultSecureMonitorConfiguration = { + .target_firmware = ams::TargetFirmware_Current, + .flags = SecureMonitorConfigurationFlag_Default, + }; + +} diff --git a/libexosphere/include/exosphere/secmon/secmon_volatile_context.hpp b/libexosphere/include/exosphere/secmon/secmon_volatile_context.hpp new file mode 100644 index 00000000..c8bc4e37 --- /dev/null +++ b/libexosphere/include/exosphere/secmon/secmon_volatile_context.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::secmon { + + /* The VolatileStack page is reserved entirely for use for core 3 SMC handling. */ + constexpr inline const Address Core3SmcStackAddress = MemoryRegionVirtualTzramVolatileStack.GetAddress() + MemoryRegionVirtualTzramVolatileStack.GetSize(); + + constexpr inline const size_t CoreExceptionStackSize = 0x80; + + /* Nintendo uses the bottom 0x740 of this as a stack for warmboot setup, and another 0x740 for the core 0/1/2 SMC stacks. */ + /* This is...wasteful. The warmboot stack is not deep. We will thus save 1K+ of nonvolatile storage by keeping the random cache in here. */ + struct VolatileData { + u8 random_cache[0x400]; + u8 se_work_block[crypto::AesEncryptor128::BlockSize]; + u8 reserved_danger_zone[0x30]; /* This memory is "available", but careful consideration must be taken before declaring it used. */ + u8 warmboot_stack[0x380]; + u8 core012_smc_stack[0x6C0]; + u8 core_exception_stacks[3][CoreExceptionStackSize]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(VolatileData) == 0x1000); + + ALWAYS_INLINE VolatileData &GetVolatileData() { + return *MemoryRegionVirtualTzramVolatileData.GetPointer(); + } + + ALWAYS_INLINE u8 *GetRandomBytesCache() { + return GetVolatileData().random_cache; + } + + constexpr ALWAYS_INLINE size_t GetRandomBytesCacheSize() { + return sizeof(VolatileData::random_cache); + } + + ALWAYS_INLINE u8 *GetSecurityEngineEphemeralWorkBlock() { + return GetVolatileData().se_work_block; + } + + constexpr inline const Address WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, warmboot_stack) + sizeof(VolatileData::warmboot_stack); + constexpr inline const Address Core012SmcStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, core012_smc_stack) + sizeof(VolatileData::core012_smc_stack); + + constexpr inline const Address Core0ExceptionStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, core_exception_stacks) + CoreExceptionStackSize; + constexpr inline const Address Core1ExceptionStackAddress = Core0ExceptionStackAddress + CoreExceptionStackSize; + constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize; + +} diff --git a/libexosphere/include/exosphere/tegra.hpp b/libexosphere/include/exosphere/tegra.hpp new file mode 100644 index 00000000..370bcc3b --- /dev/null +++ b/libexosphere/include/exosphere/tegra.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/libexosphere/include/exosphere/tegra/tegra_ahb_arbc.hpp b/libexosphere/include/exosphere/tegra/tegra_ahb_arbc.hpp new file mode 100644 index 00000000..a131cf68 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_ahb_arbc.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#define AHB_ARBC(x) (0x6000c000 + x) + +#define AHB_ARBITRATION_DISABLE (0x004) +#define AHB_ARBITRATION_PRIORITY_CTRL (0x008) +#define AHB_MASTER_SWID (0x018) +#define AHB_MASTER_SWID_1 (0x038) +#define AHB_GIZMO_TZRAM (0x054) + diff --git a/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp b/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp new file mode 100644 index 00000000..af05f365 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_apb_misc.hpp @@ -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 . + */ +#pragma once +#include + +#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 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_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_SLAVE_SECURITY_REG(0, 29, STM); +DEFINE_SLAVE_SECURITY_REG(0, 24, CEC); +DEFINE_SLAVE_SECURITY_REG(0, 23, ATOMICS); +DEFINE_SLAVE_SECURITY_REG(0, 22, LA); +DEFINE_SLAVE_SECURITY_REG(0, 21, HDA); +DEFINE_SLAVE_SECURITY_REG(0, 20, SATA); +DEFINE_SLAVE_SECURITY_REG(0, 16, KFUSE); +DEFINE_SLAVE_SECURITY_REG(0, 15, FUSE); +DEFINE_SLAVE_SECURITY_REG(0, 14, SE); +DEFINE_SLAVE_SECURITY_REG(0, 13, PMC); +DEFINE_SLAVE_SECURITY_REG(0, 11, RTC); +DEFINE_SLAVE_SECURITY_REG(0, 10, CSITE); +DEFINE_SLAVE_SECURITY_REG(0, 9, QSPI); +DEFINE_SLAVE_SECURITY_REG(0, 8, PWM); +DEFINE_SLAVE_SECURITY_REG(0, 6, DTV); +DEFINE_SLAVE_SECURITY_REG(0, 4, APE); +DEFINE_SLAVE_SECURITY_REG(0, 3, PINMUX_AUX); +DEFINE_SLAVE_SECURITY_REG(0, 2, SATA_AUX); +DEFINE_SLAVE_SECURITY_REG(0, 1, MISC_REGS); + +DEFINE_SLAVE_SECURITY_REG(1, 31, I2C6); +DEFINE_SLAVE_SECURITY_REG(1, 30, DVC); +DEFINE_SLAVE_SECURITY_REG(1, 29, I2C4); +DEFINE_SLAVE_SECURITY_REG(1, 28, I2C3); +DEFINE_SLAVE_SECURITY_REG(1, 27, I2C2); +DEFINE_SLAVE_SECURITY_REG(1, 26, I2C1); +DEFINE_SLAVE_SECURITY_REG(1, 25, SPI6); +DEFINE_SLAVE_SECURITY_REG(1, 24, SPI5); +DEFINE_SLAVE_SECURITY_REG(1, 23, SPI4); +DEFINE_SLAVE_SECURITY_REG(1, 22, SPI3); +DEFINE_SLAVE_SECURITY_REG(1, 21, SPI2); +DEFINE_SLAVE_SECURITY_REG(1, 20, SPI1); +DEFINE_SLAVE_SECURITY_REG(1, 15, UART_D); +DEFINE_SLAVE_SECURITY_REG(1, 14, UART_C); +DEFINE_SLAVE_SECURITY_REG(1, 13, UART_B); +DEFINE_SLAVE_SECURITY_REG(1, 12, UART_A); +DEFINE_SLAVE_SECURITY_REG(1, 11, EMCB); +DEFINE_SLAVE_SECURITY_REG(1, 10, MCB); +DEFINE_SLAVE_SECURITY_REG(1, 9, EMC1); +DEFINE_SLAVE_SECURITY_REG(1, 8, MC1); +DEFINE_SLAVE_SECURITY_REG(1, 5, EMC0); +DEFINE_SLAVE_SECURITY_REG(1, 4, MC0); + +DEFINE_SLAVE_SECURITY_REG(2, 21, FEK); +DEFINE_SLAVE_SECURITY_REG(2, 20, PKA1); +DEFINE_SLAVE_SECURITY_REG(2, 19, SE2); +DEFINE_SLAVE_SECURITY_REG(2, 16, DVFS); +DEFINE_SLAVE_SECURITY_REG(2, 15, MIPI_CAL); +DEFINE_SLAVE_SECURITY_REG(2, 14, XUSB_PADCTL); +DEFINE_SLAVE_SECURITY_REG(2, 13, XUSB_DEV); +DEFINE_SLAVE_SECURITY_REG(2, 12, XUSB_HOST); +DEFINE_SLAVE_SECURITY_REG(2, 11, APB2JTAG); +DEFINE_SLAVE_SECURITY_REG(2, 10, SOC_THERM); +DEFINE_SLAVE_SECURITY_REG(2, 9, DP2); +DEFINE_SLAVE_SECURITY_REG(2, 8, DDS); +DEFINE_SLAVE_SECURITY_REG(2, 7, MIPIBIF); +DEFINE_SLAVE_SECURITY_REG(2, 3, SDMMC4); +DEFINE_SLAVE_SECURITY_REG(2, 2, SDMMC3); +DEFINE_SLAVE_SECURITY_REG(2, 1, SDMMC2); +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) diff --git a/libexosphere/include/exosphere/tegra/tegra_avp_cache.hpp b/libexosphere/include/exosphere/tegra/tegra_avp_cache.hpp new file mode 100644 index 00000000..52e4c774 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_avp_cache.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#define AVP_CACHE_ADDRESS(x) (0x50040000 + x) + +#define AVP_CACHE_CONFIG (0x000) + +#define AVP_CACHE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (AVP_CACHE, NAME) +#define AVP_CACHE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (AVP_CACHE, NAME, VALUE) +#define AVP_CACHE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (AVP_CACHE, NAME, ENUM) +#define AVP_CACHE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(AVP_CACHE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_AVP_CACHE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (AVP_CACHE, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_AVP_CACHE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (AVP_CACHE, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_AVP_CACHE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (AVP_CACHE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_AVP_CACHE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(AVP_CACHE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_AVP_CACHE_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 (AVP_CACHE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_AVP_CACHE_REG_BIT_ENUM(DISABLE_WB, 10, FALSE, TRUE); +DEFINE_AVP_CACHE_REG_BIT_ENUM(DISABLE_RB, 11, FALSE, TRUE); diff --git a/libexosphere/include/exosphere/tegra/tegra_emc.hpp b/libexosphere/include/exosphere/tegra/tegra_emc.hpp new file mode 100644 index 00000000..f072b019 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_emc.hpp @@ -0,0 +1,90 @@ +/* + * 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 EMC_ADDRESS(x) (0x7001B000 + x) +#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_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (EMC, NAME) +#define EMC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (EMC, NAME, VALUE) +#define EMC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (EMC, NAME, ENUM) +#define EMC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(EMC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_EMC_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (EMC, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_EMC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (EMC, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_EMC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (EMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_EMC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(EMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_EMC_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 (EMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_EMC_REG_BIT_ENUM(CFG_DYN_SELF_REF, 28, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(CFG_DRAM_ACPD, 29, NO_POWERDOWN, ACTIVE_POWERDOWN); + +DEFINE_EMC_REG_BIT_ENUM(ADR_CFG_EMEM_NUMDEV, 0, N1, N2); + +DEFINE_EMC_REG_BIT_ENUM(TIMING_CONTROL_TIMING_UPDATE, 0, DISABLED, ENABLED); + +DEFINE_EMC_REG_BIT_ENUM(SELF_REF_SELF_REF_CMD, 0, DISABLED, ENABLED); +DEFINE_EMC_REG_BIT_ENUM(SELF_REF_ACTIVE_SELF_REF, 8, DISABLED, ENABLED); +DEFINE_EMC_REG_TWO_BIT_ENUM(SELF_REF_SREF_DEV_SELECTN, 30, BOTH, DEV1, DEV0, RESERVED); + +DEFINE_EMC_REG(MRW_OP, 0, 8); +DEFINE_EMC_REG(MRW_MA, 16, 8); +DEFINE_EMC_REG_TWO_BIT_ENUM(MRW_CNT, 26, SHORT, LONG, EXT1, EXT2); +DEFINE_EMC_REG_TWO_BIT_ENUM(MRW_DEV_SELECTN, 30, BOTH, DEV1, DEV0, RESERVED); + +DEFINE_EMC_REG_TWO_BIT_ENUM(FBIO_CFG5_DRAM_TYPE, 0, DDR4, LPDDR4, LPDDR2, DDR2); + +DEFINE_EMC_REG_BIT_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_MEASURE_STALL, 9, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_UPDATE_STALL, 10, DISABLE, ENABLE); +DEFINE_EMC_REG_BIT_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_START, 31, DISABLE, ENABLE); + +DEFINE_EMC_REG(REQ_CTRL_STALL_ALL_READS, 0, 1); +DEFINE_EMC_REG(REQ_CTRL_STALL_ALL_WRITES, 1, 1); + +DEFINE_EMC_REG_TWO_BIT_ENUM(EMC_STATUS_DRAM_IN_SELF_REFRESH, 8, DISABLED, DEV0_ENABLED, DEV1_ENABLED, BOTH_ENABLED); + +DEFINE_EMC_REG_BIT_ENUM(EMC_STATUS_DRAM_DEV0_IN_SELF_REFRESH, 8, DISABLED, ENABLED); + +DEFINE_EMC_REG_BIT_ENUM(EMC_STATUS_NO_OUTSTANDING_TRANSACTIONS, 2, WAITING, COMPLETED); +DEFINE_EMC_REG_BIT_ENUM(EMC_STATUS_TIMING_UPDATE_STALLED, 23, DONE, BUSY); + +DEFINE_EMC_REG_BIT_ENUM(CFG_DIG_DLL_CFG_DLL_EN, 0, DISABLED, ENABLED); + +DEFINE_EMC_REG(ZCAL_INTERVAL_LO, 0, 10); +DEFINE_EMC_REG(ZCAL_INTERVAL_HI, 10, 14); + +DEFINE_EMC_REG(PMC_SCRATCH3_DDR_CNTRL, 0, 19); +DEFINE_EMC_REG_BIT_ENUM(PMC_SCRATCH3_WEAK_BIAS, 30, DISABLED, ENABLED); + +DEFINE_EMC_REG_BIT_ENUM(FBIO_CFG7_CH1_ENABLE, 2, DISABLE, ENABLE); + diff --git a/libexosphere/include/exosphere/tegra/tegra_evp.hpp b/libexosphere/include/exosphere/tegra/tegra_evp.hpp new file mode 100644 index 00000000..27d61f7c --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_evp.hpp @@ -0,0 +1,19 @@ +/* + * 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 EVP_CPU_RESET_VECTOR (0x100) diff --git a/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp b/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp new file mode 100644 index 00000000..d7d3361e --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + + +#define FLOW_CTLR_FLOW_DBG_QUAL (0x050) +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL (0x098) + +#define FLOW_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (FLOW_CTLR, NAME) +#define FLOW_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (FLOW_CTLR, NAME, VALUE) +#define FLOW_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (FLOW_CTLR, NAME, ENUM) +#define FLOW_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(FLOW_CTLR, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_FLOW_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (FLOW_CTLR, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_FLOW_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (FLOW_CTLR, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_FLOW_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (FLOW_CTLR, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_FLOW_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(FLOW_CTLR, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_FLOW_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 (FLOW_CTLR, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_FLOW_REG_BIT_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, 28, DISABLE, ENABLE); + +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/libexosphere/include/exosphere/tegra/tegra_ictlr.hpp b/libexosphere/include/exosphere/tegra/tegra_ictlr.hpp new file mode 100644 index 00000000..6f11ee91 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_ictlr.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#define PRI_ICTLR(n) (0x60004000 + n) +#define SEC_ICTLR(n) (0x60004100 + n) +#define TRI_ICTLR(n) (0x60004200 + n) +#define QUAD_ICTLR(n) (0x60004300 + n) +#define PENTA_ICTLR(n) (0x60004400 + n) +#define HEXA_ICTLR(n) (0x60004500 + n) + +#define ICTLR_COP_IER_CLR (0x038) + diff --git a/libexosphere/include/exosphere/tegra/tegra_mc.hpp b/libexosphere/include/exosphere/tegra/tegra_mc.hpp new file mode 100644 index 00000000..b97b5c63 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_mc.hpp @@ -0,0 +1,329 @@ +/* + * 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 +#include + +#define MC_INTSTATUS (0x000) +#define MC_INTMASK (0x004) +#define MC_ERR_STATUS (0x008) +#define MC_ERR_ADR (0x00c) +#define MC_SMMU_CONFIG (0x010) +#define MC_SMMU_TLB_CONFIG (0x014) +#define MC_SMMU_PTC_CONFIG (0x018) +#define MC_SMMU_PTB_ASID (0x01c) +#define MC_SMMU_PTB_DATA (0x020) +#define MC_SMMU_TLB_FLUSH (0x030) +#define MC_SMMU_PTC_FLUSH (0x034) + +#define MC_SECURITY_CFG0 (0x070) +#define MC_SECURITY_CFG1 (0x074) +#define MC_SECURITY_CFG3 (0x9BC) + +#define MC_SMMU_TRANSLATION_ENABLE_0 (0x228) +#define MC_SMMU_TRANSLATION_ENABLE_1 (0x22C) +#define MC_SMMU_TRANSLATION_ENABLE_2 (0x230) +#define MC_SMMU_TRANSLATION_ENABLE_3 (0x234) +#define MC_SMMU_TRANSLATION_ENABLE_4 (0xB98) + +#define MC_SMMU_ASID_SECURITY (0x038) +#define MC_SMMU_ASID_SECURITY_1 (0x03c) +#define MC_SMMU_ASID_SECURITY_2 (0x9e0) +#define MC_SMMU_ASID_SECURITY_3 (0x9e4) +#define MC_SMMU_ASID_SECURITY_4 (0x9e8) +#define MC_SMMU_ASID_SECURITY_5 (0x9ec) +#define MC_SMMU_ASID_SECURITY_6 (0x9f0) +#define MC_SMMU_ASID_SECURITY_7 (0x9f4) + +#define MC_SEC_CARVEOUT_BOM (0x670) +#define MC_SEC_CARVEOUT_SIZE_MB (0x674) +#define MC_SEC_CARVEOUT_REG_CTRL (0x678) + +#define MC_VIDEO_PROTECT_BOM (0x648) +#define MC_VIDEO_PROTECT_SIZE_MB (0x64c) +#define MC_VIDEO_PROTECT_REG_CTRL (0x650) +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 (0x984) +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 (0x988) + +#define MC_MTS_CARVEOUT_BOM (0x9a0) +#define MC_MTS_CARVEOUT_SIZE_MB (0x9a4) +#define MC_MTS_CARVEOUT_ADR_HI (0x9a8) +#define MC_MTS_CARVEOUT_REG_CTRL (0x9ac) + +#define MC_SECURITY_CARVEOUT1_CFG0 (0xc08) +#define MC_SECURITY_CARVEOUT1_BOM (0xc0c) +#define MC_SECURITY_CARVEOUT1_BOM_HI (0xc10) +#define MC_SECURITY_CARVEOUT1_SIZE_128KB (0xc14) +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 (0xc18) +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 (0xc1c) +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 (0xc20) +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 (0xc24) +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 (0xc28) +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 (0xc2c) +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 (0xc30) +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 (0xc34) +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 (0xc38) +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 (0xc3c) + +#define MC_SECURITY_CARVEOUT2_CFG0 (0xc58) +#define MC_SECURITY_CARVEOUT2_BOM (0xc5c) +#define MC_SECURITY_CARVEOUT2_BOM_HI (0xc60) +#define MC_SECURITY_CARVEOUT2_SIZE_128KB (0xc64) +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 (0xc68) +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 (0xc6c) +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 (0xc70) +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 (0xc74) +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 (0xc78) +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 (0xc7c) +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 (0xc80) +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 (0xc84) +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 (0xc88) +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 (0xc8c) + +#define MC_SECURITY_CARVEOUT3_CFG0 (0xca8) +#define MC_SECURITY_CARVEOUT3_BOM (0xcac) +#define MC_SECURITY_CARVEOUT3_BOM_HI (0xcb0) +#define MC_SECURITY_CARVEOUT3_SIZE_128KB (0xcb4) +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 (0xcb8) +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 (0xcbc) +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 (0xcc0) +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 (0xcc4) +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 (0xcc8) +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 (0xccc) +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 (0xcd0) +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 (0xcd4) +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 (0xcd8) +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 (0xcdc) + +#define MC_SECURITY_CARVEOUT4_CFG0 (0xcf8) +#define MC_SECURITY_CARVEOUT4_BOM (0xcfc) +#define MC_SECURITY_CARVEOUT4_BOM_HI (0xd00) +#define MC_SECURITY_CARVEOUT4_SIZE_128KB (0xd04) +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 (0xd08) +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 (0xd0c) +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 (0xd10) +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 (0xd14) +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 (0xd18) +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 (0xd1c) +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 (0xd20) +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 (0xd24) +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 (0xd28) +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 (0xd2c) + +#define MC_SECURITY_CARVEOUT5_CFG0 (0xd48) +#define MC_SECURITY_CARVEOUT5_BOM (0xd4c) +#define MC_SECURITY_CARVEOUT5_BOM_HI (0xd50) +#define MC_SECURITY_CARVEOUT5_SIZE_128KB (0xd54) +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 (0xd58) +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 (0xd5c) +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 (0xd60) +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 (0xd64) +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 (0xd68) +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 (0xd6c) +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 (0xd70) +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 (0xd74) +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 (0xd78) +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 (0xd7c) + + +#define MC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (MC, NAME) +#define MC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (MC, NAME, VALUE) +#define MC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (MC, NAME, ENUM) +#define MC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(MC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_MC_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (MC, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_MC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (MC, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_MC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (MC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_MC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(MC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_MC_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 (MC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_MC_REG_BIT_ENUM(SMMU_CONFIG_SMMU_ENABLE, 0, DISABLE, ENABLE); + +DEFINE_MC_REG(SMMU_TLB_CONFIG_TLB_ACTIVE_LINES, 0, 6); +DEFINE_MC_REG_BIT_ENUM(SMMU_TLB_CONFIG_TLB_ROUND_ROBIN_ARBITRATION, 28, DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(SMMU_TLB_CONFIG_TLB_HIT_UNDER_MISS, 29, DISABLE, ENABLE); + +DEFINE_MC_REG(SMMU_PTC_CONFIG_PTC_INDEX_MAP, 0, 7); +DEFINE_MC_REG(SMMU_PTC_CONFIG_PTC_REQ_LIMIT, 24, 4); +DEFINE_MC_REG_BIT_ENUM(SMMU_PTC_CONFIG_PTC_CACHE_ENABLE, 29, DISABLE, ENABLE); + +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_0, 0, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, 1, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, 2, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, 3, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_4, 4, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_5, 5, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_6, 6, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_7, 7, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_8, 8, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_9, 9, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_10, 10, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_11, 11, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_12, 12, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_13, 13, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_14, 14, NONSECURE, SECURE); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_15, 15, NONSECURE, SECURE); + +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_0, 16, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_1, 17, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_2, 18, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_3, 19, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_4, 20, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_5, 21, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_6, 22, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_7, 23, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_8, 24, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_9, 25, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_10, 26, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_11, 27, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_12, 28, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_13, 29, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_14, 30, NONPROMOTING, PROMOTING); +DEFINE_MC_REG_BIT_ENUM(SMMU_ASID_SECURITY_PROMOTING_ASIDS_15, 31, NONPROMOTING, PROMOTING); + +DEFINE_MC_REG(SECURITY_CFG0_SECURITY_BOM, 20, 12); +DEFINE_MC_REG(SECURITY_CFG1_SECURITY_SIZE, 0, 13); +DEFINE_MC_REG(SECURITY_CFG3_SECURITY_BOM_HI, 0, 2); + +DEFINE_MC_REG_BIT_ENUM(SEC_CARVEOUT_REG_CTRL_SEC_CARVEOUT_WRITE_ACCESS, 0, ENABLED, DISABLED); + +DEFINE_MC_REG_BIT_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_WRITE_ACCESS, 0, ENABLED, DISABLED); +DEFINE_MC_REG_BIT_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_ALLOW_TZ_WRITE, 1, DISABLED, ENABLED); + +DEFINE_MC_REG_BIT_ENUM(MTS_CARVEOUT_REG_CTRL_MTS_CARVEOUT_WRITE_ACCESS, 0, ENABLED, DISABLED); + +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_PROTECT_MODE, 0, LOCKBIT_SECURE, TZ_SECURE); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_LOCK_MODE, 1, UNLOCKED, LOCKED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, 2, ANY_ADDRESS, UNTRANSLATED_ONLY); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, 3, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, 4, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, 5, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, 6, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, 7, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, 8, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, 9, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, 10, DISABLED, ENABLED); +DEFINE_MC_REG(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 11, 3); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, 14, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, 15, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, 16, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, 17, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, 18, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, 19, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, 20, ENABLE_CHECKS, DISABLE_CHECKS); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, 21, ENABLE_CHECKS, DISABLE_CHECKS); + +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, 22, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, 23, DISABLED, BYPASS_CHECK); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, 24, DISABLED, BYPASS_CHECK); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, 25, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, 26, DISABLED, ENABLED); +DEFINE_MC_REG_BIT_ENUM(SECURITY_CARVEOUT_CFG0_IS_WPR, 27, DISABLED, ENABLED); + +#define MC_CLIENT_ACCESS_NUM_CLIENTS 32 + +/* _ACCESS0 */ +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_PTCR, ( 0 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0A, ( 1 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0AB, ( 2 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0B, ( 3 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0BB, ( 4 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0C, ( 5 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAY0CB, ( 6 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_AFIR, ( 14 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_AVPCARM7R, ( 15 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAYHC, ( 16 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_DISPLAYHCB, ( 17 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_HDAR, ( 21 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_HOST1XDMAR, ( 22 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_HOST1XR, ( 23 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_NVENCSRD, ( 28 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_PPCSAHBDMAR, ( 29 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_PPCSAHBSLVR, ( 30 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS0_SATAR, ( 31 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 0)), DISABLE, ENABLE); + +/* _ACCESS1 */ +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDEBSEVR, ( 34 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDEMBER, ( 35 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDEMCER, ( 36 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDETPER, ( 37 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_MPCORELPR, ( 38 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_MPCORER, ( 39 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_NVENCSWR, ( 43 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_AFIW, ( 49 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_AVPCARM7W, ( 50 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_HDAW, ( 53 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_HOST1XW, ( 54 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_MPCORELPW, ( 56 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_MPCOREW, ( 57 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_PPCSAHBDMAW, ( 59 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_PPCSAHBSLVW, ( 60 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_SATAW, ( 61 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDEBSEVW, ( 62 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS1_VDEDBGW, ( 63 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 1)), DISABLE, ENABLE); + +/* _ACCESS2 */ +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_VDEMBEW, ( 64 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_VDETPMW, ( 65 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPRA, ( 68 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPWA, ( 70 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPWB, ( 71 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_XUSB_HOSTR, ( 74 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_XUSB_HOSTW, ( 75 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_XUSB_DEVR, ( 76 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_XUSB_DEVW, ( 77 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPRAB, ( 78 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPWAB, ( 80 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_ISPWBB, ( 81 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_TSECSRD, ( 84 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_TSECSWR, ( 85 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_A9AVPSCR, ( 86 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_A9AVPSCW, ( 87 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_GPUSRD, ( 88 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_GPUSWR, ( 89 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS2_DISPLAYT, ( 90 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 2)), DISABLE, ENABLE); + +/* _ACCESS3 */ +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCRA, ( 96 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCRAA, ( 97 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCR, ( 98 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCRAB, ( 99 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCWA, (100 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCWAA, (101 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCW, (102 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_SDMMCWAB, (103 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_VICSRD, (108 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_VICSWR, (109 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_VIW, (114 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_DISPLAYD, (115 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_NVDECSRD, (120 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_NVDECSWR, (121 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_APER, (122 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_APEW, (123 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_NVJPGSRD, (126 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS3_NVJPGSWR, (127 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 3)), DISABLE, ENABLE); + +/* _ACCESS4 */ +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_SESRD, (128 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_SESWR, (129 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_AXIAPR, (130 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_AXIAPW, (131 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_ETRR, (132 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_ETRW, (133 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_TSECRDB, (134 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_TSECWRB, (135 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_GPUSRD2, (136 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); +DEFINE_MC_REG_BIT_ENUM(CLIENT_ACCESS4_GPUSWR2, (137 - (MC_CLIENT_ACCESS_NUM_CLIENTS * 4)), DISABLE, ENABLE); diff --git a/libexosphere/include/exosphere/tegra/tegra_mselect.hpp b/libexosphere/include/exosphere/tegra/tegra_mselect.hpp new file mode 100644 index 00000000..20c5530d --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_mselect.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#define MSELECT(x) (0x50060000 + x) + +#define MSELECT_CONFIG (0x000) + diff --git a/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libexosphere/include/exosphere/tegra/tegra_pmc.hpp new file mode 100644 index 00000000..ee10391f --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_pmc.hpp @@ -0,0 +1,156 @@ +/* + * 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 +#include + +#define APBDEV_PMC_CNTRL (0x000) +#define APBDEV_PMC_DPD_SAMPLE (0x020) +#define APBDEV_PMC_DPD_ENABLE (0x024) +#define APBDEV_PMC_CLAMP_STATUS (0x02C) +#define APBDEV_PMC_PWRGATE_TOGGLE (0x030) +#define APBDEV_PMC_PWRGATE_STATUS (0x038) +#define APBDEV_PMC_SCRATCH0 (0x050) +#define APBDEV_PMC_SCRATCH1 (0x054) +#define APBDEV_PMC_SCRATCH12 (0x080) +#define APBDEV_PMC_SCRATCH13 (0x084) +#define APBDEV_PMC_SCRATCH18 (0x098) +#define APBDEV_PMC_SCRATCH20 (0x0A0) +#define APBDEV_PMC_CRYPTO_OP (0x0F4) +#define APBDEV_PM (0x014) +#define APBDEV_PMC_WAKE2_STATUS (0x168) +#define APBDEV_PMC_WEAK_BIAS (0x2C8) +#define APBDEV_PMC_CNTRL2 (0x440) +#define APBDEV_PMC_FUSE_CTRL (0x450) +#define APBDEV_PMC_IO_DPD3_REQ (0x45C) +#define APBDEV_PMC_IO_DPD3_STATUS (0x460) +#define APBDEV_PMC_IO_DPD4_REQ (0x464) +#define APBDEV_PMC_IO_DPD4_STATUS (0x468) +#define APBDEV_PMC_SET_SW_CLAMP (0x47C) +#define APBDEV_PMC_DDR_CNTRL (0x4E4) +#define APBDEV_PMC_SEC_DISABLE (0x004) +#define APBDEV_PMC_SEC_DISABLE2 (0x2C4) +#define APBDEV_PMC_SEC_DISABLE3 (0x2D8) +#define APBDEV_PMC_SEC_DISABLE4 (0x5B0) +#define APBDEV_PMC_SEC_DISABLE5 (0x5B4) +#define APBDEV_PMC_SEC_DISABLE6 (0x5B8) +#define APBDEV_PMC_SEC_DISABLE7 (0x5BC) +#define APBDEV_PMC_SEC_DISABLE8 (0x5C0) +#define APBDEV_PMC_SCRATCH43 (0x22C) +#define APBDEV_PMC_SCRATCH190 (0x818) +#define APBDEV_PMC_SCRATCH200 (0x840) +#define APBDEV_PMC_SEC_DISABLE3 (0x2D8) +#define APBDEV_PMC_SECURE_SCRATCH4 (0x0C0) +#define APBDEV_PMC_SECURE_SCRATCH5 (0x0C4) +#define APBDEV_PMC_SECURE_SCRATCH6 (0x224) +#define APBDEV_PMC_SECURE_SCRATCH7 (0x228) +#define APBDEV_PMC_SECURE_SCRATCH16 (0x320) +#define APBDEV_PMC_SECURE_SCRATCH21 (0x334) +#define APBDEV_PMC_SECURE_SCRATCH24 (0x340) +#define APBDEV_PMC_SECURE_SCRATCH25 (0x344) +#define APBDEV_PMC_SECURE_SCRATCH26 (0x348) +#define APBDEV_PMC_SECURE_SCRATCH27 (0x34C) +#define APBDEV_PMC_SECURE_SCRATCH32 (0x360) +#define APBDEV_PMC_SECURE_SCRATCH34 (0x368) +#define APBDEV_PMC_SECURE_SCRATCH35 (0x36C) +#define APBDEV_PMC_SECURE_SCRATCH39 (0x37C) +#define APBDEV_PMC_SECURE_SCRATCH51 (0x3AC) +#define APBDEV_PMC_SECURE_SCRATCH55 (0x3BC) +#define APBDEV_PMC_SECURE_SCRATCH74 (0x408) +#define APBDEV_PMC_SECURE_SCRATCH75 (0x40C) +#define APBDEV_PMC_SECURE_SCRATCH76 (0x410) +#define APBDEV_PMC_SECURE_SCRATCH77 (0x414) +#define APBDEV_PMC_SECURE_SCRATCH78 (0x418) +#define APBDEV_PMC_SECURE_SCRATCH99 (0xAE4) +#define APBDEV_PMC_SECURE_SCRATCH100 (0xAE8) +#define APBDEV_PMC_SECURE_SCRATCH101 (0xAEC) +#define APBDEV_PMC_SECURE_SCRATCH102 (0xAF0) +#define APBDEV_PMC_SECURE_SCRATCH103 (0xAF4) +#define APBDEV_PMC_SECURE_SCRATCH112 (0xB18) +#define APBDEV_PMC_SECURE_SCRATCH113 (0xB1C) +#define APBDEV_PMC_SECURE_SCRATCH114 (0xB20) +#define APBDEV_PMC_SECURE_SCRATCH115 (0xB24) + + +#define PMC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (APBDEV_PMC, NAME) +#define PMC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (APBDEV_PMC, NAME, VALUE) +#define PMC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (APBDEV_PMC, NAME, ENUM) +#define PMC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(APBDEV_PMC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_PMC_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (APBDEV_PMC, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_PMC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_PMC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_PMC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_PMC_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 (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_PMC_REG_BIT_ENUM(CNTRL_MAIN_RESET, 4, DISABLE, ENABLE) + +DEFINE_PMC_REG_BIT_ENUM(DPD_SAMPLE_ON, 0, DISABLE, ENABLE); + +DEFINE_PMC_REG_BIT_ENUM(DPD_ENABLE_ON, 0, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(DPD_ENABLE_TSC_MULT_EN, 1, DISABLE, ENABLE); + +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CRAIL, 0, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE, 2, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_PCX, 3, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_MPE, 6, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_SAX, 8, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE1, 9, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE2, 10, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE3, 11, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE0, 14, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_C0NC, 15, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_SOR, 17, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DIS, 18, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DISB, 19, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBA, 20, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBB, 21, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBC, 22, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VIC, 23, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_IRAM, 24, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_NVDEC, 25, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_NVJPG, 26, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_AUD, 27, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DFD, 28, OFF, ON); +DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE2, 29, OFF, ON); + +DEFINE_PMC_REG(SET_SW_CLAMP_CRAIL, 0, 1); + +DEFINE_PMC_REG_TWO_BIT_ENUM(IO_DPD_REQ_CODE, 30, IDLE, DPD_OFF, DPD_ON, RESERVED3); + +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CRAIL, 0, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_TE, 1, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VE, 2, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_PCX, 3, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VDE, 4, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_MPE, 6, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_HEG, 7, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_SAX, 8, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE1, 9, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE2, 10, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE3, 11, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CELP, 12, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE0, 14, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_C0NC, 15, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_SOR, 17, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_C1NC, 16, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_DIS, 18, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_DISB, 19, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBA, 20, DISABLE, ENABLE); +DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBB, 21, DISABLE, ENABLE); +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); diff --git a/libexosphere/include/exosphere/tegra/tegra_sb.hpp b/libexosphere/include/exosphere/tegra/tegra_sb.hpp new file mode 100644 index 00000000..d6827ade --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_sb.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#define SB_CSR (0x200) +#define SB_AA64_RESET_LOW (0x230) +#define SB_AA64_RESET_HIGH (0x234) + + +#define SB_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SB, NAME) +#define SB_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SB, NAME, VALUE) +#define SB_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SB, NAME, ENUM) +#define SB_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SB, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_SB_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SB, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_SB_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SB, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_SB_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SB, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_SB_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SB, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_SB_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 (SB, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_SB_REG_BIT_ENUM(CSR_SECURE_BOOT_FLAG, 0, DISABLE, ENABLE); +DEFINE_SB_REG_BIT_ENUM(CSR_NS_RST_VEC_WR_DIS, 1, ENABLE, DISABLE); +DEFINE_SB_REG_BIT_ENUM(CSR_PIROM_DISABLE, 4, ENABLE, DISABLE); +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); diff --git a/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp b/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp new file mode 100644 index 00000000..a191641f --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp @@ -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 . + */ +#pragma once +#include + +#define SYSCTR0_CNTFID0 (0x020) +#define SYSCTR0_CNTFID1 (0x024) + + +#define SYSCTR0_COUNTERID4 (0xFD0) +#define SYSCTR0_COUNTERID5 (0xFD4) +#define SYSCTR0_COUNTERID6 (0xFD8) +#define SYSCTR0_COUNTERID7 (0xFDC) +#define SYSCTR0_COUNTERID0 (0xFE0) +#define SYSCTR0_COUNTERID1 (0xFE4) +#define SYSCTR0_COUNTERID2 (0xFE8) +#define SYSCTR0_COUNTERID3 (0xFEC) +#define SYSCTR0_COUNTERID8 (0xFF0) +#define SYSCTR0_COUNTERID9 (0xFF4) +#define SYSCTR0_COUNTERID10 (0xFF8) +#define SYSCTR0_COUNTERID11 (0xFFC) + +#define SYSCTR0_COUNTERID(n) SYSCTR0_COUNTERID##n \ No newline at end of file diff --git a/libexosphere/include/exosphere/tegra/tegra_timer.hpp b/libexosphere/include/exosphere/tegra/tegra_timer.hpp new file mode 100644 index 00000000..93a7c8b6 --- /dev/null +++ b/libexosphere/include/exosphere/tegra/tegra_timer.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + + +#define TIMER_SHARED_TIMER_SECURE_CFG (0x1A4) + +#define TIMER_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (TIMER, NAME) +#define TIMER_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (TIMER, NAME, VALUE) +#define TIMER_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (TIMER, NAME, ENUM) +#define TIMER_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(TIMER, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_TIMER_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (TIMER, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_TIMER_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (TIMER, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_TIMER_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (TIMER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#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_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); +DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_TMR8, 8, DISABLE, ENABLE); + +DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_WDT0, 12, DISABLE, ENABLE); +DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_WDT1, 13, DISABLE, ENABLE); +DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_WDT2, 14, DISABLE, ENABLE); +DEFINE_TIMER_REG_BIT_ENUM(SHARED_TIMER_SECURE_CFG_WDT3, 15, DISABLE, ENABLE); \ No newline at end of file diff --git a/libexosphere/include/exosphere/tsec.hpp b/libexosphere/include/exosphere/tsec.hpp new file mode 100644 index 00000000..454da2ef --- /dev/null +++ b/libexosphere/include/exosphere/tsec.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::tsec { + + void Lock(); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/uart.hpp b/libexosphere/include/exosphere/uart.hpp new file mode 100644 index 00000000..920f3912 --- /dev/null +++ b/libexosphere/include/exosphere/uart.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::uart { + + enum Port { + Port_A = 0, + Port_B = 1, + Port_C = 2, + + Port_Count = 3, + + Port_ReservedDebug = Port_A, + Port_RightJoyCon = Port_B, + Port_LeftJoyCon = Port_C, + }; + + enum Flags { + Flag_None = (0u << 0), + Flag_Inverted = (1u << 0), + }; + + void SetRegisterAddress(uintptr_t address); + + void Initialize(Port port, int baud_rate, u32 flags); + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/util.hpp b/libexosphere/include/exosphere/util.hpp new file mode 100644 index 00000000..088033e7 --- /dev/null +++ b/libexosphere/include/exosphere/util.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::util { + + void SetRegisterAddress(uintptr_t address); + + u32 GetMicroSeconds(); + void WaitMicroSeconds(int us); + + void ClearMemory(void *ptr, size_t size); + + template requires std::integral && std::integral + constexpr T DivideUp(T x, U y) { + return (x + (y - 1)) / y; + } + +} \ No newline at end of file diff --git a/libexosphere/include/exosphere/wdt.hpp b/libexosphere/include/exosphere/wdt.hpp new file mode 100644 index 00000000..16a02f26 --- /dev/null +++ b/libexosphere/include/exosphere/wdt.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::wdt { + + void SetRegisterAddress(uintptr_t address); + void Reboot(); + +} \ No newline at end of file diff --git a/libexosphere/source/actmon/actmon_api.cpp b/libexosphere/source/actmon/actmon_api.cpp new file mode 100644 index 00000000..ee7843cb --- /dev/null +++ b/libexosphere/source/actmon/actmon_api.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::actmon { + + namespace { + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceActivityMonitor.GetAddress(); + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void HandleInterrupt() { + /* TODO */ + } + + void StartMonitoringBpmp(InterruptHandler handler) { + /* TODO */ + } + + void StopMonitoringBpmp() { + /* TODO */ + } + +} \ No newline at end of file diff --git a/libexosphere/source/clkrst/clkrst_api.cpp b/libexosphere/source/clkrst/clkrst_api.cpp new file mode 100644 index 00000000..c2de3028 --- /dev/null +++ b/libexosphere/source/clkrst/clkrst_api.cpp @@ -0,0 +1,98 @@ +/* + * 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 "clkrst_registers.hpp" + +namespace ams::clkrst { + + namespace { + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); + + struct ClockParameters { + uintptr_t reset_offset; + uintptr_t clk_enb_offset; + uintptr_t clk_src_offset; + u8 index; + u8 clk_src; + u8 clk_div; + }; + + void EnableClock(const ClockParameters ¶m) { + /* Hold reset. */ + reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1)); + + /* Disable clock. */ + reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0)); + + /* Set the clock source. */ + if (param.clk_src != 0) { + reg::Write(g_register_address + param.clk_src_offset, (param.clk_src << 29) | (param.clk_div << 0)); + } + + /* Enable clk. */ + reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 1)); + + /* Release reset. */ + reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 0)); + } + + // void DisableClock(const ClockParameters ¶m) { + // /* Hold reset. */ + // reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1)); + // + // /* Disable clock. */ + // reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0)); + // } + + #define DEFINE_CLOCK_PARAMETERS(_VARNAME_, _REG_, _NAME_, _CLK_, _DIV_) \ + constexpr inline const ClockParameters _VARNAME_ = { \ + .reset_offset = CLK_RST_CONTROLLER_RST_DEVICES_##_REG_, \ + .clk_enb_offset = CLK_RST_CONTROLLER_CLK_OUT_ENB_##_REG_, \ + .clk_src_offset = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_, \ + .index = CLK_RST_CONTROLLER_CLK_ENB_##_NAME_##_INDEX, \ + .clk_src = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_##_##_NAME_##_CLK_SRC_##_CLK_, \ + .clk_div = _DIV_, \ + } + + DEFINE_CLOCK_PARAMETERS(UartAClock, L, UARTA, PLLP_OUT0, 0); + DEFINE_CLOCK_PARAMETERS(UartBClock, L, UARTB, PLLP_OUT0, 0); + DEFINE_CLOCK_PARAMETERS(UartCClock, H, UARTC, PLLP_OUT0, 0); + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void SetFuseVisibility(bool visible) { + reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_MISC_CLK_ENB, CLK_RST_REG_BITS_VALUE(MISC_CLK_ENB_CFG_ALL_VISIBLE, visible ? 1 : 0)); + } + + void EnableUartAClock() { + EnableClock(UartAClock); + } + + void EnableUartBClock() { + EnableClock(UartAClock); + } + + void EnableUartCClock() { + EnableClock(UartAClock); + } + + +} \ No newline at end of file diff --git a/libexosphere/source/clkrst/clkrst_registers.hpp b/libexosphere/source/clkrst/clkrst_registers.hpp new file mode 100644 index 00000000..5d5cd087 --- /dev/null +++ b/libexosphere/source/clkrst/clkrst_registers.hpp @@ -0,0 +1,71 @@ +/* + * 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::clkrst { + + /* Clock source enums. */ + #define CLK_RST_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (CLK_RST_CONTROLLER, NAME) + #define CLK_RST_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (CLK_RST_CONTROLLER, NAME, VALUE) + #define CLK_RST_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (CLK_RST_CONTROLLER, NAME, ENUM) + #define CLK_RST_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(CLK_RST_CONTROLLER, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + + #define DEFINE_CLK_RST_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (CLK_RST_CONTROLLER, NAME, __OFFSET__, __WIDTH__) + #define DEFINE_CLK_RST_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (CLK_RST_CONTROLLER, NAME, __OFFSET__, ZERO, ONE) + #define DEFINE_CLK_RST_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (CLK_RST_CONTROLLER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) + #define DEFINE_CLK_RST_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(CLK_RST_CONTROLLER, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) + #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_MISC_CLK_ENB (0x048) + + DEFINE_CLK_RST_REG(MISC_CLK_ENB_CFG_ALL_VISIBLE, 28, 1); + + /* RST_DEVICES */ + #define CLK_RST_CONTROLLER_RST_DEVICES_L (0x004) + #define CLK_RST_CONTROLLER_RST_DEVICES_H (0x008) + #define CLK_RST_CONTROLLER_RST_DEVICES_U (0x00C) + #define CLK_RST_CONTROLLER_RST_DEVICES_X (0x28C) + #define CLK_RST_CONTROLLER_RST_DEVICES_Y (0x2A4) + #define CLK_RST_CONTROLLER_RST_DEVICES_V (0x358) + #define CLK_RST_CONTROLLER_RST_DEVICES_W (0x35C) + + /* CLK_OUT_ENB */ + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_L (0x010) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_H (0x014) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_U (0x018) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_X (0x280) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y (0x298) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_V (0x360) + #define CLK_RST_CONTROLLER_CLK_OUT_ENB_W (0x364) + + /* CLK_SOURCE */ + #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA (0x178) + #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB (0x17C) + #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0) + + /* CLK_ENB_*_INDEX */ + #define CLK_RST_CONTROLLER_CLK_ENB_UARTA_INDEX (0x06) + #define CLK_RST_CONTROLLER_CLK_ENB_UARTB_INDEX (0x07) + #define CLK_RST_CONTROLLER_CLK_ENB_UARTC_INDEX (0x17) + + 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) + +} diff --git a/libexosphere/source/fuse/fuse_api.cpp b/libexosphere/source/fuse/fuse_api.cpp new file mode 100644 index 00000000..73f48494 --- /dev/null +++ b/libexosphere/source/fuse/fuse_api.cpp @@ -0,0 +1,121 @@ +/* + * 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 "fuse_registers.hpp" + +namespace ams::fuse { + + namespace { + + struct OdmWord4 { + using HardwareState1 = util::BitPack32::Field<0, 2, int>; + using HardwareType1 = util::BitPack32::Field; + using DramId = util::BitPack32::Field; + using HardwareType2 = util::BitPack32::Field; + using HardwareState2 = util::BitPack32::Field; + using QuestState = util::BitPack32::Field; + using FormatVersion = util::BitPack32::Field; + using Reserved = util::BitPack32::Field; + using HardwareType3 = util::BitPack32::Field; + }; + + constexpr ALWAYS_INLINE int GetHardwareStateValue(const util::BitPack32 odm_word4) { + constexpr auto HardwareState1Shift = 0; + constexpr auto HardwareState2Shift = OdmWord4::HardwareState1::Count + HardwareState1Shift; + + return (odm_word4.Get() << HardwareState1Shift) | + (odm_word4.Get() << HardwareState2Shift); + } + + constexpr ALWAYS_INLINE int GetHardwareTypeValue(const util::BitPack32 odm_word4) { + constexpr auto HardwareType1Shift = 0; + constexpr auto HardwareType2Shift = OdmWord4::HardwareType1::Count + HardwareType1Shift; + constexpr auto HardwareType3Shift = OdmWord4::HardwareType2::Count + HardwareType2Shift; + + return (odm_word4.Get() << HardwareType1Shift) | + (odm_word4.Get() << HardwareType2Shift) | + (odm_word4.Get() << HardwareType3Shift); + } + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFuses.GetAddress(); + + ALWAYS_INLINE volatile FuseRegisterRegion *GetRegisterRegion() { + return reinterpret_cast(g_register_address); + } + + ALWAYS_INLINE volatile FuseRegisters &GetRegisters() { + return GetRegisterRegion()->fuse; + } + + ALWAYS_INLINE volatile FuseChipRegisters &GetChipRegisters() { + return GetRegisterRegion()->chip; + } + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void SetWriteSecureOnly() { + reg::Write(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE)); + } + + void Lockout() { + reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_DISABLEREGPROGRAM_VAL, ENABLE)); + } + + u32 GetOdmWord(int index) { + return GetChipRegisters().FUSE_RESERVED_ODM[index]; + } + + HardwareType GetHardwareType() { + /* Read the odm word. */ + const util::BitPack32 odm_word4 = { GetOdmWord(4) }; + + /* Get the value. */ + const auto value = GetHardwareTypeValue(odm_word4); + + switch (value) { + case 0x01: return HardwareType_Icosa; + case 0x02: return (true /* TODO: GetSocType() == SocType_Mariko */) ? HardwareType_Calcio : HardwareType_Copper; + case 0x04: return HardwareType_Iowa; + case 0x08: return HardwareType_Hoag; + case 0x10: return HardwareType_Five; + default: return HardwareType_Undefined; + } + } + + HardwareState GetHardwareState() { + /* Read the odm word. */ + const util::BitPack32 odm_word4 = { GetOdmWord(4) }; + + /* Get the value. */ + const auto value = GetHardwareStateValue(odm_word4); + + switch (value) { + case 3: return HardwareState_Development; + case 4: return HardwareState_Production; + default: return HardwareState_Undefined; + } + } + + pmic::Regulator GetRegulator() { + /* TODO: How should mariko be handled? This reads from ODM word 28 in fuses (not presesnt in erista...). */ + return pmic::Regulator_Erista_Max77621; + } + +} \ No newline at end of file diff --git a/libexosphere/source/fuse/fuse_registers.hpp b/libexosphere/source/fuse/fuse_registers.hpp new file mode 100644 index 00000000..012ef2a8 --- /dev/null +++ b/libexosphere/source/fuse/fuse_registers.hpp @@ -0,0 +1,221 @@ +/* + * 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::fuse { + + struct FuseRegisters { + u32 FUSE_FUSECTRL; + u32 FUSE_FUSEADDR; + u32 FUSE_FUSERDATA; + u32 FUSE_FUSEWDATA; + u32 FUSE_FUSETIME_RD1; + u32 FUSE_FUSETIME_RD2; + u32 FUSE_FUSETIME_PGM1; + u32 FUSE_FUSETIME_PGM2; + u32 FUSE_PRIV2INTFC_START; + u32 FUSE_FUSEBYPASS; + u32 FUSE_PRIVATEKEYDISABLE; + u32 FUSE_DISABLEREGPROGRAM; + u32 FUSE_WRITE_ACCESS_SW; + u32 FUSE_PWR_GOOD_SW; + u32 _0x38; + u32 FUSE_PRIV2RESHIFT; + u32 _0x40[0x3]; + u32 FUSE_FUSETIME_RD3; + u32 _0x50[0xC]; + u32 FUSE_PRIVATE_KEY0_NONZERO; + u32 FUSE_PRIVATE_KEY1_NONZERO; + u32 FUSE_PRIVATE_KEY2_NONZERO; + u32 FUSE_PRIVATE_KEY3_NONZERO; + u32 FUSE_PRIVATE_KEY4_NONZERO; + u32 _0x94[0x1B]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(FuseRegisters) == 0x100); + + struct FuseChipRegisters { + u32 FUSE_PRODUCTION_MODE; + u32 FUSE_JTAG_SECUREID_VALID; + u32 FUSE_ODM_LOCK; + u32 FUSE_OPT_OPENGL_EN; + u32 FUSE_SKU_INFO; + u32 FUSE_CPU_SPEEDO_0_CALIB; + u32 FUSE_CPU_IDDQ_CALIB; + u32 FUSE_DAC_CRT_CALIB; + u32 FUSE_DAC_HDTV_CALIB; + u32 FUSE_DAC_SDTV_CALIB; + u32 FUSE_OPT_FT_REV; + u32 FUSE_CPU_SPEEDO_1_CALIB; + u32 FUSE_CPU_SPEEDO_2_CALIB; + u32 FUSE_SOC_SPEEDO_0_CALIB; + u32 FUSE_SOC_SPEEDO_1_CALIB; + u32 FUSE_SOC_SPEEDO_2_CALIB; + u32 FUSE_SOC_IDDQ_CALIB; + u32 FUSE_RESERVED_PRODUCTION_WP; + u32 FUSE_FA; + u32 FUSE_RESERVED_PRODUCTION; + u32 FUSE_HDMI_LANE0_CALIB; + u32 FUSE_HDMI_LANE1_CALIB; + u32 FUSE_HDMI_LANE2_CALIB; + u32 FUSE_HDMI_LANE3_CALIB; + u32 FUSE_ENCRYPTION_RATE; + u32 FUSE_PUBLIC_KEY[0x8]; + u32 FUSE_TSENSOR1_CALIB; + u32 FUSE_TSENSOR2_CALIB; + u32 FUSE_VSENSOR_CALIB; + u32 FUSE_OPT_CP_REV; + u32 FUSE_OPT_PFG; + u32 FUSE_TSENSOR0_CALIB; + u32 FUSE_FIRST_BOOTROM_PATCH_SIZE; + u32 FUSE_SECURITY_MODE; + u32 FUSE_PRIVATE_KEY[0x5]; + u32 FUSE_ARM_JTAG_DIS; + u32 FUSE_BOOT_DEVICE_INFO; + u32 FUSE_RESERVED_SW; + u32 FUSE_OPT_VP9_DISABLE; + u32 FUSE_RESERVED_ODM[0x8]; + u32 FUSE_OBS_DIS; + u32 FUSE_NOR_INFO; + u32 FUSE_USB_CALIB; + u32 FUSE_SKU_DIRECT_CONFIG; + u32 FUSE_KFUSE_PRIVKEY_CTRL; + u32 FUSE_PACKAGE_INFO; + u32 FUSE_OPT_VENDOR_CODE; + u32 FUSE_OPT_FAB_CODE; + u32 FUSE_OPT_LOT_CODE_0; + u32 FUSE_OPT_LOT_CODE_1; + u32 FUSE_OPT_WAFER_ID; + u32 FUSE_OPT_X_COORDINATE; + u32 FUSE_OPT_Y_COORDINATE; + u32 FUSE_OPT_SEC_DEBUG_EN; + u32 FUSE_OPT_OPS_RESERVED; + u32 FUSE_SATA_CALIB; + u32 FUSE_GPU_IDDQ_CALIB; + u32 FUSE_TSENSOR3_CALIB; + u32 FUSE_SKU_BOND_OUT_L; + u32 FUSE_SKU_BOND_OUT_H; + u32 FUSE_SKU_BOND_OUT_U; + u32 FUSE_SKU_BOND_OUT_V; + u32 FUSE_SKU_BOND_OUT_W; + u32 FUSE_OPT_SAMPLE_TYPE; + u32 FUSE_OPT_SUBREVISION; + u32 FUSE_OPT_SW_RESERVED_0; + u32 FUSE_OPT_SW_RESERVED_1; + u32 FUSE_TSENSOR4_CALIB; + u32 FUSE_TSENSOR5_CALIB; + u32 FUSE_TSENSOR6_CALIB; + u32 FUSE_TSENSOR7_CALIB; + u32 FUSE_OPT_PRIV_SEC_EN; + u32 FUSE_PKC_DISABLE; + u32 _0x16C; + u32 _0x170; + u32 _0x174; + u32 _0x178; + u32 FUSE_FUSE2TSEC_DEBUG_DISABLE; + u32 FUSE_TSENSOR_COMMON; + u32 FUSE_OPT_CP_BIN; + u32 FUSE_OPT_GPU_DISABLE; + u32 FUSE_OPT_FT_BIN; + u32 FUSE_OPT_DONE_MAP; + u32 _0x194; + u32 FUSE_APB2JTAG_DISABLE; + u32 FUSE_ODM_INFO; + u32 _0x1A0; + u32 _0x1A4; + u32 FUSE_ARM_CRYPT_DE_FEATURE; + u32 _0x1AC; + u32 _0x1B0; + u32 _0x1B4; + u32 _0x1B8; + u32 _0x1BC; + u32 FUSE_WOA_SKU_FLAG; + u32 FUSE_ECO_RESERVE_1; + u32 FUSE_GCPLEX_CONFIG_FUSE; + u32 FUSE_PRODUCTION_MONTH; + u32 FUSE_RAM_REPAIR_INDICATOR; + u32 FUSE_TSENSOR9_CALIB; + u32 _0x1D8; + u32 FUSE_VMIN_CALIBRATION; + u32 FUSE_AGING_SENSOR_CALIBRATION; + u32 FUSE_DEBUG_AUTHENTICATION; + u32 FUSE_SECURE_PROVISION_INDEX; + u32 FUSE_SECURE_PROVISION_INFO; + u32 FUSE_OPT_GPU_DISABLE_CP1; + u32 FUSE_SPARE_ENDIS; + u32 FUSE_ECO_RESERVE_0; + u32 _0x1FC; + u32 _0x200; + u32 FUSE_RESERVED_CALIB0; + u32 FUSE_RESERVED_CALIB1; + u32 FUSE_OPT_GPU_TPC0_DISABLE; + u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1; + u32 FUSE_OPT_CPU_DISABLE; + u32 FUSE_OPT_CPU_DISABLE_CP1; + u32 FUSE_TSENSOR10_CALIB; + u32 FUSE_TSENSOR10_CALIB_AUX; + u32 FUSE_OPT_RAM_SVOP_DP; + u32 FUSE_OPT_RAM_SVOP_PDP; + u32 FUSE_OPT_RAM_SVOP_REG; + u32 FUSE_OPT_RAM_SVOP_SP; + u32 FUSE_OPT_RAM_SVOP_SMPDP; + u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2; + u32 FUSE_OPT_GPU_TPC1_DISABLE; + u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1; + u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2; + u32 FUSE_OPT_CPU_DISABLE_CP2; + u32 FUSE_OPT_GPU_DISABLE_CP2; + u32 FUSE_USB_CALIB_EXT; + u32 FUSE_RESERVED_FIELD; + u32 FUSE_OPT_ECC_EN; + u32 _0x25C; + u32 _0x260; + u32 _0x264; + u32 _0x268; + u32 _0x26C; + u32 _0x270; + u32 _0x274; + u32 _0x278; + u32 FUSE_SPARE_REALIGNMENT_REG; + u32 FUSE_SPARE_BIT[0x20]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(FuseChipRegisters) == 0x300); + + struct FuseRegisterRegion { + FuseRegisters fuse; + FuseChipRegisters chip; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(FuseRegisterRegion) == secmon::MemoryRegionPhysicalDeviceFuses.GetSize()); + + #define FUSE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (FUSE, NAME) + #define FUSE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (FUSE, NAME, VALUE) + #define FUSE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (FUSE, NAME, ENUM) + #define FUSE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(FUSE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + + #define DEFINE_FUSE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (FUSE, NAME, __OFFSET__, __WIDTH__) + #define DEFINE_FUSE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE) + #define DEFINE_FUSE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) + #define DEFINE_FUSE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) + #define DEFINE_FUSE_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 (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + + 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); + +} diff --git a/libexosphere/source/gic/gic_api.cpp b/libexosphere/source/gic/gic_api.cpp new file mode 100644 index 00000000..70e36002 --- /dev/null +++ b/libexosphere/source/gic/gic_api.cpp @@ -0,0 +1,217 @@ +/* + * 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::gic { + + namespace { + + struct GicDistributor { + u32 ctlr; + u32 typer; + u32 iidr; + u32 reserved_0x0c; + u32 statusr; + u32 reserved_0x14[3]; + u32 impldef_0x20[8]; + u32 setspi_nsr; + u32 reserved_0x44; + u32 clrspi_nsr; + u32 reserved_0x4c; + u32 setspi_sr; + u32 reserved_0x54; + u32 clrspi_sr; + u32 reserved_0x5c[9]; + u32 igroupr[32]; + u32 isenabler[32]; + u32 icenabler[32]; + u32 ispendr[32]; + u32 icpendr[32]; + u32 isactiver[32]; + u32 icactiver[32]; + union { + u8 bytes[1020]; + u32 words[255]; + } ipriorityr; + u32 _0x7fc; + union { + u8 bytes[1020]; + u32 words[255]; + } itargetsr; + u32 _0xbfc; + u32 icfgr[64]; + u32 igrpmodr[32]; + u32 _0xd80[32]; + u32 nsacr[64]; + u32 sgir; + u32 _0xf04[3]; + u32 cpendsgir[4]; + u32 spendsgir[4]; + u32 reserved_0xf30[52]; + + static constexpr size_t SgirCpuTargetListShift = 16; + + enum SgirTargetListFilter : u32 { + SgirTargetListFilter_CpuTargetList = (0 << 24), + SgirTargetListFilter_Others = (1 << 24), + SgirTargetListFilter_Self = (2 << 24), + SgirTargetListFilter_Reserved = (3 << 24), + }; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(GicDistributor) == 0x1000); + static_assert(sizeof(GicDistributor) == secmon::MemoryRegionPhysicalDeviceGicDistributor.GetSize()); + + struct GicCpuInterface { + u32 ctlr; + u32 pmr; + u32 bpr; + u32 iar; + u32 eoir; + u32 rpr; + u32 hppir; + u32 abpr; + u32 aiar; + u32 aeoir; + u32 ahppir; + u32 statusr; + u32 reserved_30[4]; + u32 impldef_40[36]; + u32 apr[4]; + u32 nsapr[4]; + u32 reserved_f0[3]; + u32 iidr; + u32 reserved_100[960]; + u32 dir; + u32 _0x1004[1023]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(GicCpuInterface) == 0x2000); + static_assert(sizeof(GicCpuInterface) == secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetSize()); + + constexpr inline int InterruptWords = InterruptCount / BITSIZEOF(u32); + constexpr inline int SpiIndex = BITSIZEOF(u32); + + constinit uintptr_t g_distributor_address = secmon::MemoryRegionPhysicalDeviceGicDistributor.GetAddress(); + constinit uintptr_t g_cpu_interface_address = secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetAddress(); + + volatile GicDistributor *GetDistributor() { + return reinterpret_cast(g_distributor_address); + } + + volatile GicCpuInterface *GetCpuInterface() { + return reinterpret_cast(g_cpu_interface_address); + } + + void ReadWrite(uintptr_t address, int width, int i, u32 value) { + /* This code will never be invoked with a negative interrupt id. */ + AMS_ASSUME(i >= 0); + + const int scale = BITSIZEOF(u32) / width; + const int word = i / scale; + const int bit = (i % scale) * width; + + reg::ReadWrite(address + sizeof(u32) * word, REG_BITS_VALUE(bit, width, value)); + } + + void Write(uintptr_t address, int width, int i, u32 value) { + /* This code will never be invoked with a negative interrupt id. */ + AMS_ASSUME(i >= 0); + + const int scale = BITSIZEOF(u32) / width; + const int word = i / scale; + const int bit = (i % scale) * width; + + reg::Write(address + sizeof(u32) * word, value << bit); + } + + } + + void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address) { + g_distributor_address = distributor_address; + g_cpu_interface_address = cpu_interface_address; + } + + void InitializeCommon() { + /* Get the gicd registers. */ + auto *gicd = GetDistributor(); + + /* Set IGROUPR for to be FFs. */ + for (int i = SpiIndex / BITSIZEOF(u32); i < InterruptWords; ++i) { + gicd->igroupr[i] = 0xFFFFFFFFu; + } + + /* Set IPRIORITYR for spi interrupts to be 0x80. */ + for (int i = SpiIndex; i < InterruptCount; ++i) { + gicd->ipriorityr.bytes[i] = 0x80; + } + + /* Enable group 0. */ + gicd->ctlr = 1; + } + + void InitializeCoreUnique() { + /* Get the registers. */ + auto *gicd = GetDistributor(); + auto *gicc = GetCpuInterface(); + + /* Set IGROUPR0 to be FFs. */ + gicd->igroupr[0] = 0xFFFFFFFFu; + + /* Set IPRIORITYR for core local interrupts to be 0x80. */ + for (int i = 0; i < SpiIndex; ++i) { + gicd->ipriorityr.bytes[i] = 0x80; + } + + /* Enable group 0 as FIQs. */ + gicc->ctlr = 0x1D9; + + /* Set PMR. */ + gicc->pmr = 0x80; + + /* Set BPR. */ + gicc->bpr = 7; + } + + void SetPriority(int interrupt_id, int priority) { + ReadWrite(g_distributor_address + offsetof(GicDistributor, ipriorityr), BITSIZEOF(u8), interrupt_id, priority); + } + + void SetInterruptGroup(int interrupt_id, int group) { + ReadWrite(g_distributor_address + offsetof(GicDistributor, igroupr), 1, interrupt_id, group); + } + + void SetEnable(int interrupt_id, bool enable) { + Write(g_distributor_address + offsetof(GicDistributor, isenabler), 1, interrupt_id, enable); + } + + void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask) { + ReadWrite(g_distributor_address + offsetof(GicDistributor, itargetsr), BITSIZEOF(u8), interrupt_id, cpu_mask); + } + + void SetSpiMode(int interrupt_id, InterruptMode mode) { + ReadWrite(g_distributor_address + offsetof(GicDistributor, icfgr), 2, interrupt_id, static_cast(mode) << 1); + } + + int GetInterruptRequestId() { + return reg::Read(GetCpuInterface()->iar); + } + + void SetEndOfInterrupt(int interrupt_id) { + reg::Write(GetCpuInterface()->eoir, interrupt_id); + } + +} diff --git a/libexosphere/source/hw/hw_cache.arch.arm64.cpp b/libexosphere/source/hw/hw_cache.arch.arm64.cpp new file mode 100644 index 00000000..be19c118 --- /dev/null +++ b/libexosphere/source/hw/hw_cache.arch.arm64.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::hw::arch::arm64 { + + void FlushDataCache(const void *ptr, size_t size) { + const uintptr_t start = reinterpret_cast(ptr); + const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); + + for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { + FlushDataCacheLine(reinterpret_cast(cur)); + } + } + +} \ No newline at end of file diff --git a/libexosphere/source/i2c/i2c_api.cpp b/libexosphere/source/i2c/i2c_api.cpp new file mode 100644 index 00000000..10842976 --- /dev/null +++ b/libexosphere/source/i2c/i2c_api.cpp @@ -0,0 +1,202 @@ +/* + * 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 "i2c_registers.hpp" + +namespace ams::i2c { + + namespace { + + constexpr inline size_t MaxTransferSize = sizeof(u32); + + constinit std::array g_register_addresses = [] { + std::array arr = {}; + + arr[Port_1] = secmon::MemoryRegionPhysicalDeviceI2c1.GetAddress(); + arr[Port_5] = secmon::MemoryRegionPhysicalDeviceI2c5.GetAddress(); + + return arr; + }(); + + void LoadConfig(uintptr_t address) { + /* Configure for TIMEOUT and MSTR config load. */ + /* NOTE: Nintendo writes value 1 to reserved bit 5 here. This bit is documented as having no meaning. */ + /* We will reproduce the write just in case it is undocumented. */ + reg::Write(address + I2C_CONFIG_LOAD, I2C_REG_BITS_VALUE(CONFIG_LOAD_RESERVED_BIT_5, 1), + I2C_REG_BITS_ENUM (CONFIG_LOAD_TIMEOUT_CONFIG_LOAD, ENABLE), + I2C_REG_BITS_ENUM (CONFIG_LOAD_SLV_CONFIG_LOAD, DISABLE), + I2C_REG_BITS_ENUM (CONFIG_LOAD_MSTR_CONFIG_LOAD, ENABLE)); + + /* Wait up to 20 microseconds for the master config to be loaded. */ + for (int i = 0; i < 20; ++i) { + if (reg::HasValue(address + I2C_CONFIG_LOAD, I2C_REG_BITS_ENUM(CONFIG_LOAD_MSTR_CONFIG_LOAD, DISABLE))) { + return; + } + util::WaitMicroSeconds(1); + } + } + + void ClearBus(uintptr_t address) { + /* Configure the bus clear register. */ + reg::Write(address + I2C_BUS_CLEAR_CONFIG, I2C_REG_BITS_VALUE(BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD, 9), + I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_STOP_COND, NO_STOP), + I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_TERMINATE, IMMEDIATE), + I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_ENABLE, ENABLE)); + + /* Load the config. */ + LoadConfig(address); + + /* Wait up to 250us (in 25 us increments) until the bus clear is done. */ + for (int i = 0; i < 10; ++i) { + if (reg::HasValue(address + I2C_INTERRUPT_STATUS_REGISTER, I2C_REG_BITS_ENUM(INTERRUPT_STATUS_REGISTER_BUS_CLEAR_DONE, SET))) { + break; + } + + util::WaitMicroSeconds(25); + } + + /* Read the bus clear status. */ + reg::Read(address + I2C_BUS_CLEAR_STATUS); + } + + void InitializePort(uintptr_t address) { + /* Calculate the divisor. */ + constexpr int Divisor = util::DivideUp(19200, 8 * 400); + + /* Set the divisor. */ + reg::Write(address + I2C_CLK_DIVISOR_REGISTER, I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_STD_FAST_MODE, Divisor - 1), + I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_HSMODE, 1)); + + /* Clear the bus. */ + ClearBus(address); + + /* Clear the status. */ + reg::Write(address + I2C_INTERRUPT_STATUS_REGISTER, reg::Read(address + I2C_INTERRUPT_STATUS_REGISTER)); + } + + bool Write(uintptr_t base_address, Port port, int address, const void *src, size_t src_size, bool unused) { + /* Ensure we don't write too much. */ + u32 data = 0; + if (src_size > MaxTransferSize) { + return false; + } + + /* Copy the data to a transfer word. */ + std::memcpy(std::addressof(data), src, src_size); + + + /* Configure the to write the 7-bit address. */ + reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address), + I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, WRITE)); + + /* Configure to write the data. */ + reg::Write(base_address + I2C_I2C_CMD_DATA1, data); + + /* Configure to write the correct amount of data. */ + reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T), + I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE), + I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, WRITE), + I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, src_size - 1)); + + /* Load the configuration. */ + LoadConfig(base_address); + + /* Start the command. */ + reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO)); + + /* Wait for the command to be done. */ + while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ } + + /* Check if the transfer was successful. */ + return reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL)); + } + + bool Read(uintptr_t base_address, Port port, void *dst, size_t dst_size, int address, bool unused) { + /* Ensure we don't read too much. */ + if (dst_size > MaxTransferSize) { + return false; + } + + /* Configure the to read the 7-bit address. */ + reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address), + I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, READ)); + + /* Configure to read the correct amount of data. */ + reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T), + I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE), + I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, READ), + I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, dst_size - 1)); + + /* Load the configuration. */ + LoadConfig(base_address); + + /* Start the command. */ + reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO)); + + /* Wait for the command to be done. */ + while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ } + + /* Check that the transfer was successful. */ + if (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL))) { + return false; + } + + /* Read and copy out the data. */ + u32 data = reg::Read(base_address + I2C_I2C_CMD_DATA1); + std::memcpy(dst, std::addressof(data), dst_size); + return true; + } + + } + + void SetRegisterAddress(Port port, uintptr_t address) { + g_register_addresses[port] = address; + } + + void Initialize(Port port) { + InitializePort(g_register_addresses[port]); + } + + bool Query(void *dst, size_t dst_size, Port port, int address, int r) { + const uintptr_t base_address = g_register_addresses[port]; + + /* Select the register we want to read. */ + bool success = Write(base_address, port, address, std::addressof(r), 1, false); + if (success) { + /* If we successfully selected, read data from the register. */ + success = Read(base_address, port, dst, dst_size, address, true); + } + + return success; + } + + bool Send(Port port, int address, int r, const void *src, size_t src_size) { + const uintptr_t base_address = g_register_addresses[port]; + + /* Create a transfer buffer, make sure we can use it. */ + u8 buffer[MaxTransferSize]; + if (src_size > sizeof(buffer) - 1) { + return false; + } + + /* Copy data into the buffer. */ + buffer[0] = static_cast(r); + std::memcpy(buffer + 1, src, src_size); + + return Write(base_address, port, address, buffer, src_size + 1, false); + } + +} diff --git a/libexosphere/source/i2c/i2c_registers.hpp b/libexosphere/source/i2c/i2c_registers.hpp new file mode 100644 index 00000000..48f65957 --- /dev/null +++ b/libexosphere/source/i2c/i2c_registers.hpp @@ -0,0 +1,77 @@ +/* + * 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::i2c { + + #define I2C_I2C_CNFG (0x000) + #define I2C_I2C_CMD_ADDR0 (0x004) + #define I2C_I2C_CMD_DATA1 (0x00C) + #define I2C_I2C_STATUS (0x01C) + #define I2C_INTERRUPT_STATUS_REGISTER (0x068) + #define I2C_CLK_DIVISOR_REGISTER (0x06C) + #define I2C_BUS_CLEAR_CONFIG (0x084) + #define I2C_BUS_CLEAR_STATUS (0x088) + #define I2C_CONFIG_LOAD (0x08C) + + #define I2C_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (I2C, NAME) + #define I2C_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (I2C, NAME, VALUE) + #define I2C_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (I2C, NAME, ENUM) + #define I2C_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(I2C, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + + #define DEFINE_I2C_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (I2C, NAME, __OFFSET__, __WIDTH__) + #define DEFINE_I2C_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (I2C, NAME, __OFFSET__, ZERO, ONE) + #define DEFINE_I2C_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (I2C, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) + #define DEFINE_I2C_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(I2C, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) + #define DEFINE_I2C_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 (I2C, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + + /* I2C_CNFG */ + DEFINE_I2C_REG(I2C_CNFG_LENGTH, 1, 3); + DEFINE_I2C_REG_BIT_ENUM(I2C_CNFG_CMD1, 6, WRITE, READ); + DEFINE_I2C_REG_BIT_ENUM(I2C_CNFG_SEND, 9, NOP, GO); + DEFINE_I2C_REG_BIT_ENUM(I2C_CNFG_NEW_MASTER_FSM, 11, DISABLE, ENABLE); + DEFINE_I2C_REG_THREE_BIT_ENUM(I2C_CNFG_DEBOUNCE_CNT, 12, NO_DEBOUNCE, DEBOUNCE_2T, DEBOUNCE_4T, DEBOUNCE_6T, DEBOUNCE_8T, DEBOUNCE_10T, DEBOUNCE_12T, DEBOUNCE_14T); + + /* I2C_CMD_ADDR0 */ + DEFINE_I2C_REG_BIT_ENUM(I2C_CMD_ADDR0_7BIT_RW, 0, WRITE, READ); + DEFINE_I2C_REG(I2C_CMD_ADDR0_7BIT_ADDR, 1, 7); + + /* I2C_STATUS */ + DEFINE_I2C_REG_FOUR_BIT_ENUM(I2C_STATUS_CMD1_STAT, 0, SL1_XFER_SUCCESSFUL, SL1_NOACK_FOR_BYTE1, SL1_NOACK_FOR_BYTE2, SL1_NOACK_FOR_BYTE3, SL1_NOACK_FOR_BYTE4, SL1_NOACK_FOR_BYTE5, SL1_NOACK_FOR_BYTE6, SL1_NOACK_FOR_BYTE7, SL1_NOACK_FOR_BYTE8, SL1_NOACK_FOR_BYTE9, SL1_NOACK_FOR_BYTE10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); + DEFINE_I2C_REG_FOUR_BIT_ENUM(I2C_STATUS_CMD2_STAT, 4, SL2_XFER_SUCCESSFUL, SL2_NOACK_FOR_BYTE1, SL2_NOACK_FOR_BYTE2, SL2_NOACK_FOR_BYTE3, SL2_NOACK_FOR_BYTE4, SL2_NOACK_FOR_BYTE5, SL2_NOACK_FOR_BYTE6, SL2_NOACK_FOR_BYTE7, SL2_NOACK_FOR_BYTE8, SL2_NOACK_FOR_BYTE9, SL2_NOACK_FOR_BYTE10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); + DEFINE_I2C_REG_BIT_ENUM(I2C_STATUS_BUSY, 8, NOT_BUSY, BUSY); + + /* INTERRUPT_STATUS_REGISTER */ + DEFINE_I2C_REG_BIT_ENUM(INTERRUPT_STATUS_REGISTER_BUS_CLEAR_DONE, 11, UNSET, SET); + + /* CLK_DIVISOR_REGISTER */ + DEFINE_I2C_REG(CLK_DIVISOR_REGISTER_HSMODE, 0, 16); + DEFINE_I2C_REG(CLK_DIVISOR_REGISTER_STD_FAST_MODE, 16, 16); + + /* BUS_CLEAR_CONFIG */ + DEFINE_I2C_REG_BIT_ENUM(BUS_CLEAR_CONFIG_BC_ENABLE, 0, DISABLE, ENABLE); + DEFINE_I2C_REG_BIT_ENUM(BUS_CLEAR_CONFIG_BC_TERMINATE, 1, THRESHOLD, IMMEDIATE); + DEFINE_I2C_REG_BIT_ENUM(BUS_CLEAR_CONFIG_BC_STOP_COND, 2, NO_STOP, STOP); + DEFINE_I2C_REG(BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD, 16, 8); + + /* CONFIG_LOAD */ + DEFINE_I2C_REG_BIT_ENUM(CONFIG_LOAD_MSTR_CONFIG_LOAD, 0, DISABLE, ENABLE); + DEFINE_I2C_REG_BIT_ENUM(CONFIG_LOAD_SLV_CONFIG_LOAD, 1, DISABLE, ENABLE); + DEFINE_I2C_REG_BIT_ENUM(CONFIG_LOAD_TIMEOUT_CONFIG_LOAD, 2, DISABLE, ENABLE); + DEFINE_I2C_REG(CONFIG_LOAD_RESERVED_BIT_5, 5, 1); + + +} diff --git a/libexosphere/source/libc/libc.c b/libexosphere/source/libc/libc.c new file mode 100644 index 00000000..2117f248 --- /dev/null +++ b/libexosphere/source/libc/libc.c @@ -0,0 +1,1141 @@ +/* Note: copied from newlib */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * Copyright (C) 2004 CodeSourcery, LLC + * + * Permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies. + * + * This file is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Handle ELF .{pre_init,init,fini}_array sections. */ +#include + +#ifndef HAVE_INITFINI_ARRAY +#define HAVE_INITFINI_ARRAY +#endif + +#undef HAVE_INIT_FINI + +#ifdef HAVE_INITFINI_ARRAY + +/* These magic symbols are provided by the linker. */ +extern void (*__preinit_array_start []) (void) __attribute__((weak)); +extern void (*__preinit_array_end []) (void) __attribute__((weak)); +extern void (*__init_array_start []) (void) __attribute__((weak)); +extern void (*__init_array_end []) (void) __attribute__((weak)); + +#ifdef HAVE_INIT_FINI +extern void _init (void); +#endif + +/* Iterate over all the init routines. */ +void +__libc_init_array (void) +{ + size_t count; + size_t i; + + count = __preinit_array_end - __preinit_array_start; + for (i = 0; i < count; i++) + __preinit_array_start[i] (); + +#ifdef HAVE_INIT_FINI + _init (); +#endif + + count = __init_array_end - __init_array_start; + for (i = 0; i < count; i++) + __init_array_start[i] (); +} +#endif + +#ifdef HAVE_INITFINI_ARRAY +extern void (*__fini_array_start []) (void) __attribute__((weak)); +extern void (*__fini_array_end []) (void) __attribute__((weak)); + +#ifdef HAVE_INIT_FINI +extern void _fini (void); +#endif + +/* Run all the cleanup routines. */ +void +__libc_fini_array (void) +{ + size_t count; + size_t i; + + count = __fini_array_end - __fini_array_start; + for (i = count; i > 0; i--) + __fini_array_start[i-1] (); + +#ifdef HAVE_INIT_FINI + _fini (); +#endif +} +#endif + +/* +FUNCTION + <>---move possibly overlapping memory +INDEX + memmove +SYNOPSIS + #include + void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>); +DESCRIPTION + This function moves <[length]> characters from the block of + memory starting at <<*<[src]>>> to the memory starting at + <<*<[dst]>>>. <> reproduces the characters correctly + at <<*<[dst]>>> even if the two areas overlap. +RETURNS + The function returns <[dst]> as passed. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + memmove ansi pure +*/ + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +/* How many bytes are copied each iteration of the 4X unrolled loop. */ +#define BIGBLOCKSIZE (sizeof (long) << 2) + +/* How many bytes are copied each iteration of the word copy loop. */ +#define LITTLEBLOCKSIZE (sizeof (long)) + +/* Threshhold for punting to the byte copier. */ +#undef TOO_SMALL +#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) + +/*SUPPRESS 20*/ +void * +//__inhibit_loop_to_libcall +memmove (void *dst_void, + const void *src_void, + size_t length) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + char *dst = dst_void; + const char *src = src_void; + + if (src < dst && dst < src + length) + { + /* Have to copy backwards */ + src += length; + dst += length; + while (length--) + { + *--dst = *--src; + } + } + else + { + while (length--) + { + *dst++ = *src++; + } + } + + return dst_void; +#else + char *dst = dst_void; + const char *src = src_void; + long *aligned_dst; + const long *aligned_src; + + if (src < dst && dst < src + length) + { + /* Destructive overlap...have to copy backwards */ + src += length; + dst += length; + while (length--) + { + *--dst = *--src; + } + } + else + { + /* Use optimizing algorithm for a non-destructive copy to closely + match memcpy. If the size is small or either SRC or DST is unaligned, + then punt into the byte copy loop. This should be rare. */ + if (!TOO_SMALL(length) && !UNALIGNED (src, dst)) + { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy 4X long words at a time if possible. */ + while (length >= BIGBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + length -= BIGBLOCKSIZE; + } + + /* Copy one long word at a time if possible. */ + while (length >= LITTLEBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + length -= LITTLEBLOCKSIZE; + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (length--) + { + *dst++ = *src++; + } + } + + return dst_void; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---copy memory regions +SYNOPSIS + #include + void* memcpy(void *restrict <[out]>, const void *restrict <[in]>, + size_t <[n]>); +DESCRIPTION + This function copies <[n]> bytes from the memory region + pointed to by <[in]> to the memory region pointed to by + <[out]>. + If the regions overlap, the behavior is undefined. +RETURNS + <> returns a pointer to the first byte of the <[out]> + region. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + memcpy ansi pure + */ + +void * +memcpy (void * dst0, + const void * __restrict src0, + size_t len0) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + char *dst = (char *) dst0; + char *src = (char *) src0; + + void *save = dst0; + + while (len0--) + { + *dst++ = *src++; + } + + return save; +#else + char *dst = dst0; + const char *src = src0; + long *aligned_dst; + const long *aligned_src; + + /* If the size is small, or either SRC or DST is unaligned, + then punt into the byte copy loop. This should be rare. */ + if (!TOO_SMALL(len0) && !UNALIGNED (src, dst)) + { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy 4X long words at a time if possible. */ + while (len0 >= BIGBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + len0 -= BIGBLOCKSIZE; + } + + /* Copy one long word at a time if possible. */ + while (len0 >= LITTLEBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + len0 -= LITTLEBLOCKSIZE; + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (len0--) + *dst++ = *src++; + + return dst0; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---set an area of memory +INDEX + memset +SYNOPSIS + #include + void *memset(void *<[dst]>, int <[c]>, size_t <[length]>); +DESCRIPTION + This function converts the argument <[c]> into an unsigned + char and fills the first <[length]> characters of the array + pointed to by <[dst]> to the value. +RETURNS + <> returns the value of <[dst]>. +PORTABILITY +<> is ANSI C. + <> requires no supporting OS subroutines. +QUICKREF + memset ansi pure +*/ + +#include + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +#define LBLOCKSIZE (sizeof(long)) +#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) +#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) + +void * +memset (void *m, + int c, + size_t n) +{ + char *s = (char *) m; + +#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) + unsigned int i; + unsigned long buffer; + unsigned long *aligned_addr; + unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an + unsigned variable. */ + + while (UNALIGNED (s)) + { + if (n--) + *s++ = (char) c; + else + return m; + } + + if (!TOO_SMALL (n)) + { + /* If we get this far, we know that n is large and s is word-aligned. */ + aligned_addr = (unsigned long *) s; + + /* Store D into each char sized location in BUFFER so that + we can set large blocks quickly. */ + buffer = (d << 8) | d; + buffer |= (buffer << 16); + for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) + buffer = (buffer << i) | buffer; + + /* Unroll the loop. */ + while (n >= LBLOCKSIZE*4) + { + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + n -= 4*LBLOCKSIZE; + } + + while (n >= LBLOCKSIZE) + { + *aligned_addr++ = buffer; + n -= LBLOCKSIZE; + } + /* Pick up the remainder with a bytewise loop. */ + s = (char*)aligned_addr; + } + +#endif /* not PREFER_SIZE_OVER_SPEED */ + + while (n--) + *s++ = (char) c; + + return m; +} + +/* +FUNCTION + <>---find character in memory +INDEX + memchr +SYNOPSIS + #include + void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>); +DESCRIPTION + This function searches memory starting at <<*<[src]>>> for the + character <[c]>. The search only ends with the first + occurrence of <[c]>, or after <[length]> characters; in + particular, <> does not terminate the search. +RETURNS + If the character <[c]> is found within <[length]> characters + of <<*<[src]>>>, a pointer to the character is returned. If + <[c]> is not found, then <> is returned. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + memchr ansi pure +*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) + +/* How many bytes are loaded each iteration of the word copy loop. */ +#define LBLOCKSIZE (sizeof (long)) + +/* Threshhold for punting to the bytewise iterator. */ +#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) + +#if LONG_MAX == 2147483647L +#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) +#else +#if LONG_MAX == 9223372036854775807L +/* Nonzero if X (a long int) contains a NULL byte. */ +#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) +#else +#error long int is not a 32bit or 64bit type. +#endif +#endif + +#ifndef DETECTNULL +#error long int is not a 32bit or 64bit byte +#endif + +/* DETECTCHAR returns nonzero if (long)X contains the byte used + to fill (long)MASK. */ +#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK)) + +void * +memchr (const void *src_void, + int c, + size_t length) +{ + const unsigned char *src = (const unsigned char *) src_void; + unsigned char d = c; + +#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) + unsigned long *asrc; + unsigned long mask; + unsigned int i; + + while (UNALIGNED (src)) + { + if (!length--) + return NULL; + if (*src == d) + return (void *) src; + src++; + } + + if (!TOO_SMALL (length)) + { + /* If we get this far, we know that length is large and src is + word-aligned. */ + /* The fast code reads the source one word at a time and only + performs the bytewise search on word-sized segments if they + contain the search character, which is detected by XORing + the word-sized segment with a word-sized block of the search + character and then detecting for the presence of NUL in the + result. */ + asrc = (unsigned long *) src; + mask = d << 8 | d; + mask = mask << 16 | mask; + for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) + mask = (mask << i) | mask; + + while (length >= LBLOCKSIZE) + { + if (DETECTCHAR (*asrc, mask)) + break; + length -= LBLOCKSIZE; + asrc++; + } + + /* If there are fewer than LBLOCKSIZE characters left, + then we resort to the bytewise loop. */ + + src = (unsigned char *) asrc; + } + +#endif /* not PREFER_SIZE_OVER_SPEED */ + + while (length--) + { + if (*src == d) + return (void *) src; + src++; + } + + return NULL; +} + +/* +FUNCTION + <>---compare two memory areas +INDEX + memcmp +SYNOPSIS + #include + int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>); +DESCRIPTION + This function compares not more than <[n]> characters of the + object pointed to by <[s1]> with the object pointed to by <[s2]>. +RETURNS + The function returns an integer greater than, equal to or + less than zero according to whether the object pointed to by + <[s1]> is greater than, equal to or less than the object + pointed to by <[s2]>. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + memcmp ansi pure +*/ + + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +/* How many bytes are copied each iteration of the word copy loop. */ +#define LBLOCKSIZE (sizeof (long)) + +/* Threshhold for punting to the byte copier. */ +#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) + +int +memcmp (const void *m1, + const void *m2, + size_t n) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + unsigned char *s1 = (unsigned char *) m1; + unsigned char *s2 = (unsigned char *) m2; + + while (n--) + { + if (*s1 != *s2) + { + return *s1 - *s2; + } + s1++; + s2++; + } + return 0; +#else + unsigned char *s1 = (unsigned char *) m1; + unsigned char *s2 = (unsigned char *) m2; + unsigned long *a1; + unsigned long *a2; + + /* If the size is too small, or either pointer is unaligned, + then we punt to the byte compare loop. Hopefully this will + not turn up in inner loops. */ + if (!TOO_SMALL(n) && !UNALIGNED(s1,s2)) + { + /* Otherwise, load and compare the blocks of memory one + word at a time. */ + a1 = (unsigned long*) s1; + a2 = (unsigned long*) s2; + while (n >= LBLOCKSIZE) + { + if (*a1 != *a2) + break; + a1++; + a2++; + n -= LBLOCKSIZE; + } + + /* check m mod LBLOCKSIZE remaining characters */ + + s1 = (unsigned char*)a1; + s2 = (unsigned char*)a2; + } + + while (n--) + { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return 0; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---search for character in string +INDEX + strchr +SYNOPSIS + #include + char * strchr(const char *<[string]>, int <[c]>); +DESCRIPTION + This function finds the first occurence of <[c]> (converted to + a char) in the string pointed to by <[string]> (including the + terminating null character). +RETURNS + Returns a pointer to the located character, or a null pointer + if <[c]> does not occur in <[string]>. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strchr ansi pure +*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + + +/* Nonzero if X is not aligned on a "long" boundary. */ +#define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) + +/* How many bytes are loaded each iteration of the word copy loop. */ +#define LBLOCKSIZE (sizeof (long)) + +char * +strchr (const char *s1, + int i) +{ + const unsigned char *s = (const unsigned char *)s1; + unsigned char c = i; + +#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) + unsigned long mask,j; + unsigned long *aligned_addr; + + /* Special case for finding 0. */ + if (!c) + { + while (UNALIGNED (s)) + { + if (!*s) + return (char *) s; + s++; + } + /* Operate a word at a time. */ + aligned_addr = (unsigned long *) s; + while (!DETECTNULL (*aligned_addr)) + aligned_addr++; + /* Found the end of string. */ + s = (const unsigned char *) aligned_addr; + while (*s) + s++; + return (char *) s; + } + + /* All other bytes. Align the pointer, then search a long at a time. */ + while (UNALIGNED (s)) + { + if (!*s) + return NULL; + if (*s == c) + return (char *) s; + s++; + } + + mask = c; + for (j = 8; j < LBLOCKSIZE * 8; j <<= 1) + mask = (mask << j) | mask; + + aligned_addr = (unsigned long *) s; + while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask)) + aligned_addr++; + + /* The block of bytes currently pointed to by aligned_addr + contains either a null or the target char, or both. We + catch it using the bytewise search. */ + + s = (unsigned char *) aligned_addr; + +#endif /* not PREFER_SIZE_OVER_SPEED */ + + while (*s && *s != c) + s++; + if (*s == c) + return (char *)s; + return NULL; +} + +/* +FUNCTION + <>---character string compare + +INDEX + strcmp +SYNOPSIS + #include + int strcmp(const char *<[a]>, const char *<[b]>); +DESCRIPTION + <> compares the string at <[a]> to + the string at <[b]>. +RETURNS + If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, + <> returns a number greater than zero. If the two + strings match, <> returns zero. If <<*<[a]>>> + sorts lexicographically before <<*<[b]>>>, <> returns a + number less than zero. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strcmp ansi pure +*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +int +strcmp (const char *s1, + const char *s2) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + while (*s1 != '\0' && *s1 == *s2) + { + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#else + unsigned long *a1; + unsigned long *a2; + + /* If s1 or s2 are unaligned, then compare bytes. */ + if (!UNALIGNED (s1, s2)) + { + /* If s1 and s2 are word-aligned, compare them a word at a time. */ + a1 = (unsigned long*)s1; + a2 = (unsigned long*)s2; + while (*a1 == *a2) + { + /* To get here, *a1 == *a2, thus if we find a null in *a1, + then the strings must be equal, so return zero. */ + if (DETECTNULL (*a1)) + return 0; + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of s1, so search bytewise */ + s1 = (char*)a1; + s2 = (char*)a2; + } + + while (*s1 != '\0' && *s1 == *s2) + { + s1++; + s2++; + } + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---copy string +INDEX + strcpy +SYNOPSIS + #include + char *strcpy(char *<[dst]>, const char *<[src]>); +DESCRIPTION + <> copies the string pointed to by <[src]> + (including the terminating null character) to the array + pointed to by <[dst]>. +RETURNS + This function returns the initial value of <[dst]>. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strcpy ansi pure +*/ + +/*SUPPRESS 560*/ +/*SUPPRESS 530*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +/* Nonzero if either X or Y is not aligned on a "long" boundary. */ +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +char* +strcpy (char *dst0, + const char *src0) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + char *s = dst0; + + while ((*dst0++ = *src0++)) + ; + + return s; +#else + char *dst = dst0; + const char *src = src0; + long *aligned_dst; + const long *aligned_src; + + /* If SRC or DEST is unaligned, then copy bytes. */ + if (!UNALIGNED (src, dst)) + { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* SRC and DEST are both "long int" aligned, try to do "long int" + sized copies. */ + while (!DETECTNULL(*aligned_src)) + { + *aligned_dst++ = *aligned_src++; + } + + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while ((*dst++ = *src++)) + ; + return dst0; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---character string length +INDEX + strlen +SYNOPSIS + #include + size_t strlen(const char *<[str]>); +DESCRIPTION + The <> function works out the length of the string + starting at <<*<[str]>>> by counting chararacters until it + reaches a <> character. +RETURNS + <> returns the character count. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strlen ansi pure +*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +#define LBLOCKSIZE (sizeof (long)) +#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) +size_t +strlen (const char *str) +{ + const char *start = str; + +#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) + unsigned long *aligned_addr; + + /* Align the pointer, so we can search a word at a time. */ + while (UNALIGNED (str)) + { + if (!*str) + return str - start; + str++; + } + + /* If the string is word-aligned, we can check for the presence of + a null in each word-sized block. */ + aligned_addr = (unsigned long *)str; + while (!DETECTNULL (*aligned_addr)) + aligned_addr++; + + /* Once a null is detected, we check each byte in that block for a + precise position of the null. */ + str = (char *) aligned_addr; + +#endif /* not PREFER_SIZE_OVER_SPEED */ + + while (*str) + str++; + return str - start; +} + +/* +FUNCTION + <>---character string compare + +INDEX + strncmp +SYNOPSIS + #include + int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>); +DESCRIPTION + <> compares up to <[length]> characters + from the string at <[a]> to the string at <[b]>. +RETURNS + If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, + <> returns a number greater than zero. If the two + strings are equivalent, <> returns zero. If <<*<[a]>>> + sorts lexicographically before <<*<[b]>>>, <> returns a + number less than zero. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strncmp ansi pure +*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +int +strncmp (const char *s1, + const char *s2, + size_t n) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + if (n == 0) + return 0; + + while (n-- != 0 && *s1 == *s2) + { + if (n == 0 || *s1 == '\0') + break; + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#else + unsigned long *a1; + unsigned long *a2; + + if (n == 0) + return 0; + + /* If s1 or s2 are unaligned, then compare bytes. */ + if (!UNALIGNED (s1, s2)) + { + /* If s1 and s2 are word-aligned, compare them a word at a time. */ + a1 = (unsigned long*)s1; + a2 = (unsigned long*)s2; + while (n >= sizeof (long) && *a1 == *a2) + { + n -= sizeof (long); + + /* If we've run out of bytes or hit a null, return zero + since we already know *a1 == *a2. */ + if (n == 0 || DETECTNULL (*a1)) + return 0; + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of s1, so search bytewise */ + s1 = (char*)a1; + s2 = (char*)a2; + } + + while (n-- > 0 && *s1 == *s2) + { + /* If we've run out of bytes or hit a null, return zero + since we already know *s1 == *s2. */ + if (n == 0 || *s1 == '\0') + return 0; + s1++; + s2++; + } + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---counted copy string +INDEX + strncpy +SYNOPSIS + #include + char *strncpy(char *restrict <[dst]>, const char *restrict <[src]>, + size_t <[length]>); +DESCRIPTION + <> copies not more than <[length]> characters from the + the string pointed to by <[src]> (including the terminating + null character) to the array pointed to by <[dst]>. If the + string pointed to by <[src]> is shorter than <[length]> + characters, null characters are appended to the destination + array until a total of <[length]> characters have been + written. +RETURNS + This function returns the initial value of <[dst]>. +PORTABILITY +<> is ANSI C. +<> requires no supporting OS subroutines. +QUICKREF + strncpy ansi pure +*/ + +/*SUPPRESS 560*/ +/*SUPPRESS 530*/ + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL + +#define UNALIGNED(X, Y) \ + (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) + +#define TOO_SMALL(LEN) ((LEN) < sizeof (long)) + +char * +strncpy (char *__restrict dst0, + const char *__restrict src0, + size_t count) +{ +#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + char *dscan; + const char *sscan; + + dscan = dst0; + sscan = src0; + while (count > 0) + { + --count; + if ((*dscan++ = *sscan++) == '\0') + break; + } + while (count-- > 0) + *dscan++ = '\0'; + + return dst0; +#else + char *dst = dst0; + const char *src = src0; + long *aligned_dst; + const long *aligned_src; + + /* If SRC and DEST is aligned and count large enough, then copy words. */ + if (!UNALIGNED (src, dst) && !TOO_SMALL (count)) + { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* SRC and DEST are both "long int" aligned, try to do "long int" + sized copies. */ + while (count >= sizeof (long int) && !DETECTNULL(*aligned_src)) + { + count -= sizeof (long int); + *aligned_dst++ = *aligned_src++; + } + + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (count > 0) + { + --count; + if ((*dst++ = *src++) == '\0') + break; + } + + while (count-- > 0) + *dst++ = '\0'; + + return dst0; +#endif /* not PREFER_SIZE_OVER_SPEED */ +} + +/* +FUNCTION + <>---character string length + +INDEX + strnlen +SYNOPSIS + #include + size_t strnlen(const char *<[str]>, size_t <[n]>); +DESCRIPTION + The <> function works out the length of the string + starting at <<*<[str]>>> by counting chararacters until it + reaches a NUL character or the maximum: <[n]> number of + characters have been inspected. +RETURNS + <> returns the character count or <[n]>. +PORTABILITY +<> is a GNU extension. +<> requires no supporting OS subroutines. +*/ + +size_t +strnlen (const char *str, + size_t n) +{ + const char *start = str; + + while (n-- > 0 && *str) + str++; + + return str - start; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/libexosphere/source/log/log_api.cpp b/libexosphere/source/log/log_api.cpp new file mode 100644 index 00000000..0cf20e20 --- /dev/null +++ b/libexosphere/source/log/log_api.cpp @@ -0,0 +1,53 @@ +/* + * 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::log { + + namespace { + + constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug; + constinit bool g_initialized_uart = false; + + constexpr inline u32 UartPortFlags = [] { + if constexpr (UartLogPort == uart::Port_ReservedDebug) { + /* Logging to the debug port. */ + /* Don't invert transactions. */ + return uart::Flag_None; + } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { + /* Logging to left joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { + /* Logging to right joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + } else { + __builtin_unreachable(); + } + }(); + + } + + void Initialize() { + /* Initialize the target uart port. */ + uart::Initialize(UartLogPort, 115200, UartPortFlags); + + /* Note that we've initialized. */ + g_initialized_uart = true; + } + +} \ No newline at end of file diff --git a/libexosphere/source/pmc/pmc_api.cpp b/libexosphere/source/pmc/pmc_api.cpp new file mode 100644 index 00000000..67739e58 --- /dev/null +++ b/libexosphere/source/pmc/pmc_api.cpp @@ -0,0 +1,275 @@ +/* + * 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::pmc { + + namespace { + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); + + constexpr inline u32 WriteMask = 0x1; + constexpr inline u32 ReadMask = 0x2; + + enum class LockMode { + Read, + Write, + ReadWrite, + }; + + template + constexpr inline u32 LockMask = [] { + switch (Mode) { + case LockMode::Read: return ReadMask; + case LockMode::Write: return WriteMask; + case LockMode::ReadWrite: return ReadMask | WriteMask; + default: __builtin_unreachable(); + } + }(); + + constexpr inline size_t NumSecureScratchRegisters = 120; + constexpr inline size_t NumSecureDisableRegisters = 8; + + template requires (SecureScratch < NumSecureScratchRegisters) + constexpr inline std::pair DisableRegisterIndex = [] { + if constexpr (SecureScratch < 8) { + return std::pair{0, 4 + 2 * SecureScratch}; + } else { + constexpr size_t Relative = SecureScratch - 8; + return std::pair{1 + (Relative / 16), 2 * (Relative % 16)}; + } + }(); + + struct LockInfo { + size_t scratch; + LockMode mode; + }; + + template + constexpr ALWAYS_INLINE void SetSecureScratchMask(std::array &disables) { + constexpr std::pair Location = DisableRegisterIndex; + disables[Location.first] |= LockMask << Location.second; + } + + template + constexpr ALWAYS_INLINE void SetSecureScratchMasks(std::array &disables) { + (SetSecureScratchMask(disables), ...); + } + + template + constexpr ALWAYS_INLINE void SetSecureScratchReadWriteMasks(std::array &disables) { + (SetSecureScratchMask(disables), ...); + } + + template + constexpr ALWAYS_INLINE void SetSecureScratchReadMasks(std::array &disables) { + (SetSecureScratchMask(disables), ...); + } + + template + constexpr ALWAYS_INLINE void SetSecureScratchWriteMasks(std::array &disables) { + (SetSecureScratchMask(disables), ...); + } + + template + constexpr ALWAYS_INLINE std::array GetSecureScratchMasks() { + std::array disables = {}; + + if constexpr ((Register & SecureRegister_Other) != 0) { + constexpr std::array NonOtherDisables = GetSecureScratchMasks(~SecureRegister_Other)>(); + for (size_t i = 0; i < NumSecureDisableRegisters; i++) { + disables[i] |= ~NonOtherDisables[i]; + } + disables[0] &= 0x007FFFF0; + } + if constexpr ((Register & SecureRegister_DramParameters) != 0) { + SetSecureScratchReadWriteMasks< 8, 9, 10, 11, 12, 13, 14, 15, + 17, 18, 19, 20, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 52, 53, 54, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 79, 80, 81, 82, 83, 84, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 104, 105, 106, 107 + >(disables); + } + if constexpr ((Register & SecureRegister_ResetVector) != 0) { + SetSecureScratchReadWriteMasks<34, 35>(disables); + } + if constexpr ((Register & SecureRegister_Carveout) != 0) { + SetSecureScratchReadWriteMasks<16, 39, 51, 55, 74, 75, 76, 77, 78, 99, 100, 101, 102, 103>(disables); + } + if constexpr ((Register & SecureRegister_CmacWrite) != 0) { + SetSecureScratchWriteMasks<112, 113, 114, 115>(disables); + } + if constexpr ((Register & SecureRegister_CmacRead) != 0) { + SetSecureScratchReadMasks<112, 113, 114, 115>(disables); + } + if constexpr ((Register & SecureRegister_KeySourceWrite) != 0) { + SetSecureScratchWriteMasks<24, 25, 26, 27>(disables); + } + if constexpr ((Register & SecureRegister_KeySourceRead) != 0) { + SetSecureScratchReadMasks<24, 25, 26, 27>(disables); + } + if constexpr ((Register & SecureRegister_Srk) != 0) { + SetSecureScratchReadWriteMasks<4, 5, 6, 7>(disables); + } + + return disables; + } + + /* Validate that the secure scratch masks produced are correct. */ + #include "pmc_secure_scratch_test.inc" + + ALWAYS_INLINE void LockBits(uintptr_t address, u32 mask) { + reg::Write(address, reg::Read(address) | mask); + } + + template + ALWAYS_INLINE void SetSecureScratchMasks(uintptr_t address) { + constexpr auto Masks = GetSecureScratchMasks(); + + if constexpr (Masks[0] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE , Masks[0]); } + if constexpr (Masks[1] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE2, Masks[1]); } + if constexpr (Masks[2] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE3, Masks[2]); } + if constexpr (Masks[3] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE4, Masks[3]); } + if constexpr (Masks[4] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE5, Masks[4]); } + if constexpr (Masks[5] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE6, Masks[5]); } + if constexpr (Masks[6] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE7, Masks[6]); } + if constexpr (Masks[7] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE8, Masks[7]); } + + static_assert(Masks.size() == 8); + } + + template + ALWAYS_INLINE bool TestSecureScratchMasks(uintptr_t address) { + constexpr auto Masks = GetSecureScratchMasks(); + + if constexpr (Masks[0] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE ) & Masks[0]) != Masks[0]) { return false; } } + if constexpr (Masks[1] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE2) & Masks[1]) != Masks[1]) { return false; } } + if constexpr (Masks[2] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE3) & Masks[2]) != Masks[2]) { return false; } } + if constexpr (Masks[3] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE4) & Masks[3]) != Masks[3]) { return false; } } + if constexpr (Masks[4] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE5) & Masks[4]) != Masks[4]) { return false; } } + if constexpr (Masks[5] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE6) & Masks[5]) != Masks[5]) { return false; } } + if constexpr (Masks[6] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE7) & Masks[6]) != Masks[6]) { return false; } } + if constexpr (Masks[7] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE8) & Masks[7]) != Masks[7]) { return false; } } + static_assert(Masks.size() == 8); + + return true; + } + + NOINLINE void WriteRandomValueToRegister(uintptr_t offset) { + /* Create an aligned buffer. */ + util::AlignedBuffer buf; + + /* Generate random bytes into it. */ + se::GenerateRandomBytes(buf, sizeof(u32)); + + /* Read the random value. */ + const u32 random = *reinterpret_cast(static_cast(buf)); + + /* Get the address. */ + const uintptr_t address = g_register_address + offset; + + /* Write the value. */ + reg::Write(address, random); + + /* Verify it was written. */ + AMS_ABORT_UNLESS(reg::Read(address) == random); + } + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void InitializeRandomScratch() { + /* Write random data to the scratch that contains the SRK. */ + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH4); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH5); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH6); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH7); + + /* Lock the SRK scratch. */ + LockSecureRegister(SecureRegister_Srk); + + /* Write random data to the scratch used for tzram cmac. */ + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH112); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH113); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH114); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH115); + + /* Write random data to the scratch used for tzram key source. */ + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH24); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH25); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH26); + WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH27); + + /* Here, Nintendo locks the SRK scratch a second time. */ + /* This may just be "to be sure". */ + LockSecureRegister(SecureRegister_Srk); + } + + void LockSecureRegister(SecureRegister reg) { + /* Get the address. */ + const uintptr_t address = g_register_address; + + /* Apply each mask. */ + #define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { SetSecureScratchMasks(address); } } while (0) + PMC_PROCESS_REG(Other); + PMC_PROCESS_REG(DramParameters); + PMC_PROCESS_REG(ResetVector); + PMC_PROCESS_REG(Carveout); + PMC_PROCESS_REG(CmacWrite); + PMC_PROCESS_REG(CmacRead); + PMC_PROCESS_REG(KeySourceWrite); + PMC_PROCESS_REG(KeySourceRead); + PMC_PROCESS_REG(Srk); + #undef PMC_PROCESS_REG + + } + + LockState GetSecureRegisterLockState(SecureRegister reg) { + bool all_valid = true; + bool any_valid = false; + + /* Get the address. */ + const uintptr_t address = g_register_address; + + /* Test each mask. */ + #define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { const bool test = TestSecureScratchMasks(address); all_valid &= test; any_valid |= test; } } while (0) + PMC_PROCESS_REG(Other); + PMC_PROCESS_REG(DramParameters); + PMC_PROCESS_REG(ResetVector); + PMC_PROCESS_REG(Carveout); + PMC_PROCESS_REG(CmacWrite); + PMC_PROCESS_REG(CmacRead); + PMC_PROCESS_REG(KeySourceWrite); + PMC_PROCESS_REG(KeySourceRead); + PMC_PROCESS_REG(Srk); + #undef PMC_PROCESS_REG + + if (all_valid) { + return LockState::Locked; + } else if (any_valid) { + return LockState::PartiallyLocked; + } else { + return LockState::NotLocked; + } + } + +} \ No newline at end of file diff --git a/libexosphere/source/pmc/pmc_secure_scratch_test.inc b/libexosphere/source/pmc/pmc_secure_scratch_test.inc new file mode 100644 index 00000000..b33268a2 --- /dev/null +++ b/libexosphere/source/pmc/pmc_secure_scratch_test.inc @@ -0,0 +1,100 @@ +/* + * 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 . + */ + +namespace test { + + constexpr inline auto Other = GetSecureScratchMasks(); + static_assert(Other[0] == 0x00700FF0u); + static_assert(Other[1] == 0xFC000000u); + static_assert(Other[2] == 0x3F0FFF00u); + static_assert(Other[3] == 0x00000000u); + static_assert(Other[4] == 0x00000000u); + static_assert(Other[5] == 0x0C000000u); + static_assert(Other[6] == 0x00000000u); + static_assert(Other[7] == 0xFF00FF00u); + + constexpr inline auto DramParameters = GetSecureScratchMasks(); + static_assert(DramParameters[0] == 0x00000000u); + static_assert(DramParameters[1] == 0x03FCFFFFu); + static_assert(DramParameters[2] == 0x00000000u); + static_assert(DramParameters[3] == 0x3F3FFFFFu); + static_assert(DramParameters[4] == 0xFFFFFFFFu); + static_assert(DramParameters[5] == 0xF3FFC00Fu); + static_assert(DramParameters[6] == 0x003FFFFFu); + static_assert(DramParameters[7] == 0x000000FFu); + + constexpr inline auto ResetVector = GetSecureScratchMasks(); + static_assert(ResetVector[0] == 0x00000000u); + static_assert(ResetVector[1] == 0x00000000u); + static_assert(ResetVector[2] == 0x00F00000u); + static_assert(ResetVector[3] == 0x00000000u); + static_assert(ResetVector[4] == 0x00000000u); + static_assert(ResetVector[5] == 0x00000000u); + static_assert(ResetVector[6] == 0x00000000u); + static_assert(ResetVector[7] == 0x00000000u); + + constexpr inline auto CmacWrite = GetSecureScratchMasks(); + static_assert(CmacWrite[0] == 0x00000000u); + static_assert(CmacWrite[1] == 0x00000000u); + static_assert(CmacWrite[2] == 0x00000000u); + static_assert(CmacWrite[3] == 0x00000000u); + static_assert(CmacWrite[4] == 0x00000000u); + static_assert(CmacWrite[5] == 0x00000000u); + static_assert(CmacWrite[6] == 0x00000000u); + static_assert(CmacWrite[7] == 0x00550000u); + + constexpr inline auto CmacRead = GetSecureScratchMasks(); + static_assert(CmacRead[0] == 0x00000000u); + static_assert(CmacRead[1] == 0x00000000u); + static_assert(CmacRead[2] == 0x00000000u); + static_assert(CmacRead[3] == 0x00000000u); + static_assert(CmacRead[4] == 0x00000000u); + static_assert(CmacRead[5] == 0x00000000u); + static_assert(CmacRead[6] == 0x00000000u); + static_assert(CmacRead[7] == 0x00AA0000u); + + constexpr inline auto KeySourceWrite = GetSecureScratchMasks(); + static_assert(KeySourceWrite[0] == 0x00000000u); + static_assert(KeySourceWrite[1] == 0x00000000u); + static_assert(KeySourceWrite[2] == 0x00000055u); + static_assert(KeySourceWrite[3] == 0x00000000u); + static_assert(KeySourceWrite[4] == 0x00000000u); + static_assert(KeySourceWrite[5] == 0x00000000u); + static_assert(KeySourceWrite[6] == 0x00000000u); + static_assert(KeySourceWrite[7] == 0x00000000u); + + constexpr inline auto KeySourceRead = GetSecureScratchMasks(); + static_assert(KeySourceRead[0] == 0x00000000u); + static_assert(KeySourceRead[1] == 0x00000000u); + static_assert(KeySourceRead[2] == 0x000000AAu); + static_assert(KeySourceRead[3] == 0x00000000u); + static_assert(KeySourceRead[4] == 0x00000000u); + static_assert(KeySourceRead[5] == 0x00000000u); + static_assert(KeySourceRead[6] == 0x00000000u); + static_assert(KeySourceRead[7] == 0x00000000u); + + constexpr inline auto Srk = GetSecureScratchMasks(); + static_assert(Srk[0] == 0x000FF000u); + static_assert(Srk[1] == 0x00000000u); + static_assert(Srk[2] == 0x00000000u); + static_assert(Srk[3] == 0x00000000u); + static_assert(Srk[4] == 0x00000000u); + static_assert(Srk[5] == 0x00000000u); + static_assert(Srk[6] == 0x00000000u); + static_assert(Srk[7] == 0x00000000u); + + +} \ No newline at end of file diff --git a/libexosphere/source/pmic/max77620.h b/libexosphere/source/pmic/max77620.h new file mode 100644 index 00000000..b1335544 --- /dev/null +++ b/libexosphere/source/pmic/max77620.h @@ -0,0 +1,340 @@ +/* + * Defining registers address and its bit definitions of MAX77620 and MAX20024 + * + * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef _MFD_MAX77620_H_ +#define _MFD_MAX77620_H_ + +#define MAX77620_I2C_ADDR 0x3C + +/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ +#define MAX77620_REG_CNFGGLBL1 0x00 +#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) +#define MAX77620_CNFGGLBL1_MPPLD (1 << 6) +#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E +#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) +#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) + +#define MAX77620_REG_CNFGGLBL2 0x01 +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_WDTC_MASK 0x3 +#define MAX77620_WDTOFFC (1 << 4) +#define MAX77620_WDTSLPC (1 << 3) +#define MAX77620_WDTEN (1 << 2) +#define MAX77620_TWD_MASK 0x3 +#define MAX77620_TWD_2s 0x0 +#define MAX77620_TWD_16s 0x1 +#define MAX77620_TWD_64s 0x2 +#define MAX77620_TWD_128s 0x3 + +#define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) + +#define MAX77620_REG_CNFGBBC 0x04 +#define MAX77620_CNFGBBC_ENABLE (1 << 0) +#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 +#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 +#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 +#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) +#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 +#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 +#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) + +#define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) +#define MAX77620_IRQ_TOP_SD_MASK (1 << 6) +#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) +#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) +#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) +#define MAX77620_IRQ_TOP_32K_MASK (1 << 2) +#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) + +#define MAX77620_REG_INTLBT 0x06 +#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_IRQ_LBM_MASK (1 << 3) +#define MAX77620_IRQ_TJALRM1_MASK (1 << 2) +#define MAX77620_IRQ_TJALRM2_MASK (1 << 1) + +#define MAX77620_REG_IRQSD 0x07 +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A +#define MAX77620_REG_ONOFFIRQ 0x0B +#define MAX77620_REG_NVERC 0x0C + +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_GLBLM_MASK (1 << 0) + +#define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_REG_STATLBT 0x13 +#define MAX77620_REG_STATSD 0x14 +#define MAX77620_REG_ONOFFSTAT 0x15 + +/* SD and LDO Registers */ +#define MAX77620_REG_SD0 0x16 +#define MAX77620_REG_SD1 0x17 +#define MAX77620_REG_SD2 0x18 +#define MAX77620_REG_SD3 0x19 +#define MAX77620_REG_SD4 0x1A +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x3F +#define MAX77620_SD1_VOLT_MASK 0x7F +#define MAX77620_LDO_VOLT_MASK 0x3F +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_REG_LDO0_CFG 0x23 +#define MAX77620_REG_LDO0_CFG2 0x24 +#define MAX77620_REG_LDO1_CFG 0x25 +#define MAX77620_REG_LDO1_CFG2 0x26 +#define MAX77620_REG_LDO2_CFG 0x27 +#define MAX77620_REG_LDO2_CFG2 0x28 +#define MAX77620_REG_LDO3_CFG 0x29 +#define MAX77620_REG_LDO3_CFG2 0x2A +#define MAX77620_REG_LDO4_CFG 0x2B +#define MAX77620_REG_LDO4_CFG2 0x2C +#define MAX77620_REG_LDO5_CFG 0x2D +#define MAX77620_REG_LDO5_CFG2 0x2E +#define MAX77620_REG_LDO6_CFG 0x2F +#define MAX77620_REG_LDO6_CFG2 0x30 +#define MAX77620_REG_LDO7_CFG 0x31 +#define MAX77620_REG_LDO7_CFG2 0x32 +#define MAX77620_REG_LDO8_CFG 0x33 +#define MAX77620_REG_LDO8_CFG2 0x34 +#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +#define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_POWER_MODE_NORMAL 3 +#define MAX77620_POWER_MODE_LPM 2 +#define MAX77620_POWER_MODE_GLPM 1 +#define MAX77620_POWER_MODE_DISABLE 0 +#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (1 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW 0 + +#define MAX77620_REG_LDO_CFG3 0x35 +#define MAX77620_TRACK4_MASK (1 << 5) +#define MAX77620_TRACK4_SHIFT 5 + +#define MAX77620_LDO_SLEW_RATE_MASK 0x1 + +#define MAX77620_REG_GPIO0 0x36 +#define MAX77620_REG_GPIO1 0x37 +#define MAX77620_REG_GPIO2 0x38 +#define MAX77620_REG_GPIO3 0x39 +#define MAX77620_REG_GPIO4 0x3A +#define MAX77620_REG_GPIO5 0x3B +#define MAX77620_REG_GPIO6 0x3C +#define MAX77620_REG_GPIO7 0x3D +#define MAX77620_REG_PUE_GPIO 0x3E +#define MAX77620_REG_PDE_GPIO 0x3F +#define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) + +#define MAX77620_REG_ONOFFCNFG1 0x41 +#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) +#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) +#define MAX20024_ONOFFCNFG1_CLRSE 0x18 + +#define MAX77620_REG_ONOFFCNFG2 0x42 +#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) +#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) +#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) + +/* FPS Registers */ +#define MAX77620_REG_FPS_CFG0 0x43 +#define MAX77620_REG_FPS_CFG1 0x44 +#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_LDO0 0x46 +#define MAX77620_REG_FPS_LDO1 0x47 +#define MAX77620_REG_FPS_LDO2 0x48 +#define MAX77620_REG_FPS_LDO3 0x49 +#define MAX77620_REG_FPS_LDO4 0x4A +#define MAX77620_REG_FPS_LDO5 0x4B +#define MAX77620_REG_FPS_LDO6 0x4C +#define MAX77620_REG_FPS_LDO7 0x4D +#define MAX77620_REG_FPS_LDO8 0x4E +#define MAX77620_REG_FPS_SD0 0x4F +#define MAX77620_REG_FPS_SD1 0x50 +#define MAX77620_REG_FPS_SD2 0x51 +#define MAX77620_REG_FPS_SD3 0x52 +#define MAX77620_REG_FPS_SD4 0x53 +#define MAX77620_REG_FPS_NONE 0 +#define MAX77620_FPS_SRC_MASK 0xC0 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 + +/* Minimum and maximum FPS period time (in microseconds) are + * different for MAX77620 and Max20024. + */ +#define MAX77620_FPS_COUNT 3 + +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX20024_FPS_PERIOD_MIN_US 20 + +#define MAX77620_FPS_PERIOD_MAX_US 2560 +#define MAX20024_FPS_PERIOD_MAX_US 5120 + +#define MAX77620_REG_FPS_GPIO1 0x54 +#define MAX77620_REG_FPS_GPIO2 0x55 +#define MAX77620_REG_FPS_GPIO3 0x56 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 + +#define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_REG_CID0 0x58 +#define MAX77620_REG_CID1 0x59 +#define MAX77620_REG_CID2 0x5A +#define MAX77620_REG_CID3 0x5B +#define MAX77620_REG_CID4 0x5C +#define MAX77620_REG_CID5 0x5D + +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 + +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 + +/* CNCG2SD */ +#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) + +/* Device Identification Metal */ +#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) +/* Device Indentification OTP */ +#define MAX77620_CID5_DIDO(n) ((n) & 0xF) + +/* SD CNFG1 */ +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK (1 << 3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) +#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) + +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) + +/* Interrupts */ +enum { + MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ + MAX77620_IRQ_TOP_SD, /* SD power fail */ + MAX77620_IRQ_TOP_LDO, /* LDO power fail */ + MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ + MAX77620_IRQ_TOP_RTC, /* RTC */ + MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ + MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ + MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ +}; + +/* GPIOs */ +enum { + MAX77620_GPIO0, + MAX77620_GPIO1, + MAX77620_GPIO2, + MAX77620_GPIO3, + MAX77620_GPIO4, + MAX77620_GPIO5, + MAX77620_GPIO6, + MAX77620_GPIO7, + MAX77620_GPIO_NR, +}; + +/* FPS Source */ +enum max77620_fps_src { + MAX77620_FPS_SRC_0, + MAX77620_FPS_SRC_1, + MAX77620_FPS_SRC_2, + MAX77620_FPS_SRC_NONE, + MAX77620_FPS_SRC_DEF, +}; + +enum max77620_chip_id { + MAX77620, + MAX20024, +}; + +#endif /* _MFD_MAX77620_H_ */ \ No newline at end of file diff --git a/libexosphere/source/pmic/max7762x.h b/libexosphere/source/pmic/max7762x.h new file mode 100644 index 00000000..1c820251 --- /dev/null +++ b/libexosphere/source/pmic/max7762x.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MAX7762X_H_ +#define _MAX7762X_H_ + +/* +* Switch Power domains (max77620): +* Name | Usage | uV step | uV min | uV default | uV max | Init +*-------+---------------+---------+--------+------------+---------+------------------ +* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) +* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) +* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) +* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | +* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) +* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) +* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | +* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) +* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | +* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V +* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | +* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | +*/ + +/* +* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode +* MAX77620_REG_GPIOx: 0x9 sets output and enable +*/ + +/*! MAX77620 partitions. */ +#define REGULATOR_SD0 0 +#define REGULATOR_SD1 1 +#define REGULATOR_SD2 2 +#define REGULATOR_SD3 3 +#define REGULATOR_LDO0 4 +#define REGULATOR_LDO1 5 +#define REGULATOR_LDO2 6 +#define REGULATOR_LDO3 7 +#define REGULATOR_LDO4 8 +#define REGULATOR_LDO5 9 +#define REGULATOR_LDO6 10 +#define REGULATOR_LDO7 11 +#define REGULATOR_LDO8 12 +#define REGULATOR_MAX 12 + +#define MAX77621_CPU_I2C_ADDR 0x1B +#define MAX77621_GPU_I2C_ADDR 0x1C + +#define MAX77621_VOUT_REG 0 +#define MAX77621_VOUT_DVC_REG 1 +#define MAX77621_CONTROL1_REG 2 +#define MAX77621_CONTROL2_REG 3 + +/* MAX77621_VOUT */ +#define MAX77621_VOUT_DISABLE (0 << 7) +#define MAX77621_VOUT_ENABLE (1 << 7) +#define MAX77621_VOUT_MASK 0x7F +#define MAX77621_VOUT_0_95V 0x37 +#define MAX77621_VOUT_1_09V 0x4F + +/* MAX77621_VOUT_DVC_DVS */ +#define MAX77621_DVS_VOUT_MASK 0x7F + +/* MAX77621_CONTROL1 */ +#define MAX77621_SNS_ENABLE (1 << 7) +#define MAX77621_FPWM_EN_M (1 << 6) +#define MAX77621_NFSR_ENABLE (1 << 5) +#define MAX77621_AD_ENABLE (1 << 4) +#define MAX77621_BIAS_ENABLE (1 << 3) +#define MAX77621_FREQSHIFT_9PER (1 << 2) + +#define MAX77621_RAMP_12mV_PER_US 0x0 +#define MAX77621_RAMP_25mV_PER_US 0x1 +#define MAX77621_RAMP_50mV_PER_US 0x2 +#define MAX77621_RAMP_200mV_PER_US 0x3 +#define MAX77621_RAMP_MASK 0x3 + +/* MAX77621_CONTROL2 */ +#define MAX77621_WDTMR_ENABLE (1 << 6) +#define MAX77621_DISCH_ENBABLE (1 << 5) +#define MAX77621_FT_ENABLE (1 << 4) +#define MAX77621_T_JUNCTION_120 (1 << 7) + +#define MAX77621_CKKADV_TRIP_DISABLE 0xC +#define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 +#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 +#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 + +#define MAX77621_INDUCTOR_MIN_30_PER 0x0 +#define MAX77621_INDUCTOR_NOMINAL 0x1 +#define MAX77621_INDUCTOR_PLUS_30_PER 0x2 +#define MAX77621_INDUCTOR_PLUS_60_PER 0x3 + +#endif diff --git a/libexosphere/source/pmic/pmic_api.cpp b/libexosphere/source/pmic/pmic_api.cpp new file mode 100644 index 00000000..e50723dc --- /dev/null +++ b/libexosphere/source/pmic/pmic_api.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "max77620.h" +#include "max7762x.h" + +namespace ams::pmic { + + namespace { + + constexpr inline int I2cAddressEristaMax77621 = 0x1B; + constexpr inline int I2cAddressMarikoMax77812_A = 0x31; + constexpr inline int I2cAddressMarikoMax77812_B = 0x33; + + + /* https://github.com/Atmosphere-NX/Atmosphere/blob/master/emummc/source/power/max7762x.h */ + /* TODO: Find datasheet, link to it instead. */ + /* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */ + /* This does not contain Max77621 documentation, though. */ + constexpr inline int Max77620RegisterGpio0 = 0x36; + constexpr inline int Max77620RegisterAmeGpio = 0x40; + + constexpr inline int Max77621RegisterVOut = 0x00; + constexpr inline int Max77621RegisterVOutDvc = 0x01; + constexpr inline int Max77621RegisterControl1 = 0x02; + constexpr inline int Max77621RegisterControl2 = 0x03; + + + /* https://datasheets.maximintegrated.com/en/ds/MAX77812.pdf */ + constexpr inline int Max77812RegisterEnCtrl = 0x06; + constexpr inline int Max77812RegisterM4VOut = 0x26; + + void Max77620EnableGpio(int gpio) { + u8 val; + + /* Clear the AE for the GPIO */ + if (i2c::Query(std::addressof(val), sizeof(val), i2c::Port_5, I2cAddressEristaMax77621, Max77620RegisterAmeGpio)) { + val &= ~(1 << gpio); + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77620RegisterAmeGpio, val); + } + + /* Set GPIO_DRV_PUSHPULL (bit 0), GPIO_OUTPUT_VAL_HIGH (bit 3). */ + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77620RegisterGpio0 + gpio, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); + } + + void EnableVddCpuErista() { + /* Enable GPIO 5. */ + /* TODO: What does this control? */ + Max77620EnableGpio(5); + + /* Configure Max77621 control registers. */ + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl1, MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl2, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); + + /* Configure Max77621 VOut to 0.95v */ + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOutDvc, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + } + + void DisableVddCpuErista() { + /* Disable Max77621 VOut. */ + i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_DISABLE); + } + + int GetI2cAddressForMarikoMax77812(Regulator regulator) { + switch (regulator) { + case Regulator_Mariko_Max77812_A: return I2cAddressMarikoMax77812_A; + case Regulator_Mariko_Max77812_B: return I2cAddressMarikoMax77812_B; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + void EnableVddCpuMariko(Regulator regulator) { + const int address = GetI2cAddressForMarikoMax77812(regulator); + + /* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */ + u8 ctrl; + if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) { + ctrl |= 0x40; + i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl); + } + + /* Set BUCK Master 4 output voltage to 110. */ + i2c::SendByte(i2c::Port_5, address, Max77812RegisterM4VOut, 110); + } + + void DisableVddCpuMariko(Regulator regulator) { + const int address = GetI2cAddressForMarikoMax77812(regulator); + + /* Clear EN_M3_LPM to disable BUCK Master 3 low power mode. */ + u8 ctrl; + if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) { + ctrl &= ~0x40; + i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl); + } + } + + } + + void EnableVddCpu(Regulator regulator) { + switch (regulator) { + case Regulator_Erista_Max77621: + return EnableVddCpuErista(); + case Regulator_Mariko_Max77812_A: + case Regulator_Mariko_Max77812_B: + return EnableVddCpuMariko(regulator); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + void DisableVddCpu(Regulator regulator) { + switch (regulator) { + case Regulator_Erista_Max77621: + return DisableVddCpuErista(); + case Regulator_Mariko_Max77812_A: + case Regulator_Mariko_Max77812_B: + return DisableVddCpuMariko(regulator); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + +} diff --git a/libexosphere/source/se/se_aes.cpp b/libexosphere/source/se/se_aes.cpp new file mode 100644 index 00000000..f9aac61b --- /dev/null +++ b/libexosphere/source/se/se_aes.cpp @@ -0,0 +1,209 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + constexpr inline int AesKeySizeMax = 256 / BITSIZEOF(u8); + + enum AesMode { + AesMode_Aes128 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY128 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY128 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, + AesMode_Aes192 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY192 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY192 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, + AesMode_Aes256 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY256 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY256 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, + }; + + enum MemoryInterface { + MemoryInterface_Ahb = SE_CRYPTO_CONFIG_MEMIF_AHB, + MemoryInterface_Mc = SE_CRYPTO_CONFIG_MEMIF_MCCIF, + }; + + constexpr inline u32 AesConfigEcb = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); + + void SetConfig(volatile SecurityEngineRegisters *SE, bool encrypt, SE_CONFIG_DST dst) { + reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM_SEL(CONFIG_ENC_ALG, encrypt, AES_ENC, NOP), + SE_REG_BITS_ENUM_SEL(CONFIG_DEC_ALG, encrypt, NOP, AES_DEC), + SE_REG_BITS_VALUE (CONFIG_DST, dst)); + } + + void SetAesConfig(volatile SecurityEngineRegisters *SE, int slot, bool encrypt, u32 config) { + const u32 encoded = reg::Encode(SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB), + SE_REG_BITS_VALUE (CRYPTO_CONFIG_KEY_INDEX, slot), + SE_REG_BITS_ENUM_SEL(CRYPTO_CONFIG_CORE_SEL, encrypt, ENCRYPT, DECRYPT)); + + reg::Write(SE->SE_CRYPTO_CONFIG, (config | encoded)); + } + + void SetBlockCount(volatile SecurityEngineRegisters *SE, int count) { + reg::Write(SE->SE_CRYPTO_LAST_BLOCK, count - 1); + } + + void UpdateAesMode(volatile SecurityEngineRegisters *SE, AesMode mode) { + reg::ReadWrite(SE->SE_CONFIG, REG_BITS_VALUE(16, 16, mode)); + } + + // void UpdateMemoryInterface(volatile SecurityEngineRegisters *SE, MemoryInterface memif) { + // reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_VALUE(CRYPTO_CONFIG_MEMIF, memif)); + // } + + void SetEncryptedAesKey(int dst_slot, int kek_slot, const void *key, size_t key_size, AesMode mode) { + AMS_ABORT_UNLESS(key_size <= AesKeySizeMax); + AMS_ABORT_UNLESS(0 <= dst_slot && dst_slot < AesKeySlotCount); + AMS_ABORT_UNLESS(0 <= kek_slot && kek_slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure for single AES ECB decryption to key table. */ + SetConfig(SE, false, SE_CONFIG_DST_KEYTABLE); + SetAesConfig(SE, kek_slot, false, AesConfigEcb); + UpdateAesMode(SE, mode); + SetBlockCount(SE, 1); + + /* Select the destination keyslot. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, dst_slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3)); + + /* Ensure that the se sees the keydata we want it to. */ + hw::FlushDataCache(key, key_size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, key, key_size); + } + + void EncryptAes(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) { + /* If nothing to decrypt, succeed. */ + if (src_size == 0) { return; } + + /* Validate input. */ + AMS_ABORT_UNLESS(dst_size == AesBlockSize); + AMS_ABORT_UNLESS(src_size == AesBlockSize); + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure for AES-ECB encryption to memory. */ + SetConfig(SE, true, SE_CONFIG_DST_MEMORY); + SetAesConfig(SE, slot, true, AesConfigEcb); + UpdateAesMode(SE, mode); + + /* Execute the operation. */ + ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size); + } + + } + + void ClearAesKeySlot(int slot) { + /* Validate the key slot. */ + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + for (int i = 0; i < 16; ++i) { + /* Select the keyslot. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, i)); + + /* Write the data. */ + SE->SE_CRYPTO_KEYTABLE_DATA = 0; + } + } + + void LockAesKeySlot(int slot, u32 flags) { + /* Validate the key slot. */ + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Set non per-key flags. */ + if ((flags & ~KeySlotLockFlags_PerKey) != 0) { + /* TODO: KeySlotLockFlags_DstKeyTableOnly is Mariko-only. How should we handle this? */ + /* TODO: Mariko bit support. */ + reg::ReadWrite(SE->SE_CRYPTO_KEYTABLE_ACCESS[slot], REG_BITS_VALUE(0, 7, ~flags)); + } + + /* Set per-key flag. */ + if ((flags & KeySlotLockFlags_PerKey) != 0) { + reg::ReadWrite(SE->SE_CRYPTO_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0)); + } + } + + void SetAesKey(int slot, const void *key, size_t key_size) { + /* Validate the key slot and key size. */ + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + AMS_ABORT_UNLESS(key_size <= AesKeySizeMax); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Set each key word in order. */ + const u32 *key_u32 = static_cast(key); + const int num_words = key_size / sizeof(u32); + for (int i = 0; i < num_words; ++i) { + /* Select the keyslot. */ + 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, KEY), + SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); + + /* Set the key word. */ + SE->SE_CRYPTO_KEYTABLE_DATA = *(key_u32++); + } + } + + void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size) { + return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes128); + } + + void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size) { + return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes256); + } + + void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { + return EncryptAes(dst, dst_size, slot, src, src_size, AesMode_Aes128); + } + + void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { + /* If nothing to decrypt, succeed. */ + if (src_size == 0) { return; } + + /* Validate input. */ + AMS_ABORT_UNLESS(dst_size == AesBlockSize); + AMS_ABORT_UNLESS(src_size == AesBlockSize); + AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure for AES-ECB decryption to memory. */ + SetConfig(SE, false, SE_CONFIG_DST_MEMORY); + SetAesConfig(SE, slot, false, AesConfigEcb); + + ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size); + } + +} diff --git a/libexosphere/source/se/se_execute.cpp b/libexosphere/source/se/se_execute.cpp new file mode 100644 index 00000000..dbe3cbcc --- /dev/null +++ b/libexosphere/source/se/se_execute.cpp @@ -0,0 +1,138 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + struct LinkedListEntry { + u32 zero; + u32 address; + u32 size; + }; + static_assert(util::is_pod::value); + + uintptr_t GetPhysicalAddress(const void *ptr) { + const uintptr_t virt_address = reinterpret_cast(ptr); + + #if defined(ATMOSPHERE_ARCH_ARM64) + u64 phys_address; + __asm__ __volatile__("at s1e3r, %[virt]; mrs %[phys], par_el1" : [phys]"=r"(phys_address) : [virt]"r"(virt_address) : "memory", "cc"); + return (phys_address & 0x0000FFFFFFFFF000ul) | (virt_address & 0x0000000000000FFFul); + #elif defined(ATMOSPHERE_ARCH_ARM) + return virt_address; + #else + #error "Unknown architecture for Tegra Security Engine physical address translation" + #endif + } + + constexpr void SetLinkedListEntry(LinkedListEntry *entry, const void *ptr, size_t size) { + /* Clear the zero field. */ + entry->zero = 0; + + /* Set the address. */ + if (ptr != nullptr) { + entry->address = GetPhysicalAddress(ptr); + entry->size = static_cast(size); + } else { + entry->address = 0; + entry->size = 0; + } + } + + void StartOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op) { + /* Write back the current values of the error and interrupt status. */ + reg::Write(SE->SE_ERR_STATUS, reg::Read(SE->SE_ERR_STATUS)); + reg::Write(SE->SE_INT_STATUS, reg::Read(SE->SE_INT_STATUS)); + + /* Write the operation. */ + reg::Write(SE->SE_OPERATION, SE_REG_BITS_VALUE(OPERATION_OP, op)); + } + + void WaitForOperationComplete(volatile SecurityEngineRegisters *SE) { + /* Spin until the operation is done. */ + while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, CLEAR))) { /* ... */ } + + /* Check for operation success. */ + ValidateAesOperationResult(SE); + } + + } + + void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size) { + /* Set the linked list entries. */ + LinkedListEntry src_entry; + LinkedListEntry dst_entry; + + SetLinkedListEntry(std::addressof(src_entry), src, src_size); + SetLinkedListEntry(std::addressof(dst_entry), dst, dst_size); + + /* Ensure the linked list entry data is seen correctly. */ + hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry)); + hw::FlushDataCache(std::addressof(dst_entry), sizeof(dst_entry)); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Configure the linked list addresses. */ + reg::Write(SE->SE_IN_LL_ADDR, static_cast(GetPhysicalAddress(std::addressof(src_entry)))); + reg::Write(SE->SE_OUT_LL_ADDR, static_cast(GetPhysicalAddress(std::addressof(dst_entry)))); + + /* Start the operation. */ + StartOperation(SE, op); + + /* Wait for the operation to complete. */ + WaitForOperationComplete(SE); + } + + void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) { + /* Validate sizes. */ + AMS_ABORT_UNLESS(dst_size <= AesBlockSize); + AMS_ABORT_UNLESS(src_size == AesBlockSize); + + /* Set the block count to 1. */ + reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); + + /* Create an aligned buffer. */ + util::AlignedBuffer aligned; + std::memcpy(aligned, src, AesBlockSize); + hw::FlushDataCache(aligned, AesBlockSize); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, aligned, AesBlockSize, aligned, AesBlockSize); + + /* Ensure that the CPU will see the correct output. */ + hw::DataSynchronizationBarrierInnerShareable(); + hw::FlushDataCache(aligned, AesBlockSize); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Copy the output to the destination. */ + std::memcpy(dst, aligned, dst_size); + } + + void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE) { + /* Ensure no error occurred. */ + AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR))); + + /* Ensure the security engine is idle. */ + AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))); + + /* Ensure there is no error status. */ + AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0); + } + +} diff --git a/libexosphere/source/se/se_execute.hpp b/libexosphere/source/se/se_execute.hpp new file mode 100644 index 00000000..76b0a34a --- /dev/null +++ b/libexosphere/source/se/se_execute.hpp @@ -0,0 +1,28 @@ +/* + * 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 "se_registers.hpp" + +namespace ams::se { + + volatile SecurityEngineRegisters *GetRegisters(); + + void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size); + void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size); + + void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE); + +} diff --git a/libexosphere/source/se/se_management.cpp b/libexosphere/source/se/se_management.cpp new file mode 100644 index 00000000..de845c2f --- /dev/null +++ b/libexosphere/source/se/se_management.cpp @@ -0,0 +1,114 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetAddress(); + constinit DoneHandler g_done_handler = nullptr; + + } + + volatile SecurityEngineRegisters *GetRegisters() { + return reinterpret_cast(g_register_address); + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void Initialize() { + auto *SE = GetRegisters(); + AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))); + } + + void SetSecure(bool secure) { + auto *SE = GetRegisters(); + + /* Set the security software setting. */ + if (secure) { + reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE)); + } else { + reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, NONSECURE)); + } + + /* Read the status register to force an update. */ + reg::Read(SE->SE_SE_SECURITY); + } + + void SetTzramSecure() { + auto *SE = GetRegisters(); + + /* Set the TZRAM setting to secure. */ + SE->SE_TZRAM_SECURITY = SE_TZRAM_SETTING_SECURE; + } + + void SetPerKeySecure() { + auto *SE = GetRegisters(); + + /* Clear AES PerKey security. */ + SE->SE_CRYPTO_SECURITY_PERKEY = 0; + + /* Clear RSA PerKey security. */ + SE->SE_RSA_SECURITY_PERKEY = 0; + + /* Update PERKEY_SETTING to secure. */ + reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE)); + } + + void Lockout() { + auto *SE = GetRegisters(); + + /* Lock access to the AES keyslots. */ + for (int i = 0; i < AesKeySlotCount; ++i) { + SE->SE_CRYPTO_KEYTABLE_ACCESS[i] = 0; + } + + /* Lock access to the RSA keyslots. */ + for (int i = 0; i < RsaKeySlotCount; ++i) { + SE->SE_RSA_KEYTABLE_ACCESS[i] = 0; + } + + /* Set Per Key secure. */ + SetPerKeySecure(); + + /* Configure SE_SECURITY. */ + { + reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_HARD_SETTING, SECURE), + SE_REG_BITS_ENUM(SECURITY_ENG_DIS, DISABLE), + SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE), + SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE)); + } + } + + void HandleInterrupt() { + /* Get the registers. */ + auto *SE = GetRegisters(); + + /* Disable the SE interrupt. */ + reg::Write(SE->SE_INT_ENABLE, 0); + + /* Execute the handler if we have one. */ + if (const auto handler = g_done_handler; handler != nullptr) { + g_done_handler = nullptr; + handler(); + } + } + +} diff --git a/libexosphere/source/se/se_registers.hpp b/libexosphere/source/se/se_registers.hpp new file mode 100644 index 00000000..d76e0571 --- /dev/null +++ b/libexosphere/source/se/se_registers.hpp @@ -0,0 +1,249 @@ +/* + * 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::se { + + struct SecurityEngineRegisters { + u32 SE_SE_SECURITY; + u32 SE_TZRAM_SECURITY; + u32 SE_OPERATION; + u32 SE_INT_ENABLE; + u32 SE_INT_STATUS; + u32 SE_CONFIG; + u32 SE_IN_LL_ADDR; + u32 SE_IN_CUR_BYTE_ADDR; + u32 SE_IN_CUR_LL_ID; + u32 SE_OUT_LL_ADDR; + u32 SE_OUT_CUR_BYTE_ADDR; + u32 SE_OUT_CUR_LL_ID; + u32 SE_HASH_RESULT[0x10]; + u32 SE_CTX_SAVE_CONFIG; + u32 _0x74[0x63]; + u32 SE_SHA_CONFIG; + u32 SE_SHA_MSG_LENGTH[0x4]; + u32 SE_SHA_MSG_LEFT[0x4]; + u32 _0x224[0x17]; + u32 SE_CRYPTO_SECURITY_PERKEY; + u32 SE_CRYPTO_KEYTABLE_ACCESS[0x10]; + u32 _0x2C4[0x10]; + u32 SE_CRYPTO_CONFIG; + u32 SE_CRYPTO_LINEAR_CTR[0x4]; + u32 SE_CRYPTO_LAST_BLOCK; + u32 SE_CRYPTO_KEYTABLE_ADDR; + u32 SE_CRYPTO_KEYTABLE_DATA; + u32 _0x324[0x3]; + u32 SE_CRYPTO_KEYTABLE_DST; + u32 _0x334[0x3]; + u32 SE_RNG_CONFIG; + u32 SE_RNG_SRC_CONFIG; + u32 SE_RNG_RESEED_INTERVAL; + u32 _0x34C[0x2D]; + u32 SE_RSA_CONFIG; + u32 SE_RSA_KEY_SIZE; + u32 SE_RSA_EXP_SIZE; + u32 SE_RSA_SECURITY_PERKEY; + u32 SE_RSA_KEYTABLE_ACCESS[0x2]; + u32 _0x418[0x2]; + u32 SE_RSA_KEYTABLE_ADDR; + u32 SE_RSA_KEYTABLE_DATA; + u32 SE_RSA_OUTPUT[0x40]; + u32 _0x528[0xB6]; + u32 SE_STATUS; + u32 SE_ERR_STATUS; + u32 SE_MISC; + u32 SE_SPARE; + u32 SE_ENTROPY_DEBUG_COUNTER; + u32 _0x814; + u32 _0x818; + u32 _0x81C; + u32 _0x820[0x5F8]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(SecurityEngineRegisters) == secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetSize()); + + static_assert(AesKeySlotCount == util::size(SecurityEngineRegisters{}.SE_CRYPTO_KEYTABLE_ACCESS)); + static_assert(RsaKeySlotCount == util::size(SecurityEngineRegisters{}.SE_RSA_KEYTABLE_ACCESS)); + + #define SE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SE, NAME) + #define SE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SE, NAME, VALUE) + #define SE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SE, NAME, ENUM) + #define SE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + + #define DEFINE_SE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SE, NAME, __OFFSET__, __WIDTH__) + #define DEFINE_SE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE) + #define DEFINE_SE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) + #define DEFINE_SE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) + #define DEFINE_SE_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 (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + + #define DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(NAME, __OFFSET__) \ + REG_DEFINE_NAMED_REG(SE, NAME, __OFFSET__, 1); \ + \ + enum SE_##NAME { \ + SE_##NAME##_##CLEAR = 0, \ + SE_##NAME##_##ACTIVE = 1, \ + SE_##NAME##_##SW_CLEAR = 1, \ + }; + + /* SE_STATUS. */ + DEFINE_SE_REG_TWO_BIT_ENUM(STATUS_STATE, 0, IDLE, BUSY, WAIT_OUT, WAIT_IN); + + /* SE_SECURITY */ + DEFINE_SE_REG_BIT_ENUM(SECURITY_HARD_SETTING, 0, SECURE, NONSECURE); + DEFINE_SE_REG_BIT_ENUM(SECURITY_ENG_DIS, 1, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(SECURITY_PERKEY_SETTING, 2, SECURE, NONSECURE); + DEFINE_SE_REG_BIT_ENUM(SECURITY_SOFT_SETTING, 16, SECURE, NONSECURE); + + /* SE_TZRAM_SECURITY */ + DEFINE_SE_REG(TZRAM_SETTING, 0, BITSIZEOF(u32)); + constexpr inline u32 SE_TZRAM_SETTING_SECURE = 0; + + /* SE_OPERATION */ + DEFINE_SE_REG_THREE_BIT_ENUM(OPERATION_OP, 0, ABORT, START, RESTART_OUT, CTX_SAVE, RESTART_IN, RESERVED_5, RESERVED_6, RESERVED_7); + + /* SE_INT_ENABLE */ + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_LL_BUF_RD, 0, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_DONE, 1, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_LL_BUF_WR, 2, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_DONE, 3, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_SE_OP_DONE, 4, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_RESEED_CNTR_EXHAUSTED, 5, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_ERR_STAT, 16, DISABLE, ENABLE); + + /* SE_INT_STATUS */ + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_LL_BUF_RD, 0); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_DONE, 1); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_LL_BUF_WR, 2); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_DONE, 3); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_SE_OP_DONE, 4); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_RESEED_CNTR_EXHAUSTED, 5); + DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_ERR_STAT, 16); + + /* SE_CONFIG */ + DEFINE_SE_REG(CONFIG_DST, 2, 3); + DEFINE_SE_REG(CONFIG_DEC_ALG, 8, 4); + DEFINE_SE_REG(CONFIG_ENC_ALG, 12, 4); + DEFINE_SE_REG(CONFIG_DEC_MODE, 16, 8); + DEFINE_SE_REG(CONFIG_ENC_MODE, 24, 8); + + enum SE_CONFIG_DST { + SE_CONFIG_DST_MEMORY = 0, + SE_CONFIG_DST_HASH_REG = 1, + SE_CONFIG_DST_KEYTABLE = 2, + SE_CONFIG_DST_SRK = 3, + SE_CONFIG_DST_RSA_REG = 4, + }; + + enum SE_CONFIG_DEC_ALG { + SE_CONFIG_DEC_ALG_NOP = 0, + SE_CONFIG_DEC_ALG_AES_DEC = 1, + }; + + enum SE_CONFIG_ENC_ALG { + SE_CONFIG_ENC_ALG_NOP = 0, + SE_CONFIG_ENC_ALG_AES_ENC = 1, + SE_CONFIG_ENC_ALG_RNG = 2, + SE_CONFIG_ENC_ALG_SHA = 3, + SE_CONFIG_ENC_ALG_RSA = 4, + }; + + enum SE_CONFIG_DEC_MODE { + SE_CONFIG_DEC_MODE_AESMODE_KEY128 = 0, + SE_CONFIG_DEC_MODE_AESMODE_KEY192 = 1, + SE_CONFIG_DEC_MODE_AESMODE_KEY256 = 2, + }; + + enum SE_CONFIG_ENC_MODE { + SE_CONFIG_ENC_MODE_AESMODE_KEY128 = 0, + SE_CONFIG_ENC_MODE_AESMODE_KEY192 = 1, + SE_CONFIG_ENC_MODE_AESMODE_KEY256 = 2, + + SE_CONFIG_ENC_MODE_AESMODE_SHA1 = 1, + SE_CONFIG_ENC_MODE_AESMODE_SHA224 = 4, + SE_CONFIG_ENC_MODE_AESMODE_SHA256 = 5, + SE_CONFIG_ENC_MODE_AESMODE_SHA384 = 6, + SE_CONFIG_ENC_MODE_AESMODE_SHA512 = 7, + }; + + + /* SE_CRYPTO_KEYTABLE_ADDR */ + DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, 0, 4); + DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_WORD, 0, 2); + DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, 0, 3); + + enum SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD { + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_0 = 0u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_1 = 1u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_2 = 2u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_3 = 3u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_4 = 4u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_5 = 5u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_6 = 6u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_7 = 7u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_0 = 8u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_1 = 9u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_2 = 10u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_3 = 11u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_0 = 12u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_1 = 13u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_2 = 14u, + SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_3 = 15u, + }; + + DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, 2, ORIGINAL_IV, UPDATED_IV); + DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, 3, KEY, IV); + + DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, 4, 4); + + /* SE_RSA_KEYTABLE_ADDR */ + DEFINE_SE_REG(RSA_KEYTABLE_ADDR_WORD_ADDR, 0, 6); + DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_EXPMOD_SEL, 6, EXPONENT, MODULUS); + DEFINE_SE_REG(RSA_KEYTABLE_ADDR_KEY_SLOT, 7, 1); + DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_INPUT_MODE, 8, REGISTER, MEMORY); + + /* SE_RSA_KEYTABLE_ACCESS */ + DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYREAD, 0, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUPDATE, 1, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUSE, 2, DISABLE, ENABLE); + + /* SE_CRYPTO_CONFIG */ + DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_HASH_ENB, 0, DISABLE, ENABLE); + DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_XOR_POS, 1, BYPASS, RESERVED, TOP, BOTTOM); + DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_INPUT_SEL, 3, MEMORY, RANDOM, INIT_AESOUT, LINEAR_CTR); + DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_VCTRAM_SEL, 5, MEMORY, RESERVED, INIT_AESOUT, INIT_PREV_MEMORY); + DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_IV_SELECT, 7, ORIGINAL, UPDATED); + DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_CORE_SEL, 8, DECRYPT, ENCRYPT); + DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_KEYSCH_BYPASS, 10, DISABLE, ENABLE); + DEFINE_SE_REG(CRYPTO_CONFIG_CTR_CNTN, 11, 8); + DEFINE_SE_REG(CRYPTO_CONFIG_KEY_INDEX, 24, 4); + DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_MEMIF, 31, AHB, MCCIF); + + /* SE_CRYPTO_KEYTABLE_DST */ + DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IV, UPDATED_IV); + DEFINE_SE_REG(CRYPTO_KEYTABLE_DST_KEY_INDEX, 8, 4); + + /* SE_RNG_CONFIG */ + DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_MODE, 0, NORMAL, FORCE_INSTANTIATION, FORCE_RESEED, RESERVED3); + DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_SRC, 2, NONE, ENTROPY, LFSR, RESERVED3); + + /* SE_RNG_SRC_CONFIG */ + DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, 0, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, 1, DISABLE, ENABLE); + DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_HW_DISABLE_CYA, 2, DISABLE, ENABLE); + DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_SUBSAMPLE, 4, 3); + DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_DATA_FLUSH, 8, 1); + +} diff --git a/libexosphere/source/se/se_rng.cpp b/libexosphere/source/se/se_rng.cpp new file mode 100644 index 00000000..4cb099bd --- /dev/null +++ b/libexosphere/source/se/se_rng.cpp @@ -0,0 +1,146 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + constexpr inline int RngReseedInterval = 70001; + + void ConfigRng(volatile SecurityEngineRegisters *SE, SE_CONFIG_DST dst, SE_RNG_CONFIG_MODE mode) { + /* Configure the engine to do RNG encryption. */ + reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM (CONFIG_ENC_ALG, RNG), + SE_REG_BITS_ENUM (CONFIG_DEC_ALG, NOP), + SE_REG_BITS_VALUE(CONFIG_DST, dst)); + + reg::Write(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB), + SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_CORE_SEL, ENCRYPT), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, RANDOM), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS), + SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); + + /* Configure the RNG to use Entropy as source. */ + reg::Write(SE->SE_RNG_CONFIG, SE_REG_BITS_ENUM(RNG_CONFIG_SRC, ENTROPY), SE_REG_BITS_VALUE(RNG_CONFIG_MODE, mode)); + } + + } + + void InitializeRandom() { + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Lock the entropy source. */ + reg::Write(SE->SE_RNG_SRC_CONFIG, SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, ENABLE), + SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, ENABLE)); + + /* Set the reseed interval to force a reseed every 70000 blocks. */ + SE->SE_RNG_RESEED_INTERVAL = RngReseedInterval; + + /* Initialize the DRBG. */ + { + u8 dummy_buf[AesBlockSize]; + + /* Configure the engine to force drbg instantiation by writing random to memory. */ + ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_FORCE_INSTANTIATION); + + /* Configure to do a single RNG block operation to trigger DRBG init. */ + SE->SE_CRYPTO_LAST_BLOCK = 0; + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, dummy_buf, sizeof(dummy_buf), nullptr, 0); + } + } + + void GenerateRandomBytes(void *dst, size_t size) { + /* If we're not generating any bytes, there's nothing to do. */ + if (size == 0) { + return; + } + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Determine how many blocks to generate. */ + const size_t num_blocks = size / AesBlockSize; + const size_t aligned_size = num_blocks * AesBlockSize; + const size_t fractional = size - aligned_size; + + /* Configure the RNG to generate random to memory. */ + ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_NORMAL); + + /* Generate as many aligned blocks as we can. */ + if (aligned_size > 0) { + /* Configure the engine to generate the right number of blocks. */ + SE->SE_CRYPTO_LAST_BLOCK = num_blocks - 1; + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, dst, aligned_size, nullptr, 0); + } + + /* Generate a single block to output. */ + if (fractional > 0) { + ExecuteOperationSingleBlock(SE, static_cast(dst) + aligned_size, fractional, nullptr, 0); + } + } + + void SetRandomKey(int slot) { + /* NOTE: Nintendo does not validate the destination keyslot here. */ + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure the RNG to output to the keytable. */ + ConfigRng(SE, SE_CONFIG_DST_KEYTABLE, SE_RNG_CONFIG_MODE_NORMAL); + + /* Configure the keytable destination to be the low part of the key. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3)); + + /* Configure a single block operation. */ + SE->SE_CRYPTO_LAST_BLOCK = 0; + + /* Execute the operation to generate a random low-part of the key. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); + + /* Configure the keytable destination to be the high part of the key. */ + reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_4_7)); + + /* Execute the operation to generate a random high-part of the key. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); + } + + void GenerateSrk() { + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure the RNG to output to SRK and force a reseed. */ + ConfigRng(SE, SE_CONFIG_DST_SRK, SE_RNG_CONFIG_MODE_FORCE_RESEED); + + /* Configure a single block operation. */ + SE->SE_CRYPTO_LAST_BLOCK = 0; + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); + } + +} diff --git a/libexosphere/source/se/se_rsa.cpp b/libexosphere/source/se/se_rsa.cpp new file mode 100644 index 00000000..d39a040d --- /dev/null +++ b/libexosphere/source/se/se_rsa.cpp @@ -0,0 +1,125 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + struct RsaKeyInfo { + int modulus_size_val; + int exponent_size_val; + }; + + constinit RsaKeyInfo g_rsa_key_infos[RsaKeySlotCount] = {}; + + void ClearRsaKeySlot(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) { + /* Get the engine. */ + auto *SE = GetRegisters(); + + constexpr int NumWords = se::RsaSize / sizeof(u32); + for (int i = 0; i < NumWords; ++i) { + /* Select the keyslot word. */ + reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i)); + + /* Clear the keyslot word. */ + SE->SE_RSA_KEYTABLE_DATA = 0; + } + } + + void SetRsaKey(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) { + /* Get the engine. */ + auto *SE = GetRegisters(); + + const int num_words = key_size / sizeof(u32); + for (int i = 0; i < num_words; ++i) { + /* Select the keyslot word. */ + reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod), + SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i)); + + /* Get the word. */ + const u32 word = util::LoadBigEndian(static_cast(key) + (num_words - 1 - i)); + + /* Write the keyslot word. */ + SE->SE_RSA_KEYTABLE_DATA = word; + } + } + + } + + void ClearRsaKeySlot(int slot) { + /* Validate the key slot. */ + AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); + + /* Clear the info. */ + g_rsa_key_infos[slot] = {}; + + /* Clear the modulus. */ + ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS); + + /* Clear the exponent. */ + ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT); + } + + void LockRsaKeySlot(int slot, u32 flags) { + /* Validate the key slot. */ + AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Set non per-key flags. */ + if ((flags & ~KeySlotLockFlags_PerKey) != 0) { + /* Pack the flags into the expected format. */ + u32 value = 0; + value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0; + value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0; + value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0; + + reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE), + SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE), + SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE)); + } + + /* Set per-key flag. */ + if ((flags & KeySlotLockFlags_PerKey) != 0) { + reg::ReadWrite(SE->SE_RSA_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0)); + } + } + + void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size) { + /* Validate the key slot and sizes. */ + AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); + AMS_ABORT_UNLESS(mod_size <= RsaSize); + AMS_ABORT_UNLESS(exp_size <= RsaSize); + + /* Set the sizes in the info. */ + auto &info = g_rsa_key_infos[slot]; + info.modulus_size_val = (mod_size / 64) - 1; + info.exponent_size_val = (exp_size / 4); + + /* Set the modulus and exponent. */ + SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size); + SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size); + } + +} diff --git a/libexosphere/source/se/se_suspend.cpp b/libexosphere/source/se/se_suspend.cpp new file mode 100644 index 00000000..03473deb --- /dev/null +++ b/libexosphere/source/se/se_suspend.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "se_execute.hpp" + +namespace ams::se { + + namespace { + + bool TestRegister(volatile u32 &r, u16 v) { + return (static_cast(reg::Read(r))) == v; + } + + } + + bool ValidateStickyBits(const StickyBits &bits) { + /* Get the registers. */ + auto *SE = GetRegisters(); + + /* Check SE_SECURITY. */ + if (!TestRegister(SE->SE_SE_SECURITY, bits.se_security)) { return false; } + + /* Check TZRAM_SECURITY. */ + if (!TestRegister(SE->SE_TZRAM_SECURITY, bits.tzram_security)) { return false; } + + /* Check CRYPTO_SECURITY_PERKEY. */ + if (!TestRegister(SE->SE_CRYPTO_SECURITY_PERKEY, bits.crypto_security_perkey)) { return false; } + + /* Check CRYPTO_KEYTABLE_ACCESS. */ + for (int i = 0; i < AesKeySlotCount; ++i) { + if (!TestRegister(SE->SE_CRYPTO_KEYTABLE_ACCESS[i], bits.crypto_keytable_access[i])) { return false; } + } + + /* Test RSA_SCEURITY_PERKEY */ + if (!TestRegister(SE->SE_CRYPTO_SECURITY_PERKEY, bits.rsa_security_perkey)) { return false; } + + /* Check RSA_KEYTABLE_ACCESS. */ + for (int i = 0; i < RsaKeySlotCount; ++i) { + if (!TestRegister(SE->SE_RSA_KEYTABLE_ACCESS[i], bits.rsa_keytable_access[i])) { return false; } + } + + /* All sticky bits are valid. */ + return true; + } + +} diff --git a/libexosphere/source/tsec/tsec_api.cpp b/libexosphere/source/tsec/tsec_api.cpp new file mode 100644 index 00000000..b8994ebc --- /dev/null +++ b/libexosphere/source/tsec/tsec_api.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::tsec { + + namespace { + + + + } + + void Lock() { + /* Set the tsec host1x syncpoint (160) to be secure. */ + /* TODO: constexpr value. */ + reg::ReadWrite(0x500038F8, REG_BITS_VALUE(0, 1, 0)); + + /* Clear the tsec host1x syncpoint. */ + reg::Write(0x50003300, 0); + } + +} \ No newline at end of file diff --git a/libexosphere/source/uart/uart_api.cpp b/libexosphere/source/uart/uart_api.cpp new file mode 100644 index 00000000..53374810 --- /dev/null +++ b/libexosphere/source/uart/uart_api.cpp @@ -0,0 +1,113 @@ +/* + * 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 "uart_registers.hpp" + +namespace ams::uart { + + namespace { + + constexpr inline const u16 UartRegisterOffsets[Port_Count] = { + secmon::MemoryRegionPhysicalDeviceUartA.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), + secmon::MemoryRegionPhysicalDeviceUartB.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), + secmon::MemoryRegionPhysicalDeviceUartC.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), + }; + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceUart.GetAddress(); + + volatile UartRegisters *GetRegisters(Port port) { + return reinterpret_cast(g_register_address + UartRegisterOffsets[port]); + } + + void WaitSymbols(int baud, u32 num) { + util::WaitMicroSeconds(util::DivideUp(1'000'000, baud) * num); + } + + void WaitCycles(int baud, u32 num) { + util::WaitMicroSeconds(util::DivideUp(1'000'000, 16 * baud) * num); + } + + ALWAYS_INLINE void WaitFifoNotFull(volatile UartRegisters *uart) { + while ((uart->lsr & UART_LSR_TX_FIFO_FULL) != 0) { /* ... */ } + } + + ALWAYS_INLINE void WaitFifoNotEmpty(volatile UartRegisters *uart) { + while ((uart->lsr & UART_LSR_RX_FIFO_EMPTY) != 0) { /* ... */ } + } + + void WaitIdle(volatile UartRegisters *uart, u32 vendor_state) { + if (vendor_state & UART_VENDOR_STATE_TX_IDLE) { + while ((uart->lsr & UART_LSR_TMTY) == 0) { /* ... */ } + } + + if (vendor_state & UART_VENDOR_STATE_RX_IDLE) { + while ((uart->lsr & UART_LSR_RDR) != 0) { /* ... */ } + } + } + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void Initialize(Port port, int baud_rate, u32 flags) { + /* Get the registers. */ + auto *uart = GetRegisters(port); + + /* Parse flags. */ + const bool inverted = (flags & Flag_Inverted) != 0; + + /* Calculate the baud rate divisor. */ + constexpr u32 UartClock = 408000000; + const u32 divisor = (UartClock + (baud_rate * 16) / 2) / (baud_rate * 16); + + /* Disable DLAB and all interrupts. */ + uart->lcr = uart->lcr & ~UART_LCR_DLAB; + uart->ier = 0; + uart->mcr = 0; + + /* Setup the uart in FIFO mode. */ + uart->lcr = UART_LCR_DLAB | UART_LCR_WD_LENGTH_8; + uart->dll = static_cast(divisor); + uart->dlh = static_cast(divisor >> 8); + uart->lcr = uart->lcr & ~UART_LCR_DLAB; + reg::Read(std::addressof(uart->spr)); + + /* Wait three symbols. */ + WaitSymbols(baud_rate, 3); + + /* Enable FIFO with default settings. */ + uart->fcr = UART_FCR_FCR_EN_FIFO; + uart->irda_csr = inverted ? UART_IRDA_CSR_INVERT_TXD : 0; + reg::Read(std::addressof(uart->spr)); + + /* Wait three cycles. */ + WaitCycles(baud_rate, 3); + + /* Flush the FIFO. */ + WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE); + uart->fcr = uart->fcr | UART_FCR_RX_CLR | UART_FCR_TX_CLR; + WaitCycles(baud_rate, 32); + + /* Wait for idle state. */ + WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); + + /* Set scratch register to 0. */ + uart->spr = 0; + } + +} \ No newline at end of file diff --git a/libexosphere/source/uart/uart_registers.hpp b/libexosphere/source/uart/uart_registers.hpp new file mode 100644 index 00000000..509de989 --- /dev/null +++ b/libexosphere/source/uart/uart_registers.hpp @@ -0,0 +1,180 @@ +/* + * 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::uart { + + struct UartRegisters { + union { + u32 thr; + u32 rbr; + u32 dll; + }; + union { + u32 ier; + u32 dlh; + }; + union { + u32 iir; + u32 fcr; + }; + u32 lcr; + u32 mcr; + u32 lsr; + u32 msr; + u32 spr; + u32 irda_csr; + u32 rx_fifo_cfg; + u32 mie; + u32 vendor_status; + u32 reserved_30; + u32 reserved_34; + u32 reserved_38; + u32 asr; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(UartRegisters) == 0x40); + + /* 36.3.12 UART_VENDOR_STATUS_0_0 */ + enum UartVendorStatus { + UART_VENDOR_STATE_TX_IDLE = 1 << 0, + UART_VENDOR_STATE_RX_IDLE = 1 << 1, + + /* This bit is set to 1 when a read is issued to an empty FIFO and gets cleared on register read (sticky bit until read) + 0 = NO_UNDERRUN + 1 = UNDERRUN + */ + UART_VENDOR_STATE_RX_UNDERRUN = 1 << 2, + + /* This bit is set to 1 when write data is issued to the TX FIFO when it is already full and gets cleared on register read (sticky bit until read) + 0 = NO_OVERRUN + 1 = OVERRUN + */ + UART_VENDOR_STATE_TX_OVERRUN = 1 << 3, + + UART_VENDOR_STATE_RX_FIFO_COUNTER = 0b111111 << 16, /* reflects number of current entries in RX FIFO */ + UART_VENDOR_STATE_TX_FIFO_COUNTER = 0b111111 << 24 /* reflects number of current entries in TX FIFO */ + }; + + /* 36.3.6 UART_LSR_0 */ + enum UartLineStatus { + UART_LSR_RDR = 1 << 0, /* Receiver Data Ready */ + UART_LSR_OVRF = 1 << 1, /* Receiver Overrun Error */ + UART_LSR_PERR = 1 << 2, /* Parity Error */ + UART_LSR_FERR = 1 << 3, /* Framing Error */ + UART_LSR_BRK = 1 << 4, /* BREAK condition detected on line */ + UART_LSR_THRE = 1 << 5, /* Transmit Holding Register is Empty -- OK to write data */ + UART_LSR_TMTY = 1 << 6, /* Transmit Shift Register empty status */ + UART_LSR_FIFOE = 1 << 7, /* Receive FIFO Error */ + UART_LSR_TX_FIFO_FULL = 1 << 8, /* Transmitter FIFO full status */ + UART_LSR_RX_FIFO_EMPTY = 1 << 9, /* Receiver FIFO empty status */ + }; + + /* 36.3.4 UART_LCR_0 */ + enum UartLineControl { + UART_LCR_WD_LENGTH_5 = 0, /* word length 5 */ + UART_LCR_WD_LENGTH_6 = 1, /* word length 6 */ + UART_LCR_WD_LENGTH_7 = 2, /* word length 7 */ + UART_LCR_WD_LENGTH_8 = 3, /* word length 8 */ + + /* STOP: + 0 = Transmit 1 stop bit + 1 = Transmit 2 stop bits (receiver always checks for 1 stop bit) + */ + UART_LCR_STOP = 1 << 2, + UART_LCR_PAR = 1 << 3, /* Parity enabled */ + UART_LCR_EVEN = 1 << 4, /* Even parity format. There will always be an even number of 1s in the binary representation (PAR = 1) */ + UART_LCR_SET_P = 1 << 5, /* Set (force) parity to value in LCR[4] */ + UART_LCR_SET_B = 1 << 6, /* Set BREAK condition -- Transmitter sends all zeroes to indicate BREAK */ + UART_LCR_DLAB = 1 << 7, /* Divisor Latch Access Bit (set to allow programming of the DLH, DLM Divisors) */ + }; + + /* 36.3.3 UART_IIR_FCR_0 */ + enum UartFifoControl { + UART_FCR_FCR_EN_FIFO = 1 << 0, /* Enable the transmit and receive FIFOs. This bit should be enabled */ + UART_FCR_RX_CLR = 1 << 1, /* Clears the contents of the receive FIFO and resets its counter logic to 0 (the receive shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ + UART_FCR_TX_CLR = 1 << 2, /* Clears the contents of the transmit FIFO and resets its counter logic to 0 (the transmit shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ + + /* DMA: + 0 = DMA_MODE_0 + 1 = DMA_MODE_1 + */ + UART_FCR_DMA = 1 << 3, + + /* TX_TRIG + 0 = FIFO_COUNT_GREATER_16 + 1 = FIFO_COUNT_GREATER_8 + 2 = FIFO_COUNT_GREATER_4 + 3 = FIFO_COUNT_GREATER_1 + */ + UART_FCR_TX_TRIG = 3 << 4, + UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_16 = 0 << 4, + UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_8 = 1 << 4, + UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_4 = 2 << 4, + UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_1 = 3 << 4, + + /* RX_TRIG + 0 = FIFO_COUNT_GREATER_1 + 1 = FIFO_COUNT_GREATER_4 + 2 = FIFO_COUNT_GREATER_8 + 3 = FIFO_COUNT_GREATER_16 + */ + UART_FCR_RX_TRIG = 3 << 6, + UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_1 = 0 << 6, + UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_4 = 1 << 6, + UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_8 = 2 << 6, + UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_16 = 3 << 6, + }; + + /* 36.3.2 UART_IER_DLAB_0_0 */ + enum UartInterruptEnable { + UART_IER_IE_RHR = 1 << 0, /* Interrupt enable for Received Data Interrupt */ + UART_IER_IE_THR = 1 << 1, /* Interrupt enable for Transmitter Holding Register Empty interrupt */ + UART_IER_IE_RXS = 1 << 2, /* Interrupt enable for Receiver Line Status Interrupt */ + UART_IER_IE_MSI = 1 << 3, /* Interrupt enable for Modem Status Interrupt */ + UART_IER_IE_RX_TIMEOUT = 1 << 4, /* Interrupt enable for RX FIFO timeout */ + UART_IER_IE_EORD = 1 << 5, /* Interrupt enable for Interrupt Enable for End of Received Data */ + }; + + /* 36.3.3 UART_IIR_FCR_0 */ + enum UartInterruptIdentification { + UART_IIR_IS_STA = 1 << 0, /* Interrupt Pending if ZERO */ + UART_IIR_IS_PRI0 = 1 << 1, /* Encoded Interrupt ID Refer to IIR[3:0] table [36.3.3] */ + UART_IIR_IS_PRI1 = 1 << 2, /* Encoded Interrupt ID Refer to IIR[3:0] table */ + UART_IIR_IS_PRI2 = 1 << 3, /* Encoded Interrupt ID Refer to IIR[3:0] table */ + + /* FIFO Mode Status + 0 = 16450 mode (no FIFO) + 1 = 16550 mode (FIFO) + */ + UART_IIR_EN_FIFO = 3 << 6, + UART_IIR_MODE_16450 = 0 << 6, + UART_IIR_MODE_16550 = 1 << 6, + }; + + /* 36.3.9 UART_IRDA_CSR_0 */ + enum UartIrDAPulseCodingCSR { + UART_IRDA_CSR_INVERT_RXD = 1 << 0, + UART_IRDA_CSR_INVERT_TXD = 1 << 1, + UART_IRDA_CSR_INVERT_CTS = 1 << 2, + UART_IRDA_CSR_INVERT_RTS = 1 << 3, + + UART_IRDA_CSR_PWT_A_BAUD_PULSE_3_14 = 0 << 6, + UART_IRDA_CSR_PWT_A_BAUD_PULSE_4_14 = 1 << 6, + UART_IRDA_CSR_SIR_A = 1 << 7, + }; + +} diff --git a/libexosphere/source/util/util_api.cpp b/libexosphere/source/util/util_api.cpp new file mode 100644 index 00000000..c8d46f55 --- /dev/null +++ b/libexosphere/source/util/util_api.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::util { + + namespace { + + constinit uintptr_t g_timer_register_address = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); + + ALWAYS_INLINE uintptr_t GetCurrentTimeRegisterAddress() { + return g_timer_register_address + 0x10; + } + + } + + void SetRegisterAddress(uintptr_t address) { + g_timer_register_address = address; + } + + u32 GetMicroSeconds() { + return reg::Read(GetCurrentTimeRegisterAddress()); + } + + void WaitMicroSeconds(int us) { + const u32 start = reg::Read(GetCurrentTimeRegisterAddress()); + u32 cur = start; + while ((cur - start) <= static_cast(us)) { + cur = reg::Read(GetCurrentTimeRegisterAddress()); + } + } + + void ClearMemory(void *ptr, size_t size) { + std::memset(ptr, 0, size); + } + +} \ No newline at end of file diff --git a/libexosphere/source/wdt/wdt_api.cpp b/libexosphere/source/wdt/wdt_api.cpp new file mode 100644 index 00000000..cb26f5e0 --- /dev/null +++ b/libexosphere/source/wdt/wdt_api.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 + +namespace ams::wdt { + + namespace { + + volatile uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); + + #if defined(ATMOSPHERE_ARCH_ARM64) + NOINLINE void Reboot(uintptr_t registers) { + __asm__ __volatile__( + /* Get the current core. */ + "mrs x12, mpidr_el1\n" + "and x12, x12, #0xFF\n" + + /* Get the offsets of the registers we want to write */ + "mov x10, #0x8\n" + "mov x11, #0x20\n" + "madd x10, x10, x12, %[registers]\n" + "madd x11, x11, x12, %[registers]\n" + "add x10, x10, #0x60\n" + "add x11, x11, #0x100\n" + + /* Write the magic unlock pattern. */ + "mov w9, #0xC45A\n" + "str w9, [x11, #0xC]\n" + + /* Disable the counters. */ + "mov w9, #0x2\n" + "str w9, [x11, #0x8]\n" + + /* Start periodic timer. */ + "mov w9, #0xC0000000\n" + "str w9, [x10]\n" + + /* Set reboot source to the timer we started. */ + "mov w9, #0x8015\n" + "add w9, w9, w12\n" + "str w9, [x11]\n" + + /* Enable the counters. */ + "mov w9, #0x1\n" + "str w9, [x11, #0x8]\n" + + /* Wait forever. */ + "1: b 1b" + : [registers]"=&r"(registers) + : + : "x9", "x10", "x11", "x12", "memory" + ); + } + #elif defined(ATMOSPHERE_ARCH_ARM) + NOINLINE void Reboot(uintptr_t registers) { + /* Write the magic unlock pattern. */ + reg::Write(registers + 0x18C, 0xC45A); + + /* Disable the counters. */ + reg::Write(registers + 0x188, 0x2); + + /* Start periodic timer. */ + reg::Write(registers + 0x080, 0xC0000000); + + /* Set reboot source to the timer we started. */ + reg::Write(registers + 0x180, 0x8019); + + /* Enable the counters. */ + reg::Write(registers + 0x188, 0x1); + + while (true) { /* ... */ } + } + #endif + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + NOINLINE void Reboot() { + const uintptr_t registers = g_register_address; + Reboot(registers); + } + +} \ No newline at end of file diff --git a/libstratosphere/source/diag/diag_assertion_impl.cpp b/libstratosphere/source/diag/diag_assertion_impl.cpp index 905d479a..4108343a 100644 --- a/libstratosphere/source/diag/diag_assertion_impl.cpp +++ b/libstratosphere/source/diag/diag_assertion_impl.cpp @@ -132,4 +132,8 @@ namespace ams::diag { AbortWithValue(value); } + NORETURN WEAK_SYMBOL void AbortImpl() { + AbortWithValue(0); + } + } diff --git a/libvapours/include/vapours/assert.hpp b/libvapours/include/vapours/assert.hpp index 8402cbc5..8cd61bd6 100644 --- a/libvapours/include/vapours/assert.hpp +++ b/libvapours/include/vapours/assert.hpp @@ -32,6 +32,7 @@ namespace ams::diag { NORETURN NOINLINE void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); NORETURN NOINLINE void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value); + NORETURN NOINLINE void AbortImpl(); } @@ -42,7 +43,7 @@ namespace ams::diag { #define AMS_CALL_ABORT_IMPL(cond, ...) ::ams::diag::AbortImpl(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, 0, ## __VA_ARGS__) #else #define AMS_CALL_ASSERT_FAIL_IMPL(cond, ...) ::ams::diag::AssertionFailureImpl("", 0, "", "", 0) -#define AMS_CALL_ABORT_IMPL(cond, ...) ::ams::diag::AbortImpl("", 0, "", "", 0) +#define AMS_CALL_ABORT_IMPL(cond, ...) ::ams::diag::AbortImpl() #endif #ifdef AMS_ENABLE_ASSERTIONS diff --git a/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp b/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp index b588bc2c..df5955d6 100644 --- a/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp +++ b/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp @@ -142,7 +142,7 @@ namespace ams::crypto::impl { u64 _block[IvSize / sizeof(u64)] = {}; util::StoreBigEndian(std::addressof(_block[(IvSize / sizeof(u64)) - 1]), count); - u16 acc; + u16 acc = 0; const u8 *block = reinterpret_cast(_block); for (s32 i = IvSize - 1; i >= 0; --i) { acc += (this->counter[i] + block[i]); diff --git a/libvapours/include/vapours/defines.hpp b/libvapours/include/vapours/defines.hpp index 39164080..61c73323 100644 --- a/libvapours/include/vapours/defines.hpp +++ b/libvapours/include/vapours/defines.hpp @@ -59,4 +59,6 @@ #define AMS_LIKELY(expr) AMS_PREDICT_TRUE(expr, 1.0) #define AMS_UNLIKELY(expr) AMS_PREDICT_FALSE(expr, 1.0) +#define AMS_ASSUME(expr) do { if (!static_cast((expr))) { __builtin_unreachable(); } } while (0) + #define AMS_CURRENT_FUNCTION_NAME __FUNCTION__ diff --git a/libvapours/include/vapours/literals.hpp b/libvapours/include/vapours/literals.hpp index ddd22a6b..7f741a91 100644 --- a/libvapours/include/vapours/literals.hpp +++ b/libvapours/include/vapours/literals.hpp @@ -19,16 +19,16 @@ namespace ams { inline namespace literals { - constexpr ALWAYS_INLINE size_t operator ""_KB(unsigned long long n) { - return static_cast(n) * size_t(1024); + constexpr ALWAYS_INLINE u64 operator ""_KB(unsigned long long n) { + return static_cast(n) * UINT64_C(1024); } - constexpr ALWAYS_INLINE size_t operator ""_MB(unsigned long long n) { - return operator ""_KB(n) * size_t(1024); + constexpr ALWAYS_INLINE u64 operator ""_MB(unsigned long long n) { + return operator ""_KB(n) * UINT64_C(1024); } - constexpr ALWAYS_INLINE size_t operator ""_GB(unsigned long long n) { - return operator ""_MB(n) * size_t(1024); + constexpr ALWAYS_INLINE u64 operator ""_GB(unsigned long long n) { + return operator ""_MB(n) * UINT64_C(1024); } } } diff --git a/libvapours/include/vapours/svc/arch/arm/svc_thread_local_region.hpp b/libvapours/include/vapours/svc/arch/arm/svc_thread_local_region.hpp new file mode 100644 index 00000000..391dad00 --- /dev/null +++ b/libvapours/include/vapours/svc/arch/arm/svc_thread_local_region.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::svc::arch::arm { + + constexpr inline size_t NumTlsSlots = 16; + constexpr inline size_t MessageBufferSize = 0x100; + + struct ThreadLocalRegion { + u32 message_buffer[MessageBufferSize / sizeof(u32)]; + volatile u16 disable_count; + volatile u16 interrupt_flag; + /* TODO: Should we bother adding the Nintendo aarch32 thread local context here? */ + uintptr_t TODO[(0x200 - 0x104) / sizeof(uintptr_t)]; + }; + + ALWAYS_INLINE ThreadLocalRegion *GetThreadLocalRegion() { + ThreadLocalRegion *tlr; + __asm__ __volatile__("mrc p15, 0, %[tlr], c13, c0, 3" : [tlr]"=&r"(tlr) :: "memory"); + return tlr; + } + +} diff --git a/libvapours/include/vapours/svc/svc_select_thread_local_region.hpp b/libvapours/include/vapours/svc/svc_select_thread_local_region.hpp index 3f339366..e7b3e6f6 100644 --- a/libvapours/include/vapours/svc/svc_select_thread_local_region.hpp +++ b/libvapours/include/vapours/svc/svc_select_thread_local_region.hpp @@ -25,6 +25,14 @@ using ams::svc::arch::arm64::GetThreadLocalRegion; } +#elif defined(ATMOSPHERE_ARCH_ARM) + + #include + namespace ams::svc { + using ams::svc::arch::arm::ThreadLocalRegion; + using ams::svc::arch::arm::GetThreadLocalRegion; + } + #else #error "Unknown architecture for svc::ThreadLocalRegion" diff --git a/libvapours/include/vapours/svc/svc_types_common.hpp b/libvapours/include/vapours/svc/svc_types_common.hpp index 4567e5d0..8e7a5049 100644 --- a/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libvapours/include/vapours/svc/svc_types_common.hpp @@ -225,7 +225,7 @@ namespace ams::svc { /* Thread types. */ using ThreadFunc = ams::svc::Address; -#ifdef ATMOSPHERE_ARCH_ARM64 +#if defined(ATMOSPHERE_ARCH_ARM64) struct ThreadContext { u64 r[29]; @@ -242,8 +242,23 @@ namespace ams::svc { }; static_assert(sizeof(ThreadContext) == 0x320); +#elif defined(ATMOSPHERE_ARCH_ARM) + + struct ThreadContext { + u32 r[13]; + u32 sp; + u32 lr; + u32 pc; + u32 cpsr; + u32 padding; + u64 fpu_registers[32]; + u32 fpscr; + u32 fpexc; + u32 tpidr; + }; + #else - #error >Unknown Architecture for ams::svc::ThreadContext> + #error "Unknown Architecture for ams::svc::ThreadContext" #endif enum ThreadSuspend : u32 { diff --git a/libvapours/include/vapours/types.hpp b/libvapours/include/vapours/types.hpp index d77ea21f..6807e9df 100644 --- a/libvapours/include/vapours/types.hpp +++ b/libvapours/include/vapours/types.hpp @@ -25,25 +25,28 @@ typedef uint8_t u8; ///< 8-bit unsigned integer. typedef uint16_t u16; ///< 16-bit unsigned integer. typedef uint32_t u32; ///< 32-bit unsigned integer. typedef uint64_t u64; ///< 64-bit unsigned integer. -typedef __uint128_t u128; ///< 128-bit unsigned integer. typedef int8_t s8; ///< 8-bit signed integer. typedef int16_t s16; ///< 16-bit signed integer. typedef int32_t s32; ///< 32-bit signed integer. typedef int64_t s64; ///< 64-bit signed integer. -typedef __int128_t s128; ///< 128-bit unsigned integer. typedef volatile u8 vu8; ///< 8-bit volatile unsigned integer. typedef volatile u16 vu16; ///< 16-bit volatile unsigned integer. typedef volatile u32 vu32; ///< 32-bit volatile unsigned integer. typedef volatile u64 vu64; ///< 64-bit volatile unsigned integer. -typedef volatile u128 vu128; ///< 128-bit volatile unsigned integer. typedef volatile s8 vs8; ///< 8-bit volatile signed integer. typedef volatile s16 vs16; ///< 16-bit volatile signed integer. typedef volatile s32 vs32; ///< 32-bit volatile signed integer. typedef volatile s64 vs64; ///< 64-bit volatile signed integer. + +#ifdef ATMOSPHERE_ARCH_ARM64 +typedef __uint128_t u128; ///< 128-bit unsigned integer. +typedef __int128_t s128; ///< 128-bit unsigned integer. +typedef volatile u128 vu128; ///< 128-bit volatile unsigned integer. typedef volatile s128 vs128; ///< 128-bit volatile signed integer. +#endif typedef u32 Result; ///< Function error code result type. diff --git a/libvapours/include/vapours/util.hpp b/libvapours/include/vapours/util.hpp index 43e2806e..c10fa5d3 100644 --- a/libvapours/include/vapours/util.hpp +++ b/libvapours/include/vapours/util.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/libvapours/include/vapours/util/util_aligned_buffer.hpp b/libvapours/include/vapours/util/util_aligned_buffer.hpp new file mode 100644 index 00000000..fc405490 --- /dev/null +++ b/libvapours/include/vapours/util/util_aligned_buffer.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include + +namespace ams::util { + + template + class AlignedBuffer { + private: + static constexpr size_t AlignedSize = ((Size + Alignment - 1) / Alignment) * Alignment; + static_assert(AlignedSize % Alignment == 0); + private: + u8 buffer[Alignment + AlignedSize]; + public: + ALWAYS_INLINE operator u8 *() { return reinterpret_cast(util::AlignUp(reinterpret_cast(this->buffer), Alignment)); } + }; + +} \ No newline at end of file diff --git a/libvapours/include/vapours/util/util_bitpack.hpp b/libvapours/include/vapours/util/util_bitpack.hpp index c89058d6..4b5c1e86 100644 --- a/libvapours/include/vapours/util/util_bitpack.hpp +++ b/libvapours/include/vapours/util/util_bitpack.hpp @@ -42,7 +42,7 @@ namespace ams::util { } }(); public: - template + template struct Field { using Type = T; static constexpr size_t Index = _Index; diff --git a/libvapours/include/vapours/util/util_endian.hpp b/libvapours/include/vapours/util/util_endian.hpp index 19844f20..f269796d 100644 --- a/libvapours/include/vapours/util/util_endian.hpp +++ b/libvapours/include/vapours/util/util_endian.hpp @@ -135,21 +135,21 @@ namespace ams::util { } template requires std::integral - constexpr ALWAYS_INLINE T LoadBigEndian(T *ptr) { + constexpr ALWAYS_INLINE T LoadBigEndian(const T *ptr) { return ConvertToBigEndian(*ptr); } template requires std::integral - constexpr ALWAYS_INLINE T LoadLittleEndian(T *ptr) { + constexpr ALWAYS_INLINE T LoadLittleEndian(const T *ptr) { return ConvertToLittleEndian(*ptr); } - template + template requires std::integral constexpr ALWAYS_INLINE void StoreBigEndian(T *ptr, T val) { *ptr = ConvertToBigEndian(val); } - template + template requires std::integral constexpr ALWAYS_INLINE void StoreLittleEndian(T *ptr, T val) { *ptr = ConvertToLittleEndian(val); } diff --git a/libvapours/include/vapours/util/util_tinymt.hpp b/libvapours/include/vapours/util/util_tinymt.hpp index 7611c9b7..a200fc4b 100644 --- a/libvapours/include/vapours/util/util_tinymt.hpp +++ b/libvapours/include/vapours/util/util_tinymt.hpp @@ -242,7 +242,7 @@ namespace ams::util { const u32 first = (this->GenerateRandomU32() >> Shift1st); const u32 second = (this->GenerateRandomU32() >> Shift2nd); - return (1.0 * first * (1ul << (32 - Shift2nd)) + second) * (1.0 / (1ul << MantissaBits)); + return (1.0 * first * (static_cast(1) << (32 - Shift2nd)) + second) * (1.0 / (static_cast(1) << MantissaBits)); } };