mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00: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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -80,7 +80,9 @@ else
|
|||
export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD)-dirty
|
||||
endif
|
||||
|
||||
ATMOSPHERE_DEFINES += -DATMOSPHERE_GIT_BRANCH=\"$(ATMOSPHERE_GIT_BRANCH)\" -DATMOSPHERE_GIT_REVISION=\"$(ATMOSPHERE_GIT_REVISION)\"
|
||||
export ATMOSPHERE_GIT_HASH := $(shell git rev-parse --short=16 HEAD)
|
||||
|
||||
ATMOSPHERE_DEFINES += -DATMOSPHERE_GIT_BRANCH=\"$(ATMOSPHERE_GIT_BRANCH)\" -DATMOSPHERE_GIT_REVISION=\"$(ATMOSPHERE_GIT_REVISION)\" -DATMOSPHERE_GIT_HASH="0x$(ATMOSPHERE_GIT_HASH)"
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# Ensure top directory is set.
|
||||
|
|
|
@ -31,21 +31,77 @@ namespace ams::fuse {
|
|||
HardwareType_Undefined = 0xF,
|
||||
};
|
||||
|
||||
enum SocType {
|
||||
SocType_Erista = 0,
|
||||
SocType_Mariko = 1,
|
||||
SocType_Undefined = 0xF,
|
||||
};
|
||||
|
||||
enum HardwareState {
|
||||
HardwareState_Development = 0,
|
||||
HardwareState_Production = 1,
|
||||
HardwareState_Undefined = 2,
|
||||
};
|
||||
|
||||
enum DramId {
|
||||
DramId_IcosaSamsung4GB = 0,
|
||||
DramId_IcosaHynix4GB = 1,
|
||||
DramId_IcosaMicron4GB = 2,
|
||||
DramId_CopperSamsung4GB = 3,
|
||||
DramId_IcosaSamsung6GB = 4,
|
||||
DramId_CopperHynix4GB = 5,
|
||||
DramId_CopperMicron4GB = 6,
|
||||
DramId_IowaX1X2Samsung4GB = 7,
|
||||
DramId_IowaSansung4GB = 8,
|
||||
DramId_IowaSamsung8GB = 9,
|
||||
DramId_IowaHynix4GB = 10,
|
||||
DramId_IowaMicron4GB = 11,
|
||||
DramId_HoagSamsung4GB = 12,
|
||||
DramId_HoagSamsung8GB = 13,
|
||||
DramId_HoagHynix4GB = 14,
|
||||
DramId_HoagMicron4GB = 15,
|
||||
DramId_IowaSamsung4GBY = 16,
|
||||
DramId_IowaSamsung1y4GBX = 17,
|
||||
DramId_IowaSamsung1y8GBX = 18,
|
||||
DramId_HoagSamsung1y4GBX = 19,
|
||||
DramId_IowaSamsung1y4GBY = 20,
|
||||
DramId_IowaSamsung1y8GBY = 21,
|
||||
DramId_IowaSamsung1y4GBA = 22,
|
||||
DramId_FiveSamsung1y8GBX = 23,
|
||||
DramId_FiveSamsung1y4GBX = 24,
|
||||
|
||||
DramId_Count,
|
||||
};
|
||||
|
||||
enum QuestState {
|
||||
QuestState_Disabled = 0,
|
||||
QuestState_Enabled = 1,
|
||||
};
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
void SetWriteSecureOnly();
|
||||
void Lockout();
|
||||
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
void Reload();
|
||||
|
||||
u32 ReadWord(int address);
|
||||
|
||||
u32 GetOdmWord(int index);
|
||||
|
||||
DramId GetDramId();
|
||||
|
||||
void GetEcid(br::BootEcid *out);
|
||||
HardwareType GetHardwareType();
|
||||
HardwareState GetHardwareState();
|
||||
u64 GetDeviceId();
|
||||
QuestState GetQuestState();
|
||||
pmic::Regulator GetRegulator();
|
||||
void GetEcid(br::BootEcid *out);
|
||||
int GetDeviceUniqueKeyGeneration();
|
||||
|
||||
SocType GetSocType();
|
||||
int GetExpectedFuseVersion(TargetFirmware target_fw);
|
||||
bool HasRcmVulnerabilityPatch();
|
||||
|
||||
}
|
|
@ -45,7 +45,9 @@ namespace ams::pkg1 {
|
|||
u32 secmon_start_time;
|
||||
u32 secmon_end_time;
|
||||
BctParameters bct_params;
|
||||
u8 reserved[0xD8];
|
||||
u32 deprecated_boot_reason_value;
|
||||
u8 deprecated_boot_reason_state;
|
||||
u8 reserved[0xD3];
|
||||
u32 bootloader_state;
|
||||
u32 secmon_state;
|
||||
u8 reserved2[0x100];
|
||||
|
|
|
@ -45,6 +45,14 @@ namespace ams::secmon {
|
|||
EmummcType type;
|
||||
u32 id;
|
||||
u32 fs_version;
|
||||
|
||||
constexpr bool IsValid() const {
|
||||
return this->magic == Magic;
|
||||
}
|
||||
|
||||
constexpr bool IsEmummcActive() const {
|
||||
return this->IsValid() && this->type != EmummcType_None;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<EmummcBaseConfiguration>::value);
|
||||
static_assert(sizeof(EmummcBaseConfiguration) == 0x10);
|
||||
|
@ -66,6 +74,14 @@ namespace ams::secmon {
|
|||
EmummcFileConfiguration file_cfg;
|
||||
};
|
||||
EmummcFilePath emu_dir_path;
|
||||
|
||||
constexpr bool IsValid() const {
|
||||
return this->base_cfg.IsValid();
|
||||
}
|
||||
|
||||
constexpr bool IsEmummcActive() const {
|
||||
return this->base_cfg.IsEmummcActive();
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<EmummcConfiguration>::value);
|
||||
static_assert(sizeof(EmummcConfiguration) <= 0x200);
|
||||
|
|
|
@ -65,6 +65,8 @@ namespace ams::secmon {
|
|||
constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; }
|
||||
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
||||
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
||||
|
||||
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
||||
};
|
||||
static_assert(util::is_pod<SecureMonitorConfiguration>::value);
|
||||
static_assert(sizeof(SecureMonitorConfiguration) == 0x80);
|
||||
|
|
|
@ -20,6 +20,11 @@ namespace ams::fuse {
|
|||
|
||||
namespace {
|
||||
|
||||
struct OdmWord2 {
|
||||
using DeviceUniqueKeyGeneration = util::BitPack32::Field<0, 5, int>;
|
||||
using Reserved = util::BitPack32::Field<5, 27, int>;
|
||||
};
|
||||
|
||||
struct OdmWord4 {
|
||||
using HardwareState1 = util::BitPack32::Field<0, 2, int>;
|
||||
using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>;
|
||||
|
@ -52,6 +57,9 @@ namespace ams::fuse {
|
|||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFuses.GetAddress();
|
||||
|
||||
constinit bool g_checked_for_rcm_bug_patch = false;
|
||||
constinit bool g_has_rcm_bug_patch = false;
|
||||
|
||||
ALWAYS_INLINE volatile FuseRegisterRegion *GetRegisterRegion() {
|
||||
return reinterpret_cast<volatile FuseRegisterRegion *>(g_register_address);
|
||||
}
|
||||
|
@ -64,6 +72,92 @@ namespace ams::fuse {
|
|||
return GetRegisterRegion()->chip;
|
||||
}
|
||||
|
||||
bool IsIdle() {
|
||||
return reg::HasValue(GetRegisters().FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_STATE, IDLE));
|
||||
}
|
||||
|
||||
void WaitForIdle() {
|
||||
while (!IsIdle()) { /* ... */ }
|
||||
}
|
||||
|
||||
bool IsNewFuseFormat() {
|
||||
/* On mariko, this should always be true. */
|
||||
if (GetSocType() != SocType_Erista) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Require that the format version be non-zero in odm4. */
|
||||
if (util::BitPack32{GetOdmWord(4)}.Get<OdmWord4::FormatVersion>() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that odm word 0/1 are fused with the magic values. */
|
||||
constexpr u32 NewFuseFormatMagic0 = 0x8E61ECAE;
|
||||
constexpr u32 NewFuseFormatMagic1 = 0xF2BA3BB2;
|
||||
|
||||
const u32 w0 = GetOdmWord(0);
|
||||
const u32 w1 = GetOdmWord(1);
|
||||
|
||||
return w0 == NewFuseFormatMagic0 && w1 == NewFuseFormatMagic1;
|
||||
}
|
||||
|
||||
constexpr u32 CompressLotCode(u32 lot0) {
|
||||
constexpr int Radix = 36;
|
||||
constexpr int Count = 5;
|
||||
constexpr int Width = 6;
|
||||
constexpr u32 Mask = (1u << Width) - 1;
|
||||
|
||||
u32 compressed = 0;
|
||||
|
||||
for (int i = Count - 1; i >= 0; --i) {
|
||||
compressed *= Radix;
|
||||
compressed += (lot0 >> (i * Width)) & Mask;
|
||||
}
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||
TargetFirmware_10_0_0,
|
||||
TargetFirmware_9_1_0,
|
||||
TargetFirmware_9_0_0,
|
||||
TargetFirmware_8_1_0,
|
||||
TargetFirmware_7_0_0,
|
||||
TargetFirmware_6_2_0,
|
||||
TargetFirmware_6_0_0,
|
||||
TargetFirmware_5_0_0,
|
||||
TargetFirmware_4_0_0,
|
||||
TargetFirmware_3_0_2,
|
||||
TargetFirmware_3_0_0,
|
||||
TargetFirmware_2_0_0,
|
||||
TargetFirmware_1_0_0,
|
||||
};
|
||||
|
||||
constexpr inline int NumFuseIncrements = util::size(FuseVersionIncrementFirmwares);
|
||||
|
||||
/* Verify that the fuse version increment list is sorted. */
|
||||
static_assert([] {
|
||||
for (size_t i = 0; i < util::size(FuseVersionIncrementFirmwares) - 1; ++i) {
|
||||
if (FuseVersionIncrementFirmwares[i] <= FuseVersionIncrementFirmwares[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
|
||||
constexpr int GetExpectedFuseVersionImpl(TargetFirmware target_fw) {
|
||||
for (int i = 0; i < NumFuseIncrements; ++i) {
|
||||
if (target_fw >= FuseVersionIncrementFirmwares[i]) {
|
||||
return NumFuseIncrements - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static_assert(GetExpectedFuseVersionImpl(TargetFirmware_10_0_0) == 13);
|
||||
static_assert(GetExpectedFuseVersionImpl(TargetFirmware_1_0_0) == 1);
|
||||
static_assert(GetExpectedFuseVersionImpl(static_cast<TargetFirmware>(0)) == 0);
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
|
@ -78,10 +172,84 @@ namespace ams::fuse {
|
|||
reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_DISABLEREGPROGRAM_VAL, ENABLE));
|
||||
}
|
||||
|
||||
u32 ReadWord(int address) {
|
||||
/* Require that the fuse array be idle. */
|
||||
AMS_ABORT_UNLESS(IsIdle());
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto &FUSE = GetRegisters();
|
||||
|
||||
/* Write the address to read. */
|
||||
reg::Write(FUSE.FUSE_FUSEADDR, address);
|
||||
|
||||
/* Set control to read. */
|
||||
reg::ReadWrite(FUSE.FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_CMD, READ));
|
||||
|
||||
/* Wait 1 us. */
|
||||
util::WaitMicroSeconds(1);
|
||||
|
||||
/* Wait for the array to be idle. */
|
||||
WaitForIdle();
|
||||
|
||||
return reg::Read(FUSE.FUSE_FUSERDATA);
|
||||
}
|
||||
|
||||
u32 GetOdmWord(int index) {
|
||||
return GetChipRegisters().FUSE_RESERVED_ODM[index];
|
||||
}
|
||||
|
||||
void GetEcid(br::BootEcid *out) {
|
||||
/* Get the registers. */
|
||||
const volatile auto &chip = GetChipRegisters();
|
||||
|
||||
/* Read the ecid components. */
|
||||
const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE) & ((1u << 4) - 1);
|
||||
const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1);
|
||||
const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ;
|
||||
const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1) & ((1u << 28) - 1);
|
||||
const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1);
|
||||
const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1);
|
||||
const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1);
|
||||
const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED) & ((1u << 6) - 1);
|
||||
|
||||
/* Clear the output. */
|
||||
util::ClearMemory(out, sizeof(*out));
|
||||
|
||||
/* Copy the component bits. */
|
||||
out->ecid[0] = static_cast<u32>((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved));
|
||||
out->ecid[1] = static_cast<u32>((lot0 << 26) | (lot1 >> 2));
|
||||
out->ecid[2] = static_cast<u32>((fab << 26) | (lot0 >> 6));
|
||||
out->ecid[3] = static_cast<u32>(vendor);
|
||||
}
|
||||
|
||||
u64 GetDeviceId() {
|
||||
/* Get the registers. */
|
||||
const volatile auto &chip = GetChipRegisters();
|
||||
|
||||
/* Read the device id components. */
|
||||
/* NOTE: Device ID is "basically" just an alternate encoding of Ecid. */
|
||||
/* It elides lot1 (and compresses lot0), but this is fine because */
|
||||
/* lot1 is fixed-value for all fused devices. */
|
||||
const u64 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1);
|
||||
const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ;
|
||||
const u64 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1);
|
||||
const u64 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1);
|
||||
const u64 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1);
|
||||
|
||||
/* Compress lot0 down from 32-bits to 26. */
|
||||
const u64 clot0 = CompressLotCode(lot0) & ((1u << 26) - 1);
|
||||
|
||||
return (y_coord << 0) |
|
||||
(x_coord << 9) |
|
||||
(wafer << 18) |
|
||||
(clot0 << 24) |
|
||||
(fab << 50);
|
||||
}
|
||||
|
||||
DramId GetDramId() {
|
||||
return static_cast<DramId>(util::BitPack32{GetOdmWord(4)}.Get<OdmWord4::DramId>());
|
||||
}
|
||||
|
||||
HardwareType GetHardwareType() {
|
||||
/* Read the odm word. */
|
||||
const util::BitPack32 odm_word4 = { GetOdmWord(4) };
|
||||
|
@ -113,33 +281,85 @@ namespace ams::fuse {
|
|||
}
|
||||
}
|
||||
|
||||
QuestState GetQuestState() {
|
||||
return static_cast<QuestState>(util::BitPack32{GetOdmWord(4)}.Get<OdmWord4::QuestState>());
|
||||
}
|
||||
|
||||
pmic::Regulator GetRegulator() {
|
||||
/* TODO: How should mariko be handled? This reads from ODM word 28 in fuses (not presesnt in erista...). */
|
||||
/* TODO: How should mariko be handled? This reads from ODM word 28 in fuses (not present in erista...). */
|
||||
return pmic::Regulator_Erista_Max77621;
|
||||
}
|
||||
|
||||
void GetEcid(br::BootEcid *out) {
|
||||
/* Get the registers. */
|
||||
const volatile auto &chip = GetChipRegisters();
|
||||
int GetDeviceUniqueKeyGeneration() {
|
||||
if (IsNewFuseFormat()) {
|
||||
return util::BitPack32{GetOdmWord(2)}.Get<OdmWord2::DeviceUniqueKeyGeneration>();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the ecid components. */
|
||||
const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE);
|
||||
const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE);
|
||||
const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0);
|
||||
const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1);
|
||||
const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID);
|
||||
const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE);
|
||||
const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE);
|
||||
const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED);
|
||||
SocType GetSocType() {
|
||||
switch (GetHardwareType()) {
|
||||
case HardwareType_Icosa:
|
||||
case HardwareType_Copper:
|
||||
return SocType_Erista;
|
||||
case HardwareType_Iowa:
|
||||
case HardwareType_Hoag:
|
||||
case HardwareType_Calcio:
|
||||
case HardwareType_Five:
|
||||
return SocType_Mariko;
|
||||
default:
|
||||
return SocType_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the output. */
|
||||
util::ClearMemory(out, sizeof(*out));
|
||||
int GetExpectedFuseVersion(TargetFirmware target_fw) {
|
||||
return GetExpectedFuseVersionImpl(target_fw);
|
||||
}
|
||||
|
||||
/* Copy the component bits. */
|
||||
out->ecid[0] = static_cast<u32>((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved));
|
||||
out->ecid[1] = static_cast<u32>((lot0 << 26) | (lot1 >> 2));
|
||||
out->ecid[2] = static_cast<u32>((fab << 26) | (lot0 >> 6));
|
||||
out->ecid[3] = static_cast<u32>(vendor);
|
||||
bool HasRcmVulnerabilityPatch() {
|
||||
/* Only check for RCM bug patch once, and cache our result. */
|
||||
if (!g_checked_for_rcm_bug_patch) {
|
||||
do {
|
||||
/* Mariko units are necessarily patched. */
|
||||
if (fuse::GetSocType() != SocType_Erista) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some patched units use XUSB in RCM. */
|
||||
if (reg::Read(GetChipRegisters().FUSE_RESERVED_SW) & 0x80) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Other units have a proper ipatch instead. */
|
||||
u32 word_count = reg::Read(GetChipRegisters().FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
|
||||
u32 word_addr = 191;
|
||||
|
||||
while (word_count && !g_has_rcm_bug_patch) {
|
||||
u32 word0 = ReadWord(word_addr);
|
||||
u32 ipatch_count = (word0 >> 16) & 0xF;
|
||||
|
||||
for (u32 i = 0; i < ipatch_count && !g_has_rcm_bug_patch; ++i) {
|
||||
u32 word = ReadWord(word_addr - (i + 1));
|
||||
u32 addr = (word >> 16) * 2;
|
||||
|
||||
if (addr == 0x769a) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
word_addr -= word_count;
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
g_checked_for_rcm_bug_patch = true;
|
||||
}
|
||||
|
||||
return g_has_rcm_bug_patch;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -213,6 +213,31 @@ namespace ams::fuse {
|
|||
#define DEFINE_FUSE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
|
||||
#define DEFINE_FUSE_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
DEFINE_FUSE_REG_TWO_BIT_ENUM(FUSECTRL_CMD, 0, IDLE, READ, WRITE, SENSE_CTRL);
|
||||
|
||||
DEFINE_FUSE_REG(FUSECTRL_STATE, 16, 5);
|
||||
|
||||
enum FUSE_FUSECTRL_STATE {
|
||||
FUSE_FUSECTRL_STATE_RESET = 0,
|
||||
FUSE_FUSECTRL_STATE_POST_RESET = 1,
|
||||
FUSE_FUSECTRL_STATE_LOAD_ROW0 = 2,
|
||||
FUSE_FUSECTRL_STATE_LOAD_ROW1 = 3,
|
||||
FUSE_FUSECTRL_STATE_IDLE = 4,
|
||||
FUSE_FUSECTRL_STATE_READ_SETUP = 5,
|
||||
FUSE_FUSECTRL_STATE_READ_STROBE = 6,
|
||||
FUSE_FUSECTRL_STATE_SAMPLE_FUSES = 7,
|
||||
FUSE_FUSECTRL_STATE_READ_HOLD = 8,
|
||||
FUSE_FUSECTRL_STATE_FUSE_SRC_SETUP = 9,
|
||||
FUSE_FUSECTRL_STATE_WRITE_SETUP = 10,
|
||||
FUSE_FUSECTRL_STATE_WRITE_ADDR_SETUP = 11,
|
||||
FUSE_FUSECTRL_STATE_WRITE_PROGRAM = 12,
|
||||
FUSE_FUSECTRL_STATE_WRITE_ADDR_HOLD = 13,
|
||||
FUSE_FUSECTRL_STATE_FUSE_SRC_HOLD = 14,
|
||||
FUSE_FUSECTRL_STATE_LOAD_RIR = 15,
|
||||
FUSE_FUSECTRL_STATE_READ_BEFORE_WRITE_SETUP = 16,
|
||||
FUSE_FUSECTRL_STATE_READ_DEASSERT_PD = 17,
|
||||
};
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, 4, KEY_VISIBLE, KEY_INVISIBLE);
|
||||
DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_PRIVATEKEYDISABLE_VAL_KEY, 0, VISIBLE, INVISIBLE);
|
||||
|
||||
|
|
Loading…
Reference in a new issue