From a2c89a8f3f80758b5ac21a51a18cbf95fafcd262 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 16 Nov 2020 14:32:26 -0800 Subject: [PATCH] mariko fatal: map 0xC0000000 for framebuffer usage --- .../source/fatal_device_page_table.cpp | 81 ++++++++++++++----- .../source/fatal_device_page_table.hpp | 1 + exosphere/program/source/secmon_map.cpp | 18 +++++ exosphere/program/source/secmon_map.hpp | 2 + .../source/secmon_user_power_management.cpp | 4 + .../exosphere/secmon/secmon_memory_layout.hpp | 20 +++-- 6 files changed, 102 insertions(+), 24 deletions(-) diff --git a/exosphere/mariko_fatal/source/fatal_device_page_table.cpp b/exosphere/mariko_fatal/source/fatal_device_page_table.cpp index 84d713210..e99318917 100644 --- a/exosphere/mariko_fatal/source/fatal_device_page_table.cpp +++ b/exosphere/mariko_fatal/source/fatal_device_page_table.cpp @@ -48,16 +48,21 @@ namespace ams::secmon::fatal { constexpr size_t TableCount = (1ul << DeviceVirtualAddressBits) / DeviceRegionSize; - constexpr u8 SdmmcAsid = 1; - - constexpr u32 SdmmcAsidRegisterValue = [] { + consteval u32 EncodeAsidRegisterValue(u8 asid) { u32 value = 0x80000000u; for (size_t t = 0; t < TableCount; t++) { - value |= (SdmmcAsid << (BITSIZEOF(u8) * t)); + value |= (asid << (BITSIZEOF(u8) * t)); } return value; - }(); + } + constexpr u8 SdmmcAsid = 1; + constexpr u8 DcAsid = 2; + + constexpr u32 SdmmcAsidRegisterValue = EncodeAsidRegisterValue(SdmmcAsid); + constexpr u32 DcAsidRegisterValue = EncodeAsidRegisterValue(DcAsid); + + constexpr dd::PhysicalAddress DcL0PageTablePhysical = MemoryRegionPhysicalDramDcL0DevicePageTable.GetAddress(); constexpr dd::PhysicalAddress SdmmcL0PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L0DevicePageTable.GetAddress(); constexpr dd::PhysicalAddress SdmmcL1PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L1DevicePageTable.GetAddress(); @@ -195,7 +200,11 @@ namespace ams::secmon::fatal { SmmuSynchronizationBarrier(); } - void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address) { + void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address, u8 asid, void *l0_table, dd::PhysicalAddress l0_phys, void *l1_table, dd::PhysicalAddress l1_phys) { + /* Validate L0. */ + AMS_ABORT_UNLESS(l0_table != nullptr); + AMS_ABORT_UNLESS(l0_phys != 0); + /* Cache permissions. */ const bool read = true; const bool write = true; @@ -207,7 +216,7 @@ namespace ams::secmon::fatal { const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize; /* Get and validate l1. */ - PageDirectoryEntry *l1 = static_cast(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer()); + PageDirectoryEntry *l1 = static_cast(l0_table); AMS_ASSERT(l1 != nullptr); /* Setup an l1 table/entry, if needed. */ @@ -222,8 +231,8 @@ namespace ams::secmon::fatal { hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)); /* Synchronize. */ - InvalidatePtc(SdmmcL1PageTablePhysical); - InvalidateTlbSection(SdmmcAsid, address); + InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry)); + InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); /* Advance. */ @@ -233,26 +242,32 @@ namespace ams::secmon::fatal { continue; } else { /* Make an l1 table. */ - std::memset(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer(), 0, mmu::PageSize); - hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer(), mmu::PageSize); + AMS_ABORT_UNLESS(l1_table != nullptr); + AMS_ABORT_UNLESS(l1_phys != 0); + + /* Clear the l1 table. */ + std::memset(l1_table, 0, mmu::PageSize); + hw::FlushDataCache(l1_table, mmu::PageSize); /* Set the l1 table. */ - l1[l1_index].SetTable(true, true, true, SdmmcL1PageTablePhysical); + l1[l1_index].SetTable(true, true, true, l1_phys); hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)); /* Synchronize. */ - InvalidatePtc(SdmmcL1PageTablePhysical); - InvalidateTlbSection(SdmmcAsid, address); + InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry)); + InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); } } /* If we get to this point, l1 must be a table. */ AMS_ASSERT(l1[l1_index].IsTable()); + AMS_ABORT_UNLESS(l1_table != nullptr); + AMS_ABORT_UNLESS(l1_phys != 0); /* Map l2 entries. */ { - PageTableEntry *l2 = static_cast(MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer()); + PageTableEntry *l2 = static_cast(l1_table); const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min(remaining_in_entry, remaining / DevicePageSize); @@ -266,11 +281,11 @@ namespace ams::secmon::fatal { /* Invalidate the page table cache. */ for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) { - InvalidatePtc(SdmmcL1PageTablePhysical + i * sizeof(PageTableEntry)); + InvalidatePtc(l1_phys + i * sizeof(PageTableEntry)); } /* Synchronize. */ - InvalidateTlbSection(SdmmcAsid, address); + InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); /* Advance. */ @@ -301,7 +316,37 @@ namespace ams::secmon::fatal { SetTable(SdmmcAsid, SdmmcL0PageTablePhysical); /* Map the appropriate region into the asid. */ - MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress()); + MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress(), + SdmmcAsid, + MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer(), SdmmcL0PageTablePhysical, + MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer(), SdmmcL1PageTablePhysical); + } + + void InitializeDevicePageTableForDc() { + /* Configure dc to use our new page table. */ + WriteMcRegister(MC_SMMU_DC_ASID, DcAsidRegisterValue); + SmmuSynchronizationBarrier(); + + /* Ensure consistency. */ + InvalidatePtc(); + InvalidateTlb(); + SmmuSynchronizationBarrier(); + + /* Clear the L0 Page Table. */ + std::memset(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer(), 0, mmu::PageSize); + hw::FlushDataCache(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer(), mmu::PageSize); + + /* Set the page table for the dc asid. */ + SetTable(DcAsid, DcL0PageTablePhysical); + + /* Map the appropriate region into the asid. */ + static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetAddress(), DeviceLargePageSize)); + static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetSize(), DeviceLargePageSize)); + + MapImpl(MemoryRegionDramDcFramebuffer.GetAddress(), MemoryRegionDramDcFramebuffer.GetSize(), MemoryRegionDramDcFramebuffer.GetAddress(), + DcAsid, + MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer(), DcL0PageTablePhysical, + nullptr, 0); } } diff --git a/exosphere/mariko_fatal/source/fatal_device_page_table.hpp b/exosphere/mariko_fatal/source/fatal_device_page_table.hpp index de5c70db2..f200d38ca 100644 --- a/exosphere/mariko_fatal/source/fatal_device_page_table.hpp +++ b/exosphere/mariko_fatal/source/fatal_device_page_table.hpp @@ -19,5 +19,6 @@ namespace ams::secmon::fatal { void InitializeDevicePageTableForSdmmc1(); + void InitializeDevicePageTableForDc(); } diff --git a/exosphere/program/source/secmon_map.cpp b/exosphere/program/source/secmon_map.cpp index 984b6782c..92c60c398 100644 --- a/exosphere/program/source/secmon_map.cpp +++ b/exosphere/program/source/secmon_map.cpp @@ -86,6 +86,12 @@ namespace ams::secmon { InvalidateL3Entries(l3, MemoryRegionVirtualAtmosphereUserPage.GetAddress(), MemoryRegionVirtualAtmosphereUserPage.GetSize()); } + constexpr void MapDramForMarikoProgramImpl(u64 *l1, u64 *l2, u64 *l3) { + /* Map the L1 entry corresponding to the mariko program dram entry. */ + AMS_UNUSED(l2, l3); + SetL1BlockEntry(l1, MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetSize(), MappingAttributesEl3NonSecureRwData); + } + void ClearLow(uintptr_t address, size_t size) { /* Clear the low part. */ util::ClearMemory(reinterpret_cast(address), size / 2); @@ -301,4 +307,16 @@ namespace ams::secmon { ReleaseSpinLock(g_ams_user_page_spin_lock); } + void MapDramForMarikoProgram() { + /* Get the tables. */ + u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer(); + u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer(); + + /* Map. */ + MapDramForMarikoProgramImpl(l1, l2_l3, l2_l3); + + /* Ensure the mappings are consistent. */ + secmon::EnsureMappingConsistency(); + } + } diff --git a/exosphere/program/source/secmon_map.hpp b/exosphere/program/source/secmon_map.hpp index 7cc0cbc56..a9f6f6d30 100644 --- a/exosphere/program/source/secmon_map.hpp +++ b/exosphere/program/source/secmon_map.hpp @@ -32,4 +32,6 @@ namespace ams::secmon { uintptr_t MapAtmosphereUserPage(uintptr_t address); void UnmapAtmosphereUserPage(); + void MapDramForMarikoProgram(); + } \ No newline at end of file diff --git a/exosphere/program/source/secmon_user_power_management.cpp b/exosphere/program/source/secmon_user_power_management.cpp index 63ad881d8..d4b9c1d51 100644 --- a/exosphere/program/source/secmon_user_power_management.cpp +++ b/exosphere/program/source/secmon_user_power_management.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include +#include "secmon_map.hpp" #include "secmon_page_mapper.hpp" #include "secmon_user_power_management.hpp" @@ -93,6 +94,9 @@ namespace ams::secmon { /* TODO: On cores other than 3, halt/wfi. */ + /* Map Dram for the mariko program. */ + MapDramForMarikoProgram(); + AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal."); AMS_LOG_FLUSH(); diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp index fb9f35751..3dbed0c32 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -75,6 +75,11 @@ namespace ams::secmon { constexpr inline const MemoryRegion MemoryRegionDram = MemoryRegion(UINT64_C( 0x80000000), 2_GB); constexpr inline const MemoryRegion MemoryRegionDramHigh = MemoryRegion(MemoryRegionDram.GetEndAddress(), 2_GB); + constexpr inline const MemoryRegion MemoryRegionDramForMarikoProgram = MemoryRegion(UINT64_C(0xC0000000), 1_GB); + constexpr inline const MemoryRegion MemoryRegionDramDcFramebuffer = MemoryRegion(UINT64_C(0xC0000000), 4_MB); + static_assert(MemoryRegionDram.Contains(MemoryRegionDramForMarikoProgram)); + static_assert(MemoryRegionDramForMarikoProgram.Contains(MemoryRegionDramDcFramebuffer)); + constexpr inline const MemoryRegion MemoryRegionDramGpuCarveout = MemoryRegion(UINT64_C(0x80020000), UINT64_C(0x40000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramGpuCarveout)); @@ -259,14 +264,17 @@ namespace ams::secmon { static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore)); static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore)); - constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L0DevicePageTable = MemoryRegion(UINT64_C(0x1F010F000), 0x1000); - constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L0DevicePageTable = MemoryRegion( UINT64_C(0x8001F000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmcMappedData = MemoryRegion(UINT64_C(0x1F0100000), 0xC000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmcMappedData = MemoryRegion(UINT64_C(0x80010000), 0xC000); - constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L1DevicePageTable = MemoryRegion(UINT64_C(0x1F010E000), 0x1000); - constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L1DevicePageTable = MemoryRegion( UINT64_C(0x8001E000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionVirtualDramDcL0DevicePageTable = MemoryRegion(UINT64_C(0x1F010C000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramDcL0DevicePageTable = MemoryRegion( UINT64_C(0x8001C000), 0x1000); - constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmcMappedData = MemoryRegion(UINT64_C(0x1F0100000), 0xE000); - constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmcMappedData = MemoryRegion(UINT64_C(0x80010000), 0xE000); + constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L0DevicePageTable = MemoryRegion(UINT64_C(0x1F010E000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L0DevicePageTable = MemoryRegion( UINT64_C(0x8001E000), 0x1000); + + constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L1DevicePageTable = MemoryRegion(UINT64_C(0x1F010F000), 0x1000); + constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L1DevicePageTable = MemoryRegion( UINT64_C(0x8001F000), 0x1000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x1F0100000), 0xE000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x1F010E000), 0x17C0);