update exosphere patch

This commit is contained in:
souldbminersmwc committed 2026-09-10 19:04:20 -04:00
1 parent b9bf6dd719
commit 151d8584e4
17 files changed
+5211 -18

No files matched your search

+1
View File
@@ -0,0 +1 @@
This contains a diff all modifications done to exosphere
@@ -0,0 +1,57 @@
131,156c131,159
< #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
< HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
< HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
< HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
< HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
< HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
< HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(FuseKFuse, MemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
< HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
< HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
< HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__)
---
> #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
> HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
> HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
> HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
> HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
> HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
> HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
> HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(ExternalMemoryController0, MemoryController1, UINT64_C(0x7001E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(ExternalMemoryController1, ExternalMemoryController0, UINT64_C(0x7001F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(Sdmmc, ExternalMemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
> HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
> HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
@@ -0,0 +1,29 @@
1221c1221
< const auto target_fw = GetTargetFirmware();
---
> // const auto target_fw = GetTargetFirmware();
1223,1226c1223,1226
< 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_2_0_0) {
> // /* Set the PMC secure. */ I REFUSE
> // reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE));
> // }
1228,1233c1228,1234
< 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));
< }
---
> // if (target_fw >= TargetFirmware_4_0_0) {
> // /* Set the MC secure. */ I REFUSE
> // 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));
> // }
> return;
@@ -0,0 +1,2 @@
154a155
> { 0xF0000005, Restriction_None, SmcShowError },
@@ -0,0 +1,9 @@
160c160
< /* Validate that the bpmp is appropriately halted. */
---
> /* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
161a162,165
> reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
> FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
>
> /* Validate that the bpmp is appropriately halted. */
@@ -0,0 +1,22 @@
100a101,105
> #include "secmon_define_emc_access_table.inc"
> #include "secmon_define_emc01_access_table.inc"
> #include "secmon_define_flow_controller_access_table.inc"
> #include "secmon_define_exception_vectors_access_table.inc"
> #include "secmon_define_rtc_pmc_access_table.inc"
104,107c109,118
< { PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
< { McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
< { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
< { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
---
> { PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
> { McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
> { EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
> { Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Size, },
> { Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Size, },
> { FlowControllerAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceFlowController.GetAddress(), FlowControllerAccessTable::Address, FlowControllerAccessTable::Size, },
> { ExceptionVectorsAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExceptionVectors.GetAddress(), ExceptionVectorsAccessTable::Address, ExceptionVectorsAccessTable::Size, },
> { RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
> { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
> { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
@@ -0,0 +1,25 @@
/*
* 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/>.
*/
#define __ACCESS_TABLE_NAME__ Emc01AccessTable
#define __ACCESS_TABLE_ADDRESS__ 0
#define __ACCESS_TABLE_INC__ "secmon_emc01_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__
@@ -0,0 +1,25 @@
/*
* 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/>.
*/
#define __ACCESS_TABLE_NAME__ ExceptionVectorsAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExceptionVectors.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_exception_vectors_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__
@@ -0,0 +1,25 @@
/*
* 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/>.
*/
#define __ACCESS_TABLE_NAME__ FlowControllerAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceFlowController.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_flow_controller_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -151,7 +151,9 @@ namespace ams::secmon {
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController0, MemoryController1, UINT64_C(0x7001E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController1, ExternalMemoryController0, UINT64_C(0x7001F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Sdmmc, ExternalMemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,571 @@
/*
* 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_cache.hpp"
#include "../secmon_cpu_context.hpp"
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_se_lock.hpp"
#include "sc7fw_bin.h"
namespace ams::secmon {
/* Declare assembly functionality. */
void *GetCoreExceptionStackVirtual();
}
namespace ams::secmon::smc {
/* Declare assembly power-management functionality. */
void PivotStackAndInvoke(void *stack, void (*function)());
void FinalizePowerOff();
namespace {
constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
constexpr inline const uintptr_t APB_MISC = MemoryRegionVirtualDeviceApbMisc.GetAddress();
constexpr inline const uintptr_t GPIO = MemoryRegionVirtualDeviceGpio.GetAddress();
constexpr inline const uintptr_t CLK_RST = MemoryRegionVirtualDeviceClkRst.GetAddress();
constexpr inline const uintptr_t EVP = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress();
constexpr inline const uintptr_t FLOW_CTLR = MemoryRegionVirtualDeviceFlowController.GetAddress();
constexpr inline const uintptr_t AHB_ARBC = MemoryRegionVirtualDeviceSystem.GetAddress();
constexpr inline uintptr_t CommonSmcStackTop = MemoryRegionVirtualTzramVolatileData.GetEndAddress() - (0x80 * (NumCores - 1));
enum PowerStateType {
PowerStateType_StandBy = 0,
PowerStateType_PowerDown = 1,
};
enum PowerStateId {
PowerStateId_Sc7 = 27,
};
/* http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf Page 46 */
struct SuspendCpuPowerState {
using StateId = util::BitPack32::Field< 0, 16, PowerStateId>;
using StateType = util::BitPack32::Field<16, 1, PowerStateType>;
using PowerLevel = util::BitPack32::Field<24, 2, u32>;
};
constinit bool g_charger_hi_z_mode_enabled = false;
constinit const reg::BitsMask CpuPowerGateStatusMasks[NumCores] = {
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE0),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE1),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE2),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE3),
};
constinit const APBDEV_PMC_PWRGATE_TOGGLE_PARTID CpuPowerGateTogglePartitionIds[NumCores] = {
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE1,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE2,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE3,
};
bool IsCpuPoweredOn(const reg::BitsMask mask) {
return reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, REG_BITS_VALUE_FROM_MASK(mask, APBDEV_PMC_PWRGATE_STATUS_STATUS_ON));
}
void PowerOnCpu(const reg::BitsMask mask, u32 toggle_partid) {
/* If the cpu is already on, we have nothing to do. */
if (IsCpuPoweredOn(mask)) {
return;
}
/* Wait until nothing is being powergated. */
int timeout = 5000;
while (true) {
if (reg::HasValue(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, DISABLE))) {
break;
}
util::WaitMicroSeconds(1);
if ((--timeout) < 0) {
/* NOTE: Nintendo doesn't do any error handling here... */
return;
}
}
/* Toggle on the cpu partition. */
reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE),
PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, toggle_partid));
/* Wait up to 5000 us for the powergate to complete. */
timeout = 5000;
while (true) {
if (IsCpuPoweredOn(mask)) {
break;
}
util::WaitMicroSeconds(1);
if ((--timeout) < 0) {
/* NOTE: Nintendo doesn't do any error handling here... */
return;
}
}
}
void ResetCpu(int which_core) {
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
}
void StartCpu(int which_core) {
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
}
void PowerOffCpuImpl() {
/* Get the current core id. */
const auto core_id = hw::GetCurrentCoreId();
/* Configure the flow controller to prepare for shutting down the current core. */
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_ONLY);
flow::SetHaltCpuEvents(core_id, false);
flow::SetCc4Ctrl(core_id, 0);
/* Save the core's context for restoration on next power-on. */
SaveDebugRegisters();
SetCoreOff();
/* Ensure there are no pending memory transactions prior to our power-down. */
FlushEntireDataCache();
/* Finalize our powerdown and wait for an interrupt. */
FinalizePowerOff();
}
void ValidateSocStateForSuspend() {
/* Validate that all other cores are off. */
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
/* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
const bool jtag = 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_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
/* Validate that the bpmp is appropriately halted. */
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED)));
/* Further validations aren't guaranteed on < 6.0.0. */
if (GetTargetFirmware() < TargetFirmware_6_0_0) {
return;
}
/* Validate that USB2, APB-DMA, AHB-DMA are held in reset. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_USB2_RST, ENABLE),
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_APBDMA_RST, ENABLE),
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_AHBDMA_RST, ENABLE)));
/* Validate that USBD is held in reset. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_USBD_RST, ENABLE)));
/* Validate that AHB-DMA, USB, USB2, COP are not allowed to arbitrate on the AHB. */
AMS_ABORT_UNLESS(reg::HasValue(AHB_ARBC + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_AHBDMA, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB2, DISABLE)));
/* Validate that the GPIO controller has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_GPIO, ENABLE)));
/* Validate that both FUSE and KFUSE have clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_FUSE, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_KFUSE, ENABLE)));
/* Validate that all of IRAM has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMA, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMB, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMC, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMD, ENABLE)));
/* Validate that ACTMON has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_V_CLK_ENB_ACTMON, ENABLE)));
/* Validate that ENTROPY has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_W_CLK_ENB_ENTROPY, ENABLE)));
}
void GenerateCryptographicallyRandomBytes(void * const dst, int size) {
/* Flush the region we're about to fill to ensure consistency with the SE. */
hw::FlushDataCache(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes. */
se::GenerateRandomBytes(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Flush to ensure the CPU sees consistent data for the region. */
hw::FlushDataCache(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
}
void SaveSecureContextForErista() {
/* Generate a random key source. */
util::AlignedBuffer<hw::DataCacheLineSize, se::AesBlockSize> key_source;
GenerateCryptographicallyRandomBytes(key_source, se::AesBlockSize);
const u32 * const key_source_32 = reinterpret_cast<const u32 *>(static_cast<u8 *>(key_source));
/* Ensure that the key source registers are not locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) != pmc::LockState::Locked);
/* Write the key source, lock writes to the key source, and verify that the key source is write-locked. */
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, key_source_32[0]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, key_source_32[1]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, key_source_32[2]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, key_source_32[3]);
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceWrite);
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceWrite) == pmc::LockState::Locked);
/* Verify the key source is correct in registers, and read-lock the key source registers. */
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24) == key_source_32[0]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25) == key_source_32[1]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26) == key_source_32[2]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27) == key_source_32[3]);
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceRead);
/* Ensure that the key source registers are locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) == pmc::LockState::Locked);
/* Generate a random kek into keyslot 2. */
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
/* Verify that the se is in a validate state, context save, and validate again. */
{
se::ValidateErrStatus();
ON_SCOPE_EXIT { se::ValidateErrStatus(); };
{
/* Transition to non-secure mode for the duration of the context save operation. */
se::SetSecure(false);
ON_SCOPE_EXIT { se::SetSecure(true); };
/* Get a pointer to the context storage. */
se::Context * const context = MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetPointer<se::Context>();
static_assert(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetSize() == sizeof(*context));
/* Save the context. */
se::SaveContext(context);
/* Ensure that the cpu sees consistent data. */
hw::FlushDataCache(context, sizeof(*context));
hw::DataSynchronizationBarrierInnerShareable();
/* Write the context pointer to pmc scratch, so that the bootrom will restore it on wake. */
reg::Write(PMC + APBDEV_PMC_SCRATCH43, MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState.GetAddress());
}
}
/* Clear keyslot 3, and then derive the save key. */
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, se::AesBlockSize);
/* Declare a temporary block to be used as both iv and mac. */
u32 temp_block[se::AesBlockSize / sizeof(u32)] = {};
/* Ensure that the SE sees consistent data for tzram. */
const void * const tzram_save_src = MemoryRegionVirtualTzramReadOnlyAlias.GetPointer<u8>() + MemoryRegionVirtualTzramVolatileData.GetSize() + MemoryRegionVirtualTzramVolatileStack.GetSize();
void * const tzram_save_dst = MemoryRegionVirtualIramSc7Work.GetPointer<void>();
constexpr size_t TzramSaveSize = MemoryRegionVirtualDramSecureDataStoreTzram.GetSize();
hw::FlushDataCache(tzram_save_src, TzramSaveSize);
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Encrypt tzram using our random key. */
se::EncryptAes256Cbc(tzram_save_dst, TzramSaveSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize, temp_block, se::AesBlockSize);
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Copy the data from work space to the secure storage destination. */
void * const tzram_store_dst = MemoryRegionVirtualDramSecureDataStoreTzram.GetPointer<void>();
std::memcpy(tzram_store_dst, tzram_save_dst, TzramSaveSize);
hw::FlushDataCache(tzram_store_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Compute cmac of tzram into our temporary block. */
se::ComputeAes256Cmac(temp_block, se::AesBlockSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize);
/* Ensure that the cmac registers are not locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) != pmc::LockState::Locked);
/* Write the cmac, lock writes to the cmac, and verify that the cmac is write-locked. */
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, temp_block[0]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, temp_block[1]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, temp_block[2]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, temp_block[3]);
pmc::LockSecureRegister(pmc::SecureRegister_CmacWrite);
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacWrite) == pmc::LockState::Locked);
/* Verify the key source is correct in registers, and read-lock the key source registers. */
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112) == temp_block[0]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113) == temp_block[1]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114) == temp_block[2]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115) == temp_block[3]);
pmc::LockSecureRegister(pmc::SecureRegister_CmacRead);
/* Ensure that the key source registers are locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) == pmc::LockState::Locked);
}
void SaveSecureContextForMariko() {
/* Save security engine context to TZRAM SE carveout (inaccessible to cpu). */
se::SaveContextAutomatic();
/* Save TZRAM to shadow-TZRAM in always-on power domain. */
se::SaveTzramAutomatic();
}
void SaveSecureContext() {
/* Save the appropriate secure context. */
const auto soc_type = GetSocType();
if (soc_type == fuse::SocType_Erista) {
SaveSecureContextForErista();
} else /* if (soc_type == fuse::SocType_Mariko) */ {
SaveSecureContextForMariko();
}
/* Save the debug code. */
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
{
const void * const debug_code_src = MemoryRegionVirtualDebugCode.GetPointer<void>();
void * const debug_code_dst = MemoryRegionVirtualDramDebugDataStore.GetPointer<void>();
std::memcpy(debug_code_dst, debug_code_src, MemoryRegionVirtualDebugCode.GetSize());
hw::FlushDataCache(debug_code_dst, MemoryRegionVirtualDebugCode.GetSize());
hw::DataSynchronizationBarrierInnerShareable();
}
#endif
}
void LoadAndStartSc7BpmpFirmware() {
/* Set BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE));
/* Set the PMC as insecure, so that the BPMP firmware can access it. */
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, DISABLE));
/* Set the exception vectors for the bpmp. RESET should point to RESET, all others should point to generic exception/panic. */
constexpr const u32 Sc7FirmwareResetVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x0);
constexpr const u32 Sc7FirmwarePanicVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x4);
reg::Write(EVP + EVP_COP_RESET_VECTOR, Sc7FirmwareResetVector);
reg::Write(EVP + EVP_COP_UNDEF_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_SWI_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_RSVD_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_IRQ_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_FIQ_VECTOR, Sc7FirmwarePanicVector);
/* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */
actmon::StopMonitoringBpmp();
/* Load the bpmp firmware. */
void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>();
std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size);
hw::FlushDataCache(sc7fw_load_address, sc7fw_bin_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Ensure that the bpmp firmware was loaded. */
AMS_ABORT_UNLESS(crypto::IsSameBytes(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size));
/* Clear BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_COP_RST, ENABLE));
/* Start the bpmp. */
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_NONE));
}
void SaveSecureContextAndSuspend() {
/* Ensure there are no pending memory transactions before we continue */
FlushEntireDataCache();
hw::DataSynchronizationBarrierInnerShareable();
/* Save all secure context (security engine state + tzram). */
SaveSecureContext();
/* Load and start the sc7 firmware on the bpmp. */
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
LoadAndStartSc7BpmpFirmware();
}
/* Log our suspension. */
/* NOTE: Nintendo only does this on dev, but we will always do it. */
if (true /* !pkg1::IsProduction() */) {
log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags());
log::SendText("OYASUMI\n", 8);
log::Flush();
}
/* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */
if (GetSocType() == fuse::SocType_Erista) {
reg::Write(PMC + APBDEV_PMC_SCRATCH31, 0x2202E012);
reg::Write(PMC + APBDEV_PMC_SCRATCH32, 0x6001DC28);
}
/* Finalize our powerdown and wait for an interrupt. */
FinalizePowerOff();
}
SmcResult SuspendCpuImpl(SmcArguments &args) {
/* Decode arguments. */
const util::BitPack32 power_state = { static_cast<u32>(args.r[1]) };
const uintptr_t entry_point = args.r[2];
const uintptr_t context_id = args.r[3];
const auto state_type = power_state.Get<SuspendCpuPowerState::StateType>();
const auto state_id = power_state.Get<SuspendCpuPowerState::StateId>();
const auto core_id = hw::GetCurrentCoreId();
/* Validate arguments. */
SMC_R_UNLESS(state_type == PowerStateType_PowerDown, PsciDenied);
SMC_R_UNLESS(state_id == PowerStateId_Sc7, PsciDenied);
/* Orchestrate charger transition to Hi-Z mode if needed. */
if (IsChargerHiZModeEnabled()) {
/* Ensure we can do comms over i2c-1. */
clkrst::EnableI2c1Clock();
/* If the charger isn't in hi-z mode, perform a transition. */
if (!charger::IsHiZMode()) {
charger::EnterHiZMode();
/* Wait up to 50ms for the transition to complete. */
const auto start_time = util::GetMicroSeconds();
auto current_time = start_time;
while ((current_time - start_time) <= 50'000) {
if (auto intr_status = reg::Read(GPIO + 0x634); (intr_status & 1) == 0) {
/* Wait 256 us to ensure the transition completes. */
util::WaitMicroSeconds(256);
break;
}
current_time = util::GetMicroSeconds();
}
}
/* Disable i2c-1, since we're done communicating over it. */
clkrst::DisableI2c1Clock();
}
/* Enable wake event detection. */
pmc::EnableWakeEventDetection();
/* Ensure that i2c-5 is usable for communicating with the pmic. */
clkrst::EnableI2c5Clock();
i2c::Initialize(i2c::Port_5);
/* Orchestrate sleep entry with the pmic. */
pmic::EnableSleep();
/* Ensure that the soc is in a state valid for us to suspend. */
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
ValidateSocStateForSuspend();
}
/* Configure the pmc for sc7 entry. */
pmc::ConfigureForSc7Entry();
/* Configure the flow controller for sc7 entry. */
flow::SetCc4Ctrl(core_id, 0);
flow::SetHaltCpuEvents(core_id, false);
flow::ClearL2FlushControl();
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_TURNOFF_CPURAIL);
/* Save the entry context. */
SetEntryContext(core_id, entry_point, context_id);
/* Configure the cpu context for reset. */
SaveDebugRegisters();
SetCoreOff();
SetResetExpected(true);
/* Switch to use the common smc stack (all other cores are off), and perform suspension. */
PivotStackAndInvoke(reinterpret_cast<void *>(CommonSmcStackTop), SaveSecureContextAndSuspend);
/* This code will never be reached. */
__builtin_unreachable();
}
}
void PowerOffCpu() {
/* Get the current core id. */
const auto core_id = hw::GetCurrentCoreId();
/* Note that we're expecting a reset for the current core. */
SetResetExpected(true);
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
if (core_id == NumCores - 1) {
PowerOffCpuImpl();
} else {
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl);
}
/* This code will never be reached. */
__builtin_unreachable();
}
SmcResult SmcPowerOffCpu(SmcArguments &args) {
AMS_UNUSED(args);
PowerOffCpu();
}
SmcResult SmcPowerOnCpu(SmcArguments &args) {
/* Get and validate the core to power on. */
const int which_core = args.r[1];
SMC_R_UNLESS(0 <= which_core && which_core < NumCores, PsciInvalidParameters);
/* Ensure the core isn't already on. */
SMC_R_UNLESS(!IsCoreOn(which_core), PsciAlreadyOn);
/* Save the entry context. */
SetEntryContext(which_core, args.r[2], args.r[3]);
/* Reset the cpu. */
ResetCpu(which_core);
/* Turn on the core. */
PowerOnCpu(CpuPowerGateStatusMasks[which_core], CpuPowerGateTogglePartitionIds[which_core]);
/* Start the core. */
StartCpu(which_core);
return SmcResult::PsciSuccess;
}
SmcResult SmcSuspendCpu(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, SuspendCpuImpl);
}
bool IsChargerHiZModeEnabled() {
return g_charger_hi_z_mode_enabled;
}
void SetChargerHiZModeEnabled(bool en) {
g_charger_hi_z_mode_enabled = en;
}
}
@@ -99,16 +99,23 @@ namespace ams::secmon::smc {
#include "secmon_define_pmc_access_table.inc"
#include "secmon_define_mc_access_table.inc"
#include "secmon_define_emc_access_table.inc"
#include "secmon_define_emc01_access_table.inc"
#include "secmon_define_flow_controller_access_table.inc"
#include "secmon_define_exception_vectors_access_table.inc"
#include "secmon_define_rtc_pmc_access_table.inc"
#include "secmon_define_mc01_access_table.inc"
constexpr const AccessTableEntry AccessTables[] = {
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
{ RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
{ Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Size, },
{ Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Size, },
{ FlowControllerAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceFlowController.GetAddress(), FlowControllerAccessTable::Address, FlowControllerAccessTable::Size, },
{ ExceptionVectorsAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExceptionVectors.GetAddress(), ExceptionVectorsAccessTable::Address, ExceptionVectorsAccessTable::Size, },
{ RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
};
constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) {
@@ -170,12 +177,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. */
+15 -7
View File
@@ -76,13 +76,21 @@ if [ "$NO_EXO" -eq 0 ]; then
EXO_DEST="build/atmosphere/exosphere/program/source/smc"
LIBEXO_DEST="build/atmosphere/libraries/libexosphere/include/exosphere/secmon"
cp -v "$EXO_SRC/secmon_emc_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_emc_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_rtc_pmc_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_rtc_pmc_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_smc_register_access.cpp" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_smc_handler.cpp" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_memory_layout.hpp" "$LIBEXO_DEST/"
cp -v "$EXO_SRC/secmon_setup.cpp" "$EXO_PROGRAM_DEST/"
cp -v "$EXO_SRC/secmon_define_emc_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_emc_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_emc01_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_emc01_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_rtc_pmc_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_rtc_pmc_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_flow_controller_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_flow_controller_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_define_exception_vectors_access_table.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_exception_vectors_access_table_data.inc" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_smc_register_access.cpp" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_smc_handler.cpp" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_smc_power_management.cpp" "$EXO_DEST/"
cp -v "$EXO_SRC/secmon_memory_layout.hpp" "$LIBEXO_DEST/"
fi
echo