mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-24 11:46:58 -04:00
exo2: implement SmcGetConfig
This commit is contained in:
parent
e3eadcd2e3
commit
6bf283ec2e
15 changed files with 640 additions and 45 deletions
|
@ -36,6 +36,8 @@ namespace ams::diag {
|
|||
}
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x50) = 0x02;
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x00) = 0x10;
|
||||
|
||||
util::WaitMicroSeconds(1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -67,8 +69,8 @@ namespace ams::secmon {
|
|||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x0C) = static_cast<u32>(temp_reg >> 32);
|
||||
|
||||
__asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory");
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x18) = static_cast<u32>(temp_reg >> 0);
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x1C) = static_cast<u32>(temp_reg >> 32);
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x10) = static_cast<u32>(temp_reg >> 0);
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x14) = static_cast<u32>(temp_reg >> 32);
|
||||
|
||||
__asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory");
|
||||
*(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x18) = static_cast<u32>(temp_reg >> 0);
|
||||
|
|
|
@ -211,7 +211,7 @@ _ZN3ams6secmon25HandleSmcExceptionCore012Ev:
|
|||
|
||||
/* Restore our core-specific stack. */
|
||||
ldp x29, x30, [sp], #0x10
|
||||
mov x30, sp
|
||||
mov sp, x30
|
||||
|
||||
/* Release our exclusive access to the common smc stack. */
|
||||
stp x0, x1, [sp, #-0x10]!
|
||||
|
|
|
@ -23,11 +23,18 @@ namespace ams::secmon {
|
|||
constinit pkg1::BctParameters g_bct_params = {};
|
||||
constinit se::Sha256Hash g_package2_hash = {};
|
||||
|
||||
constinit u32 g_deprecated_boot_reason_value = {};
|
||||
constinit u8 g_deprecated_boot_reason_state = {};
|
||||
|
||||
}
|
||||
|
||||
void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params) {
|
||||
/* Save the BCT parameters. */
|
||||
g_bct_params = secmon_params.bct_params;
|
||||
|
||||
/* Save the deprecated boot reason. */
|
||||
g_deprecated_boot_reason_value = secmon_params.deprecated_boot_reason_value;
|
||||
g_deprecated_boot_reason_state = secmon_params.deprecated_boot_reason_state;
|
||||
}
|
||||
|
||||
bool IsRecoveryBoot() {
|
||||
|
@ -52,4 +59,8 @@ namespace ams::secmon {
|
|||
g_package2_hash = hash;
|
||||
}
|
||||
|
||||
u32 GetDeprecatedBootReason() {
|
||||
return (static_cast<u32>(g_deprecated_boot_reason_state) << 24) | (g_deprecated_boot_reason_value & 0x00FFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,4 +29,6 @@ namespace ams::secmon {
|
|||
void GetPackage2Hash(se::Sha256Hash *out);
|
||||
void SetPackage2Hash(const se::Sha256Hash &hash);
|
||||
|
||||
u32 GetDeprecatedBootReason();
|
||||
|
||||
}
|
|
@ -128,7 +128,7 @@ namespace ams::secmon::smc {
|
|||
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
|
||||
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
|
||||
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
|
||||
{ 0xC3000002, Restriction_Normal, SmcGetConfigKern },
|
||||
{ 0xC3000004, Restriction_Normal, SmcGetConfigKern },
|
||||
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
|
||||
{ 0xC3000006, Restriction_Normal, SmcShowError },
|
||||
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
|
||||
|
@ -240,6 +240,17 @@ namespace ams::secmon::smc {
|
|||
*(volatile u32 *)(MemoryRegionVirtualDevicePmc.GetAddress() + 0x50) = 0x02;
|
||||
*(volatile u32 *)(MemoryRegionVirtualDevicePmc.GetAddress() + 0x00) = 0x10;
|
||||
|
||||
util::WaitMicroSeconds(1000);
|
||||
}
|
||||
if (args.r[0] != static_cast<u64>(SmcResult::Success)) {
|
||||
*(volatile u32 *)(MemoryRegionVirtualDebug.GetAddress()) = 0xCCCCCCCC;
|
||||
*(volatile u32 *)(MemoryRegionVirtualDebug.GetAddress() + 0x10) = static_cast<u32>(info.function_id);
|
||||
for (size_t i = 0; i < sizeof(args) / sizeof(u32); ++i) {
|
||||
((volatile u32 *)(MemoryRegionVirtualDebug.GetAddress() + 0x20))[i] = reinterpret_cast<u32 *>(std::addressof(args))[i];
|
||||
}
|
||||
*(volatile u32 *)(MemoryRegionVirtualDevicePmc.GetAddress() + 0x50) = 0x02;
|
||||
*(volatile u32 *)(MemoryRegionVirtualDevicePmc.GetAddress() + 0x00) = 0x10;
|
||||
|
||||
util::WaitMicroSeconds(1000);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -15,18 +15,272 @@
|
|||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "../secmon_error.hpp"
|
||||
#include "../secmon_misc.hpp"
|
||||
#include "secmon_smc_info.hpp"
|
||||
#include "secmon_smc_power_management.hpp"
|
||||
|
||||
namespace ams::secmon::smc {
|
||||
|
||||
namespace {
|
||||
|
||||
struct KernelConfiguration {
|
||||
/* Secure Monitor view. */
|
||||
using Flags1 = util::BitPack32::Field< 0, 8>;
|
||||
using Flags0 = util::BitPack32::Field< 8, 8>;
|
||||
using PhysicalMemorySize = util::BitPack32::Field<16, 2>;
|
||||
|
||||
/* Kernel view, from libmesosphere. */
|
||||
using DebugFillMemory = util::BitPack32::Field<0, 1, bool>;
|
||||
using EnableUserExceptionHandlers = util::BitPack32::Field<DebugFillMemory::Next, 1, bool>;
|
||||
using EnableUserPmuAccess = util::BitPack32::Field<EnableUserExceptionHandlers::Next, 1, bool>;
|
||||
using IncreaseThreadResourceLimit = util::BitPack32::Field<EnableUserPmuAccess::Next, 1, bool>;
|
||||
using Reserved4 = util::BitPack32::Field<IncreaseThreadResourceLimit::Next, 4, u32>;
|
||||
using UseSecureMonitorPanicCall = util::BitPack32::Field<Reserved4::Next, 1, bool>;
|
||||
using Reserved9 = util::BitPack32::Field<UseSecureMonitorPanicCall::Next, 7, u32>;
|
||||
using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, u32>; /* smc::MemorySize = pkg1::MemorySize */
|
||||
};
|
||||
|
||||
constexpr const pkg1::MemorySize DramIdToMemorySize[fuse::DramId_Count] = {
|
||||
[fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_CopperSamsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
|
||||
[fuse::DramId_CopperHynix4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_CopperMicron4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung8GB] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_IowaHynix4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaMicron4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagSamsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagSamsung8GB] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_HoagHynix4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagMicron4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung4GBY] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y4GBX] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y8GBX] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_HoagSamsung1y4GBX] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y4GBY] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y8GBY] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_IowaSamsung1y4GBA] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_FiveSamsung1y8GBX] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_FiveSamsung1y4GBX] = pkg1::MemorySize_4GB,
|
||||
};
|
||||
|
||||
constexpr const pkg1::MemoryMode MemoryModes[] = {
|
||||
pkg1::MemoryMode_Auto,
|
||||
|
||||
pkg1::MemoryMode_4GB,
|
||||
pkg1::MemoryMode_4GBAppletDev,
|
||||
pkg1::MemoryMode_4GBSystemDev,
|
||||
|
||||
pkg1::MemoryMode_6GB,
|
||||
pkg1::MemoryMode_6GBAppletDev,
|
||||
|
||||
pkg1::MemoryMode_8GB,
|
||||
};
|
||||
|
||||
constexpr bool IsValidMemoryMode(pkg1::MemoryMode mode) {
|
||||
for (const auto known_mode : MemoryModes) {
|
||||
if (mode == known_mode) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pkg1::MemoryMode SanitizeMemoryMode(pkg1::MemoryMode mode) {
|
||||
if (IsValidMemoryMode(mode)) {
|
||||
return mode;
|
||||
}
|
||||
return pkg1::MemoryMode_Auto;
|
||||
}
|
||||
|
||||
pkg1::MemorySize GetPhysicalMemorySize() {
|
||||
const auto dram_id = fuse::GetDramId();
|
||||
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
|
||||
return DramIdToMemorySize[dram_id];
|
||||
}
|
||||
|
||||
pkg1::MemorySize GetAvailableMemorySize(pkg1::MemorySize size) {
|
||||
return std::min(GetPhysicalMemorySize(), size);
|
||||
}
|
||||
|
||||
pkg1::MemoryMode GetMemoryMode(pkg1::MemoryMode mode) {
|
||||
/* Sanitize the mode. */
|
||||
mode = SanitizeMemoryMode(mode);
|
||||
|
||||
/* If the mode is auto, construct the memory mode. */
|
||||
if (mode == pkg1::MemoryMode_Auto) {
|
||||
return pkg1::MakeMemoryMode(GetPhysicalMemorySize(), pkg1::MemoryArrange_Normal);
|
||||
} else {
|
||||
const auto mode_size = GetMemorySize(mode);
|
||||
const auto mode_arrange = GetMemoryArrange(mode);
|
||||
const auto size = GetAvailableMemorySize(mode_size);
|
||||
const auto arrange = (size == mode_size) ? mode_arrange : pkg1::MemoryArrange_Normal;
|
||||
return pkg1::MakeMemoryMode(size, arrange);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetMemoryMode() {
|
||||
/* Unless development function is enabled, we're 4 GB. */
|
||||
u32 memory_mode = pkg1::MemoryMode_4GB;
|
||||
|
||||
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
|
||||
memory_mode = GetMemoryMode(bcd.GetMemoryMode());
|
||||
}
|
||||
|
||||
return memory_mode;
|
||||
}
|
||||
|
||||
u32 GetKernelConfiguration() {
|
||||
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
|
||||
util::BitPack32 value = {};
|
||||
|
||||
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
|
||||
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
|
||||
|
||||
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
|
||||
value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0());
|
||||
}
|
||||
|
||||
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
|
||||
|
||||
/* Exosphere extensions. */
|
||||
const auto &sc = GetSecmonConfiguration();
|
||||
|
||||
if (!sc.DisableUserModeExceptionHandlers()) {
|
||||
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
|
||||
}
|
||||
|
||||
if (sc.EnableUserModePerformanceCounterAccess()) {
|
||||
value.Set<KernelConfiguration::EnableUserPmuAccess>(true);
|
||||
}
|
||||
|
||||
return value.value;
|
||||
}
|
||||
|
||||
SmcResult GetConfig(SmcArguments &args, bool kern) {
|
||||
switch (static_cast<ConfigItem>(args.r[1])) {
|
||||
case ConfigItem::DisableProgramVerification:
|
||||
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
|
||||
break;
|
||||
case ConfigItem::DramId:
|
||||
args.r[1] = fuse::GetDramId();
|
||||
break;
|
||||
case ConfigItem::SecurityEngineInterruptNumber:
|
||||
args.r[1] = SecurityEngineUserInterruptId;
|
||||
break;
|
||||
case ConfigItem::FuseVersion:
|
||||
args.r[1] = fuse::GetExpectedFuseVersion(GetTargetFirmware());
|
||||
break;
|
||||
case ConfigItem::HardwareType:
|
||||
args.r[1] = fuse::GetHardwareType();
|
||||
break;
|
||||
case ConfigItem::HardwareState:
|
||||
args.r[1] = fuse::GetHardwareState();
|
||||
break;
|
||||
case ConfigItem::IsRecoveryBoot:
|
||||
args.r[1] = IsRecoveryBoot();
|
||||
break;
|
||||
case ConfigItem::DeviceId:
|
||||
args.r[1] = fuse::GetDeviceId();
|
||||
break;
|
||||
case ConfigItem::BootReason:
|
||||
{
|
||||
/* This was removed in firmware 4.0.0. */
|
||||
if (GetTargetFirmware() >= TargetFirmware_4_0_0) {
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
|
||||
args.r[1] = GetDeprecatedBootReason();
|
||||
}
|
||||
break;
|
||||
case ConfigItem::MemoryMode:
|
||||
args.r[1] = GetMemoryMode();
|
||||
break;
|
||||
case ConfigItem::IsDevelopmentFunctionEnabled:
|
||||
args.r[1] = GetSecmonConfiguration().IsDevelopmentFunctionEnabled(kern) || GetBootConfig().data.IsDevelopmentFunctionEnabled();
|
||||
break;
|
||||
case ConfigItem::KernelConfiguration:
|
||||
args.r[1] = GetKernelConfiguration();
|
||||
break;
|
||||
case ConfigItem::IsChargerHiZModeEnabled:
|
||||
args.r[1] = IsChargerHiZModeEnabled();
|
||||
break;
|
||||
case ConfigItem::QuestState:
|
||||
args.r[1] = fuse::GetQuestState();
|
||||
break;
|
||||
case ConfigItem::RegulatorType:
|
||||
args.r[1] = fuse::GetRegulator();
|
||||
break;
|
||||
case ConfigItem::DeviceUniqueKeyGeneration:
|
||||
args.r[1] = fuse::GetDeviceUniqueKeyGeneration();
|
||||
break;
|
||||
case ConfigItem::Package2Hash:
|
||||
{
|
||||
/* Only allow getting the package2 hash in recovery boot. */
|
||||
if (!IsRecoveryBoot()) {
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
|
||||
/* Get the hash. */
|
||||
se::Sha256Hash tmp_hash;
|
||||
GetPackage2Hash(std::addressof(tmp_hash));
|
||||
|
||||
/* Copy it out. */
|
||||
static_assert(sizeof(args) - sizeof(args.r[0]) >= sizeof(tmp_hash));
|
||||
std::memcpy(std::addressof(args.r[1]), std::addressof(tmp_hash), sizeof(tmp_hash));
|
||||
}
|
||||
break;
|
||||
case ConfigItem::ExosphereApiVersion:
|
||||
/* Get information about the current exosphere version. */
|
||||
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
|
||||
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
|
||||
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
|
||||
(static_cast<u64>(GetKeyGeneration()) << 32) |
|
||||
(static_cast<u64>(GetTargetFirmware()) << 00);
|
||||
break;
|
||||
case ConfigItem::ExosphereNeedsReboot:
|
||||
/* We are executing, so we aren't in the process of rebooting. */
|
||||
args.r[1] = 0;
|
||||
break;
|
||||
case ConfigItem::ExosphereNeedsShutdown:
|
||||
/* We are executing, so we aren't in the process of shutting down. */
|
||||
args.r[1] = 0;
|
||||
break;
|
||||
case ConfigItem::ExosphereGitCommitHash:
|
||||
/* Get information about the current exosphere git commit hash. */
|
||||
args.r[1] = ATMOSPHERE_GIT_HASH;
|
||||
break;
|
||||
case ConfigItem::ExosphereHasRcmBugPatch:
|
||||
/* Get information about whether this unit has the RCM bug patched. */
|
||||
args.r[1] = fuse::HasRcmVulnerabilityPatch();
|
||||
break;
|
||||
case ConfigItem::ExosphereBlankProdInfo:
|
||||
/* Get whether this unit should simulate a "blanked" PRODINFO. */
|
||||
args.r[1] = GetSecmonConfiguration().ShouldUseBlankCalibrationBinary();
|
||||
break;
|
||||
case ConfigItem::ExosphereAllowCalWrites:
|
||||
/* Get whether this unit should allow writing to the calibration partition. */
|
||||
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc());
|
||||
break;
|
||||
default:
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
|
||||
return SmcResult::Success;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SmcResult SmcGetConfigUser(SmcArguments &args) {
|
||||
/* TODO */
|
||||
return SmcResult::NotImplemented;
|
||||
return GetConfig(args, false);
|
||||
}
|
||||
|
||||
SmcResult SmcGetConfigKern(SmcArguments &args) {
|
||||
/* TODO */
|
||||
return SmcResult::NotImplemented;
|
||||
return GetConfig(args, true);
|
||||
}
|
||||
|
||||
SmcResult SmcSetConfig(SmcArguments &args) {
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace ams::secmon::smc {
|
|||
IsDevelopmentFunctionEnabled = 11,
|
||||
KernelConfiguration = 12,
|
||||
IsChargerHiZModeEnabled = 13,
|
||||
IsQuest = 14,
|
||||
QuestState = 14,
|
||||
RegulatorType = 15,
|
||||
DeviceUniqueKeyGeneration = 16,
|
||||
Package2Hash = 17,
|
||||
|
|
|
@ -24,9 +24,7 @@ namespace ams::secmon::smc {
|
|||
template<size_t N>
|
||||
constexpr void SetRegisterTableAllowed(std::array<u8, N> &arr, uintptr_t reg) {
|
||||
/* All registers should be four byte aligned. */
|
||||
if (reg % sizeof(u32) != 0) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
AMS_ASSUME(reg % sizeof(u32) == 0);
|
||||
|
||||
/* Reduce the register to an index. */
|
||||
reg /= sizeof(u32);
|
||||
|
@ -36,24 +34,18 @@ namespace ams::secmon::smc {
|
|||
const auto mask = (1u << (reg % BITSIZEOF(u8)));
|
||||
|
||||
/* Check that the permission bit isn't already set. */
|
||||
if ((arr[index] & mask) != 0) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
AMS_ASSUME((arr[index] & mask) == 0);
|
||||
|
||||
/* Set the permission bit. */
|
||||
arr[index] |= mask;
|
||||
|
||||
/* Ensure that indices are set in sorted order. */
|
||||
for (auto i = (reg % BITSIZEOF(u8)) + 1; i < 8; ++i) {
|
||||
if ((arr[index] & (1u << i)) != 0) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
AMS_ASSUME((arr[index] & (1u << i)) == 0);
|
||||
}
|
||||
|
||||
for (auto i = index + 1; i < arr.size(); ++i) {
|
||||
if (arr[i] != 0) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
AMS_ASSUME(arr[i] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +64,7 @@ namespace ams::secmon::smc {
|
|||
}
|
||||
|
||||
/* All empty perm table is disallowed. */
|
||||
__builtin_unreachable();
|
||||
AMS_ASSUME(false);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue