mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-31 11:15:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1289 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1289 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 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 <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <exosphere.hpp>
 | |
| #include "secmon_setup.hpp"
 | |
| #include "secmon_error.hpp"
 | |
| #include "secmon_map.hpp"
 | |
| #include "secmon_cpu_context.hpp"
 | |
| #include "secmon_mariko_fatal_error.hpp"
 | |
| #include "secmon_interrupt_handler.hpp"
 | |
| #include "secmon_misc.hpp"
 | |
| #include "smc/secmon_random_cache.hpp"
 | |
| #include "smc/secmon_smc_power_management.hpp"
 | |
| #include "smc/secmon_smc_se_lock.hpp"
 | |
| 
 | |
| namespace ams::secmon {
 | |
| 
 | |
|     namespace {
 | |
| 
 | |
|         constexpr inline const uintptr_t TIMER     = secmon::MemoryRegionVirtualDeviceTimer.GetAddress();
 | |
|         constexpr inline const uintptr_t SYSTEM    = secmon::MemoryRegionVirtualDeviceSystem.GetAddress();
 | |
|         constexpr inline const uintptr_t APB_MISC  = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress();
 | |
|         constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionVirtualDeviceFlowController.GetAddress();
 | |
|         constexpr inline const uintptr_t PMC       = secmon::MemoryRegionVirtualDevicePmc.GetAddress();
 | |
|         constexpr inline const uintptr_t MC        = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
 | |
|         constexpr inline const uintptr_t EVP       = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress();
 | |
|         constexpr inline const uintptr_t CLK_RST   = secmon::MemoryRegionVirtualDeviceClkRst.GetAddress();
 | |
| 
 | |
|         alignas(8) constinit u8 g_se_aes_key_slot_test_vector[se::AesBlockSize] = {};
 | |
| 
 | |
|         struct Carveout {
 | |
|             uintptr_t address;
 | |
|             size_t    size;
 | |
|         };
 | |
| 
 | |
|         constinit Carveout g_kernel_carveouts[KernelCarveoutCount] = {
 | |
|             { secmon::MemoryRegionDramDefaultKernelCarveout.GetAddress(), secmon::MemoryRegionDramDefaultKernelCarveout.GetSize(), },
 | |
|             { 0, 0, },
 | |
|         };
 | |
| 
 | |
|         constinit bool g_is_cold_boot = true;
 | |
| 
 | |
|         constinit se::StickyBits ExpectedSeStickyBits = {
 | |
|             .se_security            = (1 << 0), /* SE_HARD_SETTING */
 | |
|             .tzram_security         = 0,
 | |
|             .crypto_security_perkey = (1 << pkg1::AesKeySlot_UserEnd) - 1,
 | |
|             .crypto_keytable_access = {
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  0: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  1: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  2: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  3: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  4: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  5: User    keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /*  6: Unused  keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /*  7: Unused  keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  8: Temp    keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /*  9: SmcTemp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1   keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (0 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2   keyslot. KEY. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master  keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused  keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|                 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device  keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
 | |
|             },
 | |
|             .rsa_security_perkey = 0,
 | |
|             .rsa_keytable_access = {
 | |
|                 (0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
 | |
|                 (0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
 | |
|             },
 | |
|         };
 | |
| 
 | |
|         void InitializeConfigurationContext() {
 | |
|             /* Get the global context. */
 | |
|             auto &ctx = ::ams::secmon::impl::GetConfigurationContext();
 | |
| 
 | |
|             /* Clear the context to zero. */
 | |
|             std::memset(std::addressof(ctx), 0, sizeof(ctx));
 | |
| 
 | |
|             /* If the storage context is valid, we want to copy it to the global context. */
 | |
|             if (const auto &storage_ctx = *MemoryRegionPhysicalDramMonitorConfiguration.GetPointer<const SecureMonitorStorageConfiguration>(); storage_ctx.IsValid()) {
 | |
|                 ctx.secmon_cfg.CopyFrom(storage_ctx);
 | |
|                 ctx.emummc_cfg = storage_ctx.emummc_cfg;
 | |
|             } else {
 | |
|                 /* If we don't have a valid storage context, we can just use the default one. */
 | |
|                 ctx.secmon_cfg = DefaultSecureMonitorConfiguration;
 | |
|             }
 | |
| 
 | |
|             /* Cache the fuse info for quick access. */
 | |
|             ctx.secmon_cfg.SetFuseInfo();
 | |
|         }
 | |
| 
 | |
|         void GenerateSecurityEngineAesKeySlotTestVector(void *dst, size_t size) {
 | |
|             /* Clear the output. */
 | |
|             AMS_ABORT_UNLESS(size == se::AesBlockSize);
 | |
|             std::memset(dst, 0, se::AesBlockSize);
 | |
| 
 | |
|             /* Ensure output is seen as cleared by the se. */
 | |
|             hw::FlushDataCache(dst, se::AesBlockSize);
 | |
|             hw::DataSynchronizationBarrierInnerShareable();
 | |
| 
 | |
|             /* Declare a block. */
 | |
|             alignas(8) u8 empty_block[se::AesBlockSize];
 | |
| 
 | |
|             /* Iteratively transform an empty block. */
 | |
|             #define TRANSFORM_WITH_KEY(key)                                                                   \
 | |
|                 __builtin_memset(empty_block, 0, sizeof(empty_block));                                        \
 | |
|                 se::SetEncryptedAesKey256(pkg1::AesKeySlot_Temporary, key, empty_block, sizeof(empty_block)); \
 | |
|                 se::DecryptAes128(dst, se::AesBlockSize, pkg1::AesKeySlot_Temporary, dst, se::AesBlockSize)
 | |
| 
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
 | |
| 
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
 | |
|             TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
 | |
| 
 | |
|             /* Ensure output is seen correctly by the cpu. */
 | |
|             hw::FlushDataCache(dst, se::AesBlockSize);
 | |
|             hw::DataSynchronizationBarrierInnerShareable();
 | |
| 
 | |
|             /* Clear the temporary key slot. */
 | |
|             se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
 | |
|         }
 | |
| 
 | |
|         void VerifySecurityEngineStickyBits() {
 | |
|             /* On mariko, an extra sticky bit is set. */
 | |
|             if (GetSocType() == fuse::SocType_Mariko) {
 | |
|                 ExpectedSeStickyBits.se_security |= (1 << 5);
 | |
|             } else /* if (GetSocType() == fuse::SocType_Erista) */ {
 | |
|                 /* Erista does not support DST_KEYTABLE_ONLY, and so all keys will have the bit clear. */
 | |
|                 for (size_t i = 0; i < util::size(ExpectedSeStickyBits.crypto_keytable_access); ++i) {
 | |
|                     ExpectedSeStickyBits.crypto_keytable_access[i] &= ~(1 << 7);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (!se::ValidateStickyBits(ExpectedSeStickyBits)) {
 | |
|                 SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits);
 | |
|                 AMS_ABORT("Invalid sticky bits");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void VerifySecurityEngineAesKeySlotTestVector() {
 | |
|             alignas(8) u8 test_vector[se::AesBlockSize];
 | |
|             GenerateSecurityEngineAesKeySlotTestVector(test_vector, sizeof(test_vector));
 | |
| 
 | |
|             AMS_ABORT_UNLESS(crypto::IsSameBytes(g_se_aes_key_slot_test_vector, test_vector, se::AesBlockSize));
 | |
|         }
 | |
| 
 | |
|         void ClearAesKeySlots() {
 | |
|             /* Clear all non-secure monitor keys. */
 | |
|             for (int i = 0; i < pkg1::AesKeySlot_SecmonStart; ++i) {
 | |
|                 se::ClearAesKeySlot(i);
 | |
|             }
 | |
| 
 | |
|             /* Clear the secure-monitor temporary keys. */
 | |
|             se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
 | |
|             se::ClearAesKeySlot(pkg1::AesKeySlot_Smc);
 | |
|         }
 | |
| 
 | |
|         void ClearRsaKeySlots() {
 | |
|             /* Clear all rsa keyslots. */
 | |
|             for (int i = 0; i < se::RsaKeySlotCount; ++i) {
 | |
|                 se::ClearRsaKeySlot(i);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void SetupKernelCarveouts() {
 | |
|             #define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE)
 | |
| 
 | |
|             constexpr u32 ClientAccess0     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, PTCR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0A),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0AB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0B),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0BB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0C),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0CB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, AFIR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHC),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHCB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, HDAR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, HOST1XDMAR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, HOST1XR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, NVENCSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBDMAR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR));
 | |
| 
 | |
|             constexpr u32 ClientAccess1     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, MPCORER),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, NVENCSWR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, AFIW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, HDAW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, HOST1XW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, MPCOREW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBDMAW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBSLVW));
 | |
| 
 | |
|             constexpr u32 ClientAccess2     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW));
 | |
| 
 | |
|             constexpr u32 ClientAccess2_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, TSECSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(2, TSECSWR));
 | |
| 
 | |
|             constexpr u32 ClientAccess3     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, APER),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, APEW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
 | |
| 
 | |
|             constexpr u32 ClientAccess3_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVDECSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVDECSWR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, APER),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, APEW),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
 | |
| 
 | |
|             constexpr u32 ClientAccess4     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(4, SESWR));
 | |
| 
 | |
|             constexpr u32 ClientAccess4_800 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(4, SESWR),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(4, TSECRDB),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(4, TSECWRB));
 | |
| 
 | |
| 
 | |
|             constexpr u32 ClientAccess4_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
 | |
|                                                           MC_ENABLE_CLIENT_ACCESS(4, SESWR));
 | |
| 
 | |
|             #undef MC_ENABLE_CLIENT_ACCESS
 | |
| 
 | |
|             constexpr u32 ForceInternalAccess0     = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE));
 | |
|             constexpr u32 ForceInternalAccess0_100 = 0;
 | |
| 
 | |
|             constexpr u32 ForceInternalAccess1     = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE));
 | |
|             constexpr u32 ForceInternalAccess1_100 = 0;
 | |
| 
 | |
|             constexpr u32 CarveoutConfig        = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   0),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                     ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                    DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                     ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                      ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                     DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                     DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                      ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                        ANY_ADDRESS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                                LOCKED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                          TZ_SECURE));
 | |
| 
 | |
|             constexpr u32 CarveoutConfig_100    = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                        DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                               MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   0),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                    DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                    DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                     ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                     DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                     DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                     DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                      ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                        ANY_ADDRESS),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                                LOCKED),
 | |
|                                                               MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                          TZ_SECURE));
 | |
| 
 | |
|             const u32 target_fw = GetTargetFirmware();
 | |
|             u32 client_access_2;
 | |
|             u32 client_access_3;
 | |
|             u32 client_access_4;
 | |
|             u32 carveout_config;
 | |
|             if (target_fw >= TargetFirmware_8_1_0) {
 | |
|                 client_access_2 = ClientAccess2;
 | |
|                 client_access_3 = ClientAccess3;
 | |
|                 client_access_4 = ClientAccess4;
 | |
|                 carveout_config = CarveoutConfig;
 | |
|             } else if (target_fw >= TargetFirmware_8_0_0) {
 | |
|                 client_access_2 = ClientAccess2;
 | |
|                 client_access_3 = ClientAccess3;
 | |
|                 client_access_4 = ClientAccess4_800;
 | |
|                 carveout_config = CarveoutConfig;
 | |
|             } else {
 | |
|                 client_access_2 = ClientAccess2_100;
 | |
|                 client_access_3 = ClientAccess3_100;
 | |
|                 client_access_4 = ClientAccess4_100;
 | |
|                 carveout_config = CarveoutConfig_100;
 | |
|             }
 | |
| 
 | |
|             /* Configure carveout 4. */
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM,                                                                             g_kernel_carveouts[0].address >>  0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI,                                                                          g_kernel_carveouts[0].address >> 32);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB,                                                                      g_kernel_carveouts[0].size / 128_KB);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0,                                                                                        ClientAccess0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1,                                                                                        ClientAccess1);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2,                                                                                      client_access_2);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3,                                                                                      client_access_3);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4,                                                                                      client_access_4);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess0 : ForceInternalAccess0_100);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess1 : ForceInternalAccess1_100);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2,                                                                                     0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3,                                                                                     0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4,                                                                                     0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0,                                                                                                carveout_config);
 | |
| 
 | |
|             /* Configure carveout 5. */
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM,                           g_kernel_carveouts[0].address >>  0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM_HI,                        g_kernel_carveouts[0].address >> 32);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_SIZE_128KB,                    g_kernel_carveouts[0].size / 128_KB);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0,                                      ClientAccess0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1,                                      ClientAccess1);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2,                                    client_access_2);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3,                                    client_access_3);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4,                                    client_access_4);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0,                                   0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1,                                   0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2,                                   0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3,                                   0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4,                                   0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT5_CFG0,                                              carveout_config);
 | |
|         }
 | |
| 
 | |
|         void ConfigureSlaveSecurity() {
 | |
|             u32 reg0, reg1, reg2;
 | |
|             if (GetTargetFirmware() > TargetFirmware_1_0_0) {
 | |
|                 reg0 =  reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(0, DTV,      ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI,     ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(0, SE,       ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(0, SATA,     ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(0, LA,       ENABLE));
 | |
| 
 | |
|                 reg1 =  reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
 | |
|                                     SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
 | |
| 
 | |
|                 reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC3, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(2, DDS,    ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(2, DP2,    ENABLE));
 | |
| 
 | |
|                 const auto hw_type = GetHardwareType();
 | |
| 
 | |
|                 /* Switch Lite can't use HDMI, so set CEC to secure on hoag. */
 | |
|                 if (hw_type == fuse::HardwareType_Hoag) {
 | |
|                     reg0 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, CEC, ENABLE));
 | |
|                 }
 | |
| 
 | |
|                 /* Icosa, Iowa, and Aula all set I2C4 to be secure. */
 | |
|                 if (hw_type == fuse::HardwareType_Icosa && hw_type == fuse::HardwareType_Iowa && hw_type == fuse::HardwareType_Aula) {
 | |
|                     reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, I2C4, ENABLE));
 | |
| 
 | |
|                 }
 | |
| 
 | |
|                 /* Hoag additionally sets UART_B to secure. */
 | |
|                 if (hw_type == fuse::HardwareType_Hoag) {
 | |
|                     reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE));
 | |
|                 }
 | |
| 
 | |
|                 /* Copper and Calcio lack a lot of hardware, so set the corresponding registers to secure for them. */
 | |
|                 if (hw_type == fuse::HardwareType_Calcio || hw_type == fuse::HardwareType_Copper) {
 | |
|                     reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(1, UART_C, ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(1, SPI4,   ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(1, I2C2,   ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(1, I2C3,   ENABLE));
 | |
| 
 | |
|                     /* Copper/Calcio have no gamecard reader, and thus set SDMMC2 as secure. */
 | |
|                     reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC2, ENABLE));
 | |
|                 }
 | |
| 
 | |
|                 /* Mariko hardware types (not Icosa or Copper) additionally set mariko-only mmio (SE2, PKA1, FEK) as secure. */
 | |
|                 if (hw_type != fuse::HardwareType_Icosa && hw_type != fuse::HardwareType_Copper) {
 | |
|                     reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SE2,  ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(2, PKA1, ENABLE),
 | |
|                                         SLAVE_SECURITY_REG_BITS_ENUM(2, FEK,  ENABLE));
 | |
|                 }
 | |
|             } else {
 | |
|                 reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(0, DTV,      ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI,     ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(0, SATA,     ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(0, LA,       ENABLE));
 | |
| 
 | |
|                 reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
 | |
|                                    SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
 | |
| 
 | |
|                 reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE),
 | |
|                                    REG_BITS_VALUE(5, 1, 1),  /* Note: Bit 5 is not documented in TRM. */
 | |
|                                    REG_BITS_VALUE(4, 1, 1)); /* Note: Bit 4 is not documented in TRM. */
 | |
|             }
 | |
| 
 | |
|             reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, reg0);
 | |
|             reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, reg1);
 | |
|             reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0, reg2);
 | |
|         }
 | |
| 
 | |
|         void SetupSecureRegisters() {
 | |
|             /* Configure timers 5-8 and watchdog timers 0-3 as secure. */
 | |
|             reg::Write(TIMER + TIMER_SHARED_TIMER_SECURE_CFG, TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR5, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR6, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR7, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR8, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT0, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT1, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT2, ENABLE),
 | |
|                                                               TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT3, ENABLE));
 | |
| 
 | |
|             /* Lock cluster switching, to prevent usage of the A53 cores. */
 | |
|             reg::Write(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER_LOCK,    ENABLE),
 | |
|                                                                    FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_CLUSTER_SWITCH_ENABLE, DISABLE),
 | |
|                                                                    FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER,           FAST));
 | |
| 
 | |
|             /* Enable flow controller debug qualifier for legacy FIQs. */
 | |
|             reg::Write(FLOW_CTLR + FLOW_CTLR_FLOW_DBG_QUAL, FLOW_REG_BITS_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, ENABLE));
 | |
| 
 | |
|             /* Configure the PMC to disable deep power-down. */
 | |
|             reg::Write(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, DISABLE),
 | |
|                                                     PMC_REG_BITS_ENUM(DPD_ENABLE_ON,          DISABLE));
 | |
| 
 | |
|             /* Configure the video protect region. */
 | |
|             reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_0, 1);
 | |
|             reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 0);
 | |
|             reg::Write(MC + MC_VIDEO_PROTECT_BOM,            0);
 | |
|             reg::Write(MC + MC_VIDEO_PROTECT_SIZE_MB,        0);
 | |
|             reg::Write(MC + MC_VIDEO_PROTECT_REG_CTRL,       MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_ALLOW_TZ_WRITE, DISABLED),
 | |
|                                                              MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_WRITE_ACCESS,   DISABLED));
 | |
| 
 | |
|             /* Configure the SEC carveout. */
 | |
|             reg::Write(MC + MC_SEC_CARVEOUT_BOM,      0);
 | |
|             reg::Write(MC + MC_SEC_CARVEOUT_SIZE_MB,  0);
 | |
|             reg::Write(MC + MC_SEC_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(SEC_CARVEOUT_REG_CTRL_SEC_CARVEOUT_WRITE_ACCESS,   DISABLED));
 | |
| 
 | |
|             /* Configure the MTS carveout. */
 | |
|             reg::Write(MC + MC_MTS_CARVEOUT_BOM,      0);
 | |
|             reg::Write(MC + MC_MTS_CARVEOUT_SIZE_MB,  0);
 | |
|             reg::Write(MC + MC_MTS_CARVEOUT_ADR_HI,   0);
 | |
|             reg::Write(MC + MC_MTS_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(MTS_CARVEOUT_REG_CTRL_MTS_CARVEOUT_WRITE_ACCESS,   DISABLED));
 | |
| 
 | |
|             /* Configure the security carveout. */
 | |
|             reg::Write(MC + MC_SECURITY_CFG0, MC_REG_BITS_VALUE(SECURITY_CFG0_SECURITY_BOM,    0));
 | |
|             reg::Write(MC + MC_SECURITY_CFG1, MC_REG_BITS_VALUE(SECURITY_CFG1_SECURITY_SIZE,   0));
 | |
|             reg::Write(MC + MC_SECURITY_CFG3, MC_REG_BITS_VALUE(SECURITY_CFG3_SECURITY_BOM_HI, 3));
 | |
| 
 | |
|             /* Configure security carveout 1. */
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM,                           0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM_HI,                        0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_SIZE_128KB,                    0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT1_CFG0,                          MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                 ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   0),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                     DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                     DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                     DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                     DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                  UNTRANSLATED_ONLY),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                                LOCKED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                     LOCKBIT_SECURE));
 | |
| 
 | |
|             /* Security carveout 2 will be configured later by SetupGpuCarveout, after magic values are written to configure gpu/tsec. */
 | |
| 
 | |
|             /* Configure carveout 3. */
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM,                           0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM_HI,                        0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_SIZE_128KB,                    0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2,                MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD,  ENABLE),
 | |
|                                                                                  MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR,  ENABLE));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4,                MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE),
 | |
|                                                                                  MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT3_CFG0,                          MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                 ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                         ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   3),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                     ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                     ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                  UNTRANSLATED_ONLY),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                                LOCKED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                     LOCKBIT_SECURE));
 | |
| 
 | |
|             /* If we're cold-booting and on 1.0.0, alter the default carveout size. */
 | |
|             if (g_is_cold_boot && GetTargetFirmware() <= TargetFirmware_1_0_0) {
 | |
|                 g_kernel_carveouts[0].size = 200 * 128_KB;
 | |
|             }
 | |
| 
 | |
|             /* NOTE: Here Nintendo configures the two kernel carveouts; we will do this later, to allow fusee to continue using AVP_CACHE. */
 | |
|             /* SetupKernelCarveouts(); */
 | |
| 
 | |
|             /* Configure slave register security. */
 | |
|             ConfigureSlaveSecurity();
 | |
|         }
 | |
| 
 | |
|         void SetupSmmu() {
 | |
|             /* Turn on SMMU translation for all devices. */
 | |
|             reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_0, ~0u);
 | |
|             reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_1, ~0u);
 | |
|             reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_2, ~0u);
 | |
|             reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_3, ~0u);
 | |
|             reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_4, ~0u);
 | |
| 
 | |
|             /* On modern firmware, configure ASIDs 1-3 as secure, and all others as non-secure. */
 | |
|             if (GetTargetFirmware() >= TargetFirmware_4_0_0) {
 | |
|                 reg::Write(MC + MC_SMMU_ASID_SECURITY,   MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, SECURE),
 | |
|                                                          MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, SECURE),
 | |
|                                                          MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, SECURE));
 | |
|             } else {
 | |
|                 /* Legacy firmware accesses the MC directly, though, and so correspondingly we must allow ASIDs to be edited by non-secure world. */
 | |
|                 reg::Write(MC + MC_SMMU_ASID_SECURITY, 0);
 | |
|             }
 | |
| 
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_1, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_2, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_3, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_4, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_5, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_6, 0);
 | |
|             reg::Write(MC + MC_SMMU_ASID_SECURITY_7, 0);
 | |
| 
 | |
|             /* Initialize the PTB registers to zero .*/
 | |
|             reg::Write(MC + MC_SMMU_PTB_ASID, 0);
 | |
|             reg::Write(MC + MC_SMMU_PTB_DATA, 0);
 | |
| 
 | |
|             /* Configure the TLB and PTC, then read TLB_CONFIG to ensure configuration takes. */
 | |
|             reg::Write(MC + MC_SMMU_TLB_CONFIG, MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_HIT_UNDER_MISS,          ENABLE),
 | |
|                                                 MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_ROUND_ROBIN_ARBITRATION, ENABLE),
 | |
|                                                 MC_REG_BITS_VALUE(SMMU_TLB_CONFIG_TLB_ACTIVE_LINES,              0x30));
 | |
| 
 | |
|             reg::Write(MC + MC_SMMU_PTC_CONFIG, MC_REG_BITS_ENUM (SMMU_PTC_CONFIG_PTC_CACHE_ENABLE, ENABLE),
 | |
|                                                 MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_REQ_LIMIT,         8),
 | |
|                                                 MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_INDEX_MAP,      0x3F));
 | |
| 
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
| 
 | |
|             /* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
 | |
|             reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0);
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
| 
 | |
|             /* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
 | |
|             reg::Write(MC + MC_SMMU_TLB_FLUSH, 0);
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
| 
 | |
|             /* Enable the SMMU, and read TLB_CONFIG to ensure the enable takes. */
 | |
|             reg::Write(MC + MC_SMMU_CONFIG, MC_REG_BITS_ENUM (SMMU_CONFIG_SMMU_ENABLE, ENABLE));
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
|         }
 | |
| 
 | |
|         void SetupSecureEl2AndEl1SystemRegisters() {
 | |
|             /* Setup actlr_el2 and actlr_el3. */
 | |
|             {
 | |
|                 util::BitPack32 actlr = {};
 | |
| 
 | |
|                 actlr.Set<hw::ActlrCortexA57::Cpuactlr>(1); /* Enable access to cpuactlr from lower EL. */
 | |
|                 actlr.Set<hw::ActlrCortexA57::Cpuectlr>(1); /* Enable access to cpuectlr from lower EL. */
 | |
|                 actlr.Set<hw::ActlrCortexA57::L2ctlr>(1);   /* Enable access to l2ctlr from lower EL. */
 | |
|                 actlr.Set<hw::ActlrCortexA57::L2actlr>(1);  /* Enable access to l2actlr from lower EL. */
 | |
|                 actlr.Set<hw::ActlrCortexA57::L2ectlr>(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<hw::HcrEl2::Rw>(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<hw::SctlrEl1::M>(0);       /* Globally disable the MMU. */
 | |
|                 sctlr.Set<hw::SctlrEl1::A>(0);       /* Disable alignment fault checking. */
 | |
|                 sctlr.Set<hw::SctlrEl1::C>(0);       /* Globally disable the data and unified caches. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Sa>(1);      /* Enable stack alignment checking. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Sa0>(1);     /* Enable el0 stack alignment checking. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Cp15BEn>(1); /* Enable cp15 barrier operations. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Thee>(0);    /* Disable ThumbEE. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Itd>(0);     /* Enable itd instructions. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Sed>(0);     /* Enable setend instruction. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Uma>(0);     /* Disable el0 interrupt mask access. */
 | |
|                 sctlr.Set<hw::SctlrEl1::I>(0);       /* Globally disable the instruction cache. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Dze>(0);     /* Disable el0 access to dc zva instruction. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Ntwi>(1);    /* wfi instructions in el0 trap. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Ntwe>(1);    /* wfe instructions in el0 trap. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Wxn>(0);     /* Do not force writable pages to be ExecuteNever. */
 | |
|                 sctlr.Set<hw::SctlrEl1::E0e>(0);     /* Data accesses in el0 are little endian. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Ee>(0);      /* Exceptions should be little endian. */
 | |
|                 sctlr.Set<hw::SctlrEl1::Uci>(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 };
 | |
| 
 | |
|                 sctlr.Set<hw::SctlrEl2::M>(0);       /* Globally disable the MMU. */
 | |
|                 sctlr.Set<hw::SctlrEl2::A>(0);       /* Disable alignment fault checking. */
 | |
|                 sctlr.Set<hw::SctlrEl2::C>(0);       /* Globally disable the data and unified caches. */
 | |
|                 sctlr.Set<hw::SctlrEl2::Sa>(1);      /* Enable stack alignment checking. */
 | |
|                 sctlr.Set<hw::SctlrEl2::I>(0);       /* Globally disable the instruction cache. */
 | |
|                 sctlr.Set<hw::SctlrEl2::Wxn>(0);     /* Do not force writable pages to be ExecuteNever. */
 | |
|                 sctlr.Set<hw::SctlrEl2::Ee>(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<hw::CnthctlEl2::El1PctEn>(1); /* Do not trap accesses to cntpct_el0. */
 | |
|                 cnthctl.Set<hw::CnthctlEl2::El1PcEn>(1);  /* Do not trap accesses to cntp_ctl_el0, cntp_cval_el0, and cntp_tval_el0. */
 | |
|                 cnthctl.Set<hw::CnthctlEl2::EvntEn>(0);   /* Disable the event stream. */
 | |
|                 cnthctl.Set<hw::CnthctlEl2::EvntDir>(0);  /* Trigger events on 0 -> 1 transition. */
 | |
|                 cnthctl.Set<hw::CnthctlEl2::EvntI>(0);    /* Select bit0 of cntpct_el0 as the event stream trigger. */
 | |
| 
 | |
|                 HW_CPU_SET_CNTHCTL_EL2(cnthctl);
 | |
|             }
 | |
| 
 | |
|             /* Ensure instruction consistency. */
 | |
|             hw::InstructionSynchronizationBarrier();
 | |
|         }
 | |
| 
 | |
|         void SetupGpuCarveout() {
 | |
|             /* Configure carveout 2. */
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_BOM,                           static_cast<u32>(MemoryRegionDramGpuCarveout.GetAddress() >> 0));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_BOM_HI,                        static_cast<u32>(MemoryRegionDramGpuCarveout.GetAddress() >> BITSIZEOF(u32)));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_SIZE_128KB,                    MemoryRegionDramGpuCarveout.GetSize() / 128_KB);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2,                MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD,  ENABLE),
 | |
|                                                                                  MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR,  ENABLE),
 | |
|                                                                                  MC_REG_BITS_ENUM (CLIENT_ACCESS2_TSECSRD, ENABLE));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3,                0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4,                MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE),
 | |
|                                                                                  MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE));
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
 | |
|             reg::Write(MC + MC_SECURITY_CARVEOUT2_CFG0,                          MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                 ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                         ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                                                  MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   2),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                     ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                     ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                    DISABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                      ENABLED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                  UNTRANSLATED_ONLY),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                                LOCKED),
 | |
|                                                                                  MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                     LOCKBIT_SECURE));
 | |
|         }
 | |
| 
 | |
|         void DisableArc() {
 | |
|             /* Configure IRAM top/bottom to point to memory ends (disabling redirection). */
 | |
|             reg::Write(MC + MC_IRAM_BOM, MC_REG_BITS_VALUE(IRAM_BOM_IRAM_BOM, (~0u)));
 | |
|             reg::Write(MC + MC_IRAM_TOM, MC_REG_BITS_VALUE(IRAM_TOM_IRAM_TOM, ( 0u)));
 | |
| 
 | |
|             /* Lock the IRAM aperture. */
 | |
|             reg::ReadWrite(MC + MC_IRAM_REG_CTRL, MC_REG_BITS_ENUM(IRAM_REG_CTRL_IRAM_CFG_WRITE_ACCESS, DISABLED));
 | |
| 
 | |
|             /* Disable the ARC clock gate override. */
 | |
|             reg::ReadWrite(CLK_RST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, CLK_RST_REG_BITS_ENUM(LVL2_CLK_GATE_OVRD_ARC_CLK_OVR_ON, OFF));
 | |
| 
 | |
|             /* Read IRAM REG CTRL to make sure our writes take. */
 | |
|             reg::Read(MC + MC_IRAM_REG_CTRL);
 | |
|         }
 | |
| 
 | |
|         void DisableUntranslatedDeviceMemoryAccess() {
 | |
|             /* If we can (mariko only), disable GMMU accesses that bypass the SMMU. */
 | |
|             /* Additionally, force all untranslated acccesses to hit one of the carveouts. */
 | |
|             if (GetSocType() == fuse::SocType_Mariko) {
 | |
|                 reg::Write(MC + MC_UNTRANSLATED_REGION_CHECK, MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_UNTRANSLATED_REGION_CHECK_ACCESS,          DISABLED),
 | |
|                                                               MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_CLIENTS_HIT_CARVEOUT,  ENABLED),
 | |
|                                                               MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_GPU_HIT_CARVEOUT,      ENABLED));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void FinalizeCarveoutSecureScratchRegisters() {
 | |
|             /* Define carveout scratch values. */
 | |
|             constexpr uintptr_t WarmbootCarveoutAddress = MemoryRegionDram.GetAddress();
 | |
|             constexpr size_t    WarmbootCarveoutSize    = 128_KB;
 | |
| 
 | |
|             #define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE)
 | |
| 
 | |
|             constexpr u32 WarmbootCarveoutClientAccess0     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, AVPCARM7R),
 | |
|                                                                           MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR));
 | |
| 
 | |
|             constexpr u32 WarmbootCarveoutClientAccess1     = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, AVPCARM7W));
 | |
| 
 | |
|             #undef MC_ENABLE_CLIENT_ACCESS
 | |
| 
 | |
|             constexpr u32 WarmbootCarveoutForceInternalAccess0     = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R,   ENABLE),
 | |
|                                                                  MC_REG_BITS_ENUM(CLIENT_ACCESS0_PPCSAHBSLVR, ENABLE));
 | |
| 
 | |
|             constexpr u32 WarmbootCarveoutForceInternalAccess1     = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE));
 | |
| 
 | |
|             constexpr u32 WarmbootCarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR,                                 DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH,                DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH,             DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN,                        DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN,                        DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU,                        DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3,  ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2,  ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1,  ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0,  ENABLE_CHECKS),
 | |
