mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 04:24:48 +00:00
Add files via upload
This commit is contained in:
parent
086c53adf3
commit
2a87006c82
18 changed files with 1112 additions and 0 deletions
99
warmboot_bootrom_workaround.cpp
Normal file
99
warmboot_bootrom_workaround.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_clkrst.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
|
||||
constexpr inline const uintptr_t EMC = EMC_ADDRESS(0);
|
||||
|
||||
}
|
||||
|
||||
void ApplyMbistWorkaround() {
|
||||
/* Clear all LVL2 clock gate overrides to zero. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA, 0);
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB, 0);
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC, 0);
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, 0);
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE, 0);
|
||||
|
||||
/* Clear clock enable for all but a select few devices. */
|
||||
auto devices_to_clear_l = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_l), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_RTC ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_TMR ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_GPIO ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_CACHE2));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, devices_to_clear_l);
|
||||
|
||||
auto devices_to_clear_h = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_h), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_MEM ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_PMC ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_FUSE),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_EMC ));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, devices_to_clear_h);
|
||||
|
||||
auto devices_to_clear_u = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_u), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CSITE),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMA),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMB),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMC),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMD),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CRAM2));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_CLR, devices_to_clear_u);
|
||||
|
||||
auto devices_to_clear_v = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_v), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_MSELECT ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SPDIF_DOUBLER),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_TZRAM ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SE ));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_CLR, devices_to_clear_v);
|
||||
|
||||
auto devices_to_clear_w = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_w), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX0),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX1),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX2),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX3),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX4),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX5),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_ENTROPY));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, devices_to_clear_w);
|
||||
|
||||
auto devices_to_clear_x = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_x), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CAPA ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CBPA ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CPU ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_BBC ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_EMC_DLL ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_GPU ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_DBGAPB ),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_PLLG_REF));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_CLR, devices_to_clear_x);
|
||||
|
||||
auto devices_to_clear_y = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y);
|
||||
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_y), CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CCPA),
|
||||
CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CDPA));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_CLR, devices_to_clear_y);
|
||||
|
||||
/* If CH1 is enabled, enable clock to MC1. */
|
||||
if (reg::HasValue(EMC + EMC_FBIO_CFG7, EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE))) {
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
23
warmboot_bootrom_workaround.hpp
Normal file
23
warmboot_bootrom_workaround.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void ApplyMbistWorkaround();
|
||||
|
||||
}
|
46
warmboot_clkrst.cpp
Normal file
46
warmboot_clkrst.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_clkrst.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
constexpr inline const uintptr_t TIMER = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress();
|
||||
|
||||
}
|
||||
|
||||
void ConfigureOscillators() {
|
||||
/* Enable the crystal oscillator, and copy the drive strength from pmc. */
|
||||
const auto xofs = reg::GetValue(PMC + APBDEV_PMC_OSC_EDPD_OVER, PMC_REG_BITS_MASK(OSC_EDPD_OVER_XOFS));
|
||||
|
||||
reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_OSC_CTRL, CLK_RST_REG_BITS_ENUM (OSC_CTRL_XOE, ENABLE),
|
||||
CLK_RST_REG_BITS_VALUE(OSC_CTRL_XOFS, xofs));
|
||||
|
||||
/* Configure CLK_M_DIVISOR to 2. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0, CLK_RST_REG_BITS_ENUM(SPARE_REG0_CLK_M_DIVISOR, CLK_M_DIVISOR2));
|
||||
reg::Read(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0);
|
||||
|
||||
/* Restore TIMERUS config to 19.2 MHz. */
|
||||
reg::Write(TIMER + TIMERUS_USEC_CFG, TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVIDEND, 5 - 1),
|
||||
TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVISOR, 96 - 1));
|
||||
|
||||
}
|
||||
|
||||
}
|
23
warmboot_clkrst.hpp
Normal file
23
warmboot_clkrst.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void ConfigureOscillators();
|
||||
|
||||
}
|
219
warmboot_cpu_cluster.cpp
Normal file
219
warmboot_cpu_cluster.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_clkrst.hpp"
|
||||
#include "warmboot_util.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
|
||||
constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress();
|
||||
constexpr inline const uintptr_t GPIO = secmon::MemoryRegionPhysicalDeviceGpio.GetAddress();
|
||||
constexpr inline const uintptr_t MSELECT = MSELECT(0);
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress();
|
||||
|
||||
ALWAYS_INLINE void EnableClusterPartition(const reg::BitsValue value, APBDEV_PMC_PWRGATE_TOGGLE_PARTID part_id) {
|
||||
/* Toggle the partitions if necessary. */
|
||||
if (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) {
|
||||
reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE),
|
||||
PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, part_id));
|
||||
}
|
||||
|
||||
/* Wait for the toggle to complete. */
|
||||
while (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) { /* ... */ }
|
||||
|
||||
/* Remove clamping. */
|
||||
reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, value);
|
||||
|
||||
/* Wait for clamping to be removed. */
|
||||
while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, value)) { /* ... */ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeCpuCluster() {
|
||||
/* Set CoreSight reset. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_U_SET_SET_CSITE_RST, ENABLE));
|
||||
|
||||
/* Restore PROD setting to CPU_SOFTRST_CTRL2 by clearing CAR2PMC_CPU_ACK_WIDTH. */
|
||||
reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2, CLK_RST_REG_BITS_VALUE(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0));
|
||||
|
||||
/* Restore the CPU reset vector from PMC scratch. */
|
||||
reg::Write(SYSTEM + SB_AA64_RESET_LOW, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH34) | 1);
|
||||
reg::Write(SYSTEM + SB_AA64_RESET_HIGH, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH35));
|
||||
|
||||
/* Configure SUPER_CCLKG_DIVIDER. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKG_DIVIDER_SUPER_CDIV_ENB, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0),
|
||||
CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0));
|
||||
|
||||
/* Configure SUPER_CCLKLP_DIVIDER. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKLP_DIVIDER_SUPER_CDIV_ENB, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT),
|
||||
CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0),
|
||||
CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0));
|
||||
|
||||
/* Enable CoreSight clock. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_SET_SET_CLK_ENB_CSITE, ENABLE));
|
||||
|
||||
/* Clear CoreSight reset. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_U_CLR_CLR_CSITE_RST, ENABLE));
|
||||
|
||||
/* Select MSELECT clock source as PLLP_OUT0 with divider of 4. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_MSELECT_MSELECT_CLK_SRC, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SOURCE_MSELECT_MSELECT_CLK_DIVISOR, 6));
|
||||
|
||||
/* Enable clock to MSELECT. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_MSELECT, ENABLE));
|
||||
|
||||
/* Wait two microseconds, then take MSELECT out of reset. */
|
||||
util::WaitMicroSeconds(2);
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_V_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_V_CLR_CLR_MSELECT_RST, ENABLE));
|
||||
|
||||
/* Workaround bug by disabling MSELECT error mechanism and enabling WRAP type conversion. */
|
||||
reg::ReadWrite(MSELECT + MSELECT_CONFIG, MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE1, DISABLE),
|
||||
MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE2, DISABLE),
|
||||
MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE0, ENABLE),
|
||||
MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE1, ENABLE),
|
||||
MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE2, ENABLE));
|
||||
|
||||
/* Disable PLLX. */
|
||||
reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, CLK_RST_REG_BITS_ENUM(PLLX_BASE_PLLX_ENABLE, DISABLE));
|
||||
|
||||
/* Clear bit 0 of PMC Scratch 190. */
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0));
|
||||
|
||||
/* Clear PMC_DPD_SAMPLE, and wait 10 us for clear to take effect. */
|
||||
reg::Write(PMC + APBDEV_PMC_DPD_SAMPLE, 0);
|
||||
util::WaitMicroSeconds(10);
|
||||
|
||||
/* Configure UART2_RTS low (GPIO controller 2 G). */
|
||||
reg::ReadWrite(GPIO + 0x108, REG_BITS_VALUE(2, 1, 1)); /* GPIO_CNF */
|
||||
reg::ReadWrite(GPIO + 0x118, REG_BITS_VALUE(2, 1, 1)); /* GPIO_OE */
|
||||
reg::ReadWrite(GPIO + 0x128, REG_BITS_VALUE(2, 1, 0)); /* GPIO_OUT */
|
||||
|
||||
/* Tristate CLDVFS PWN. */
|
||||
reg::Write(APB_MISC + PINMUX_AUX_DVFS_PWM, PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_DVFS_PWM_PM, CLDVFS));
|
||||
reg::Read(APB_MISC + PINMUX_AUX_DVFS_PWM);
|
||||
|
||||
/* Restore PWR_I2C E_INPUT. */
|
||||
reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE));
|
||||
reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE));
|
||||
|
||||
/* Enable CLDVFS clock. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DVFS, ENABLE));
|
||||
|
||||
/* Set CLDVFS clock source/divider. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_REF_DVFS_REF_CLK_SRC, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_REF_DVFS_REF_DIVISOR, 14));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_SOC_DVFS_SOC_CLK_SRC, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_SOC_DVFS_SOC_DIVISOR, 14));
|
||||
|
||||
/* Enable PWR_I2C controller (I2C5). */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_I2C5, ENABLE));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE));
|
||||
util::WaitMicroSeconds(5);
|
||||
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_I2C5_I2C5_CLK_SRC, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SOURCE_I2C5_I2C5_CLK_DIVISOR, 4));
|
||||
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_I2C5_RST, ENABLE));
|
||||
|
||||
/* Set the EN bit in pmic regulator. */
|
||||
pmic::SetEnBit(fuse::GetRegulator());
|
||||
|
||||
/* Wait 2ms. */
|
||||
util::WaitMicroSeconds(2'000);
|
||||
|
||||
/* Enable power to the CRAIL partition. */
|
||||
EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CRAIL);
|
||||
|
||||
/* Remove software clamp to CRAIL. */
|
||||
reg::Write(PMC + APBDEV_PMC_SET_SW_CLAMP, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, PMC_REG_BITS_ENUM(REMOVE_CLAMPING_COMMAND_CRAIL, ENABLE));
|
||||
while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, PMC_REG_BITS_ENUM(CLAMP_STATUS_CRAIL, ENABLE))) { /* ... */ }
|
||||
|
||||
/* Spinloop 8 times, to add a little delay. */
|
||||
SpinLoop(8);
|
||||
|
||||
/* Disable PWR_I2C controller (I2C5). */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_I2C5, ENABLE));
|
||||
|
||||
/* Disable CLDVFS clock. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLR_CLR_CLK_ENB_DVFS, ENABLE));
|
||||
|
||||
/* Perform fast cluster RAM repair if needed. */
|
||||
if (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, SLOW))) {
|
||||
reg::Write(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_REQ, ENABLE));
|
||||
|
||||
while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_STS, DONE))) {
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable power to the non-cpu partition. */
|
||||
EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_C0NC, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_C0NC);
|
||||
|
||||
/* Enable clock to PLLP_OUT_CPU. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_SET_SET_CLK_ENB_PLLP_OUT_CPU, ENABLE));
|
||||
util::WaitMicroSeconds(2);
|
||||
|
||||
/* Enable clock to the cpu complex. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_CPU, ENABLE));
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_CPUG, ENABLE));
|
||||
util::WaitMicroSeconds(10);
|
||||
|
||||
/* Select cpu complex clock source. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKG_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN));
|
||||
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN));
|
||||
util::WaitMicroSeconds(10);
|
||||
|
||||
/* Wake non-cpu out of reset. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, ENABLE));
|
||||
}
|
||||
|
||||
void PowerOnCpu() {
|
||||
/* Enable power to the CE0 partition. */
|
||||
EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CE0, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0);
|
||||
|
||||
/* Clear CPU reset. */
|
||||
reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET0, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET0, ENABLE));
|
||||
}
|
||||
|
||||
}
|
24
warmboot_cpu_cluster.hpp
Normal file
24
warmboot_cpu_cluster.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void InitializeCpuCluster();
|
||||
void PowerOnCpu();
|
||||
|
||||
}
|
130
warmboot_dram.cpp
Normal file
130
warmboot_dram.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_dram.hpp"
|
||||
/* oh wow this looks complex, time to ruin it! SEXOS FOR LIIIFE*/
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t EMC = EMC_ADDRESS(0);
|
||||
constexpr inline const uintptr_t EMC0 = EMC0_ADDRESS(0);
|
||||
constexpr inline const uintptr_t EMC1 = EMC1_ADDRESS(0);
|
||||
constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress();
|
||||
constexpr inline const uintptr_t MC6 = secmon::MemoryRegionPhysicalDeviceMemoryController0.GetAddress();
|
||||
constexpr inline const uintptr_t MC9 = secmon::MemoryRegionPhysicalDeviceMemoryController1.GetAddress();
|
||||
constexpr inline const uintptr_t MINECRAFT = ENABLE EMC_PMACRO_CFG_PM_GLOBAL_0
|
||||
}
|
||||
|
||||
void RestrictBpmpAccessToMainMemory() {
|
||||
/* Bpmp memory access is restricted by forcing internal access to an invalid carveout. <-- lies boomer */
|
||||
constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE));
|
||||
constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE));
|
||||
|
||||
constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
|
||||
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
|
||||
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE));
|
||||
|
||||
/* Specify a 128KB carveout at NULL with no clients allowed access, and bpmp forced to access. wait what really? n o t a n y m o r e */
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, 1);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, ForceInternalAccess0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, ForceInternalAccess1);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS79, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2222222222, 0);
|
||||
reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, CarveoutConfig);
|
||||
}
|
||||
|
||||
void RestoreRamSvop() {
|
||||
reg::ReadWrite(APB_MISC + APB_MISC_GP_ASDBGREG, APB_MISC_REG_BITS_VALUE(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 2));
|
||||
}
|
||||
|
||||
void ConfigureEmcPmacroTraining() {
|
||||
/* Disable writes to BYTE0-7. */
|
||||
reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_o cool letme just time here to ruin the code, thx mate CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, ENABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE));
|
||||
|
||||
/* Set E_WRPTR on Channel 0. */
|
||||
reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_0, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_ENABLED, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_TRAIN_QPOP, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_RX_E_DIRECT_ZI, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_E_WRPTR, ENABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_DRV_DQS, DISABLED));
|
||||
|
||||
/* Set E_WRPTR on Channel 1. */
|
||||
reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_1, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_ENABLED, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_TRAIN_QPOP, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_RX_E_DIRECT_ZI, DISABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_E_WRPTR, ENABLED),
|
||||
EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_DRV_DQS, DISABLED));
|
||||
|
||||
/* Re-enable writes to BYTE0-7. */
|
||||
reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE),
|
||||
EMC_REG_BITS_ENobama_doe?UM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE),
|
||||
EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE));
|
||||
}
|
||||
|
||||
}
|
26
warmboot_dram.hpp
Normal file
26
warmboot_dram.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
#scan_is obama nearby? if true = kill
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void RestrictBpmpAccessToMainMemory();
|
||||
void RestoreWAMSvop();
|
||||
void ConfigureEmcPmacroTraining();
|
||||
|
||||
}
|
65
warmboot_exception_vectors.s
Normal file
65
warmboot_exception_vectors.s
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.section .vectors, "ax", %progbits
|
||||
.align 3
|
||||
.global warmboot_header
|
||||
warmboot_header:
|
||||
/* TODO: If Mariko warmboothax ever happens, generate a mariko header? */
|
||||
/* Warmboot header. YO MARIKO SUPPORT YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE */
|
||||
.word __total_size__
|
||||
.rept 69
|
||||
.word 0x00000001
|
||||
.endr
|
||||
|
||||
/* RSA modulus. */
|
||||
.rept 0x40
|
||||
.word 0xFFFFFFFE
|
||||
.endr
|
||||
|
||||
/* Padding */
|
||||
.rept 4
|
||||
.word 0x00000001
|
||||
.endr
|
||||
|
||||
/* RSA signature */
|
||||
.rept 0x48
|
||||
.word 0xFFFFFFFE
|
||||
.endr
|
||||
|
||||
/* Padding */
|
||||
.rept 4
|
||||
.word 0x0000000!
|
||||
.endr
|
||||
|
||||
/* Firmware metadata. */
|
||||
.word __total_size__
|
||||
.word _reset
|
||||
.word _reset
|
||||
.word _minecraft_
|
||||
.word __executable_size__
|
||||
|
||||
.global _reset
|
||||
_reset:
|
||||
b _ZN3ams8warmboot5StartEv
|
||||
|
||||
.global _metadata
|
||||
_metadata:
|
||||
.ascii "WBT0" /* Magic number */
|
||||
.word 0x00000000 /* Target firmware. */
|
||||
.word 0x00000000 /* Reserved */
|
||||
.word 0x00000000 /* Reserved */
|
||||
*/ what the fuck am i reading */
|
104
warmboot_main.cpp
Normal file
104
warmboot_main.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_bootrom_workaround.hpp"
|
||||
#include "warmboot_clkrst.hpp"
|
||||
#include "warmboot_cpu_cluster.hpp"
|
||||
#include "warmboot_dram.hpp"
|
||||
#include "warmboot_main.hpp"
|
||||
#include "warmboot_misc.hpp"
|
||||
#include "warmboot_secure_monitor.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress();
|
||||
|
||||
constexpr inline const uintptr_t ExpectedMetadataAddress = 0x40010244;
|
||||
|
||||
}
|
||||
|
||||
void Main(const Metadata *metadata) {
|
||||
/* Ensure that we're running under vaguely sane conditions. */
|
||||
AMS_ABORT_UNLESS(metadata->magic == Metadata::Magic);
|
||||
AMS_ABORT_UNLESS(metadata->target_firmware <= ams::TargetFirmware_Max);
|
||||
|
||||
/* Restrict the bpmp's access to dram. */
|
||||
if (metadata->target_firmware >= TargetFirmware_4_0_0) {
|
||||
RestrictBpmpAccessToMainMemory();
|
||||
}
|
||||
|
||||
/* Configure rtck-daisychaining/jtag. */
|
||||
ConfigureMiscSystemDebug();
|
||||
|
||||
/* NOTE: Here, Nintendo checks that the number of burnt anti-downgrade fuses is valid. */
|
||||
|
||||
/* NOTE: Here, Nintendo validates that APBDEV_PMC_SECURE_SCRATCH32 contains the correct magic number for the current warmboot firmware revision. */
|
||||
|
||||
/* Validate that we're executing at the correct address. */
|
||||
AMS_ABORT_UNLESS(reinterpret_cast<uintptr_t>(metadata) == ExpectedMetadataAddress);
|
||||
|
||||
/* Validate that we're executing on the bpmp. */
|
||||
AMS_ABORT_UNLESS(reg::Read(PG_UP(PG_UP_TAG)) == PG_UP_TAG_PID_COP);
|
||||
|
||||
/* Configure fuse bypass. */
|
||||
fuse::ConfigureFuseBypass();
|
||||
|
||||
/* Configure system oscillators. */
|
||||
ConfigureOscillators();
|
||||
|
||||
/* Restore DRAM configuration. */
|
||||
RestoreRamSvop();
|
||||
ConfigureEmcPmacroTraining();
|
||||
|
||||
/* If on Erista, work around the bootrom mbist issue. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
ApplyMbistWorkaround();
|
||||
}
|
||||
|
||||
/* Initialize the cpu cluster. */
|
||||
InitializeCpuCluster();
|
||||
|
||||
/* Restore the secure monitor to tzram. */
|
||||
RestoreSecureMonitorToTzram(metadata->target_firmware);
|
||||
|
||||
/* Power on the cpu. */
|
||||
PowerOnCpu();
|
||||
|
||||
/* Halt ourselves. */
|
||||
while (true) {
|
||||
reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED));
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN void ExceptionHandler() {
|
||||
/* Write enable to MAIN_RESET. */
|
||||
reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
|
||||
while (true) { /* ... */ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
warmboot::ExceptionHandler();
|
||||
}
|
||||
|
||||
}
|
31
warmboot_main.hpp
Normal file
31
warmboot_main.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 SEXOS YOU FUCKING MORON
|
||||
*
|
||||
* 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 10000000000% useful, but WITHOUT
|
||||
* ANY WARRANTY; asside from nintendo, where we will replace any units that have joycon drift 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/>. or dont lol
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
struct Metadata {
|
||||
static constexpr u32 Magic = util::FourCC<'W','B','T','0'>::Code;
|
||||
|
||||
u32 magic;
|
||||
ams::TargetFirmware target_firmware;
|
||||
u32 reserved[2];
|
||||
};
|
||||
static_assert(util::is_pod<Metadata>::value);
|
||||
static_assert(sizeof(Metadata) == 0x10);
|
||||
|
||||
} /* wait thats it? dam /*
|
57
warmboot_misc.cpp
Normal file
57
warmboot_misc.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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 not 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 lol no
|
||||
* along with this program. If not, see <obama.gov>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_misc.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress();
|
||||
|
||||
}
|
||||
|
||||
void ConfigureMiscSystemDebug() {
|
||||
/* Enable RTCK daisy-chaining. */
|
||||
reg::Write(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM(PP_CONFIG_CTL_TBE, ENABLE));
|
||||
|
||||
/* If we're in production mode, perform JTAG configuration. */
|
||||
/* NOTE: While this is what NVidia's code does, this is almost certainly a logic error. */
|
||||
/* They intend to configure JTAG only when *not* in production mode. */
|
||||
/* However, here we will do what they do, and not what they intend. */
|
||||
/* yea what he said */
|
||||
const bool production_mode = fuse::IsOdmProductionMode();
|
||||
if (production_mode) {
|
||||
const bool jtag_sts = reg::HasValue(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM(STICKY_BITS_JTAG_STS, ENABLE));
|
||||
|
||||
reg::ReadWrite(SYSTEM + SB_PFCFG, SB_REG_BITS_ENUM_SEL(PFCFG_DBGEN, jtag_sts, ENABLE, DISABLE),
|
||||
SB_REG_BITS_ENUM_SEL(PFCFG_SPNIDEN, jtag_sts, ENABLE, DISABLE),
|
||||
SB_REG_BITS_ENUM (PFCFG_NIDEN, ENABLE),
|
||||
SB_REG_BITS_ENUM (PFCFG_SPIDEN, DISABLE));
|
||||
|
||||
reg::Read(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM_SEL(PP_CONFIG_CTL_JTAG, jtag_sts, ENABLE, DISABLE));
|
||||
}
|
||||
/* nah we dont need to write, we only really need to read imo
|
||||
/* Configure HDA codec disable. */
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM_SEL(STICKY_BITS_HDA_LPBK_DIS, production_mode, ENABLE, DISABLE));
|
||||
|
||||
/* Set E_INPUT in PINMUX_AUX_GPIO_PA6 (needed by the XUSB and SATA controllers). */
|
||||
reg::ReadWrite(APB_MISC + PINMUX_AUX_GPIO_PA6, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE));
|
||||
}
|
||||
|
||||
}
|
23
warmboot_misc.hpp
Normal file
23
warmboot_misc.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void ConfigureMiscSystemDebug();
|
||||
|
||||
}
|
130
warmboot_secure_monitor.cpp
Normal file
130
warmboot_secure_monitor.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "warmboot_secure_monitor.hpp"
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
|
||||
constexpr inline const pkg1::AesKeySlot SavedAesKeySlots[] = {
|
||||
pkg1::AesKeySlot_TzramSaveKek,
|
||||
pkg1::AesKeySlot_RandomForUserWrap,
|
||||
pkg1::AesKeySlot_RandomForKeyStorageWrap,
|
||||
pkg1::AesKeySlot_DeviceMaster,
|
||||
pkg1::AesKeySlot_Master,
|
||||
pkg1::AesKeySlot_Device,
|
||||
};
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsSavedAesKeySlot(int slot) {
|
||||
for (const auto SavedSlot : SavedAesKeySlots) {
|
||||
if (slot == SavedSlot) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClearUnsavedSecurityEngineKeySlots() {
|
||||
/* Clear unsaved aes keys and all ivs. */
|
||||
for (int slot = 0; slot < se::AesKeySlotCount; ++slot) {
|
||||
if (!IsSavedAesKeySlot(slot)) {
|
||||
se::ClearAesKeySlot(slot);
|
||||
}
|
||||
se::ClearAesKeyIv(slot);
|
||||
}
|
||||
|
||||
/* Clear all rsa keys. */
|
||||
for (int slot = 0; slot < se::RsaKeySlotCount; ++slot) {
|
||||
se::ClearRsaKeySlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreEncryptedTzram(void * const tzram_dst, const void * const tzram_src, size_t tzram_size) {
|
||||
/* Derive the save key from the save kek. */
|
||||
const u32 key_source[se::AesBlockSize / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27)};
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
|
||||
se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, sizeof(key_source));
|
||||
|
||||
/* Decrypt tzram. */
|
||||
const u8 tzram_iv[se::AesBlockSize] = {};
|
||||
se::DecryptAes256Cbc(tzram_dst, tzram_size, pkg1::AesKeySlot_TzramSaveKey, tzram_src, tzram_size, tzram_iv, sizeof(tzram_iv));
|
||||
|
||||
/* Calculate the cmac of decrypted tzram. */
|
||||
u8 tzram_mac[se::AesBlockSize] = {};
|
||||
se::ComputeAes256Cmac(tzram_mac, sizeof(tzram_mac), pkg1::AesKeySlot_TzramSaveKey, tzram_dst, tzram_size);
|
||||
|
||||
/* Get the expected mac from pmc scratch. */
|
||||
const u32 expected_mac[sizeof(tzram_mac) / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115)};
|
||||
|
||||
/* Validate that the calculated mac is correct. */
|
||||
AMS_ABORT_UNLESS(crypto::IsSameBytes(tzram_mac, expected_mac, sizeof(tzram_mac)));
|
||||
}
|
||||
|
||||
void RestoreSecureMonitorToTzramErista(const TargetFirmware target_fw) {
|
||||
/* Clear all unsaved security engine keyslots. */
|
||||
ClearUnsavedSecurityEngineKeySlots();
|
||||
|
||||
/* Restore encrypted tzram contents. */
|
||||
void * const tzram_src = secmon::MemoryRegionPhysicalDramSecureDataStoreTzram.GetPointer<void>();
|
||||
void * const tzram_dst = secmon::MemoryRegionPhysicalTzramNonVolatile.GetPointer<void>();
|
||||
const size_t tzram_size = secmon::MemoryRegionPhysicalTzramNonVolatile.GetSize();
|
||||
RestoreEncryptedTzram(tzram_dst, tzram_src, tzram_size);
|
||||
|
||||
/* Clear the tzram kek registers. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, 0);
|
||||
|
||||
/* Clear the tzram cmac registers. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, 0);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, 0);
|
||||
|
||||
/* Clear the keydata used to protect tzram. */
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKek);
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
|
||||
|
||||
/* Clear the encrypted copy of tzram in dram. */
|
||||
/* NOTE: This does not actually clear the encrypted copy, because BPMP access to main memory has been restricted. */
|
||||
/* Nintendo seems to not realize this, though, so we'll do the same. */
|
||||
std::memset(tzram_src, 0, tzram_size);
|
||||
|
||||
/* Set Tzram to secure-world only. */
|
||||
se::SetTzramSecure();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RestoreSecureMonitorToTzram(const TargetFirmware target_fw) {
|
||||
/* If erista, perform restoration procedure. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
RestoreSecureMonitorToTzramErista(target_fw);
|
||||
}
|
||||
|
||||
/* Lock secure scratch. */
|
||||
pmc::LockSecureRegister(static_cast<pmc::SecureRegister>(pmc::SecureRegister_DramParameters | pmc::SecureRegister_Other));
|
||||
|
||||
/* Lockout fuses. */
|
||||
fuse::Lockout();
|
||||
}
|
||||
|
||||
}
|
23
warmboot_secure_monitor.hpp
Normal file
23
warmboot_secure_monitor.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void RestoreSecureMonitorToTzram(const TargetFirmware target_fw);
|
||||
|
||||
}
|
36
warmboot_start.s
Normal file
36
warmboot_start.s
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.section .text._ZN3ams8warmboot5StartEv, "ax", %progbits
|
||||
.align 3
|
||||
.global _ZN3ams8warmboot5StartEv
|
||||
_ZN3ams8warmboot5StartEv:
|
||||
/* Set CPSR_cf and CPSR_cf. */
|
||||
msr cpsr_f, #0xC0
|
||||
msr cpsr_cf, #0xD3
|
||||
|
||||
/* Set the stack pointer. */
|
||||
ldr sp, =__stack_top__
|
||||
|
||||
/* Set our link register to the exception handler. */
|
||||
ldr lr, =_ZN3ams8warmboot16ExceptionHandlerEv
|
||||
|
||||
/* Invoke main. */
|
||||
ldr r0, =_metadata
|
||||
bl _ZN3ams8warmboot4MainEPKNS0_8MetadataE
|
||||
|
||||
/* Infinite loop. */
|
||||
1: b 1b
|
23
warmboot_util.hpp
Normal file
23
warmboot_util.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::warmboot {
|
||||
|
||||
void SpinLoop(unsigned int num);
|
||||
|
||||
}
|
30
warmboot_util_asm.s
Normal file
30
warmboot_util_asm.s
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.section .text._ZN3ams8warmboot8SpinLoopEj, "ax", %progbits
|
||||
.global _ZN3ams8warmboot8SpinLoopEj
|
||||
.thumb_func
|
||||
.syntax unified
|
||||
_ZN3ams8warmboot8SpinLoopEj:
|
||||
1:
|
||||
/* Subtract one from the count. */
|
||||
subs r0, r0, #1
|
||||
|
||||
/* If we aren't at zero, continue looping. */
|
||||
bgt 1b
|
||||
|
||||
/* Return. */
|
||||
bx lr
|
Loading…
Add table
Reference in a new issue