exo2: first pass at backwards-compat

This commit is contained in:
Michael Scire 2020-06-11 19:17:20 -07:00 committed by SciresM
parent 42f1a3bf60
commit da4107996a
9 changed files with 195 additions and 48 deletions

View file

@ -17,6 +17,7 @@
#include "secmon_boot.hpp"
#include "secmon_boot_functions.hpp"
#include "../smc/secmon_random_cache.hpp"
#include "../smc/secmon_smc_handler.hpp"
#include "../secmon_cache.hpp"
#include "../secmon_cpu_context.hpp"
#include "../secmon_misc.hpp"
@ -180,6 +181,9 @@ namespace ams::secmon {
/* Perform final initialization. */
secmon::SetupSocProtections();
secmon::SetupCpuSErrorDebug();
/* Configure the smc handler tables to reflect the current target firmware. */
secmon::smc::ConfigureSmcHandlersForTargetFirmware();
}
}

View file

@ -584,6 +584,11 @@ namespace ams::secmon {
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE));
/* If we're cold-booting and on 1.0.0, alter the default carveout size. */
if (g_is_cold_boot && GetTargetFirmware() <= TargetFirmware_1_0_0) {
g_kernel_carveouts[0].size = 200 * 128_KB;
}
/* Configure the two kernel carveouts. */
SetupKernelCarveouts();
@ -599,10 +604,15 @@ namespace ams::secmon {
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_3, ~0u);
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_4, ~0u);
/* Configure ASIDs 1-3 as secure, and all others as non-secure. */
/* On modern firmware, configure ASIDs 1-3 as secure, and all others as non-secure. */
if (GetTargetFirmware() >= TargetFirmware_4_0_0) {
reg::Write(MC + MC_SMMU_ASID_SECURITY, MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, SECURE),
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, SECURE),
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, SECURE));
} else {
/* Legacy firmware accesses the MC directly, though, and so correspondingly we must allow ASIDs to be edited by non-secure world. */
reg::Write(MC + MC_SMMU_ASID_SECURITY, 0);
}
reg::Write(MC + MC_SMMU_ASID_SECURITY_1, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_2, 0);
@ -1115,6 +1125,11 @@ namespace ams::secmon {
/* Disable the ARC. */
DisableArc();
/* Further protections are applied only on 4.0.0+. */
if (GetTargetFirmware() < TargetFirmware_4_0_0) {
return;
}
/* Finalize and lock the carveout scratch registers. */
FinalizeCarveoutSecureScratchRegisters();
pmc::LockSecureRegister(pmc::SecureRegister_Carveout);
@ -1155,14 +1170,20 @@ namespace ams::secmon {
}
void SetupPmcAndMcSecure() {
const auto target_fw = GetTargetFirmware();
if (target_fw >= TargetFirmware_2_0_0) {
/* Set the PMC secure. */
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE));
}
if (target_fw >= TargetFirmware_4_0_0) {
/* Set the MC secure. */
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, SLAVE_SECURITY_REG_BITS_ENUM(1, MC0, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, MC1, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, MCB, ENABLE));
}
}
void SetupCpuCoreContext() {
/* Get the tsc frequency. */

View file

@ -114,6 +114,9 @@ namespace ams::secmon::smc {
struct DecryptDeviceUniqueDataOption {
using DeviceUniqueDataIndex = util::BitPack32::Field<0, 3, DeviceUniqueData>;
using Reserved = util::BitPack32::Field<3, 29, u32>;
/* Legacy. */
using EnforceDeviceUnique = util::BitPack32::Field<0, 1, bool>;
};
constexpr const u8 SealKeySources[SealKey_Count][AesKeySize] = {
@ -499,7 +502,7 @@ namespace ams::secmon::smc {
/* Decode arguments. */
std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source));
const int generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max(0, static_cast<int>(args.r[3]) - 1) : 0;
const int generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, static_cast<int>(args.r[3]) - 1) : pkg1::KeyGeneration_1_0_0;
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
@ -517,11 +520,23 @@ namespace ams::secmon::smc {
return SmcResult::Success;
}
SmcResult ValidateDeviceUniqueDataSize(DeviceUniqueData mode, size_t data_size) {
constexpr size_t GetDiscountedMinimumDeviceUniqueDataSize(bool enforce_device_unique) {
if (enforce_device_unique) {
return 0;
} else {
return DeviceUniqueDataTotalMetaSize - DeviceUniqueDataIvSize;
}
}
SmcResult ValidateDeviceUniqueDataSize(DeviceUniqueData mode, size_t data_size, bool enforce_device_unique) {
/* Determine the discounted size towards the minimum. */
const size_t discounted_size = GetDiscountedMinimumDeviceUniqueDataSize(enforce_device_unique);
SMC_R_UNLESS(enforce_device_unique || fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, InvalidArgument);
switch (mode) {
case DeviceUniqueData_DecryptDeviceUniqueData:
{
SMC_R_UNLESS(data_size < DeviceUniqueDataSizeMax, InvalidArgument);
SMC_R_UNLESS(DeviceUniqueDataTotalMetaSize - discounted_size < data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument);
}
break;
case DeviceUniqueData_ImportLotusKey:
@ -529,7 +544,7 @@ namespace ams::secmon::smc {
case DeviceUniqueData_ImportSslKey:
case DeviceUniqueData_ImportEsClientCertKey:
{
SMC_R_UNLESS(DeviceUniqueDataSizeMin <= data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument);
SMC_R_UNLESS(DeviceUniqueDataSizeMin - discounted_size <= data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument);
}
break;
default:
@ -539,23 +554,9 @@ namespace ams::secmon::smc {
return SmcResult::Success;
}
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
SmcResult DecryptDeviceUniqueDataImpl(const u8 *access_key, const u8 *key_source, const DeviceUniqueData mode, const uintptr_t data_address, const size_t data_size, bool enforce_device_unique) {
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size));
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique));
/* Decrypt the device unique data. */
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
@ -571,7 +572,7 @@ namespace ams::secmon::smc {
const u8 * const seal_key_source = SealKeySources[seal_key_type];
/* Decrypt the data. */
if (!DecryptDeviceUniqueData(work_buffer, data_size, nullptr, seal_key_source, se::AesBlockSize, access_key, sizeof(access_key), key_source, sizeof(key_source), work_buffer, data_size)) {
if (!DecryptDeviceUniqueData(work_buffer, data_size, nullptr, seal_key_source, se::AesBlockSize, access_key, sizeof(access_key), key_source, sizeof(key_source), work_buffer, data_size, enforce_device_unique)) {
return SmcResult::InvalidArgument;
}
@ -599,6 +600,89 @@ namespace ams::secmon::smc {
return SmcResult::Success;
}
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>() : DeviceUniqueData_DecryptDeviceUniqueData;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = GetTargetFirmware() >= TargetFirmware_5_0_0 ? true : option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult DecryptAndImportEsDeviceKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = DeviceUniqueData_ImportEsDeviceKey;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Ensure that the key is exactly the correct size. */
if (enforce_device_unique) {
SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataTotalMetaSize, InvalidArgument);
} else {
SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataIvSize, InvalidArgument);
}
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult DecryptAndImportLotusKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = DeviceUniqueData_ImportLotusKey;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Ensure that the key is exactly the correct size. */
if (enforce_device_unique) {
SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataTotalMetaSize, InvalidArgument);
} else {
SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataIvSize, InvalidArgument);
}
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult ReencryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key_dec[se::AesBlockSize];
@ -617,9 +701,11 @@ namespace ams::secmon::smc {
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = true;
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size));
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique));
/* Decrypt the device unique data. */
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
@ -640,7 +726,7 @@ namespace ams::secmon::smc {
/* Determine the seal key to use. */
const u8 * const seal_key_source = SealKeySources[SealKey_ReencryptDeviceUniqueData];
if (!DecryptDeviceUniqueData(work_buffer, data_size, std::addressof(device_id_high), seal_key_source, se::AesBlockSize, access_key_dec, sizeof(access_key_dec), key_source_dec, sizeof(key_source_dec), work_buffer, data_size)) {
if (!DecryptDeviceUniqueData(work_buffer, data_size, std::addressof(device_id_high), seal_key_source, se::AesBlockSize, access_key_dec, sizeof(access_key_dec), key_source_dec, sizeof(key_source_dec), work_buffer, data_size, enforce_device_unique)) {
return SmcResult::InvalidArgument;
}
}
@ -721,13 +807,11 @@ namespace ams::secmon::smc {
/* Legacy APIs. */
SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
return LockSecurityEngineAndInvoke(args, DecryptAndImportEsDeviceKeyImpl);
}
SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
return LockSecurityEngineAndInvoke(args, DecryptAndImportLotusKeyImpl);
}
/* Es encryption utilities. */

