bpmpfw: disable SMMU for FW

This commit is contained in:
souldbminersmwc committed 2026-08-27 18:48:52 -04:00
1 parent cbaa61385c
commit 6980a12324
2 files changed
+72 -4

No files matched your search

@@ -174,12 +174,12 @@ namespace ams::secmon::smc {
/* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */
/* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */
constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress();
SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
// SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
/* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
if (GetTargetFirmware() < TargetFirmware_2_0_0) {
// /* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
// if (GetTargetFirmware() < TargetFirmware_2_0_0) {
virtual_address = MemoryRegionVirtualDeviceMemoryController.GetAddress() + (address - MC);
}
// }
}
/* Perform the read or write, if we should. */
@@ -53,6 +53,32 @@ namespace bpmp {
constexpr u32 ActmonGlbPeriodCtrlUsec = (1u << 8);
constexpr u32 ActmonCopCtrlStockArmed = (1u << 31) | (1u << 30) | (1u << 18);
/* MC SMMU handling for the BPMP. */
constexpr u64 McPhysBase = 0x70019000;
constexpr u32 McSmmuTlbConfig = 0x014;
constexpr u32 McSmmuPtbAsid = 0x01C;
constexpr u32 McSmmuPtbData = 0x020;
constexpr u32 McSmmuTlbFlush = 0x030;
constexpr u32 McSmmuPtcFlush = 0x034;
constexpr u32 McSmmuAvpcAsid = 0x23C;
constexpr u32 McSmmuPpcs1Asid = 0x298;
/* Page table is backed by the security engine's MMIO aperture. */
constexpr u64 BpmpSmmuPdeBase = 0x70012000;
constexpr u32 BpmpSmmuAsid = 1;
/* MC_SMMU_PTB_ASID */
constexpr u32 SmmuPtbAsidCurrentAsid = BpmpSmmuAsid; /* [0:7] */
/* MC_SMMU_PTB_DATA */
constexpr u32 SmmuPtbDataPdeMask = 0x7FFFFF; /* [0:22] */
/* MC_SMMU_AVPC_ASID / MC_SMMU_PPCS1_ASID */
constexpr u32 SmmuClientSmmuEnableBit = (1u << 31);
constexpr u32 SmmuAvpcAsidValue = (SmmuClientSmmuEnableBit | BpmpSmmuAsid);
constexpr u32 SmmuPpcs1AsidValue = (SmmuClientSmmuEnableBit | BpmpSmmuAsid);
constexpr u32 EvpCopResetVector = 0x200;
constexpr u32 EvpCopUndefVector = 0x204;
constexpr u32 EvpCopSwiVector = 0x208;
@@ -122,6 +148,43 @@ namespace bpmp {
fileUtils::LogLine("[bpmp] RequestBpmpExitAndWait: BPMP timeout (cannot sleep)");
}
void EnableBpmpSmmu() {
/* Point the ASID page table at the security engine aperture. */
const u32 pde_base = static_cast<u32>(BpmpSmmuPdeBase / 0x1000);
/* Select the ASID and configure its page table entry. */
SmcReadWriteRegister(McPhysBase + McSmmuPtbAsid, 0xFFFFFFFF, SmmuPtbAsidCurrentAsid);
SmcReadWriteRegister(McPhysBase + McSmmuPtbData, 0xFFFFFFFF, pde_base & SmmuPtbDataPdeMask);
/* Route BPMP (AVPC) and PPCS1 through the SMMU. */
SmcReadWriteRegister(McPhysBase + McSmmuAvpcAsid, 0xFFFFFFFF, SmmuAvpcAsidValue);
SmcReadWriteRegister(McPhysBase + McSmmuPpcs1Asid, 0xFFFFFFFF, SmmuPpcs1AsidValue);
/* Flush the page table cache. */
SmcReadWriteRegister(McPhysBase + McSmmuPtcFlush, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
/* Flush the translation lookaside buffer. */
SmcReadWriteRegister(McPhysBase + McSmmuTlbFlush, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
}
void DisableBpmpSmmu() {
/* Clear the ASID page table. */
SmcReadWriteRegister(McPhysBase + McSmmuPtbAsid, 0xFFFFFFFF, SmmuPtbAsidCurrentAsid);
SmcReadWriteRegister(McPhysBase + McSmmuPtbData, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuAvpcAsid, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuPpcs1Asid, 0xFFFFFFFF, 0);
/* Flush the page table cache. */
SmcReadWriteRegister(McPhysBase + McSmmuPtcFlush, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
/* Flush the translation lookaside buffer. */
SmcReadWriteRegister(McPhysBase + McSmmuTlbFlush, 0xFFFFFFFF, 0);
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
}
void RestoreStockState() {
RequestBpmpExitAndWait();
@@ -140,6 +203,8 @@ namespace bpmp {
Mmio(board::actmonVirtAddr, ActmonCopUpperWmark) = 0;
Mmio(board::actmonVirtAddr, ActmonCopIntrStatus) = Mmio(board::actmonVirtAddr, ActmonCopIntrStatus);
Mmio(board::actmonVirtAddr, ActmonCopCtrl) = ActmonCopCtrlStockArmed;
EnableBpmpSmmu();
}
void PscThreadFunc(void *) {
@@ -194,6 +259,9 @@ namespace bpmp {
fileUtils::LogLine("[bpmp] StartBpmfwExecution: loading %zu bytes at 0x%llx",
fw_size, static_cast<unsigned long long>(FwIramPhysBase));
/* Disable the SMMU so DRAM can be accessed */
DisableBpmpSmmu();
/* Set BPMP reset */
Mmio(board::clkVirtAddr, ClkRstRstDevLSet) = RstDevLCopRstBit;