diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp index 329005051..7e0af46ef 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include namespace ams::kern::arch::arm64::cpu { @@ -156,6 +157,11 @@ namespace ams::kern::arch::arm64::cpu { void FlushEntireDataCacheSharedForInit(); void FlushEntireDataCacheLocalForInit(); + Result InvalidateDataCache(void *addr, size_t size); + Result StoreDataCache(const void *addr, size_t size); + Result FlushDataCache(const void *addr, size_t size); + Result InvalidateInstructionCache(void *addr, size_t size); + ALWAYS_INLINE void ClearPageToZero(void *page) { MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast(page), PageSize)); MESOSPHERE_ASSERT(page != nullptr); diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp index 20627edab..828b49f17 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp @@ -20,6 +20,11 @@ namespace ams::kern::arch::arm64 { void UserspaceMemoryAccessFunctionAreaBegin(); + bool StoreDataCache(uintptr_t start, uintptr_t end); + bool FlushDataCache(uintptr_t start, uintptr_t end); + bool InvalidateDataCache(uintptr_t start, uintptr_t end); + bool InvalidateInstructionCache(uintptr_t start, uintptr_t end); + void UserspaceMemoryAccessFunctionAreaEnd(); } \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp new file mode 100644 index 000000000..48e5c8e99 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::kern::board::nintendo::nx { + + using KDeviceVirtualAddress = u64; + + class KDevicePageTable { + private: + static constexpr size_t TableCount = 4; + private: + KVirtualAddress tables[TableCount]; + u8 table_asids[TableCount]; + u64 attached_device; + u32 attached_value; + u32 detached_value; + u32 hs_attached_value; + u32 hs_detached_value; + private: + static ALWAYS_INLINE KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress addr) { + return KPageTable::GetHeapVirtualAddress(addr); + } + + static ALWAYS_INLINE KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress addr) { + return KPageTable::GetHeapPhysicalAddress(addr); + } + + static ALWAYS_INLINE KVirtualAddress GetPageTableVirtualAddress(KPhysicalAddress addr) { + return KPageTable::GetPageTableVirtualAddress(addr); + } + + static ALWAYS_INLINE KPhysicalAddress GetPageTablePhysicalAddress(KVirtualAddress addr) { + return KPageTable::GetPageTablePhysicalAddress(addr); + } + public: + constexpr KDevicePageTable() : tables(), table_asids(), attached_device(), attached_value(), detached_value(), hs_attached_value(), hs_detached_value() { /* ... */ } + + static void Initialize(); + }; + +} \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index e14c73474..499159bb7 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -45,6 +45,21 @@ namespace ams::kern::board::nintendo::nx { static void GenerateRandomBytes(void *dst, size_t size); static u64 GenerateRandomRange(u64 min, u64 max); + /* Privileged Access. */ + static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); + static void ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); + + static ALWAYS_INLINE u32 ReadRegisterPrivileged(ams::svc::PhysicalAddress address) { + u32 v; + ReadWriteRegisterPrivileged(std::addressof(v), address, 0x00000000u, 0); + return v; + } + + static ALWAYS_INLINE void WriteRegisterPrivileged(ams::svc::PhysicalAddress address, u32 value) { + u32 v; + ReadWriteRegisterPrivileged(std::addressof(v), address, 0xFFFFFFFFu, value); + } + /* Power management. */ static void SleepSystem(); static NORETURN void StopSystem(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp index 7262962f7..74fe90922 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp @@ -17,12 +17,15 @@ #include #include #include +#include namespace ams::kern { class KDeviceAddressSpace final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject); public: + static void Initialize(); + /* TODO: This is a placeholder definition. */ }; diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp index a5216097c..683ddc284 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp @@ -463,6 +463,10 @@ namespace ams::kern { return GetPhysicalMemoryRegionTree().FindFirstDerivedRegion(KMemoryRegionType_Uart)->GetPairAddress(); } + static NOINLINE KMemoryRegion &GetMemoryControllerRegion() { + return *GetPhysicalMemoryRegionTree().FindFirstDerivedRegion(KMemoryRegionType_MemoryController); + } + static NOINLINE KMemoryRegion &GetMetadataPoolRegion() { return *GetVirtualMemoryRegionTree().FindFirstRegionByType(KMemoryRegionType_VirtualDramMetadataPool); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 68f5ab34a..1a85d2107 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -216,6 +216,10 @@ namespace ams::kern { return GetLinearVirtualAddress(addr); } + static ALWAYS_INLINE KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress addr) { + return GetLinearPhysicalAddress(addr); + } + static ALWAYS_INLINE KVirtualAddress GetPageTableVirtualAddress(KPhysicalAddress addr) { return GetLinearVirtualAddress(addr); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_manager.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_manager.hpp index 1b12e82d1..85af722a3 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_manager.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_manager.hpp @@ -33,6 +33,8 @@ namespace ams::kern { class KPageTableManager : public KDynamicSlabHeap { public: using RefCount = u16; + static constexpr size_t PageTableSize = sizeof(impl::PageTablePage); + static_assert(PageTableSize == PageSize); private: using BaseHeap = KDynamicSlabHeap; private: diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index a505423c0..5dc1b3c8b 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -231,6 +231,9 @@ namespace ams::kern { this->GetStackParameters().disable_count--; } + NOINLINE void DisableCoreMigration(); + NOINLINE void EnableCoreMigration(); + ALWAYS_INLINE void SetInExceptionHandler() { MESOSPHERE_ASSERT_THIS(); this->GetStackParameters().is_in_exception_handler = true; diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_device_page_table.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_device_page_table.hpp new file mode 100644 index 000000000..51e4db302 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_select_device_page_table.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX + #include + + namespace ams::kern { + using ams::kern::board::nintendo::nx::KDevicePageTable; + } + +#else + #error "Unknown board for KDevicePageTable" +#endif diff --git a/libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp b/libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp index 25afa811b..0a28dacf1 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp @@ -23,6 +23,13 @@ namespace ams::kern::arch::arm64::cpu { namespace { + class KScopedCoreMigrationDisable { + public: + ALWAYS_INLINE KScopedCoreMigrationDisable() { GetCurrentThread().DisableCoreMigration(); } + + ALWAYS_INLINE ~KScopedCoreMigrationDisable() { GetCurrentThread().EnableCoreMigration(); } + }; + /* Nintendo registers a handler for a SGI on thread termination, but does not handle anything. */ /* This is sufficient, because post-interrupt scheduling is all they really intend to occur. */ class KThreadTerminationInterruptHandler : public KInterruptHandler { @@ -284,6 +291,38 @@ namespace ams::kern::arch::arm64::cpu { __asm__ __volatile__("wfe" ::: "memory"); } + ALWAYS_INLINE Result InvalidateDataCacheRange(uintptr_t start, uintptr_t end) { + MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); + MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); + R_UNLESS(arm64::InvalidateDataCache(start, end), svc::ResultInvalidCurrentMemory()); + DataSynchronizationBarrier(); + return ResultSuccess(); + } + + ALWAYS_INLINE Result StoreDataCacheRange(uintptr_t start, uintptr_t end) { + MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); + MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); + R_UNLESS(arm64::StoreDataCache(start, end), svc::ResultInvalidCurrentMemory()); + DataSynchronizationBarrier(); + return ResultSuccess(); + } + + ALWAYS_INLINE Result FlushDataCacheRange(uintptr_t start, uintptr_t end) { + MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); + MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); + R_UNLESS(arm64::FlushDataCache(start, end), svc::ResultInvalidCurrentMemory()); + DataSynchronizationBarrier(); + return ResultSuccess(); + } + + ALWAYS_INLINE Result InvalidateInstructionCacheRange(uintptr_t start, uintptr_t end) { + MESOSPHERE_ASSERT(util::IsAligned(start, InstructionCacheLineSize)); + MESOSPHERE_ASSERT(util::IsAligned(end, InstructionCacheLineSize)); + R_UNLESS(arm64::InvalidateInstructionCache(start, end), svc::ResultInvalidCurrentMemory()); + EnsureInstructionConsistency(); + return ResultSuccess(); + } + } void FlushEntireDataCacheSharedForInit() { @@ -294,6 +333,59 @@ namespace ams::kern::arch::arm64::cpu { return PerformCacheOperationBySetWayLocal(FlushDataCacheLineBySetWayImpl); } + Result InvalidateDataCache(void *addr, size_t size) { + KScopedCoreMigrationDisable dm; + const uintptr_t start = reinterpret_cast(addr); + const uintptr_t end = start + size; + uintptr_t aligned_start = util::AlignDown(start, DataCacheLineSize); + uintptr_t aligned_end = util::AlignUp(end, DataCacheLineSize); + + if (aligned_start != start) { + R_TRY(FlushDataCacheRange(aligned_start, aligned_start + DataCacheLineSize)); + aligned_start += DataCacheLineSize; + } + + if (aligned_start < aligned_end && (aligned_end != end)) { + aligned_end -= DataCacheLineSize; + R_TRY(FlushDataCacheRange(aligned_end, aligned_end + DataCacheLineSize)); + } + + if (aligned_start < aligned_end) { + R_TRY(InvalidateDataCacheRange(aligned_start, aligned_end)); + } + + return ResultSuccess(); + } + + Result StoreDataCache(const void *addr, size_t size) { + KScopedCoreMigrationDisable dm; + const uintptr_t start = util::AlignDown(reinterpret_cast(addr), DataCacheLineSize); + const uintptr_t end = util::AlignUp( reinterpret_cast(addr), DataCacheLineSize); + + return StoreDataCacheRange(start, end); + } + + Result FlushDataCache(const void *addr, size_t size) { + KScopedCoreMigrationDisable dm; + const uintptr_t start = util::AlignDown(reinterpret_cast(addr), DataCacheLineSize); + const uintptr_t end = util::AlignUp( reinterpret_cast(addr), DataCacheLineSize); + + return FlushDataCacheRange(start, end); + } + + Result InvalidateInstructionCache(void *addr, size_t size) { + KScopedCoreMigrationDisable dm; + const uintptr_t start = util::AlignDown(reinterpret_cast(addr), InstructionCacheLineSize); + const uintptr_t end = util::AlignUp( reinterpret_cast(addr), InstructionCacheLineSize); + + R_TRY(InvalidateInstructionCacheRange(start, end)); + + /* Request the interrupt helper to invalidate, too. */ + g_cache_operation_handler.RequestOperation(KCacheHelperInterruptHandler::Operation::InvalidateInstructionCache); + + return ResultSuccess(); + } + void InitializeInterruptThreads(s32 core_id) { /* Initialize the cache operation handler. */ g_cache_operation_handler.Initialize(core_id); diff --git a/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s b/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s new file mode 100644 index 000000000..99c474d27 --- /dev/null +++ b/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* ams::kern::arch::arm64::UserspaceMemoryAccessFunctionAreaBegin() */ +.section .text._ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv, "ax", %progbits +.global _ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv +.type _ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv, %function +_ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv: +/* NOTE: This is not a real function, and only exists as a label for safety. */ + +/* ================ All Userspace Memory Functions after this line. ================ */ + +/* ams::kern::arch::arm64::StoreDataCache(uintptr_t start, uintptr_t end) */ +.section .text._ZN3ams4kern4arch5arm6414StoreDataCacheEmm, "ax", %progbits +.global _ZN3ams4kern4arch5arm6414StoreDataCacheEmm +.type _ZN3ams4kern4arch5arm6414StoreDataCacheEmm, %function +_ZN3ams4kern4arch5arm6414StoreDataCacheEmm: + /* Check if we have any work to do. */ + cmp x1, x0 + b.eq 2f + +1: /* Loop, storing each cache line. */ + dc cvac, x0 + add x0, x0, #0x40 + cmp x1, x0 + b.ne 1b + +2: /* We're done! */ + mov x0, #1 + ret + +/* ams::kern::arch::arm64::FlushDataCache(uintptr_t start, uintptr_t end) */ +.section .text._ZN3ams4kern4arch5arm6414FlushDataCacheEmm, "ax", %progbits +.global _ZN3ams4kern4arch5arm6414FlushDataCacheEmm +.type _ZN3ams4kern4arch5arm6414FlushDataCacheEmm, %function +_ZN3ams4kern4arch5arm6414FlushDataCacheEmm: + /* Check if we have any work to do. */ + cmp x1, x0 + b.eq 2f + +1: /* Loop, flushing each cache line. */ + dc civac, x0 + add x0, x0, #0x40 + cmp x1, x0 + b.ne 1b + +2: /* We're done! */ + mov x0, #1 + ret + +/* ams::kern::arch::arm64::InvalidateDataCache(uintptr_t start, uintptr_t end) */ +.section .text._ZN3ams4kern4arch5arm6419InvalidateDataCacheEmm, "ax", %progbits +.global _ZN3ams4kern4arch5arm6419InvalidateDataCacheEmm +.type _ZN3ams4kern4arch5arm6419InvalidateDataCacheEmm, %function +_ZN3ams4kern4arch5arm6419InvalidateDataCacheEmm: + /* Check if we have any work to do. */ + cmp x1, x0 + b.eq 2f + +1: /* Loop, invalidating each cache line. */ + dc ivac, x0 + add x0, x0, #0x40 + cmp x1, x0 + b.ne 1b + +2: /* We're done! */ + mov x0, #1 + ret + +/* ams::kern::arch::arm64::InvalidateInstructionCache(uintptr_t start, uintptr_t end) */ +.section .text._ZN3ams4kern4arch5arm6426InvalidateInstructionCacheEmm, "ax", %progbits +.global _ZN3ams4kern4arch5arm6426InvalidateInstructionCacheEmm +.type _ZN3ams4kern4arch5arm6426InvalidateInstructionCacheEmm, %function +_ZN3ams4kern4arch5arm6426InvalidateInstructionCacheEmm: + /* Check if we have any work to do. */ + cmp x1, x0 + b.eq 2f + +1: /* Loop, invalidating each cache line. */ + ic ivau, x0 + add x0, x0, #0x40 + cmp x1, x0 + b.ne 1b + +2: /* We're done! */ + mov x0, #1 + ret + +/* ================ All Userspace Memory Functions before this line. ================ */ + +/* ams::kern::arch::arm64::UserspaceMemoryAccessFunctionAreaEnd() */ +.section .text._ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv, "ax", %progbits +.global _ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv +.type _ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv, %function +_ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv: +/* NOTE: This is not a real function, and only exists as a label for safety. */ \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp new file mode 100644 index 000000000..d0943016a --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "kern_mc_registers.hpp" + +namespace ams::kern::board::nintendo::nx { + + namespace { + + /* Definitions. */ + constexpr size_t PageDirectorySize = KPageTableManager::PageTableSize; + constexpr size_t PageTableSize = KPageTableManager::PageTableSize; + static_assert(PageDirectorySize == PageSize); + + constexpr size_t AsidCount = 0x80; + constexpr size_t PhysicalAddressBits = 34; + constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul; + constexpr size_t DeviceVirtualAddressBits = 34; + constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul; + + constexpr size_t DevicePageBits = 12; + constexpr size_t DevicePageSize = (1ul << DevicePageBits); + constexpr size_t DeviceLargePageBits = 22; + constexpr size_t DeviceLargePageSize = (1ul << DevicePageBits); + static_assert(DevicePageSize == PageSize); + + constexpr size_t DeviceAsidRegisterOffsets[] = { + [ams::svc::DeviceName_Afi] = MC_SMMU_AFI_ASID, + [ams::svc::DeviceName_Avpc] = MC_SMMU_AVPC_ASID, + [ams::svc::DeviceName_Dc] = MC_SMMU_DC_ASID, + [ams::svc::DeviceName_Dcb] = MC_SMMU_DCB_ASID, + [ams::svc::DeviceName_Hc] = MC_SMMU_HC_ASID, + [ams::svc::DeviceName_Hda] = MC_SMMU_HDA_ASID, + [ams::svc::DeviceName_Isp2] = MC_SMMU_ISP2_ASID, + [ams::svc::DeviceName_MsencNvenc] = MC_SMMU_MSENC_NVENC_ASID, + [ams::svc::DeviceName_Nv] = MC_SMMU_NV_ASID, + [ams::svc::DeviceName_Nv2] = MC_SMMU_NV2_ASID, + [ams::svc::DeviceName_Ppcs] = MC_SMMU_PPCS_ASID, + [ams::svc::DeviceName_Sata] = MC_SMMU_SATA_ASID, + [ams::svc::DeviceName_Vi] = MC_SMMU_VI_ASID, + [ams::svc::DeviceName_Vic] = MC_SMMU_VIC_ASID, + [ams::svc::DeviceName_XusbHost] = MC_SMMU_XUSB_HOST_ASID, + [ams::svc::DeviceName_XusbDev] = MC_SMMU_XUSB_DEV_ASID, + [ams::svc::DeviceName_Tsec] = MC_SMMU_TSEC_ASID, + [ams::svc::DeviceName_Ppcs1] = MC_SMMU_PPCS1_ASID, + [ams::svc::DeviceName_Dc1] = MC_SMMU_DC1_ASID, + [ams::svc::DeviceName_Sdmmc1a] = MC_SMMU_SDMMC1A_ASID, + [ams::svc::DeviceName_Sdmmc2a] = MC_SMMU_SDMMC2A_ASID, + [ams::svc::DeviceName_Sdmmc3a] = MC_SMMU_SDMMC3A_ASID, + [ams::svc::DeviceName_Sdmmc4a] = MC_SMMU_SDMMC4A_ASID, + [ams::svc::DeviceName_Isp2b] = MC_SMMU_ISP2B_ASID, + [ams::svc::DeviceName_Gpu] = MC_SMMU_GPU_ASID, + [ams::svc::DeviceName_Gpub] = MC_SMMU_GPUB_ASID, + [ams::svc::DeviceName_Ppcs2] = MC_SMMU_PPCS2_ASID, + [ams::svc::DeviceName_Nvdec] = MC_SMMU_NVDEC_ASID, + [ams::svc::DeviceName_Ape] = MC_SMMU_APE_ASID, + [ams::svc::DeviceName_Se] = MC_SMMU_SE_ASID, + [ams::svc::DeviceName_Nvjpg] = MC_SMMU_NVJPG_ASID, + [ams::svc::DeviceName_Hc1] = MC_SMMU_HC1_ASID, + [ams::svc::DeviceName_Se1] = MC_SMMU_SE1_ASID, + [ams::svc::DeviceName_Axiap] = MC_SMMU_AXIAP_ASID, + [ams::svc::DeviceName_Etr] = MC_SMMU_ETR_ASID, + [ams::svc::DeviceName_Tsecb] = MC_SMMU_TSECB_ASID, + [ams::svc::DeviceName_Tsec1] = MC_SMMU_TSEC1_ASID, + [ams::svc::DeviceName_Tsecb1] = MC_SMMU_TSECB1_ASID, + [ams::svc::DeviceName_Nvdec1] = MC_SMMU_NVDEC1_ASID, + }; + static_assert(util::size(DeviceAsidRegisterOffsets) == ams::svc::DeviceName_Count); + constexpr bool DeviceAsidRegistersValid = [] { + for (size_t i = 0; i < ams::svc::DeviceName_Count; i++) { + if (DeviceAsidRegisterOffsets[i] == 0 || !util::IsAligned(DeviceAsidRegisterOffsets[i], sizeof(u32))) { + return false; + } + } + return true; + }(); + + static_assert(DeviceAsidRegistersValid); + + constexpr ALWAYS_INLINE int GetDeviceAsidRegisterOffset(ams::svc::DeviceName dev) { + if (dev < ams::svc::DeviceName_Count) { + return DeviceAsidRegisterOffsets[dev]; + } else { + return -1; + } + } + + constexpr ams::svc::DeviceName HsDevices[] = { + ams::svc::DeviceName_Afi, + ams::svc::DeviceName_Dc, + ams::svc::DeviceName_Dcb, + ams::svc::DeviceName_Hda, + ams::svc::DeviceName_Isp2, + ams::svc::DeviceName_Sata, + ams::svc::DeviceName_XusbHost, + ams::svc::DeviceName_XusbDev, + ams::svc::DeviceName_Tsec, + ams::svc::DeviceName_Dc1, + ams::svc::DeviceName_Sdmmc1a, + ams::svc::DeviceName_Sdmmc2a, + ams::svc::DeviceName_Sdmmc3a, + ams::svc::DeviceName_Sdmmc4a, + ams::svc::DeviceName_Isp2b, + ams::svc::DeviceName_Gpu, + ams::svc::DeviceName_Gpub, + ams::svc::DeviceName_Axiap, + ams::svc::DeviceName_Etr, + ams::svc::DeviceName_Tsecb, + ams::svc::DeviceName_Tsec1, + ams::svc::DeviceName_Tsecb1, + }; + constexpr size_t NumHsDevices = util::size(HsDevices); + + constexpr u64 HsDeviceMask = [] { + u64 mask = 0; + for (size_t i = 0; i < NumHsDevices; i++) { + mask |= 1ul << HsDevices[i]; + } + return mask; + }(); + + constexpr ALWAYS_INLINE bool IsHsSupported(ams::svc::DeviceName dv) { + return (HsDeviceMask & (1ul << dv)) != 0; + } + + constexpr ALWAYS_INLINE bool IsValidPhysicalAddress(KPhysicalAddress addr) { + return (static_cast(GetInteger(addr)) & ~PhysicalAddressMask) == 0; + } + + /* Types. */ + class EntryBase { + protected: + enum Bit : u32 { + Bit_Table = 28, + Bit_NonSecure = 29, + Bit_Writeable = 30, + Bit_Readable = 31, + }; + private: + u32 value; + protected: + constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const { + return (this->value & (1u << n)); + } + + constexpr ALWAYS_INLINE bool GetBit(Bit n) const { + return this->SelectBit(n) != 0; + } + + static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) { + return en ? (1u << n) : 0; + } + + static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, KPhysicalAddress addr, bool t) { + return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast(addr >> DevicePageBits); + } + + ALWAYS_INLINE void SetValue(u32 v) { + /* Prevent re-ordering around entry modifications. */ + __asm__ __volatile__("" ::: "memory"); + this->value = v; + __asm__ __volatile__("" ::: "memory"); + } + public: + static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(KPhysicalAddress addr) { + return EncodeValue(true, true, true, addr, false); + } + public: + constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); } + constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); } + constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); } + constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); } + + constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); } + + constexpr ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() { return (static_cast(this->value) << DevicePageBits) & PhysicalAddressMask; } + + ALWAYS_INLINE void Invalidate() { this->SetValue(0); } + }; + + class PageDirectoryEntry : public EntryBase { + public: + constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); } + + ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, KPhysicalAddress addr) { + MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); + MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DevicePageSize)); + this->SetValue(EncodeValue(r, w, ns, addr, true)); + } + + ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, KPhysicalAddress addr) { + MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); + MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DeviceLargePageSize)); + this->SetValue(EncodeValue(r, w, ns, addr, false)); + } + }; + + class PageTableEntry : public EntryBase { + public: + ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, KPhysicalAddress addr) { + MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); + MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DevicePageSize)); + this->SetValue(EncodeValue(r, w, ns, addr, true)); + } + }; + + class KAsidManager { + private: + using WordType = u32; + static constexpr u8 ReservedAsids[] = { 0, 1, 2, 3 }; + static constexpr size_t NumReservedAsids = util::size(ReservedAsids); + static constexpr size_t BitsPerWord = BITSIZEOF(WordType); + static constexpr size_t NumWords = AsidCount / BitsPerWord; + static constexpr WordType FullWord = ~WordType(0u); + private: + WordType state[NumWords]; + KLightLock lock; + private: + constexpr void ReserveImpl(u8 asid) { + this->state[asid / BitsPerWord] |= (1u << (asid % BitsPerWord)); + } + + constexpr void ReleaseImpl(u8 asid) { + this->state[asid / BitsPerWord] &= ~(1u << (asid % BitsPerWord)); + } + + static constexpr ALWAYS_INLINE WordType ClearLeadingZero(WordType value) { + return __builtin_clzll(value) - (BITSIZEOF(unsigned long long) - BITSIZEOF(WordType)); + } + public: + constexpr KAsidManager() : state(), lock() { + for (size_t i = 0; i < NumReservedAsids; i++) { + this->ReserveImpl(ReservedAsids[i]); + } + } + + Result Reserve(u8 *out, size_t num_desired) { + KScopedLightLock lk(this->lock); + MESOSPHERE_ASSERT(num_desired > 0); + + size_t num_reserved = 0; + for (size_t i = 0; i < NumWords; i++) { + while (this->state[i] != FullWord) { + WordType clear_bit = (this->state[i] + 1) ^ (this->state[i]); + this->state[i] |= clear_bit; + out[num_reserved++] = static_cast(BitsPerWord * i + BitsPerWord - 1 - ClearLeadingZero(clear_bit)); + R_UNLESS(num_reserved != num_desired, ResultSuccess()); + } + } + + /* We failed, so free what we reserved. */ + for (size_t i = 0; i < num_reserved; i++) { + this->ReleaseImpl(out[i]); + } + return svc::ResultOutOfResource(); + } + + void Release(u8 asid) { + KScopedLightLock lk(this->lock); + this->ReleaseImpl(asid); + } + }; + + /* Globals. */ + KLightLock g_lock; + u8 g_reserved_asid; + KPhysicalAddress g_memory_controller_address; + KPhysicalAddress g_reserved_table_phys_addr; + KAsidManager g_asid_manager; + + /* Memory controller access functionality. */ + void WriteMcRegister(size_t offset, u32 value) { + KSystemControl::WriteRegisterPrivileged(GetInteger(g_memory_controller_address) + offset, value); + } + + u32 ReadMcRegister(size_t offset) { + return KSystemControl::ReadRegisterPrivileged(GetInteger(g_memory_controller_address) + offset); + } + + void SmmuSynchronizationBarrier() { + ReadMcRegister(MC_SMMU_CONFIG); + } + + void InvalidatePtc() { + WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0); + } + +/* + void InvalidatePtc(KPhysicalAddress address) { + WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast(GetInteger(address)) >> 32)); + WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (GetInteger(address) & 0xFFFFFFF0u) | 1u); + } +*/ + + enum TlbFlushVaMatch : u32 { + TlbFlushVaMatch_All = 0, + TlbFlushVaMatch_Section = 2, + TlbFlushVaMatch_Group = 3, + }; + + static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, KDeviceVirtualAddress address, TlbFlushVaMatch match) { + return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match); + } + + void InvalidateTlb() { + return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All)); + } + + void InvalidateTlb(u8 asid) { + return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All)); + } + +/* + void InvalidateTlbSection(u8 asid, KDeviceVirtualAddress address) { + return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section)); + } +*/ + + void SetTable(u8 asid, KPhysicalAddress address) { + /* Write the table address. */ + { + KScopedLightLock lk(g_lock); + + WriteMcRegister(MC_SMMU_PTB_ASID, asid); + WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address)); + + SmmuSynchronizationBarrier(); + } + + /* Ensure consistency. */ + InvalidatePtc(); + InvalidateTlb(asid); + SmmuSynchronizationBarrier(); + } + + } + + void KDevicePageTable::Initialize() { + /* Set the memory controller register address. */ + g_memory_controller_address = KMemoryLayout::GetMemoryControllerRegion().GetAddress(); + + /* Allocate a page to use as a reserved/no device table. */ + const KVirtualAddress table_virt_addr = Kernel::GetPageTableManager().Allocate(); + MESOSPHERE_ABORT_UNLESS(table_virt_addr != Null); + const KPhysicalAddress table_phys_addr = GetPageTablePhysicalAddress(table_virt_addr); + MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr)); + Kernel::GetPageTableManager().Open(table_virt_addr, 1); + + /* Clear the page and save it. */ + /* NOTE: Nintendo does not check the result of StoreDataCache. */ + cpu::ClearPageToZero(GetVoidPointer(table_virt_addr)); + cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize); + g_reserved_table_phys_addr = table_phys_addr; + + /* Reserve an asid to correspond to no device. */ + MESOSPHERE_R_ABORT_UNLESS(g_asid_manager.Reserve(std::addressof(g_reserved_asid), 1)); + + /* Set all asids to the reserved table. */ + static_assert(AsidCount <= std::numeric_limits::max()); + for (size_t i = 0; i < AsidCount; i++) { + SetTable(static_cast(i), g_reserved_table_phys_addr); + } + + /* Set all devices to the reserved asid. */ + for (size_t i = 0; i < ams::svc::DeviceName_Count; i++) { + u32 value = 0x80000000u; + if (IsHsSupported(static_cast(i))) { + for (size_t t = 0; t < TableCount; t++) { + value |= (g_reserved_asid << (BITSIZEOF(u8) * t)); + } + } else { + value |= g_reserved_asid; + } + + WriteMcRegister(GetDeviceAsidRegisterOffset(static_cast(i)), value); + SmmuSynchronizationBarrier(); + } + + /* Ensure consistency. */ + InvalidatePtc(); + InvalidateTlb(); + SmmuSynchronizationBarrier(); + + /* Clear int status. */ + WriteMcRegister(MC_INTSTATUS, ReadMcRegister(MC_INTSTATUS)); + + /* Enable the SMMU */ + WriteMcRegister(MC_SMMU_CONFIG, 1); + SmmuSynchronizationBarrier(); + + /* TODO: Install interrupt handler. */ + } + +} diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index c0c6cd808..46788d815 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -116,6 +116,14 @@ namespace ams::kern::board::nintendo::nx { return GetConfigU64(which) != 0; } + bool IsRegisterAccessibleToPrivileged(ams::svc::PhysicalAddress address) { + if (!KMemoryLayout::GetMemoryControllerRegion().Contains(address)) { + return false; + } + /* TODO: Validate specific offsets. */ + return true; + } + } /* Initialization. */ @@ -275,6 +283,17 @@ namespace ams::kern::board::nintendo::nx { return KMemoryManager::Pool_Application; } + /* Privileged Access. */ + void KSystemControl::ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { + MESOSPHERE_ABORT_UNLESS(util::IsAligned(address, sizeof(u32))); + MESOSPHERE_ABORT_UNLESS(IsRegisterAccessibleToPrivileged(address)); + MESOSPHERE_ABORT_UNLESS(smc::ReadWriteRegister(out, address, mask, value)); + } + + void KSystemControl::ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { + MESOSPHERE_TODO_IMPLEMENT(); + } + /* Randomness. */ void KSystemControl::GenerateRandomBytes(void *dst, size_t size) { MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_mc_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_mc_registers.hpp new file mode 100644 index 000000000..edd925ee2 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_mc_registers.hpp @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#define MC_INTSTATUS 0x0 +#define MC_INTMASK 0x4 +#define MC_ERR_STATUS 0x8 +#define MC_ERR_ADR 0xc +#define MC_SMMU_CONFIG 0x10 +#define MC_SMMU_TLB_CONFIG 0x14 +#define MC_SMMU_PTC_CONFIG 0x18 +#define MC_SMMU_PTB_ASID 0x1c +#define MC_SMMU_PTB_DATA 0x20 +#define MC_SMMU_TLB_FLUSH 0x30 +#define MC_SMMU_PTC_FLUSH_0 0x34 +#define MC_SMMU_PTC_FLUSH_1 0x9b8 +#define MC_SMMU_ASID_SECURITY 0x38 +#define MC_SMMU_ASID_SECURITY_1 0x3c +#define MC_SMMU_ASID_SECURITY_2 0x9e0 +#define MC_SMMU_ASID_SECURITY_3 0x9e4 +#define MC_SMMU_ASID_SECURITY_4 0x9e8 +#define MC_SMMU_ASID_SECURITY_5 0x9ec +#define MC_SMMU_ASID_SECURITY_6 0x9f0 +#define MC_SMMU_ASID_SECURITY_7 0x9f4 +#define MC_SMMU_AFI_ASID 0x238 +#define MC_SMMU_AVPC_ASID 0x23c +#define MC_SMMU_DC_ASID 0x240 +#define MC_SMMU_DCB_ASID 0x244 +#define MC_SMMU_HC_ASID 0x250 +#define MC_SMMU_HDA_ASID 0x254 +#define MC_SMMU_ISP2_ASID 0x258 +#define MC_SMMU_MSENC_NVENC_ASID 0x264 +#define MC_SMMU_NV_ASID 0x268 +#define MC_SMMU_NV2_ASID 0x26c +#define MC_SMMU_PPCS_ASID 0x270 +#define MC_SMMU_SATA_ASID 0x274 +#define MC_SMMU_VDE_ASID 0x27c +#define MC_SMMU_VI_ASID 0x280 +#define MC_SMMU_VIC_ASID 0x284 +#define MC_SMMU_XUSB_HOST_ASID 0x288 +#define MC_SMMU_XUSB_DEV_ASID 0x28c +#define MC_SMMU_TSEC_ASID 0x294 +#define MC_SMMU_PPCS1_ASID 0x298 +#define MC_SMMU_DC1_ASID 0xa88 +#define MC_SMMU_SDMMC1A_ASID 0xa94 +#define MC_SMMU_SDMMC2A_ASID 0xa98 +#define MC_SMMU_SDMMC3A_ASID 0xa9c +#define MC_SMMU_SDMMC4A_ASID 0xaa0 +#define MC_SMMU_ISP2B_ASID 0xaa4 +#define MC_SMMU_GPU_ASID 0xaa8 +#define MC_SMMU_GPUB_ASID 0xaac +#define MC_SMMU_PPCS2_ASID 0xab0 +#define MC_SMMU_NVDEC_ASID 0xab4 +#define MC_SMMU_APE_ASID 0xab8 +#define MC_SMMU_SE_ASID 0xabc +#define MC_SMMU_NVJPG_ASID 0xac0 +#define MC_SMMU_HC1_ASID 0xac4 +#define MC_SMMU_SE1_ASID 0xac8 +#define MC_SMMU_AXIAP_ASID 0xacc +#define MC_SMMU_ETR_ASID 0xad0 +#define MC_SMMU_TSECB_ASID 0xad4 +#define MC_SMMU_TSEC1_ASID 0xad8 +#define MC_SMMU_TSECB1_ASID 0xadc +#define MC_SMMU_NVDEC1_ASID 0xae0 +#define MC_SMMU_TRANSLATION_ENABLE_0 0x228 +#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c +#define MC_SMMU_TRANSLATION_ENABLE_2 0x230 +#define MC_SMMU_TRANSLATION_ENABLE_3 0x234 +#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98 +#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0 +#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4 +#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8 +#define MC_PCFIFO_CLIENT_CONFIG3 0xddc +#define MC_PCFIFO_CLIENT_CONFIG4 0xde0 +#define MC_EMEM_CFG 0x50 +#define MC_EMEM_ADR_CFG 0x54 +#define MC_EMEM_ADR_CFG_DEV0 0x58 +#define MC_EMEM_ADR_CFG_DEV1 0x5c +#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60 +#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64 +#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68 +#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c +#define MC_SECURITY_CFG0 0x70 +#define MC_SECURITY_CFG1 0x74 +#define MC_SECURITY_CFG3 0x9bc +#define MC_SECURITY_RSV 0x7c +#define MC_EMEM_ARB_CFG 0x90 +#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 +#define MC_EMEM_ARB_TIMING_RCD 0x98 +#define MC_EMEM_ARB_TIMING_RP 0x9c +#define MC_EMEM_ARB_TIMING_RC 0xa0 +#define MC_EMEM_ARB_TIMING_RAS 0xa4 +#define MC_EMEM_ARB_TIMING_FAW 0xa8 +#define MC_EMEM_ARB_TIMING_RRD 0xac +#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 +#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 +#define MC_EMEM_ARB_TIMING_R2R 0xb8 +#define MC_EMEM_ARB_TIMING_W2W 0xbc +#define MC_EMEM_ARB_TIMING_R2W 0xc0 +#define MC_EMEM_ARB_TIMING_W2R 0xc4 +#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0 +#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4 +#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0 +#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4 +#define MC_EMEM_ARB_DA_TURNS 0xd0 +#define MC_EMEM_ARB_DA_COVERS 0xd4 +#define MC_EMEM_ARB_MISC0 0xd8 +#define MC_EMEM_ARB_MISC1 0xdc +#define MC_EMEM_ARB_MISC2 0xc8 +#define MC_EMEM_ARB_RING1_THROTTLE 0xe0 +#define MC_EMEM_ARB_RING3_THROTTLE 0xe4 +#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0 +#define MC_EMEM_ARB_OVERRIDE 0xe8 +#define MC_EMEM_ARB_RSV 0xec +#define MC_CLKEN_OVERRIDE 0xf4 +#define MC_TIMING_CONTROL_DBG 0xf8 +#define MC_TIMING_CONTROL 0xfc +#define MC_STAT_CONTROL 0x100 +#define MC_STAT_STATUS 0x104 +#define MC_STAT_EMC_CLOCK_LIMIT 0x108 +#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c +#define MC_STAT_EMC_CLOCKS 0x110 +#define MC_STAT_EMC_CLOCKS_MSBS 0x114 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158 +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c +#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20 +#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8 +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac +#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28 +#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c +#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0 +#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0 +#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120 +#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c +#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c +#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134 +#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174 +#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c +#define MC_STAT_EMC_SET0_COUNT 0x138 +#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c +#define MC_STAT_EMC_SET1_COUNT 0x178 +#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c +#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140 +#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144 +#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180 +#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184 +#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148 +#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c +#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188 +#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c +#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150 +#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190 +#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8 +#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc +#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8 +#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc +#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0 +#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0 +#define MC_CLIENT_HOTRESET_CTRL 0x200 +#define MC_CLIENT_HOTRESET_CTRL_1 0x970 +#define MC_CLIENT_HOTRESET_STATUS 0x204 +#define MC_CLIENT_HOTRESET_STATUS_1 0x974 +#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208 +#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c +#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210 +#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214 +#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94 +#define MC_EMEM_ARB_HYSTERESIS_0 0x218 +#define MC_EMEM_ARB_HYSTERESIS_1 0x21c +#define MC_EMEM_ARB_HYSTERESIS_2 0x220 +#define MC_EMEM_ARB_HYSTERESIS_3 0x224 +#define MC_EMEM_ARB_HYSTERESIS_4 0xb84 +#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0 +#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4 +#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8 +#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc +#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0 +#define MC_EMEM_ARB_DHYST_CTRL 0xbcc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8 +#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec +#define MC_RESERVED_RSV 0x3fc +#define MC_DISB_EXTRA_SNAP_LEVELS 0x408 +#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4 +#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0 +#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18 +#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08 +#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10 +#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c +#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40 +#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414 +#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc +#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c +#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14 +#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0 +#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac +#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c +#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48 +#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8 +#define MC_USBX_EXTRA_SNAP_LEVELS 0x404 +#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8 +#define MC_SD_EXTRA_SNAP_LEVELS 0xa04 +#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c +#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8 +#define MC_GK_EXTRA_SNAP_LEVELS 0xa00 +#define MC_VE2_EXTRA_SNAP_LEVELS 0x410 +#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44 +#define MC_VIDEO_PROTECT_BOM 0x648 +#define MC_VIDEO_PROTECT_SIZE_MB 0x64c +#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978 +#define MC_VIDEO_PROTECT_REG_CTRL 0x650 +#define MC_ERR_VPR_STATUS 0x654 +#define MC_ERR_VPR_ADR 0x658 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418 +#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590 +#define MC_IRAM_BOM 0x65c +#define MC_IRAM_TOM 0x660 +#define MC_IRAM_ADR_HI 0x980 +#define MC_IRAM_REG_CTRL 0x964 +#define MC_EMEM_CFG_ACCESS_CTRL 0x664 +#define MC_TZ_SECURITY_CTRL 0x668 +#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c +#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4 +#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc +#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8 +#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80 +#define MC_SEC_CARVEOUT_BOM 0x670 +#define MC_SEC_CARVEOUT_SIZE_MB 0x674 +#define MC_SEC_CARVEOUT_ADR_HI 0x9d4 +#define MC_SEC_CARVEOUT_REG_CTRL 0x678 +#define MC_ERR_SEC_STATUS 0x67c +#define MC_ERR_SEC_ADR 0x680 +#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684 +#define MC_STUTTER_CONTROL 0x688 +#define MC_RESERVED_RSV_1 0x958 +#define MC_DVFS_PIPE_SELECT 0x95c +#define MC_AHB_PTSA_MIN 0x4e0 +#define MC_AUD_PTSA_MIN 0x54c +#define MC_MLL_MPCORER_PTSA_RATE 0x44c +#define MC_RING2_PTSA_RATE 0x440 +#define MC_USBD_PTSA_RATE 0x530 +#define MC_USBX_PTSA_MIN 0x528 +#define MC_USBD_PTSA_MIN 0x534 +#define MC_APB_PTSA_MAX 0x4f0 +#define MC_JPG_PTSA_RATE 0x584 +#define MC_DIS_PTSA_MIN 0x420 +#define MC_AVP_PTSA_MAX 0x4fc +#define MC_AVP_PTSA_RATE 0x4f4 +#define MC_RING1_PTSA_MIN 0x480 +#define MC_DIS_PTSA_MAX 0x424 +#define MC_SD_PTSA_MAX 0x4d8 +#define MC_MSE_PTSA_RATE 0x4c4 +#define MC_VICPC_PTSA_MIN 0x558 +#define MC_PCX_PTSA_MAX 0x4b4 +#define MC_ISP_PTSA_RATE 0x4a0 +#define MC_A9AVPPC_PTSA_MIN 0x48c +#define MC_RING2_PTSA_MAX 0x448 +#define MC_AUD_PTSA_RATE 0x548 +#define MC_HOST_PTSA_MIN 0x51c +#define MC_MLL_MPCORER_PTSA_MAX 0x454 +#define MC_SD_PTSA_MIN 0x4d4 +#define MC_RING1_PTSA_RATE 0x47c +#define MC_JPG_PTSA_MIN 0x588 +#define MC_HDAPC_PTSA_MIN 0x62c +#define MC_AVP_PTSA_MIN 0x4f8 +#define MC_JPG_PTSA_MAX 0x58c +#define MC_VE_PTSA_MAX 0x43c +#define MC_DFD_PTSA_MAX 0x63c +#define MC_VICPC_PTSA_RATE 0x554 +#define MC_GK_PTSA_MAX 0x544 +#define MC_VICPC_PTSA_MAX 0x55c +#define MC_SDM_PTSA_MAX 0x624 +#define MC_SAX_PTSA_RATE 0x4b8 +#define MC_PCX_PTSA_MIN 0x4b0 +#define MC_APB_PTSA_MIN 0x4ec +#define MC_GK2_PTSA_MIN 0x614 +#define MC_PCX_PTSA_RATE 0x4ac +#define MC_RING1_PTSA_MAX 0x484 +#define MC_HDAPC_PTSA_RATE 0x628 +#define MC_MLL_MPCORER_PTSA_MIN 0x450 +#define MC_GK2_PTSA_MAX 0x618 +#define MC_AUD_PTSA_MAX 0x550 +#define MC_GK2_PTSA_RATE 0x610 +#define MC_ISP_PTSA_MAX 0x4a8 +#define MC_DISB_PTSA_RATE 0x428 +#define MC_VE2_PTSA_MAX 0x49c +#define MC_DFD_PTSA_MIN 0x638 +#define MC_FTOP_PTSA_RATE 0x50c +#define MC_A9AVPPC_PTSA_RATE 0x488 +#define MC_VE2_PTSA_MIN 0x498 +#define MC_USBX_PTSA_MAX 0x52c +#define MC_DIS_PTSA_RATE 0x41c +#define MC_USBD_PTSA_MAX 0x538 +#define MC_A9AVPPC_PTSA_MAX 0x490 +#define MC_USBX_PTSA_RATE 0x524 +#define MC_FTOP_PTSA_MAX 0x514 +#define MC_HDAPC_PTSA_MAX 0x630 +#define MC_SD_PTSA_RATE 0x4d0 +#define MC_DFD_PTSA_RATE 0x634 +#define MC_FTOP_PTSA_MIN 0x510 +#define MC_SDM_PTSA_RATE 0x61c +#define MC_AHB_PTSA_RATE 0x4dc +#define MC_SMMU_SMMU_PTSA_MAX 0x460 +#define MC_RING2_PTSA_MIN 0x444 +#define MC_SDM_PTSA_MIN 0x620 +#define MC_APB_PTSA_RATE 0x4e8 +#define MC_MSE_PTSA_MIN 0x4c8 +#define MC_HOST_PTSA_RATE 0x518 +#define MC_VE_PTSA_RATE 0x434 +#define MC_AHB_PTSA_MAX 0x4e4 +#define MC_SAX_PTSA_MIN 0x4bc +#define MC_SMMU_SMMU_PTSA_MIN 0x45c +#define MC_ISP_PTSA_MIN 0x4a4 +#define MC_HOST_PTSA_MAX 0x520 +#define MC_SAX_PTSA_MAX 0x4c0 +#define MC_VE_PTSA_MIN 0x438 +#define MC_GK_PTSA_MIN 0x540 +#define MC_MSE_PTSA_MAX 0x4cc +#define MC_DISB_PTSA_MAX 0x430 +#define MC_DISB_PTSA_MIN 0x42c +#define MC_SMMU_SMMU_PTSA_RATE 0x458 +#define MC_VE2_PTSA_RATE 0x494 +#define MC_GK_PTSA_RATE 0x53c +#define MC_PTSA_GRANT_DECREMENT 0x960 +#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4 +#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0 +#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380 +#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384 +#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc +#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8 +#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370 +#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0 +#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374 +#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8 +#define MC_LATENCY_ALLOWANCE_VIC_0 0x394 +#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8 +#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8 +#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc +#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390 +#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694 +#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348 +#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c +#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344 +#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0 +#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698 +#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec +#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0 +#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4 +#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8 +#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4 +#define MC_LATENCY_ALLOWANCE_HC_1 0x314 +#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0 +#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4 +#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c +#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec +#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320 +#define MC_LATENCY_ALLOWANCE_VI2_0 0x398 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4 +#define MC_LATENCY_ALLOWANCE_SATA_0 0x350 +#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690 +#define MC_LATENCY_ALLOWANCE_HC_0 0x310 +#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8 +#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac +#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4 +#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388 +#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328 +#define MC_LATENCY_ALLOWANCE_HDA_0 0x318 +#define MC_MIN_LENGTH_APE_0 0xb34 +#define MC_MIN_LENGTH_DCB_2 0x8a8 +#define MC_MIN_LENGTH_A9AVP_0 0x950 +#define MC_MIN_LENGTH_TSEC_0 0x93c +#define MC_MIN_LENGTH_DC_1 0x898 +#define MC_MIN_LENGTH_AXIAP_0 0x94c +#define MC_MIN_LENGTH_ISP2B_0 0x930 +#define MC_MIN_LENGTH_VI2_0 0x944 +#define MC_MIN_LENGTH_DCB_0 0x8a0 +#define MC_MIN_LENGTH_DCB_1 0x8a4 +#define MC_MIN_LENGTH_PPCS_1 0x8f4 +#define MC_MIN_LENGTH_NVJPG_0 0xb3c +#define MC_MIN_LENGTH_HDA_0 0x8c4 +#define MC_MIN_LENGTH_NVENC_0 0x8d4 +#define MC_MIN_LENGTH_SDMMC_0 0xb18 +#define MC_MIN_LENGTH_ISP2B_1 0x934 +#define MC_MIN_LENGTH_HC_1 0x8c0 +#define MC_MIN_LENGTH_DC_3 0xb20 +#define MC_MIN_LENGTH_AVPC_0 0x890 +#define MC_MIN_LENGTH_VIC_0 0x940 +#define MC_MIN_LENGTH_ISP2_0 0x91c +#define MC_MIN_LENGTH_HC_0 0x8bc +#define MC_MIN_LENGTH_SE_0 0xb38 +#define MC_MIN_LENGTH_NVDEC_0 0xb30 +#define MC_MIN_LENGTH_SATA_0 0x8fc +#define MC_MIN_LENGTH_DC_0 0x894 +#define MC_MIN_LENGTH_XUSB_1 0x92c +#define MC_MIN_LENGTH_DC_2 0x89c +#define MC_MIN_LENGTH_SDMMCAA_0 0xb14 +#define MC_MIN_LENGTH_GPU_0 0xb04 +#define MC_MIN_LENGTH_ETR_0 0xb44 +#define MC_MIN_LENGTH_AFI_0 0x88c +#define MC_MIN_LENGTH_PPCS_0 0x8f0 +#define MC_MIN_LENGTH_ISP2_1 0x920 +#define MC_MIN_LENGTH_XUSB_0 0x928 +#define MC_MIN_LENGTH_MPCORE_0 0x8cc +#define MC_MIN_LENGTH_TSECB_0 0xb48 +#define MC_MIN_LENGTH_SDMMCA_0 0xb10 +#define MC_MIN_LENGTH_GPU2_0 0xb40 +#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c +#define MC_MIN_LENGTH_PTC_0 0x8f8 +#define MC_EMEM_ARB_OVERRIDE_1 0x968 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984 +#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988 +#define MC_EMEM_ARB_STATS_0 0x990 +#define MC_EMEM_ARB_STATS_1 0x994 +#define MC_MTS_CARVEOUT_BOM 0x9a0 +#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4 +#define MC_MTS_CARVEOUT_ADR_HI 0x9a8 +#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac +#define MC_ERR_MTS_STATUS 0x9b0 +#define MC_ERR_MTS_ADR 0x9b4 +#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00 +#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74 +#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10 +#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c +#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4 +#define MC_SECURITY_CARVEOUT2_CFG0 0xc58 +#define MC_SECURITY_CARVEOUT1_CFG0 0xc08 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68 +#define MC_SECURITY_CARVEOUT3_BOM 0xcac +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60 +#define MC_SECURITY_CARVEOUT3_CFG0 0xca8 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8 +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88 +#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64 +#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50 +#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14 +#define MC_SECURITY_CARVEOUT1_BOM 0xc0c +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24 +#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4 +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c +#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8 +#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60 +#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00 +#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc +#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80 +#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54 +#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4 +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74 +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc +#define MC_SECURITY_CARVEOUT4_BOM 0xcfc +#define MC_SECURITY_CARVEOUT5_CFG0 0xd48 +#define MC_SECURITY_CARVEOUT2_BOM 0xc5c +#define MC_SECURITY_CARVEOUT5_BOM 0xd4c +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24 +#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c +#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0 +#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10 +#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20 +#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c +#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c +#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08 +#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0 +#define MC_DA_CONFIG0 0x9dc diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp index d3797d7ea..49f2ac286 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp @@ -152,6 +152,13 @@ namespace ams::kern::board::nintendo::nx::smc { } } + bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { + SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value }; + CallPrivilegedSecureMonitorFunction(args); + *out = static_cast(args.x[1]); + return static_cast(args.x[0]) == SmcResult::Success; + } + void ConfigureCarveout(size_t which, uintptr_t address, size_t size) { SecureMonitorArguments args = { FunctionId_ConfigureCarveout, static_cast(which), static_cast(address), static_cast(size) }; CallPrivilegedSecureMonitorFunction(args); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp index dcf1c4dca..fa78b0ee2 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -86,7 +86,9 @@ namespace ams::kern::board::nintendo::nx::smc { /* TODO: Rest of Secure Monitor API. */ void GenerateRandomBytes(void *dst, size_t size); void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); + bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); void ConfigureCarveout(size_t which, uintptr_t address, size_t size); + void NORETURN Panic(u32 color); namespace init { diff --git a/libraries/libmesosphere/source/kern_k_device_address_space.cpp b/libraries/libmesosphere/source/kern_k_device_address_space.cpp new file mode 100644 index 000000000..ffe27b765 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_device_address_space.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::kern { + + void KDeviceAddressSpace::Initialize() { + /* This just forwards to the device page table manager. */ + KDevicePageTable::Initialize(); + } + +} diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 83bf3a36b..e9f3f5ef9 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -255,6 +255,56 @@ namespace ams::kern { MESOSPHERE_TODO_IMPLEMENT(); } + void KThread::DisableCoreMigration() { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); + + KScopedSchedulerLock sl; + MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0); + if ((this->num_core_migration_disables++) == 0) { + /* Save our ideal state to restore when we can migrate again. */ + this->original_ideal_core_id = this->ideal_core_id; + this->original_affinity_mask = this->affinity_mask; + + /* Bind outselves to this core. */ + const s32 active_core = this->GetActiveCore(); + this->ideal_core_id = active_core; + this->affinity_mask.SetAffinityMask(1ul << active_core); + + if (this->affinity_mask.GetAffinityMask() != this->original_affinity_mask.GetAffinityMask()) { + KScheduler::OnThreadAffinityMaskChanged(this, this->original_affinity_mask, active_core); + } + } + } + + void KThread::EnableCoreMigration() { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); + + KScopedSchedulerLock sl; + MESOSPHERE_ASSERT(this->num_core_migration_disables > 0); + if ((--this->num_core_migration_disables) == 0) { + const KAffinityMask old_mask = this->affinity_mask; + + /* Restore our ideals. */ + this->ideal_core_id = this->original_ideal_core_id; + this->original_affinity_mask = this->affinity_mask; + + if (this->affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { + const s32 active_core = this->GetActiveCore(); + + if (!this->affinity_mask.GetAffinity(active_core)) { + if (this->ideal_core_id >= 0) { + this->SetActiveCore(this->ideal_core_id); + } else { + this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->affinity_mask.GetAffinityMask())); + } + } + KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); + } + } + } + Result KThread::SetPriorityToIdle() { MESOSPHERE_ASSERT_THIS(); diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp index 9d06110a5..3209e3129 100644 --- a/libraries/libmesosphere/source/kern_main.cpp +++ b/libraries/libmesosphere/source/kern_main.cpp @@ -113,7 +113,8 @@ namespace ams::kern { /* Setup so that we may sleep later, and reserve memory for secure applets. */ KSystemControl::InitializePhase2(); - MESOSPHERE_TODO("KDeviceAddressSpace::Initialize();"); + /* Initialize the SMMU. */ + KDeviceAddressSpace::Initialize(); MESOSPHERE_TODO("CreateAndRunInitialProcesses();"); diff --git a/mesosphere/kernel/source/arch/arm64/kern_userspace_memory_access_asm.s b/mesosphere/kernel/source/arch/arm64/kern_userspace_memory_access_asm.s deleted file mode 100644 index a2ad76d5d..000000000 --- a/mesosphere/kernel/source/arch/arm64/kern_userspace_memory_access_asm.s +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* ams::kern::arch::arm64::UserspaceMemoryAccessFunctionAreaBegin() */ -.section .text._ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv, "ax", %progbits -.global _ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv -.type _ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv, %function -_ZN3ams4kern4arch5arm6438UserspaceMemoryAccessFunctionAreaBeginEv: -/* NOTE: This is not a real function, and only exists as a label for safety. */ - -/* ================ All Userspace Memory Functions after this line. ================ */ - -/* TODO */ - -/* ================ All Userspace Memory Functions before this line. ================ */ - -/* ams::kern::arch::arm64::UserspaceMemoryAccessFunctionAreaEnd() */ -.section .text._ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv, "ax", %progbits -.global _ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv -.type _ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv, %function -_ZN3ams4kern4arch5arm6436UserspaceMemoryAccessFunctionAreaEndEv: -/* NOTE: This is not a real function, and only exists as a label for safety. */ \ No newline at end of file