From cbcd1d87fb1c9ee3223356daa5e272c5a02ec6f6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 11 May 2020 18:54:35 -0700 Subject: [PATCH] exo2: implement through end of random cache init --- .../program/source/boot/secmon_main.cpp | 7 +- exosphere2/program/source/secmon_setup.cpp | 123 ++++++++++++++++++ exosphere2/program/source/secmon_setup.hpp | 2 + .../program/source/secmon_setup_warm.cpp | 2 +- .../source/smc/secmon_random_cache.cpp | 103 +++++++++++++++ .../source/smc/secmon_random_cache.hpp | 26 ++++ libraries/libexosphere/include/exosphere.hpp | 1 + .../libexosphere/include/exosphere/flow.hpp | 25 ++++ .../hw/hw_arm64_system_registers.hpp | 103 +++++++++++++-- .../exosphere/tegra/tegra_flow_ctlr.hpp | 15 +++ .../libexosphere/source/flow/flow_api.cpp | 51 ++++++++ 11 files changed, 447 insertions(+), 11 deletions(-) create mode 100644 exosphere2/program/source/smc/secmon_random_cache.cpp create mode 100644 exosphere2/program/source/smc/secmon_random_cache.hpp create mode 100644 libraries/libexosphere/include/exosphere/flow.hpp create mode 100644 libraries/libexosphere/source/flow/flow_api.cpp diff --git a/exosphere2/program/source/boot/secmon_main.cpp b/exosphere2/program/source/boot/secmon_main.cpp index 738452dab..9818f7ef7 100644 --- a/exosphere2/program/source/boot/secmon_main.cpp +++ b/exosphere2/program/source/boot/secmon_main.cpp @@ -16,6 +16,7 @@ #include #include "secmon_boot.hpp" #include "secmon_boot_functions.hpp" +#include "../smc/secmon_random_cache.hpp" #include "../secmon_setup.hpp" #include "../secmon_misc.hpp" @@ -56,13 +57,17 @@ namespace ams::secmon { /* Setup the SoC security measures. */ secmon::SetupSocSecurity(); - /* TODO: More init. */ + /* Setup the Cpu core context. */ + secmon::SetupCpuCoreContext(); /* Clear the crt0 code that was present in iram. */ secmon::boot::ClearIram(); /* Alert the bootloader that we're initialized. */ secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized; + + /* Initialize the random cache. */ + secmon::smc::FillRandomCache(); } } diff --git a/exosphere2/program/source/secmon_setup.cpp b/exosphere2/program/source/secmon_setup.cpp index a468d6dce..7bb95aa63 100644 --- a/exosphere2/program/source/secmon_setup.cpp +++ b/exosphere2/program/source/secmon_setup.cpp @@ -629,6 +629,99 @@ namespace ams::secmon { reg::Read (MC + MC_SMMU_TLB_CONFIG); } + void SetupSecureEl2AndEl1SystemRegisters() { + /* Setup actlr_el2 and actlr_el3. */ + { + util::BitPack32 actlr = {}; + + actlr.Set(1); /* Enable access to cpuactlr from lower EL. */ + actlr.Set(1); /* Enable access to cpuectlr from lower EL. */ + actlr.Set(1); /* Enable access to l2ctlr from lower EL. */ + actlr.Set(1); /* Enable access to l2actlr from lower EL. */ + actlr.Set(1); /* Enable access to l2ectlr from lower EL. */ + + HW_CPU_SET_ACTLR_EL3(actlr); + HW_CPU_SET_ACTLR_EL2(actlr); + } + + /* Setup hcr_el2. */ + { + util::BitPack64 hcr = {}; + + hcr.Set(1); /* EL1 is aarch64 mode. */ + + HW_CPU_SET_HCR_EL2(hcr); + } + + /* Configure all domain access permissions as manager. */ + HW_CPU_SET_DACR32_EL2(~0u); + + /* Setup sctlr_el1. */ + { + util::BitPack64 sctlr = { hw::SctlrEl1::Res1 }; + + sctlr.Set(0); /* Globally disable the MMU. */ + sctlr.Set(0); /* Disable alignment fault checking. */ + sctlr.Set(0); /* Globally disable the data and unified caches. */ + sctlr.Set(1); /* Enable stack alignment checking. */ + sctlr.Set(1); /* Enable el0 stack alignment checking. */ + sctlr.Set(1); /* Enable cp15 barrier operations. */ + sctlr.Set(0); /* Disable ThumbEE. */ + sctlr.Set(0); /* Enable itd instructions. */ + sctlr.Set(0); /* Enable setend instruction. */ + sctlr.Set(0); /* Disable el0 interrupt mask access. */ + sctlr.Set(0); /* Globally disable the instruction cache. */ + sctlr.Set(0); /* Disable el0 access to dc zva instruction. */ + sctlr.Set(1); /* wfi instructions in el0 trap. */ + sctlr.Set(1); /* wfe instructions in el0 trap. */ + sctlr.Set(0); /* Do not force writable pages to be ExecuteNever. */ + sctlr.Set(0); /* Data accesses in el0 are little endian. */ + sctlr.Set(0); /* Exceptions should be little endian. */ + sctlr.Set(0); /* Disable el0 access to dc cvau, dc civac, dc cvac, ic ivau. */ + + HW_CPU_SET_SCTLR_EL1(sctlr); + } + + /* Setup sctlr_el2. */ + { + util::BitPack64 sctlr = { hw::SctlrEl2::Res1 }; // 0x30C5083 + + sctlr.Set(0); /* Globally disable the MMU. */ + sctlr.Set(0); /* Disable alignment fault checking. */ + sctlr.Set(0); /* Globally disable the data and unified caches. */ + sctlr.Set(1); /* Enable stack alignment checking. */ + sctlr.Set(0); /* Globally disable the instruction cache. */ + sctlr.Set(0); /* Do not force writable pages to be ExecuteNever. */ + sctlr.Set(0); /* Exceptions should be little endian. */ + + HW_CPU_SET_SCTLR_EL2(sctlr); + } + + /* Ensure instruction consistency. */ + hw::InstructionSynchronizationBarrier(); + } + + void SetupNonSecureSystemRegisters(u32 tsc_frequency) { + /* Set cntfrq_el0. */ + HW_CPU_SET_CNTFRQ_EL0(tsc_frequency); + + /* Set cnthctl_el2. */ + { + util::BitPack32 cnthctl = {}; + + cnthctl.Set(1); /* Do not trap accesses to cntpct_el0. */ + cnthctl.Set(1); /* Do not trap accesses to cntp_ctl_el0, cntp_cval_el0, and cntp_tval_el0. */ + cnthctl.Set(0); /* Disable the event stream. */ + cnthctl.Set(0); /* Trigger events on 0 -> 1 transition. */ + cnthctl.Set(0); /* Select bit0 of cntpct_el0 as the event stream trigger. */ + + HW_CPU_SET_CNTHCTL_EL2(cnthctl); + } + + /* Ensure instruction consistency. */ + hw::InstructionSynchronizationBarrier(); + } + } void Setup1() { @@ -747,4 +840,34 @@ namespace ams::secmon { } + void SetupCpuCoreContext() { + /* Get the tsc frequency. */ + const u32 tsc_frequency = reg::Read(MemoryRegionVirtualDeviceSysCtr0.GetAddress() + SYSCTR0_CNTFID0); + + /* Setup the secure EL2/EL1 system registers. */ + SetupSecureEl2AndEl1SystemRegisters(); + + /* Setup the non-secure system registers. */ + SetupNonSecureSystemRegisters(tsc_frequency); + + /* Reset the cpu flow controller registers. */ + flow::ResetCpuRegisters(hw::GetCurrentCoreId()); + + /* Initialize the core unique gic registers. */ + gic::InitializeCoreUnique(); + + /* Configure cpu fiq. */ + constexpr int FiqInterruptId = 28; + gic::SetPriority (FiqInterruptId, gic::HighestPriority); + gic::SetInterruptGroup(FiqInterruptId, 0); + gic::SetEnable (FiqInterruptId, true); + + /* Restore the cpu's debug registers. */ + RestoreDebugRegisters(); + } + + void SetupCpuSErrorDebug() { + + } + } \ No newline at end of file diff --git a/exosphere2/program/source/secmon_setup.hpp b/exosphere2/program/source/secmon_setup.hpp index 4113c7905..623e10e74 100644 --- a/exosphere2/program/source/secmon_setup.hpp +++ b/exosphere2/program/source/secmon_setup.hpp @@ -24,6 +24,8 @@ namespace ams::secmon { constexpr inline int KernelCarveoutCount = 2; void SetupCpuMemoryControllersEnableMmu(); + void SetupCpuCoreContext(); + void SetupCpuSErrorDebug(); void SetupSocDmaControllers(); void SetupSocSecurity(); diff --git a/exosphere2/program/source/secmon_setup_warm.cpp b/exosphere2/program/source/secmon_setup_warm.cpp index 1f168d89a..e0b661d3b 100644 --- a/exosphere2/program/source/secmon_setup_warm.cpp +++ b/exosphere2/program/source/secmon_setup_warm.cpp @@ -122,7 +122,7 @@ namespace ams::secmon { void EnableMmu() { /* Create sctlr value. */ - util::BitPack32 sctlr = { hw::SctlrEl3::Res1 }; + util::BitPack64 sctlr = { hw::SctlrEl3::Res1 }; sctlr.Set(1); /* Globally enable the MMU. */ sctlr.Set(0); /* Disable alignment fault checking. */ sctlr.Set(1); /* Globally enable the data and unified caches. */ diff --git a/exosphere2/program/source/smc/secmon_random_cache.cpp b/exosphere2/program/source/smc/secmon_random_cache.cpp new file mode 100644 index 000000000..bcbed1df7 --- /dev/null +++ b/exosphere2/program/source/smc/secmon_random_cache.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "secmon_smc_common.hpp" +#include "secmon_random_cache.hpp" + +namespace ams::secmon::smc { + + namespace { + + constexpr inline size_t MaxRandomBytes = sizeof(SmcArguments) - sizeof(SmcArguments{}.r[0]); + + constinit int g_random_offset_low = 0; + constinit int g_random_offset_high = 0; + + void FillRandomCache(int offset, int size) { + /* Get the cache. */ + u8 * const random_cache_loc = GetRandomBytesCache() + offset; + + /* Flush the region we're about to fill to ensure consistency with the SE. */ + hw::FlushDataCache(random_cache_loc, size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Generate random bytes. */ + se::GenerateRandomBytes(random_cache_loc, size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Flush to ensure the CPU sees consistent data for the region. */ + hw::FlushDataCache(random_cache_loc, size); + hw::DataSynchronizationBarrierInnerShareable(); + } + + } + + void FillRandomCache() { + /* Fill the cache. */ + FillRandomCache(0, GetRandomBytesCacheSize()); + + /* Set the extents. */ + g_random_offset_low = 0; + g_random_offset_high = GetRandomBytesCacheSize() - 1; + } + + void RefillRandomCache() { + /* Check that we need to do any refilling. */ + if (const int used_start = (g_random_offset_high + 1) % GetRandomBytesCacheSize(); used_start != g_random_offset_low) { + if (used_start < g_random_offset_low) { + /* The region we need to fill is after used_start but before g_random_offset_low. */ + const auto size = g_random_offset_low - used_start; + FillRandomCache(used_start, size); + g_random_offset_high += size; + } else { + /* We need to fill the space from high to the end and from low to start. */ + const int high_size = GetRandomBytesCacheSize() - used_start; + if (high_size > 0) { + FillRandomCache(used_start, high_size); + g_random_offset_high += high_size; + } + + const int low_size = g_random_offset_low; + if (low_size > 0) { + FillRandomCache(0, low_size); + g_random_offset_high += low_size; + } + + } + + g_random_offset_high %= GetRandomBytesCacheSize(); + } + } + + void GetRandomFromCache(void *dst, size_t size) { + u8 * const cache = GetRandomBytesCache(); + u8 * cur_dst = static_cast(dst); + + /* NOTE: Nintendo does not do bounds checking here, and does not do multiple reads when the get would wrap around. */ + while (size > 0) { + const size_t copy_size = std::min(size, static_cast(GetRandomBytesCacheSize() - g_random_offset_low)); + std::memcpy(cur_dst, cache + g_random_offset_low, copy_size); + + cur_dst += copy_size; + size -= copy_size; + + if (g_random_offset_low + copy_size >= GetRandomBytesCacheSize()) { + g_random_offset_low = 0; + } + } + } + +} diff --git a/exosphere2/program/source/smc/secmon_random_cache.hpp b/exosphere2/program/source/smc/secmon_random_cache.hpp new file mode 100644 index 000000000..f3cbdc731 --- /dev/null +++ b/exosphere2/program/source/smc/secmon_random_cache.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 +#include "secmon_smc_common.hpp" + +namespace ams::secmon::smc { + + void FillRandomCache(); + void RefillRandomCache(); + void GetRandomFromCache(void *dst, size_t size); + +} diff --git a/libraries/libexosphere/include/exosphere.hpp b/libraries/libexosphere/include/exosphere.hpp index db9b2cb2d..c92a382d9 100644 --- a/libraries/libexosphere/include/exosphere.hpp +++ b/libraries/libexosphere/include/exosphere.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libexosphere/include/exosphere/flow.hpp b/libraries/libexosphere/include/exosphere/flow.hpp new file mode 100644 index 000000000..93cfb98c3 --- /dev/null +++ b/libraries/libexosphere/include/exosphere/flow.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::flow { + + void SetRegisterAddress(uintptr_t address); + + void ResetCpuRegisters(int core); + +} diff --git a/libraries/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp b/libraries/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp index 637f3c026..5792ee713 100644 --- a/libraries/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp +++ b/libraries/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp @@ -141,17 +141,79 @@ namespace ams::hw::arch::arm64 { #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) + #define HW_CPU_GET_CNTFRQ_EL0(value) HW_CPU_GET_SYSREG(cntfrq_el0, value) + #define HW_CPU_SET_CNTFRQ_EL0(value) HW_CPU_SET_SYSREG(cntfrq_el0, value) + + #define HW_CPU_GET_CNTHCTL_EL2(value) HW_CPU_GET_SYSREG(cnthctl_el2, value) + #define HW_CPU_SET_CNTHCTL_EL2(value) HW_CPU_SET_SYSREG(cnthctl_el2, value) + + #define HW_CPU_GET_ACTLR_EL2(value) HW_CPU_GET_SYSREG(actlr_el2, value) + #define HW_CPU_SET_ACTLR_EL2(value) HW_CPU_SET_SYSREG(actlr_el2, value) + + #define HW_CPU_GET_ACTLR_EL3(value) HW_CPU_GET_SYSREG(actlr_el3, value) + #define HW_CPU_SET_ACTLR_EL3(value) HW_CPU_SET_SYSREG(actlr_el3, value) + + #define HW_CPU_GET_HCR_EL2(value) HW_CPU_GET_SYSREG(hcr_el2, value) + #define HW_CPU_SET_HCR_EL2(value) HW_CPU_SET_SYSREG(hcr_el2, value) + + #define HW_CPU_GET_DACR32_EL2(value) HW_CPU_GET_SYSREG(dacr32_el2, value) + #define HW_CPU_SET_DACR32_EL2(value) HW_CPU_SET_SYSREG(dacr32_el2, value) + + #define HW_CPU_GET_SCTLR_EL2(value) HW_CPU_GET_SYSREG(sctlr_el2, value) + #define HW_CPU_SET_SCTLR_EL2(value) HW_CPU_SET_SYSREG(sctlr_el2, value) + + #define HW_CPU_GET_SCTLR_EL1(value) HW_CPU_GET_SYSREG(sctlr_el1, value) + #define HW_CPU_SET_SCTLR_EL1(value) HW_CPU_SET_SYSREG(sctlr_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>; + using M = util::BitPack64::Field< 0, 1>; + using A = util::BitPack64::Field< 1, 1>; + using C = util::BitPack64::Field< 2, 1>; + using Sa = util::BitPack64::Field< 3, 1>; + using I = util::BitPack64::Field<12, 1>; + using Wxn = util::BitPack64::Field<19, 1>; + using Ee = util::BitPack64::Field<25, 1>; - static constexpr u32 Res1 = 0x30C50830; + static constexpr u64 Res1 = 0x30C50830; + }; + + /* https://static.docs.arm.com/ddi0487/fb/DDI0487F_b_armv8_arm.pdf */ + struct SctlrEl2 { + using M = util::BitPack64::Field< 0, 1>; + using A = util::BitPack64::Field< 1, 1>; + using C = util::BitPack64::Field< 2, 1>; + using Sa = util::BitPack64::Field< 3, 1>; + using I = util::BitPack64::Field<12, 1>; + using Wxn = util::BitPack64::Field<19, 1>; + using Ee = util::BitPack64::Field<25, 1>; + + static constexpr u64 Res1 = 0x30C50830; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el1 */ + struct SctlrEl1 { + using M = util::BitPack64::Field< 0, 1>; + using A = util::BitPack64::Field< 1, 1>; + using C = util::BitPack64::Field< 2, 1>; + using Sa = util::BitPack64::Field< 3, 1>; + using Sa0 = util::BitPack64::Field< 4, 1>; + using Cp15BEn = util::BitPack64::Field< 5, 1>; + using Thee = util::BitPack64::Field< 6, 1>; + using Itd = util::BitPack64::Field< 7, 1>; + using Sed = util::BitPack64::Field< 8, 1>; + using Uma = util::BitPack64::Field< 9, 1>; + using I = util::BitPack64::Field<12, 1>; + using Dze = util::BitPack64::Field<14, 1>; + using Uct = util::BitPack64::Field<15, 1>; + using Ntwi = util::BitPack64::Field<16, 1>; + using Ntwe = util::BitPack64::Field<18, 1>; + using Wxn = util::BitPack64::Field<19, 1>; + using E0e = util::BitPack64::Field<24, 1>; + using Ee = util::BitPack64::Field<25, 1>; + using Uci = util::BitPack64::Field<26, 1>; + + static constexpr u64 Res1 = 0x30D00800; }; /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABGIHHJ.html */ @@ -242,4 +304,27 @@ namespace ams::hw::arch::arm64 { using Snid = util::BitPack32::Field<6, 2>; }; -} \ No newline at end of file + /* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/cnthctl_el2 */ + struct CnthctlEl2 { + using El1PctEn = util::BitPack32::Field<0, 1>; + using El1PcEn = util::BitPack32::Field<1, 1>; + using EvntEn = util::BitPack32::Field<2, 1>; + using EvntDir = util::BitPack32::Field<3, 1>; + using EvntI = util::BitPack32::Field<4, 4>; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/auxiliary-control-register-el3 */ + struct ActlrCortexA57 { + using Cpuactlr = util::BitPack32::Field<0, 1>; + using Cpuectlr = util::BitPack32::Field<1, 1>; + using L2ctlr = util::BitPack32::Field<4, 1>; + using L2ectlr = util::BitPack32::Field<5, 1>; + using L2actlr = util::BitPack32::Field<6, 1>; + }; + + /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/hypervisor-configuration-register-el2 */ + struct HcrEl2 { + using Rw = util::BitPack64::Field<31, 1>; + }; + +} diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp index d7d3361e1..eca5115ff 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_flow_ctlr.hpp @@ -20,6 +20,21 @@ #define FLOW_CTLR_FLOW_DBG_QUAL (0x050) #define FLOW_CTLR_BPMP_CLUSTER_CONTROL (0x098) +#define FLOW_CTLR_CPU0_CSR (0x008) +#define FLOW_CTLR_CPU1_CSR (0x018) +#define FLOW_CTLR_CPU2_CSR (0x020) +#define FLOW_CTLR_CPU3_CSR (0x028) + +#define FLOW_CTLR_HALT_CPU0_EVENTS (0x000) +#define FLOW_CTLR_HALT_CPU1_EVENTS (0x014) +#define FLOW_CTLR_HALT_CPU2_EVENTS (0x01C) +#define FLOW_CTLR_HALT_CPU3_EVENTS (0x024) + +#define FLOW_CTLR_CC4_CORE0_CTRL (0x06C) +#define FLOW_CTLR_CC4_CORE1_CTRL (0x070) +#define FLOW_CTLR_CC4_CORE2_CTRL (0x074) +#define FLOW_CTLR_CC4_CORE3_CTRL (0x078) + #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) diff --git a/libraries/libexosphere/source/flow/flow_api.cpp b/libraries/libexosphere/source/flow/flow_api.cpp new file mode 100644 index 000000000..613c78c07 --- /dev/null +++ b/libraries/libexosphere/source/flow/flow_api.cpp @@ -0,0 +1,51 @@ +/* + * 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::flow { + + namespace { + + struct FlowControllerRegisterOffset { + u16 cpu_csr; + u16 halt_cpu_events; + u16 cc4_core_ctrl; + }; + + constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); + + constexpr const FlowControllerRegisterOffset FlowControllerRegisterOffsets[] = { + { FLOW_CTLR_CPU0_CSR, FLOW_CTLR_HALT_CPU0_EVENTS, FLOW_CTLR_CC4_CORE0_CTRL, }, + { FLOW_CTLR_CPU1_CSR, FLOW_CTLR_HALT_CPU1_EVENTS, FLOW_CTLR_CC4_CORE1_CTRL, }, + { FLOW_CTLR_CPU2_CSR, FLOW_CTLR_HALT_CPU2_EVENTS, FLOW_CTLR_CC4_CORE2_CTRL, }, + { FLOW_CTLR_CPU3_CSR, FLOW_CTLR_HALT_CPU3_EVENTS, FLOW_CTLR_CC4_CORE3_CTRL, }, + }; + + } + + void SetRegisterAddress(uintptr_t address) { + g_register_address = address; + } + + void ResetCpuRegisters(int core) { + AMS_ASSUME(core >= 0); + + const auto &offsets = FlowControllerRegisterOffsets[core]; + reg::Write(g_register_address + offsets.cpu_csr, 0); + reg::Write(g_register_address + offsets.halt_cpu_events, 0); + } + +} \ No newline at end of file