|                                                                MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID,                                   0),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3,                    DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2,                    DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1,                    DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0,                     ENABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3,                     DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2,                     DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1,                     DISABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0,                      ENABLED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE,                        ANY_ADDRESS),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE,                              UNLOCKED),
 | |
|                                                                MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE,                     LOCKBIT_SECURE));
 | |
| 
 | |
|             /* Save the carveout values into secure scratch. */
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_BOM. */
 | |
|             reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH51, REG_BITS_VALUE( 0, 15, WarmbootCarveoutAddress >> 17));
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_BOM_HI. */
 | |
|             reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH16, REG_BITS_VALUE(30,  2, WarmbootCarveoutAddress >> 32));
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_SIZE_128KB. */
 | |
|             reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH55, REG_BITS_VALUE(12, 12, WarmbootCarveoutSize / 128_KB));
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_CLIENT_ACCESS. */
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH74, WarmbootCarveoutClientAccess0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH75, WarmbootCarveoutClientAccess1);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH76, 0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH77, 0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH78, 0);
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_FORCE_INTERNAL_ACCESS. */
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH99,  WarmbootCarveoutForceInternalAccess0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH100, WarmbootCarveoutForceInternalAccess1);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH101, 0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH102, 0);
 | |
|             reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH103, 0);
 | |
| 
 | |
|             /* Save MC_SECURITY_CARVEOUT4_CFG0. */
 | |
|             reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH39, REG_BITS_VALUE(0, 27, WarmbootCarveoutConfig));
 | |
|         }
 | |
| 
 | |
|         void EnableBpmpSmmu() {
 | |
|             /* Define the ASID contents. */
 | |
|             constexpr int       BpmpAsid    = 1;
 | |
|             constexpr uintptr_t BpmpAsidPde = MemoryRegionPhysicalDeviceSecurityEngine.GetAddress();
 | |
| 
 | |
|             /* Configure the ASID. */
 | |
|             reg::Write(MC + MC_SMMU_PTB_ASID, MC_REG_BITS_VALUE(SMMU_PTB_ASID_CURRENT_ASID,  BpmpAsid));
 | |
| 
 | |
|             reg::Write(MC + MC_SMMU_PTB_DATA, MC_REG_BITS_VALUE(SMMU_PTB_DATA_ASID_PDE_BASE,  BpmpAsidPde / 4_KB),
 | |
|                                               MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_NONSECURE,            DISABLE),
 | |
|                                               MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_WRITABLE,             DISABLE),
 | |
|                                               MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_READABLE,             DISABLE));
 | |
| 
 | |
|             /* Configure the BPMP and PPCS1 to use the asid. */
 | |
|             reg::Write(MC + MC_SMMU_AVPC_ASID,  MC_REG_BITS_ENUM(SMMU_AVPC_ASID_AVPC_SMMU_ENABLE, ENABLE),   MC_REG_BITS_VALUE(SMMU_AVPC_ASID_AVPC_ASID,   BpmpAsid));
 | |
|             reg::Write(MC + MC_SMMU_PPCS1_ASID, MC_REG_BITS_ENUM(SMMU_PPCS1_ASID_PPCS1_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_PPCS1_ASID_PPCS1_ASID, BpmpAsid));
 | |
| 
 | |
|             /* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
 | |
|             reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0);
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
| 
 | |
|             /* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
 | |
|             reg::Write(MC + MC_SMMU_TLB_FLUSH, 0);
 | |
|             reg::Read (MC + MC_SMMU_TLB_CONFIG);
 | |
|         }
 | |
| 
 | |
|         void ValidateResetExpected() {
 | |
|             /* We're coming out of reset, so check that we expected to come out of reset. */
 | |
|             if (!IsResetExpected()) {
 | |
|                 secmon::SetError(pkg1::ErrorInfo_UnexpectedReset);
 | |
|                 AMS_ABORT("unexpected reset");
 | |
|             }
 | |
|             SetResetExpected(false);
 | |
|         }
 | |
| 
 | |
|         void ActmonInterruptHandler() {
 | |
|             SetError(pkg1::ErrorInfo_ActivityMonitorInterrupt);
 | |
|             AMS_ABORT("actmon observed bpmp wakeup");
 | |
|         }
 | |
| 
 | |
|         void ExitChargerHiZMode() {
 | |
|             /* Setup I2c-1. */
 | |
|             pinmux::SetupI2c1();
 | |
|             clkrst::EnableI2c1Clock();
 | |
| 
 | |
|             /* Initialize I2c-1. */
 | |
|             i2c::Initialize(i2c::Port_1);
 | |
| 
 | |
|             /* Exit Hi-Z mode. */
 | |
|             charger::ExitHiZMode();
 | |
| 
 | |
|             /* Disable clock to I2c-1. */
 | |
|             clkrst::DisableI2c1Clock();
 | |
|         }
 | |
| 
 | |
|         bool IsExitLp0() {
 | |
|             return reg::Read(MC + MC_SECURITY_CFG3) == 0;
 | |
|         }
 | |
| 
 | |
|         void SetupLogForBoot() {
 | |
|             log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags());
 | |
|             log::SendText("OHAYO\n", 6);
 | |
|             log::Flush();
 | |
|         }
 | |
| 
 | |
