mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
exo/mariko fatal: halt other cores when beginning fatal program
This commit is contained in:
parent
7f1a7cfd2d
commit
45830472c1
10 changed files with 211 additions and 131 deletions
|
@ -21,17 +21,6 @@ namespace ams {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool SaveSystemStateForDebug = false;
|
constexpr bool SaveSystemStateForDebug = false;
|
||||||
constexpr bool LogSystemStateForDebug = false;
|
|
||||||
|
|
||||||
void LogU64(u64 value) {
|
|
||||||
char buffer[2 * sizeof(value)];
|
|
||||||
for (size_t i = 0; i < sizeof(value); ++i) {
|
|
||||||
buffer[sizeof(buffer) - 1 - (2 * i) - 0] = "0123456789ABCDEF"[(value >> 0) & 0xF];
|
|
||||||
buffer[sizeof(buffer) - 1 - (2 * i) - 1] = "0123456789ABCDEF"[(value >> 4) & 0xF];
|
|
||||||
value >>= 8;
|
|
||||||
}
|
|
||||||
log::SendText(buffer, sizeof(buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,57 +103,6 @@ namespace ams::secmon {
|
||||||
util::WaitMicroSeconds(1000);
|
util::WaitMicroSeconds(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void LogSystemStateForDebugErrorReboot(u64 lr, u64 sp) {
|
|
||||||
log::SendText("*** Error Reboot ***\n", 21);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
u64 temp_reg;
|
|
||||||
|
|
||||||
__asm__ __volatile__("mrs %0, esr_el3" : "=r"(temp_reg) :: "memory");
|
|
||||||
log::SendText("ESR_EL3: ", 9);
|
|
||||||
LogU64(temp_reg);
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
__asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory");
|
|
||||||
log::SendText("ELR_EL3: ", 9);
|
|
||||||
LogU64(temp_reg);
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
__asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory");
|
|
||||||
log::SendText("FAR_EL3: ", 9);
|
|
||||||
LogU64(temp_reg);
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
log::SendText("LR: ", 9);
|
|
||||||
LogU64(lr);
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
log::SendText("SP: ", 9);
|
|
||||||
LogU64(sp);
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
log::SendText("Stack:\n", 7);
|
|
||||||
log::Flush();
|
|
||||||
|
|
||||||
char buf[2];
|
|
||||||
for (int i = 0; i < 0x100; ++i) {
|
|
||||||
const u8 byte = *(volatile u8 *)(sp + i);
|
|
||||||
buf[0] = "0123456789ABCDEF"[(byte >> 4) & 0xF];
|
|
||||||
buf[1] = "0123456789ABCDEF"[(byte >> 0) & 0xF];
|
|
||||||
log::SendText(buf, 2);
|
|
||||||
log::Flush();
|
|
||||||
if (util::IsAligned(i + 1, 0x10)) {
|
|
||||||
log::SendText("\n", 1);
|
|
||||||
log::Flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetError(pkg1::ErrorInfo info) {
|
void SetError(pkg1::ErrorInfo info) {
|
||||||
|
@ -181,14 +119,6 @@ namespace ams::secmon {
|
||||||
SaveSystemStateForDebugErrorReboot();
|
SaveSystemStateForDebugErrorReboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (LogSystemStateForDebug) {
|
|
||||||
u64 lr, sp;
|
|
||||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
|
||||||
__asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory");
|
|
||||||
|
|
||||||
LogSystemStateForDebugErrorReboot(lr, sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lockout the security engine. */
|
/* Lockout the security engine. */
|
||||||
se::Lockout();
|
se::Lockout();
|
||||||
|
|
||||||
|
|
|
@ -163,22 +163,22 @@ vector_entry irq_a64
|
||||||
check_vector_size irq_a64
|
check_vector_size irq_a64
|
||||||
|
|
||||||
vector_entry fiq_a64
|
vector_entry fiq_a64
|
||||||
/* Save X29, X30. */
|
/* Save x18, x26-x30. */
|
||||||
stp x29, x30, [sp, #-0x10]!
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
|
||||||
/* Get the current core ID, ensure it's core 3. */
|
|
||||||
mrs x29, mpidr_el1
|
|
||||||
and x29, x29, #3
|
|
||||||
cmp x29, #3
|
|
||||||
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
|
||||||
|
|
||||||
/* Save x26-x28, x18. */
|
|
||||||
stp x28, x18, [sp, #-0x10]!
|
stp x28, x18, [sp, #-0x10]!
|
||||||
stp x26, x27, [sp, #-0x10]!
|
stp x26, x27, [sp, #-0x10]!
|
||||||
|
|
||||||
/* Set x18 to the global data region. */
|
/* Set x18 to the global data region. */
|
||||||
ldr x18, =0x1F01FA000
|
ldr x18, =0x1F01FA000
|
||||||
|
|
||||||
|
/* Get the current core. */
|
||||||
|
mrs x29, mpidr_el1
|
||||||
|
and x29, x29, #3
|
||||||
|
|
||||||
|
/* If we're not on core 3, take the core0-2 handler. */
|
||||||
|
cmp x29, #3
|
||||||
|
b.ne _ZN3ams6secmon25HandleFiqExceptionCore012Ev
|
||||||
|
|
||||||
/* Handle the fiq exception. */
|
/* Handle the fiq exception. */
|
||||||
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
||||||
|
|
||||||
|
@ -326,7 +326,41 @@ _ZN3ams6secmon18HandleFiqExceptionEv:
|
||||||
vector_entry serror_a32
|
vector_entry serror_a32
|
||||||
/* An unexpected exception was taken. */
|
/* An unexpected exception was taken. */
|
||||||
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
|
||||||
check_vector_size serror_a32
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
_ZN3ams6secmon25HandleFiqExceptionCore012Ev:
|
||||||
|
/* Acquire exclusive access to the common smc stack. */
|
||||||
|
stp x4, x5, [sp, #-0x10]!
|
||||||
|
stp x2, x3, [sp, #-0x10]!
|
||||||
|
stp x0, x1, [sp, #-0x10]!
|
||||||
|
bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv
|
||||||
|
ldp x0, x1, [sp], #0x10
|
||||||
|
ldp x2, x3, [sp], #0x10
|
||||||
|
ldp x4, x5, [sp], #0x10
|
||||||
|
|
||||||
|
/* Pivot to use the common smc stack. */
|
||||||
|
mov x30, sp
|
||||||
|
ldr x29, =0x1F01F6E80
|
||||||
|
mov sp, x29
|
||||||
|
stp x29, x30, [sp, #-0x10]!
|
||||||
|
|
||||||
|
/* Handle the fiq exception. */
|
||||||
|
bl _ZN3ams6secmon18HandleFiqExceptionEv
|
||||||
|
|
||||||
|
/* Restore our core-specific stack. */
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
mov sp, x30
|
||||||
|
|
||||||
|
/* Release our exclusive access to the common smc stack. */
|
||||||
|
stp x0, x1, [sp, #-0x10]!
|
||||||
|
bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
|
||||||
|
ldp x0, x1, [sp], #0x10
|
||||||
|
|
||||||
|
/* Return. */
|
||||||
|
ldp x26, x27, [sp], #0x10
|
||||||
|
ldp x28, x18, [sp], #0x10
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
eret
|
||||||
|
|
||||||
/* Instantiate the literal pool for the exception vectors. */
|
/* Instantiate the literal pool for the exception vectors. */
|
||||||
.ltorg
|
.ltorg
|
||||||
|
|
|
@ -25,14 +25,16 @@ namespace ams::secmon {
|
||||||
|
|
||||||
constinit InterruptHandler g_handlers[InterruptHandlersMax] = {};
|
constinit InterruptHandler g_handlers[InterruptHandlersMax] = {};
|
||||||
constinit int g_interrupt_ids[InterruptHandlersMax] = {};
|
constinit int g_interrupt_ids[InterruptHandlersMax] = {};
|
||||||
|
constinit u8 g_interrupt_core_masks[InterruptHandlersMax] = {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInterruptHandler(int interrupt_id, InterruptHandler handler) {
|
void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler) {
|
||||||
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||||
if (g_interrupt_ids[i] == 0) {
|
if (g_interrupt_ids[i] == 0) {
|
||||||
g_interrupt_ids[i] = interrupt_id;
|
g_interrupt_ids[i] = interrupt_id;
|
||||||
g_handlers[i] = handler;
|
g_handlers[i] = handler;
|
||||||
|
g_interrupt_core_masks[i] = core_mask;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +53,9 @@ namespace ams::secmon {
|
||||||
/* Check each handler. */
|
/* Check each handler. */
|
||||||
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
for (int i = 0; i < InterruptHandlersMax; ++i) {
|
||||||
if (g_interrupt_ids[i] == interrupt_id) {
|
if (g_interrupt_ids[i] == interrupt_id) {
|
||||||
|
/* Validate that we can invoke the handler. */
|
||||||
|
AMS_ABORT_UNLESS((g_interrupt_core_masks[i] & (1u << hw::GetCurrentCoreId())) != 0);
|
||||||
|
|
||||||
/* Invoke the handler. */
|
/* Invoke the handler. */
|
||||||
g_handlers[i]();
|
g_handlers[i]();
|
||||||
gic::SetEndOfInterrupt(interrupt_id);
|
gic::SetEndOfInterrupt(interrupt_id);
|
||||||
|
|
|
@ -20,6 +20,6 @@ namespace ams::secmon {
|
||||||
|
|
||||||
using InterruptHandler = void (*)();
|
using InterruptHandler = void (*)();
|
||||||
|
|
||||||
void SetInterruptHandler(int interrupt_id, InterruptHandler handler);
|
void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
90
exosphere/program/source/secmon_mariko_fatal_error.cpp
Normal file
90
exosphere/program/source/secmon_mariko_fatal_error.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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 "secmon_cpu_context.hpp"
|
||||||
|
#include "secmon_map.hpp"
|
||||||
|
#include "secmon_page_mapper.hpp"
|
||||||
|
#include "secmon_mariko_fatal_error.hpp"
|
||||||
|
#include "smc/secmon_smc_power_management.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constinit u8 g_fatal_error_mask = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMarikoFatalErrorInterrupt() {
|
||||||
|
/* This interrupt handler doesn't return, so mark that we're at end of interrupt. */
|
||||||
|
gic::SetEndOfInterrupt(MarikoFatalErrorInterruptId);
|
||||||
|
|
||||||
|
/* Get the current core id. */
|
||||||
|
const auto core_id = hw::GetCurrentCoreId();
|
||||||
|
|
||||||
|
/* Set that we received the fatal on the current core. */
|
||||||
|
g_fatal_error_mask |= (1u << core_id);
|
||||||
|
hw::FlushDataCache(std::addressof(g_fatal_error_mask), sizeof(g_fatal_error_mask));
|
||||||
|
hw::DataSynchronizationBarrier();
|
||||||
|
|
||||||
|
/* If not all cores have received the fatal, we need to trigger the interrupt on other cores. */
|
||||||
|
if (g_fatal_error_mask != (1u << NumCores) - 1) {
|
||||||
|
|
||||||
|
/* Configure and send the interrupt to the next core. */
|
||||||
|
const auto next_core = __builtin_ctz(~g_fatal_error_mask);
|
||||||
|
gic::SetSpiTargetCpu(MarikoFatalErrorInterruptId, (1u << next_core));
|
||||||
|
gic::SetPending(MarikoFatalErrorInterruptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If current core is not 3, kill ourselves. */
|
||||||
|
if (core_id != NumCores - 1) {
|
||||||
|
smc::PowerOffCpu();
|
||||||
|
} else {
|
||||||
|
/* Wait for all cores to kill themselves. */
|
||||||
|
while (g_fatal_error_mask != (1u << NumCores) - 1) {
|
||||||
|
util::WaitMicroSeconds(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the fatal error context to mariko tzram. */
|
||||||
|
{
|
||||||
|
/* Map the iram page. */
|
||||||
|
constexpr uintptr_t FatalErrorPhysicalAddress = MemoryRegionPhysicalIramFatalErrorContext.GetAddress();
|
||||||
|
AtmosphereIramPageMapper mapper(FatalErrorPhysicalAddress);
|
||||||
|
if (mapper.Map()) {
|
||||||
|
/* Copy the fatal error context. */
|
||||||
|
void *dst = MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<void>();
|
||||||
|
const void *src = mapper.GetPointerTo(FatalErrorPhysicalAddress, sizeof(ams::impl::FatalErrorContext));
|
||||||
|
std::memcpy(dst, src, sizeof(ams::impl::FatalErrorContext));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map Dram for the mariko program. */
|
||||||
|
MapDramForMarikoProgram();
|
||||||
|
|
||||||
|
AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal.");
|
||||||
|
AMS_LOG_FLUSH();
|
||||||
|
|
||||||
|
/* Jump to the mariko fatal program. */
|
||||||
|
reinterpret_cast<void (*)()>(secmon::MemoryRegionVirtualTzramMarikoProgram.GetAddress())();
|
||||||
|
|
||||||
|
/* The mariko fatal program never returns. */
|
||||||
|
__builtin_unreachable();
|
||||||
|
|
||||||
|
AMS_INFINITE_LOOP();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
exosphere/program/source/secmon_mariko_fatal_error.hpp
Normal file
25
exosphere/program/source/secmon_mariko_fatal_error.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon {
|
||||||
|
|
||||||
|
constexpr inline int MarikoFatalErrorInterruptId = 198;
|
||||||
|
|
||||||
|
NORETURN void HandleMarikoFatalErrorInterrupt();
|
||||||
|
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
#include "secmon_error.hpp"
|
#include "secmon_error.hpp"
|
||||||
#include "secmon_map.hpp"
|
#include "secmon_map.hpp"
|
||||||
#include "secmon_cpu_context.hpp"
|
#include "secmon_cpu_context.hpp"
|
||||||
|
#include "secmon_mariko_fatal_error.hpp"
|
||||||
#include "secmon_interrupt_handler.hpp"
|
#include "secmon_interrupt_handler.hpp"
|
||||||
#include "secmon_misc.hpp"
|
#include "secmon_misc.hpp"
|
||||||
#include "smc/secmon_random_cache.hpp"
|
#include "smc/secmon_random_cache.hpp"
|
||||||
|
@ -1082,25 +1083,36 @@ namespace ams::secmon {
|
||||||
|
|
||||||
/* Setup the security engine interrupt. */
|
/* Setup the security engine interrupt. */
|
||||||
constexpr int SecurityEngineInterruptId = 90;
|
constexpr int SecurityEngineInterruptId = 90;
|
||||||
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
|
constexpr u8 SecurityEngineInterruptCoreMask = (1 << 3);
|
||||||
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
|
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
|
||||||
gic::SetEnable (SecurityEngineInterruptId, true);
|
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
|
||||||
gic::SetSpiTargetCpu (SecurityEngineInterruptId, (1 << 3));
|
gic::SetEnable (SecurityEngineInterruptId, true);
|
||||||
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
|
gic::SetSpiTargetCpu (SecurityEngineInterruptId, SecurityEngineInterruptCoreMask);
|
||||||
|
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
|
||||||
|
|
||||||
/* Setup the activity monitor interrupt. */
|
/* Setup the activity monitor interrupt. */
|
||||||
constexpr int ActivityMonitorInterruptId = 77;
|
constexpr int ActivityMonitorInterruptId = 77;
|
||||||
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
|
constexpr u8 ActivityMonitorInterruptCoreMask = (1 << 3);
|
||||||
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
|
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
|
||||||
gic::SetEnable (ActivityMonitorInterruptId, true);
|
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
|
||||||
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, (1 << 3));
|
gic::SetEnable (ActivityMonitorInterruptId, true);
|
||||||
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
|
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask);
|
||||||
|
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
|
||||||
|
|
||||||
|
/* Setup the mariko fatal error interrupt. */
|
||||||
|
constexpr u8 MarikoFatalInterruptCoreMask = 0b1111;
|
||||||
|
gic::SetPriority (MarikoFatalErrorInterruptId, gic::HighestPriority);
|
||||||
|
gic::SetInterruptGroup(MarikoFatalErrorInterruptId, 0);
|
||||||
|
gic::SetEnable (MarikoFatalErrorInterruptId, true);
|
||||||
|
gic::SetSpiTargetCpu (MarikoFatalErrorInterruptId, 0);
|
||||||
|
gic::SetSpiMode (MarikoFatalErrorInterruptId, gic::InterruptMode_Level);
|
||||||
|
|
||||||
/* If we're coldboot, perform one-time setup. */
|
/* If we're coldboot, perform one-time setup. */
|
||||||
if (g_is_cold_boot) {
|
if (g_is_cold_boot) {
|
||||||
/* Register both interrupt handlers. */
|
/* Register all interrupt handlers. */
|
||||||
SetInterruptHandler(SecurityEngineInterruptId, se::HandleInterrupt);
|
SetInterruptHandler(SecurityEngineInterruptId, SecurityEngineInterruptCoreMask, se::HandleInterrupt);
|
||||||
SetInterruptHandler(ActivityMonitorInterruptId, actmon::HandleInterrupt);
|
SetInterruptHandler(ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask, actmon::HandleInterrupt);
|
||||||
|
SetInterruptHandler(MarikoFatalErrorInterruptId, MarikoFatalInterruptCoreMask, secmon::HandleMarikoFatalErrorInterrupt);
|
||||||
|
|
||||||
/* We're expecting the other cores to come out of reset. */
|
/* We're expecting the other cores to come out of reset. */
|
||||||
for (int i = 1; i < NumCores; ++i) {
|
for (int i = 1; i < NumCores; ++i) {
|
||||||
|
|
|
@ -14,8 +14,9 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <exosphere.hpp>
|
#include <exosphere.hpp>
|
||||||
#include "secmon_map.hpp"
|
#include "secmon_cpu_context.hpp"
|
||||||
#include "secmon_page_mapper.hpp"
|
#include "secmon_page_mapper.hpp"
|
||||||
|
#include "secmon_mariko_fatal_error.hpp"
|
||||||
#include "secmon_user_power_management.hpp"
|
#include "secmon_user_power_management.hpp"
|
||||||
|
|
||||||
#include "rebootstub_bin.h"
|
#include "rebootstub_bin.h"
|
||||||
|
@ -90,34 +91,11 @@ namespace ams::secmon {
|
||||||
/* On Erista, we reboot to fatal error by jumping to fusee primary's handler. */
|
/* On Erista, we reboot to fatal error by jumping to fusee primary's handler. */
|
||||||
return PerformUserRebootToPayload();
|
return PerformUserRebootToPayload();
|
||||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
||||||
/* TODO: Send a SGI FIQ to the other CPUs, so that user code stops executing. */
|
/* Call the fatal error handler. */
|
||||||
|
HandleMarikoFatalErrorInterrupt();
|
||||||
|
|
||||||
/* TODO: On cores other than 3, halt/wfi. */
|
/* We should never get to this point. */
|
||||||
|
AMS_ABORT("Returned from Mariko Fatal handler?\n");
|
||||||
/* Copy the fatal error context to mariko tzram. */
|
|
||||||
{
|
|
||||||
/* Map the iram page. */
|
|
||||||
constexpr uintptr_t FatalErrorPhysicalAddress = MemoryRegionPhysicalIramFatalErrorContext.GetAddress();
|
|
||||||
AtmosphereIramPageMapper mapper(FatalErrorPhysicalAddress);
|
|
||||||
if (mapper.Map()) {
|
|
||||||
/* Copy the fatal error context. */
|
|
||||||
void *dst = MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<void>();
|
|
||||||
const void *src = mapper.GetPointerTo(FatalErrorPhysicalAddress, sizeof(ams::impl::FatalErrorContext));
|
|
||||||
std::memcpy(dst, src, sizeof(ams::impl::FatalErrorContext));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map Dram for the mariko program. */
|
|
||||||
MapDramForMarikoProgram();
|
|
||||||
|
|
||||||
AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal.");
|
|
||||||
AMS_LOG_FLUSH();
|
|
||||||
|
|
||||||
/* Jump to the mariko fatal program. */
|
|
||||||
reinterpret_cast<void (*)()>(secmon::MemoryRegionVirtualTzramMarikoProgram.GetAddress())();
|
|
||||||
|
|
||||||
/* The mariko fatal program never returns. */
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace ams::secmon::smc {
|
||||||
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
|
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerOffCpu() {
|
void PowerOffCpuImpl() {
|
||||||
/* Get the current core id. */
|
/* Get the current core id. */
|
||||||
const auto core_id = hw::GetCurrentCoreId();
|
const auto core_id = hw::GetCurrentCoreId();
|
||||||
|
|
||||||
|
@ -503,9 +503,7 @@ namespace ams::secmon::smc {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmcResult SmcPowerOffCpu(SmcArguments &args) {
|
void PowerOffCpu() {
|
||||||
AMS_UNUSED(args);
|
|
||||||
|
|
||||||
/* Get the current core id. */
|
/* Get the current core id. */
|
||||||
const auto core_id = hw::GetCurrentCoreId();
|
const auto core_id = hw::GetCurrentCoreId();
|
||||||
|
|
||||||
|
@ -514,15 +512,21 @@ namespace ams::secmon::smc {
|
||||||
|
|
||||||
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
|
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
|
||||||
if (core_id == NumCores - 1) {
|
if (core_id == NumCores - 1) {
|
||||||
PowerOffCpu();
|
PowerOffCpuImpl();
|
||||||
} else {
|
} else {
|
||||||
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpu);
|
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This code will never be reached. */
|
/* This code will never be reached. */
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SmcResult SmcPowerOffCpu(SmcArguments &args) {
|
||||||
|
AMS_UNUSED(args);
|
||||||
|
|
||||||
|
PowerOffCpu();
|
||||||
|
}
|
||||||
|
|
||||||
SmcResult SmcPowerOnCpu(SmcArguments &args) {
|
SmcResult SmcPowerOnCpu(SmcArguments &args) {
|
||||||
/* Get and validate the core to power on. */
|
/* Get and validate the core to power on. */
|
||||||
const int which_core = args.r[1];
|
const int which_core = args.r[1];
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
namespace ams::secmon::smc {
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
|
NORETURN void PowerOffCpu();
|
||||||
|
|
||||||
SmcResult SmcPowerOffCpu(SmcArguments &args);
|
SmcResult SmcPowerOffCpu(SmcArguments &args);
|
||||||
SmcResult SmcPowerOnCpu(SmcArguments &args);
|
SmcResult SmcPowerOnCpu(SmcArguments &args);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue