mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-31 14:58:22 -04:00
exo2: implement SmcGetConfig
This commit is contained in:
parent
e3eadcd2e3
commit
6bf283ec2e
15 changed files with 640 additions and 45 deletions
|
@ -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