|         void LogExitLp0() {
 | |
|             /* NOTE: Nintendo only does this on dev, but we will always do it. */
 | |
|             if (true /* !pkg1::IsProduction() */) {
 | |
|                 SetupLogForBoot();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void SetupForLp0Exit() {
 | |
|             /* Exit HiZ mode in charger, if we need to. */
 | |
|             const auto target_fw = GetTargetFirmware();
 | |
|             const bool force_exit_hiz_mode = (target_fw < TargetFirmware_4_0_0) || (target_fw < TargetFirmware_8_0_0 && fuse::GetHardwareType() == fuse::HardwareType_Icosa);
 | |
|             if (force_exit_hiz_mode || smc::IsChargerHiZModeEnabled()) {
 | |
|                 ExitChargerHiZMode();
 | |
|             }
 | |
| 
 | |
|             /* Refill the random cache, which is volatile and thus wiped on warmboot. */
 | |
|             smc::FillRandomCache();
 | |
| 
 | |
|             /* Unlock the security engine. */
 | |
|             secmon::smc::UnlockSecurityEngine();
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     void Setup1() {
 | |
|         /* Load the global configuration context. */
 | |
|         InitializeConfigurationContext();
 | |
| 
 | |
|         /* Initialize uart for logging. */
 | |
|         SetupLogForBoot();
 | |
| 
 | |
|         /* Initialize the security engine. */
 | |
|         se::Initialize();
 | |
| 
 | |
|         /* Initialize the gic. */
 | |
|         gic::InitializeCommon();
 | |
|     }
 | |
| 
 | |
|     void Setup1ForWarmboot() {
 | |
|         /* Initialize the security engine. */
 | |
|         se::Initialize();
 | |
| 
 | |
|         /* Initialize the gic. */
 | |
|         gic::InitializeCommon();
 | |
|     }
 | |
| 
 | |
|     void SaveSecurityEngineAesKeySlotTestVector() {
 | |
|         GenerateSecurityEngineAesKeySlotTestVector(g_se_aes_key_slot_test_vector, sizeof(g_se_aes_key_slot_test_vector));
 | |
|     }
 | |
| 
 | |
|     void SetupSocSecurity() {
 | |
|         /* Set the fuse visibility. */
 | |
|         clkrst::SetFuseVisibility(true);
 | |
| 
 | |
|         /* Set fuses as only secure-writable. */
 | |
|         fuse::SetWriteSecureOnly();
 | |
| 
 | |
|         /* Lockout the fuses. */
 | |
|         fuse::Lockout();
 | |
| 
 | |
|         /* Set the security engine to secure mode. */
 | |
|         se::SetSecure(true);
 | |
| 
 | |
|         /* Verify the security engine's sticky bits. */
 | |
|         VerifySecurityEngineStickyBits();
 | |
| 
 | |
|         /* Verify the security engine's Aes slots contain correct contents. */
 | |
|         VerifySecurityEngineAesKeySlotTestVector();
 | |
| 
 | |
|         /* Clear aes keyslots. */
 | |
|         ClearAesKeySlots();
 | |
| 
 | |
|         /* Clear rsa keyslots. */
 | |
|         ClearRsaKeySlots();
 | |
| 
 | |
|         /* Overwrite keys that we want to be random with random contents. */
 | |
|         se::InitializeRandom();
 | |
|         se::ConfigureAutomaticContextSave();
 | |
|         se::SetRandomKey(pkg1::AesKeySlot_Temporary);
 | |
|         se::GenerateSrk();
 | |
|         se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
 | |
| 
 | |
|         /* Initialize pmc secure scratch. */
 | |
|         if (GetSocType() == fuse::SocType_Erista) {
 | |
|             pmc::InitializeRandomScratch();
 | |
|         }
 | |
|         pmc::LockSecureRegister(pmc::SecureRegister_Srk);
 | |
| 
 | |
|         /* Setup secure registers. */
 | |
|         SetupSecureRegisters();
 | |
| 
 | |
|         /* Setup the smmu. */
 | |
|         SetupSmmu();
 | |
| 
 | |
|         /* Clear the cpu reset vector. */
 | |
|         reg::Write(EVP + EVP_CPU_RESET_VECTOR, 0);
 | |
| 
 | |
|         /* Configure the SB registers to our start address. */
 | |
|         constexpr u32 ResetVectorLow  = static_cast<u32>((PhysicalTzramProgramResetVector >> 0));
 | |
|         constexpr u32 ResetVectorHigh = static_cast<u32>((PhysicalTzramProgramResetVector >> BITSIZEOF(u32)));
 | |
| 
 | |
|         /* Write our reset vector to the secure boot registers. */
 | |
|         reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_LOW,  ResetVectorLow | 1);
 | |
|         reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_HIGH, ResetVectorHigh);
 | |
| 
 | |
|         /* Disable non-secure writes to the reset vector. */
 | |
|         reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR, SB_REG_BITS_ENUM(CSR_NS_RST_VEC_WR_DIS, DISABLE));
 | |
| 
 | |
|         /* Read back SB_CSR to make sure our non-secure write disable takes. */
 | |
|         reg::Read(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR);
 | |
| 
 | |
|         /* Write our reset vector to scratch registers used by warmboot, and lock those scratch registers. */
 | |
|         reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH34, ResetVectorLow);
 | |
|         reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH35, ResetVectorHigh);
 | |
|         pmc::LockSecureRegister(pmc::SecureRegister_ResetVector);
 | |
| 
 | |
|         /* Setup the security engine interrupt. */
 | |
|         constexpr int SecurityEngineInterruptId = 90;
 | |
|         constexpr u8  SecurityEngineInterruptCoreMask = (1 << 3);
 | |
|         gic::SetPriority      (SecurityEngineInterruptId,            gic::HighestPriority);
 | |
|         gic::SetInterruptGroup(SecurityEngineInterruptId,                               0);
 | |
|         gic::SetEnable        (SecurityEngineInterruptId,                            true);
 | |
|         gic::SetSpiTargetCpu  (SecurityEngineInterruptId, SecurityEngineInterruptCoreMask);
 | |
|         gic::SetSpiMode       (SecurityEngineInterruptId,        gic::InterruptMode_Level);
 | |
| 
 | |
|         /* Setup the activity monitor interrupt. */
 | |
|         constexpr int ActivityMonitorInterruptId = 77;
 | |
|         constexpr u8  ActivityMonitorInterruptCoreMask = (1 << 3);
 | |
|         gic::SetPriority      (ActivityMonitorInterruptId,            gic::HighestPriority);
 | |
|         gic::SetInterruptGroup(ActivityMonitorInterruptId,                               0);
 | |
|         gic::SetEnable        (ActivityMonitorInterruptId,                            true);
 | |
|         gic::SetSpiTargetCpu  (ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask);
 | |
|         gic::SetSpiMode       (ActivityMonitorInterruptId,        gic::InterruptMode_Level);
 | |
| 
 | |
|         /* Setup the mariko fatal error interrupt. */
 | |
|         constexpr u8 MarikoFatalInterruptCoreMask = 0b1111;
 | |
|         gic::SetPriority      (MarikoFatalErrorInterruptId,         gic::HighestPriority);
 | |
|         gic::SetInterruptGroup(MarikoFatalErrorInterruptId,                            0);
 | |
|         gic::SetEnable        (MarikoFatalErrorInterruptId,                         true);
 | |
|         gic::SetSpiTargetCpu  (MarikoFatalErrorInterruptId,                            0);
 | |
|         gic::SetSpiMode       (MarikoFatalErrorInterruptId,     gic::InterruptMode_Level);
 | |
| 
 | |
|         /* If we're coldboot, perform one-time setup. */
 | |
|         if (g_is_cold_boot) {
 | |
|             /* Register all interrupt handlers. */
 | |
|             SetInterruptHandler(SecurityEngineInterruptId,   SecurityEngineInterruptCoreMask,      se::HandleInterrupt);
 | |
|             SetInterruptHandler(ActivityMonitorInterruptId,  ActivityMonitorInterruptCoreMask, actmon::HandleInterrupt);
 | |
|             SetInterruptHandler(MarikoFatalErrorInterruptId, MarikoFatalInterruptCoreMask,     secmon::HandleMarikoFatalErrorInterrupt);
 | |
| 
 | |
|             /* We're expecting the other cores to come out of reset. */
 | |
|             for (int i = 1; i < NumCores; ++i) {
 | |
|                 SetResetExpected(i, true);
 | |
|             }
 | |
| 
 | |
|             /* We only coldboot once. */
 | |
|             g_is_cold_boot = false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void SetupSocSecurityWarmboot() {
 | |
|         /* Check that we're allowed to continue. */
 | |
|         ValidateResetExpected();
 | |
| 
 | |
|         /* Unmap the tzram identity mapping. */
 | |
|         UnmapTzram();
 | |
| 
 | |
|         /* If we're exiting LP0, there's a little more work for us to do. */
 | |
|         if (IsExitLp0()) {
 | |
|             /* Log that we're exiting LP0. */
 | |
|             LogExitLp0();
 | |
| 
 | |
|             /* Perform initial setup. */
 | |
|             Setup1ForWarmboot();
 | |
| 
 | |
|             /* Generate a random srk. */
 | |
|             se::GenerateSrk();
 | |
| 
 | |
|             /* Setup the Soc security. */
 | |
|             SetupSocSecurity();
 | |
| 
 | |
|             /* Set the PMC and MC as secure-only. */
 | |
|             SetupPmcAndMcSecure();
 | |
| 
 | |
|             /* Perform Lp0-exit specific init. */
 | |
|             SetupForLp0Exit();
 | |
| 
 | |
|             /* Setup the Soc protections. */
 | |
|             SetupSocProtections();
 | |
|         }
 | |
| 
 | |
|         /* Perform remaining CPU initialization. */
 | |
|         SetupCpuCoreContext();
 | |
|         SetupCpuSErrorDebug();
 | |
|     }
 | |
| 
 | |
|     void SetupSocProtections() {
 | |
|         /* Setup the GPU carveout. */
 | |
|         SetupGpuCarveout();
 | |
| 
 | |
|         /* Configure the two kernel carveouts. */
 | |
|         SetupKernelCarveouts();
 | |
| 
 | |
|         /* Disable the ARC. */
 | |
|         DisableArc();
 | |
| 
 | |
|         /* Disable untranslated memory accesses by devices. */
 | |
|         DisableUntranslatedDeviceMemoryAccess();
 | |
| 
 | |
|         /* Further protections aren't applied on <= 1.0.0. */
 | |
|         if (GetTargetFirmware() <= TargetFirmware_1_0_0) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         /* Finalize and lock the carveout scratch registers. */
 | |
|         FinalizeCarveoutSecureScratchRegisters();
 | |
|         pmc::LockSecureRegister(pmc::SecureRegister_Carveout);
 | |
| 
 | |
|         /* Clear all the BPMP exception vectors to a fixed value. */
 | |
|         constexpr u32 BpmpExceptionVector = 0x7D000000;
 | |
|         reg::Write(EVP + EVP_COP_RESET_VECTOR,          BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_UNDEF_VECTOR,          BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_SWI_VECTOR,            BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR,     BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_RSVD_VECTOR,           BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_IRQ_VECTOR,            BpmpExceptionVector);
 | |
|         reg::Write(EVP + EVP_COP_FIQ_VECTOR,            BpmpExceptionVector);
 | |
| 
 | |
|         /* Disable arbitration for the bpmp. */
 | |
|         reg::ReadWrite(SYSTEM + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE));
 | |
| 
 | |
|         /* Turn on the SMMU for the BPMP. */
 | |
|         EnableBpmpSmmu();
 | |
| 
 | |
|         /* Wait until the flow controller reports that the BPMP is halted. */
 | |
|         while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP))) {
 | |
|             util::WaitMicroSeconds(1);
 | |
|         }
 | |
| 
 | |
|         /* Enable clock to the activity monitor. */
 | |
|         clkrst::EnableActmonClock();
 | |
| 
 | |
|         /* If JTAG is disabled, disable JTAG. */
 | |
|         if (!secmon::IsJtagEnabled()) {
 | |
|             reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
 | |
|                                                               FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG,       DISABLED));
 | |
| 
 | |
|             /* Turn on the activity monitor to prevent booting up the bpmp. */
 | |
|             actmon::StartMonitoringBpmp(ActmonInterruptHandler);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void SetupPmcAndMcSecure() {
 | |
|         const auto target_fw = GetTargetFirmware();
 | |
| 
 | |
|         if (target_fw >= TargetFirmware_2_0_0) {
 | |
|             /* Set the PMC secure. */
 | |
|             reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE));
 | |
|         }
 | |
| 
 | |
|         if (target_fw >= TargetFirmware_4_0_0) {
 | |
|             /* Set the MC secure. */
 | |
|             reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, SLAVE_SECURITY_REG_BITS_ENUM(1, MC0, ENABLE),
 | |
|                                                                                              SLAVE_SECURITY_REG_BITS_ENUM(1, MC1, ENABLE),
 | |
|                                                                                              SLAVE_SECURITY_REG_BITS_ENUM(1, MCB, ENABLE));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     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() {
 | |
|         /* Get whether we should enable SError debug. */
 | |
|         const auto &bc_data = secmon::GetBootConfig().data;
 | |
|         const bool enabled  = bc_data.IsDevelopmentFunctionEnabled() && bc_data.IsSErrorDebugEnabled();
 | |
| 
 | |
|         /* Get and set scr_el3. */
 | |
|         {
 | |
|             util::BitPack32 scr;
 | |
|             HW_CPU_GET_SCR_EL3(scr);
 | |
| 
 | |
|             scr.Set<hw::ScrEl3::Ea>(enabled ? 0 : 1);
 | |
|             HW_CPU_SET_SCR_EL3(scr);
 | |
|         }
 | |
| 
 | |
|         /* Prevent reordering instructions around this call. */
 | |
|         hw::InstructionSynchronizationBarrier();
 | |
|     }
 | |
| 
 | |
|     void SetKernelCarveoutRegion(int index, uintptr_t address, size_t size) {
 | |
|         /* Configure the carveout. */
 | |
|         auto &carveout = g_kernel_carveouts[index];
 | |
|         carveout.address = address;
 | |
|         carveout.size    = size;
 | |
| 
 | |
|         SetupKernelCarveouts();
 | |
|     }
 | |
| 
 | |
| } |