View file

@ -90,13 +90,13 @@ namespace ams::secmon::smc {
}
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size) {
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique) {
/* Determine how much decrypted data there will be. */
const size_t enc_size = src_size - DeviceUniqueDataOuterMetaSize;
const size_t enc_size = src_size - (enforce_device_unique ? DeviceUniqueDataOuterMetaSize : DeviceUniqueDataIvSize);
const size_t dec_size = enc_size - DeviceUniqueDataInnerMetaSize;
/* Ensure that our sizes are allowed. */
AMS_ABORT_UNLESS(src_size > DeviceUniqueDataTotalMetaSize);
AMS_ABORT_UNLESS(src_size > (enforce_device_unique ? DeviceUniqueDataTotalMetaSize : DeviceUniqueDataIvSize));
AMS_ABORT_UNLESS(dst_size >= enc_size);
/* Determine the extents of the data. */
@ -120,6 +120,11 @@ namespace ams::secmon::smc {
/* Decrypt the data. */
ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Smc, enc, enc_size, temp_iv, DeviceUniqueDataIvSize);
/* If we're not enforcing device unique, there's no mac/device id. */
if (!enforce_device_unique) {
return true;
}
/* Compute the gmac. */
ComputeGmac(calc_mac, DeviceUniqueDataMacSize, dst, enc_size, temp_iv, DeviceUniqueDataIvSize);

View file

@ -28,7 +28,7 @@ namespace ams::secmon::smc {
constexpr inline size_t DeviceUniqueDataInnerMetaSize = DeviceUniqueDataPaddingSize + DeviceUniqueDataDeviceIdSize;
constexpr inline size_t DeviceUniqueDataTotalMetaSize = DeviceUniqueDataOuterMetaSize + DeviceUniqueDataInnerMetaSize;
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size);
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique);
void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high);
}

View file

@ -122,6 +122,15 @@ namespace ams::secmon::smc {
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey }
};
/* Deprecated handlerss. */
constexpr inline const HandlerInfo DecryptAndImportEsDeviceKeyHandlerInfo = {
0xC300100C, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptAndImportEsDeviceKey
};
constexpr inline const HandlerInfo DecryptAndImportLotusKeyHandlerInfo = {
0xC300100E, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptAndImportLotusKey
};
constinit HandlerInfo g_kern_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
@ -266,6 +275,15 @@ namespace ams::secmon::smc {
}
void ConfigureSmcHandlersForTargetFirmware() {
const auto target_fw = GetTargetFirmware();
if (target_fw < TargetFirmware_5_0_0) {
g_user_handlers[DecryptAndImportEsDeviceKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportEsDeviceKeyHandlerInfo;
g_user_handlers[DecryptAndImportLotusKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportLotusKeyHandlerInfo;
}
}
void HandleSmc(int type, SmcArguments &args) {
/* Get the table. */
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);

View file

@ -21,4 +21,6 @@ namespace ams::secmon::smc {
using SmcHandler = SmcResult (*)(SmcArguments &args);
void ConfigureSmcHandlersForTargetFirmware();
}

View file

@ -157,8 +157,9 @@ namespace ams::secmon::smc {
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
/* Validate that the bpmp is appropriately halted. */
const bool jtag = IsJtagEnabled() || GetTargetFirmware() < TargetFirmware_4_0_0;
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, IsJtagEnabled(), ENABLED, DISABLED)));
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED)));
/* TODO */
}
@ -300,6 +301,9 @@ namespace ams::secmon::smc {
}
void LoadAndStartSc7BpmpFirmware() {
/* Set BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE));
/* Set the PMC as insecure, so that the BPMP firmware can access it. */
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, DISABLE));
@ -319,9 +323,6 @@ namespace ams::secmon::smc {
/* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */
actmon::StopMonitoringBpmp();
/* Set BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE));
/* Load the bpmp firmware. */
void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>();
std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size);
@ -417,7 +418,9 @@ namespace ams::secmon::smc {
pmic::EnableSleep();
/* Ensure that the soc is in a state valid for us to suspend. */
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
ValidateSocStateForSuspend();
}
/* Configure the pmc for sc7 entry. */
pmc::ConfigureForSc7Entry();

View file

@ -43,6 +43,16 @@ namespace ams::secmon::smc {
};
constexpr size_t ModularExponentiateByStorageKeyTableSize = util::size(ModularExponentiateByStorageKeyTable);
consteval u32 GetModeForImportRsaKey(ImportRsaKey import_key) {
for (size_t i = 0; i < ModularExponentiateByStorageKeyTableSize; ++i) {
if (static_cast<ImportRsaKey>(ModularExponentiateByStorageKeyTable[i]) == import_key) {
return i;
}
}
AMS_ASSUME(false);
}
class PrepareEsDeviceUniqueKeyAsyncArguments {
private:
int generation;
@ -200,7 +210,7 @@ namespace ams::secmon::smc {
const uintptr_t mod_address = args.r[2];
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const auto mode = option.Get<ModularExponentiateByStorageKeyOption::Mode>();
const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<ModularExponentiateByStorageKeyOption::Mode>() : GetModeForImportRsaKey(ImportRsaKey_Lotus);
const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>();
/* Validate arguments. */
@ -250,7 +260,7 @@ namespace ams::secmon::smc {
std::memcpy(label_digest, std::addressof(args.r[3]), sizeof(label_digest));
const util::BitPack32 option = { static_cast<u32>(args.r[7]) };
const auto generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max(0, option.Get<PrepareEsDeviceUniqueKeyOption::KeyGeneration>() - 1) : 0;
const auto generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, option.Get<PrepareEsDeviceUniqueKeyOption::KeyGeneration>() - 1) : pkg1::KeyGeneration_1_0_0;
const auto type = option.Get<PrepareEsDeviceUniqueKeyOption::Type>();
const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>();