Merge pull request #2744 from alula/22_support
Basic ("the console boots and functions as expected") 22.0.0 support
This commit is contained in:
@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
||||
/* TODO: Update on next change of keys. */
|
||||
/* Mariko Development Master Kek Source. */
|
||||
.byte 0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB
|
||||
.byte 0x2E, 0x27, 0x44, 0xEA, 0x32, 0xF8, 0x2C, 0xF0, 0x6F, 0xCA, 0xCD, 0x77, 0xAE, 0xAE, 0x1A, 0x1B
|
||||
|
||||
/* Mariko Production Master Kek Source. */
|
||||
.byte 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46
|
||||
.byte 0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13
|
||||
|
||||
/* Development Master Key Vectors. */
|
||||
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
||||
@@ -112,6 +112,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 /* Master key 11 encrypted with Master key 12. */
|
||||
.byte 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE /* Master key 12 encrypted with Master key 13. */
|
||||
.byte 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E /* Master key 13 encrypted with Master key 14. */
|
||||
.byte 0x97, 0xB3, 0x61, 0x88, 0x5C, 0x0D, 0xA1, 0x38, 0x73, 0xA4, 0x2F, 0x1A, 0x46, 0xA1, 0x09, 0xBF /* Master key 14 encrypted with Master key 15. */
|
||||
|
||||
/* Production Master Key Vectors. */
|
||||
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
||||
@@ -135,6 +136,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 /* Master key 11 encrypted with Master key 12. */
|
||||
.byte 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 /* Master key 12 encrypted with Master key 13. */
|
||||
.byte 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA /* Master key 13 encrypted with Master key 14. */
|
||||
.byte 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 /* Master key 14 encrypted with Master key 15. */
|
||||
|
||||
/* Device Master Key Source Sources. */
|
||||
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
|
||||
@@ -155,6 +157,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 /* 19.0.0 Device Master Key Source Source. */
|
||||
.byte 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 /* 20.0.0 Device Master Key Source Source. */
|
||||
.byte 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F /* 21.0.0 Device Master Key Source Source. */
|
||||
.byte 0xF8, 0xF4, 0x22, 0xA4, 0x34, 0xAE, 0x0E, 0x0C, 0x4D, 0x5C, 0x5B, 0xA1, 0x1B, 0x46, 0x1C, 0x78 /* 22.0.0 Device Master Key Source Source. */
|
||||
|
||||
/* Development Device Master Kek Sources. */
|
||||
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
||||
@@ -175,6 +178,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.0.0 Device Master Kek Source. */
|
||||
.byte 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D /* 20.0.0 Device Master Kek Source. */
|
||||
.byte 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F /* 21.0.0 Device Master Kek Source. */
|
||||
.byte 0xF3, 0xBC, 0xB5, 0xB5, 0x5F, 0x01, 0x50, 0x2B, 0x69, 0x69, 0x3A, 0x6B, 0xF9, 0x2C, 0x11, 0x9F /* 22.0.0 Device Master Kek Source. */
|
||||
|
||||
/* Production Device Master Kek Sources. */
|
||||
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
||||
@@ -194,4 +198,5 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */
|
||||
.byte 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F /* 19.0.0 Device Master Kek Source. */
|
||||
.byte 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 /* 20.0.0 Device Master Kek Source. */
|
||||
.byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */
|
||||
.byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */
|
||||
.byte 0xC4, 0x6F, 0x0E, 0x72, 0x43, 0xCE, 0x87, 0xFC, 0x38, 0x95, 0x9B, 0xC9, 0x31, 0x44, 0x97, 0x63 /* 22.0.0 Device Master Kek Source. */
|
||||
@@ -94,7 +94,7 @@ namespace ams::secmon::boot {
|
||||
}
|
||||
|
||||
/* Check that the key generation is one that we can use. */
|
||||
static_assert(pkg1::KeyGeneration_Count == 21);
|
||||
static_assert(pkg1::KeyGeneration_Count == 22);
|
||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@ namespace ams::nxboot {
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46
|
||||
0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB
|
||||
0x2E, 0x27, 0x44, 0xEA, 0x32, 0xF8, 0x2C, 0xF0, 0x6F, 0xCA, 0xCD, 0x77, 0xAE, 0xAE, 0x1A, 0x1B
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0x66, 0xC8, 0xCB, 0x3D, 0xEC, 0xF4, 0x59, 0x73, 0x54, 0x88, 0xE1, 0x2E, 0xE6, 0x3D, 0x68, 0x46
|
||||
0x15, 0xAC, 0x96, 0x34, 0xF5, 0x32, 0x56, 0x68, 0xFE, 0x5B, 0x9D, 0xD7, 0xED, 0x19, 0xB7, 0x8E
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
||||
@@ -75,6 +75,7 @@ namespace ams::nxboot {
|
||||
{ 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */
|
||||
{ 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, /* 20.0.0 Device Master Key Source Source. */
|
||||
{ 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, /* 21.0.0 Device Master Key Source Source. */
|
||||
{ 0xF8, 0xF4, 0x22, 0xA4, 0x34, 0xAE, 0x0E, 0x0C, 0x4D, 0x5C, 0x5B, 0xA1, 0x1B, 0x46, 0x1C, 0x78 }, /* 22.0.0 Device Master Key Source Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
@@ -96,6 +97,7 @@ namespace ams::nxboot {
|
||||
{ 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */
|
||||
{ 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, /* 20.0.0 Device Master Kek Source. */
|
||||
{ 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, /* 21.0.0 Device Master Kek Source. */
|
||||
{ 0xC4, 0x6F, 0x0E, 0x72, 0x43, 0xCE, 0x87, 0xFC, 0x38, 0x95, 0x9B, 0xC9, 0x31, 0x44, 0x97, 0x63 }, /* 22.0.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
@@ -117,6 +119,7 @@ namespace ams::nxboot {
|
||||
{ 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */
|
||||
{ 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D }, /* 20.0.0 Device Master Kek Source. */
|
||||
{ 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F }, /* 21.0.0 Device Master Kek Source. */
|
||||
{ 0xF3, 0xBC, 0xB5, 0xB5, 0x5F, 0x01, 0x50, 0x2B, 0x69, 0x69, 0x3A, 0x6B, 0xF9, 0x2C, 0x11, 0x9F }, /* 22.0.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||
@@ -141,6 +144,7 @@ namespace ams::nxboot {
|
||||
{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */
|
||||
{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, /* Master key 12 encrypted with Master key 13. */
|
||||
{ 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, /* Master key 13 encrypted with Master key 14. */
|
||||
{ 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 }, /* Master key 14 encrypted with Master key 15. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||
@@ -165,6 +169,7 @@ namespace ams::nxboot {
|
||||
{ 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */
|
||||
{ 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE }, /* Master key 12 encrypted with Master key 13. */
|
||||
{ 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E }, /* Master key 13 encrypted with Master key 14. */
|
||||
{ 0x97, 0xB3, 0x61, 0x88, 0x5C, 0x0D, 0xA1, 0x38, 0x73, 0xA4, 0x2F, 0x1A, 0x46, 0xA1, 0x09, 0xBF }, /* Master key 14 encrypted with Master key 15. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace ams::nxboot {
|
||||
}
|
||||
|
||||
/* Check that the key generation is one that we can use. */
|
||||
static_assert(pkg1::KeyGeneration_Count == 21);
|
||||
static_assert(pkg1::KeyGeneration_Count == 22);
|
||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -267,6 +267,8 @@ namespace ams::nxboot {
|
||||
return ams::TargetFirmware_20_0_0;
|
||||
} else if (std::memcmp(package1 + 0x10, "20251009", 8) == 0) {
|
||||
return ams::TargetFirmware_21_0_0;
|
||||
} else if (std::memcmp(package1 + 0x10, "20260123", 8) == 0) {
|
||||
return ams::TargetFirmware_22_0_0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -192,6 +192,9 @@ namespace ams::nxboot {
|
||||
FsVersion_21_2_0,
|
||||
FsVersion_21_2_0_Exfat,
|
||||
|
||||
FsVersion_22_0_0,
|
||||
FsVersion_22_0_0_Exfat,
|
||||
|
||||
FsVersion_Count,
|
||||
};
|
||||
|
||||
@@ -296,6 +299,9 @@ namespace ams::nxboot {
|
||||
|
||||
{ 0xAF, 0x1D, 0xBD, 0xC7, 0x82, 0x98, 0x3C, 0xBD }, /* FsVersion_21_2_0 */
|
||||
{ 0x56, 0x25, 0x17, 0xA1, 0x92, 0xC3, 0xC8, 0xF0 }, /* FsVersion_21_2_0_Exfat */
|
||||
|
||||
{ 0xB7, 0xA2, 0x97, 0x39, 0xB7, 0xED, 0xDE, 0xFC }, /* FsVersion_22_0_0 */
|
||||
{ 0xFB, 0x0B, 0x68, 0xDB, 0x24, 0x03, 0xD1, 0x19 }, /* FsVersion_22_0_0_Exfat */
|
||||
};
|
||||
|
||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||
@@ -700,7 +706,7 @@ namespace ams::nxboot {
|
||||
case FsVersion_21_0_0:
|
||||
case FsVersion_21_2_0:
|
||||
AddPatch(fs_meta, 0x1AC9ED, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1ACA05 , NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1ACA05, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x17FBE0, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_21_0_0_Exfat:
|
||||
@@ -709,6 +715,16 @@ namespace ams::nxboot {
|
||||
AddPatch(fs_meta, 0x1B7B65, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_22_0_0:
|
||||
AddPatch(fs_meta, 0x1B023D, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1B0255, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x183060, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_22_0_0_Exfat:
|
||||
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace ams::pkg1 {
|
||||
KeyGeneration_19_0_0 = 0x12,
|
||||
KeyGeneration_20_0_0 = 0x13,
|
||||
KeyGeneration_21_0_0 = 0x14,
|
||||
KeyGeneration_22_0_0 = 0x15,
|
||||
|
||||
KeyGeneration_Count,
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace ams::pkg2 {
|
||||
constexpr inline int PayloadCount = 3;
|
||||
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0x18;
|
||||
constexpr inline int CurrentBootloaderVersion = 0x17;
|
||||
|
||||
struct Package2Meta {
|
||||
using Magic = util::FourCC<'P','K','2','1'>;
|
||||
|
||||
@@ -177,6 +177,7 @@ namespace ams::fuse {
|
||||
}
|
||||
|
||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||
TargetFirmware_22_0_0,
|
||||
TargetFirmware_21_0_0,
|
||||
TargetFirmware_20_0_0,
|
||||
TargetFirmware_19_0_0,
|
||||
|
||||
@@ -200,6 +200,7 @@ namespace ams::kern {
|
||||
bool m_is_kernel;
|
||||
bool m_enable_aslr;
|
||||
bool m_enable_device_address_space_merge;
|
||||
bool m_allowed_exec_device_mapping;
|
||||
KMemoryBlockSlabManager *m_memory_block_slab_manager;
|
||||
KBlockInfoManager *m_block_info_manager;
|
||||
KResourceLimit *m_resource_limit;
|
||||
@@ -217,7 +218,7 @@ namespace ams::kern {
|
||||
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
||||
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(),
|
||||
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
||||
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
||||
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(),
|
||||
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
||||
m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value()
|
||||
{
|
||||
@@ -520,6 +521,8 @@ namespace ams::kern {
|
||||
size_t GetAliasCodeDataSize() const;
|
||||
|
||||
u32 GetAllocateOption() const { return m_allocate_option; }
|
||||
|
||||
void AllowDeviceMappingOfExecPages() { m_allowed_exec_device_mapping = true; }
|
||||
public:
|
||||
static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) {
|
||||
return KMemoryLayout::GetLinearVirtualAddress(addr);
|
||||
|
||||
@@ -102,8 +102,8 @@ namespace ams::kern {
|
||||
IoRegionList m_io_region_list;
|
||||
bool m_is_suspended;
|
||||
bool m_is_immortal;
|
||||
bool m_is_jit_debug;
|
||||
bool m_is_handle_table_initialized;
|
||||
bool m_is_jit_debug;
|
||||
ams::svc::DebugEvent m_jit_debug_event_type;
|
||||
ams::svc::DebugException m_jit_debug_exception_type;
|
||||
uintptr_t m_jit_debug_params[4];
|
||||
|
||||
@@ -285,7 +285,7 @@ namespace ams::kern {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0);
|
||||
|
||||
/* Ensure that the size we need to reserve is as we expect it to be. */
|
||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||
const u32 total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(total_size == expected_size);
|
||||
MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax);
|
||||
|
||||
|
||||
@@ -211,6 +211,7 @@ namespace ams::kern {
|
||||
/* Set other basic fields. */
|
||||
m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||
m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||
m_allowed_exec_device_mapping = false;
|
||||
m_address_space_start = start;
|
||||
m_address_space_end = end;
|
||||
m_is_kernel = false;
|
||||
@@ -3077,7 +3078,9 @@ namespace ams::kern {
|
||||
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None);
|
||||
size_t num_allocator_blocks;
|
||||
KMemoryState old_state;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared));
|
||||
const KMemoryPermission perm_mask = static_cast<KMemoryPermission>(perm | (m_allowed_exec_device_mapping ? KMemoryPermission_None : KMemoryPermission_UserExecute));
|
||||
|
||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm_mask, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared));
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
|
||||
@@ -185,6 +185,11 @@ namespace ams::kern {
|
||||
/* Validate that the intended kernel version isn't too high for us to support. */
|
||||
R_UNLESS(m_capabilities.GetIntendedKernelVersion() <= ams::svc::SupportedKernelVersion, svc::ResultInvalidCombination());
|
||||
|
||||
/* Enable mapping device pages as executable on legacy processes. */
|
||||
if (m_capabilities.GetIntendedKernelMajorVersion() < 26) {
|
||||
m_page_table.GetBasePageTable().AllowDeviceMappingOfExecPages();
|
||||
}
|
||||
|
||||
/* Create and clear the process local region. */
|
||||
R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address)));
|
||||
m_plr_heap_address = this->GetThreadLocalRegionPointer(m_plr_address);
|
||||
@@ -976,6 +981,9 @@ namespace ams::kern {
|
||||
/* Set the thread arguments. */
|
||||
main_thread->GetContext().SetArguments(0, thread_handle);
|
||||
|
||||
/* Pass the thread handle to the thread local region. */
|
||||
static_cast<ams::svc::ThreadLocalRegion *>(main_thread->GetThreadLocalRegionHeapAddress())->thread_handle = thread_handle;
|
||||
|
||||
/* Update our state. */
|
||||
this->ChangeState((state == State_Created) ? State_Running : State_RunningAttached);
|
||||
ON_RESULT_FAILURE_2 { this->ChangeState(state); };
|
||||
|
||||
@@ -66,6 +66,9 @@ namespace ams::kern::svc {
|
||||
/* Add the thread to the handle table. */
|
||||
R_TRY(process.GetHandleTable().Add(out, thread));
|
||||
|
||||
/* Pass the thread handle to the thread local region. */
|
||||
static_cast<ams::svc::ThreadLocalRegion *>(thread->GetThreadLocalRegionHeapAddress())->thread_handle = *out;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -661,7 +661,7 @@
|
||||
HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ControllerStyleList, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ControllerStyleListDeprecated, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
@@ -1014,4 +1014,4 @@
|
||||
HANDLER(ModuleClockEnableFlags, 1032, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ModulePowerEnableFlags, 1033, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(BluetoothAudioConnectionCount, 1034, BluetoothAudioInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(ControllerStyleList, 1035, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None )
|
||||
HANDLER(ControllerStyleList, 1035, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None )
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace ams::erpt {
|
||||
|
||||
#define GENERATE_ENUM(NAME, ID, ...) NAME = ID,
|
||||
|
||||
enum FieldType {
|
||||
enum FieldType: u8 {
|
||||
AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM)
|
||||
FieldType_Count,
|
||||
};
|
||||
@@ -243,4 +243,33 @@ namespace ams::erpt {
|
||||
Map16 = 0xDE,
|
||||
};
|
||||
|
||||
constexpr inline u32 ErrorCodeSizeMax = 15;
|
||||
constexpr inline u32 ProgramIdSizeMax = 17;
|
||||
|
||||
struct RecentReportEntry {
|
||||
char error_code[ErrorCodeSizeMax];
|
||||
char program_id[ProgramIdSizeMax];
|
||||
u8 is_visible;
|
||||
u8 is_system_abort;
|
||||
u8 is_application_abort;
|
||||
};
|
||||
static_assert(sizeof(RecentReportEntry) == 35);
|
||||
|
||||
struct RecentReportSummary : public sf::LargeData, public sf::PrefersAutoSelectTransferMode {
|
||||
u32 entry_count;
|
||||
RecentReportEntry entries[50];
|
||||
char firmware_display_version[0x18];
|
||||
char private_os_version[96];
|
||||
char product_model[16];
|
||||
char region_code[34];
|
||||
};
|
||||
static_assert(sizeof(RecentReportSummary) == 0x784);
|
||||
|
||||
struct SystemInfo {
|
||||
char os_version[0x18];
|
||||
char private_os_version[96];
|
||||
char product_model[16];
|
||||
const char *region;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetStorageUsageStatistics, (ams::sf::Out<erpt::StorageUsageStatistics> out), (out), hos::Version_5_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 5, Result, GetAttachmentListDeprecated, (const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_buf, report_id), hos::Version_8_0_0, hos::Version_19_0_1) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAttachmentList, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_count, out_buf, report_id), hos::Version_20_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 7, Result, GetRecentReportSummary, (ams::sf::Out<erpt::RecentReportSummary> out), (out), hos::Version_22_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, GetReportSizeMax, (ams::sf::Out<u32> out), (out), hos::Version_20_0_0)
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ namespace ams::erpt::srv {
|
||||
Result Initialize(u8 *mem, size_t mem_size);
|
||||
Result InitializeAndStartService();
|
||||
|
||||
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len);
|
||||
const SystemInfo &GetSystemInfo();
|
||||
|
||||
Result SetSerialNumber(const char *sn, u32 sn_len);
|
||||
Result SetProductModel(const char *model, u32 model_len);
|
||||
Result SetRegionSetting(const char *region, u32 region_len);
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (u32 id, const fssrv::sf::FspPath &path), (id, path), hos::Version_Min, hos::Version_9_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (s64 size, s64 journal_size), (size, journal_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (const fssrv::sf::FspPath &path), (path)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), (), hos::Version_Min, hos::Version_21_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (u32 mode), (mode)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (ams::sf::Out<u32> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (const ams::sf::InBuffer &buf), (buf)) \
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace ams::hos {
|
||||
Version_21_0_1 = ::ams::TargetFirmware_21_0_1,
|
||||
Version_21_1_0 = ::ams::TargetFirmware_21_1_0,
|
||||
Version_21_2_0 = ::ams::TargetFirmware_21_2_0,
|
||||
Version_22_0_0 = ::ams::TargetFirmware_22_0_0,
|
||||
|
||||
Version_Current = ::ams::TargetFirmware_Current,
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace ams::erpt::srv {
|
||||
Result JournalForAttachments::GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id) {
|
||||
if (hos::GetVersion() >= hos::Version_20_0_0) {
|
||||
/* TODO: What define gives a minimum of 10? */
|
||||
R_UNLESS(max_out_infos >= 10, erpt::ResultInvalidArgument());
|
||||
R_UNLESS(max_out_infos >= 10, erpt::ResultTooManyOutAttachments());
|
||||
}
|
||||
|
||||
u32 count = 0;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "erpt_srv_journal.hpp"
|
||||
#include "erpt_srv_service.hpp"
|
||||
#include "erpt_srv_forced_shutdown.hpp"
|
||||
#include "erpt_srv_recent_report.hpp"
|
||||
|
||||
namespace ams::erpt::srv {
|
||||
|
||||
@@ -33,6 +34,7 @@ namespace ams::erpt::srv {
|
||||
constexpr u32 SystemSaveDataFlags = fs::SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData;
|
||||
constexpr s64 SystemSaveDataSize = 11_MB;
|
||||
constexpr s64 SystemSaveDataJournalSize = 2720_KB;
|
||||
constexpr u32 DefaultThrottleTimeWindowSeconds = 3;
|
||||
|
||||
constinit bool g_automatic_report_cleanup_enabled = true;
|
||||
|
||||
@@ -53,7 +55,9 @@ namespace ams::erpt::srv {
|
||||
}
|
||||
|
||||
Result MountSystemSaveData() {
|
||||
fs::DisableAutoSaveDataCreation();
|
||||
if (hos::GetVersion() < hos::Version_21_0_0) {
|
||||
fs::DisableAutoSaveDataCreation();
|
||||
}
|
||||
|
||||
/* Extend the system save data. */
|
||||
/* NOTE: Nintendo used to not check the result of this; they do now, but . */
|
||||
@@ -71,6 +75,72 @@ namespace ams::erpt::srv {
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) {
|
||||
switch (model) {
|
||||
case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast<int>(dst_size));
|
||||
case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast<int>(dst_size));
|
||||
default: return util::SNPrintf(dst, dst_size, "%d", static_cast<int>(model));
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetRegionString(settings::system::RegionCode code) {
|
||||
switch (code) {
|
||||
case settings::system::RegionCode_Japan: return "Japan";
|
||||
case settings::system::RegionCode_Usa: return "Usa";
|
||||
case settings::system::RegionCode_Europe: return "Europe";
|
||||
case settings::system::RegionCode_Australia: return "Australia";
|
||||
case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea";
|
||||
case settings::system::RegionCode_China: return "China";
|
||||
default: return "RegionUnknown";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const erpt::SystemInfo &GetSystemInfo() {
|
||||
static const erpt::SystemInfo s_info = [] {
|
||||
erpt::SystemInfo info = {};
|
||||
|
||||
settings::system::FirmwareVersion firmware_version = {};
|
||||
settings::system::GetFirmwareVersion(std::addressof(firmware_version));
|
||||
|
||||
util::Strlcpy(info.os_version, firmware_version.display_version, sizeof(info.os_version));
|
||||
|
||||
const auto os_priv_len = util::SNPrintf(info.private_os_version, sizeof(info.private_os_version), "%s (%.8s)", firmware_version.display_name, firmware_version.revision);
|
||||
AMS_ASSERT(static_cast<size_t>(os_priv_len) < sizeof(info.private_os_version));
|
||||
AMS_UNUSED(os_priv_len);
|
||||
|
||||
const auto pm_len = MakeProductModelString(info.product_model, sizeof(info.product_model), settings::system::GetProductModel());
|
||||
AMS_ASSERT(static_cast<size_t>(pm_len) < sizeof(info.product_model));
|
||||
AMS_UNUSED(pm_len);
|
||||
|
||||
settings::system::RegionCode region_code;
|
||||
settings::system::GetRegionCode(std::addressof(region_code));
|
||||
info.region = GetRegionString(region_code);
|
||||
|
||||
return info;
|
||||
}();
|
||||
return s_info;
|
||||
}
|
||||
|
||||
u32 GetThrottleTimeWindowSecondsImpl() {
|
||||
u32 seconds = DefaultThrottleTimeWindowSeconds;
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(seconds), sizeof(seconds), "erpt", "throttle_time_window_seconds") != sizeof(seconds)) {
|
||||
return DefaultThrottleTimeWindowSeconds;
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void SetReportThrottleTimeSpan() {
|
||||
u32 seconds = GetThrottleTimeWindowSecondsImpl();
|
||||
|
||||
const TimeSpan time_span = TimeSpan::FromSeconds(static_cast<s64>(seconds));
|
||||
|
||||
Reporter::SetThrottleTimeSpan(time_span);
|
||||
}
|
||||
|
||||
Result Initialize(u8 *mem, size_t mem_size) {
|
||||
R_ABORT_UNLESS(time::Initialize());
|
||||
|
||||
@@ -101,6 +171,10 @@ namespace ams::erpt::srv {
|
||||
}
|
||||
}
|
||||
|
||||
if (hos::GetVersion() >= hos::Version_22_0_0) {
|
||||
SetReportThrottleTimeSpan();
|
||||
}
|
||||
|
||||
R_ABORT_UNLESS(MountSystemSaveData());
|
||||
|
||||
g_sf_allocator.Attach(g_heap_handle);
|
||||
@@ -110,8 +184,18 @@ namespace ams::erpt::srv {
|
||||
AMS_ABORT_UNLESS(ctx != nullptr);
|
||||
}
|
||||
|
||||
if (R_FAILED(Journal::Restore())) {
|
||||
/* TODO: Nintendo deletes system savedata when this fails. Should we?. */
|
||||
if (hos::GetVersion() >= hos::Version_21_0_0) {
|
||||
/* >= 21.0.0, Nintendo checks the result of restore and deletes the save data if it fails. */
|
||||
if (R_FAILED(Journal::Restore())) {
|
||||
/* Delete and recreate the system save data. */
|
||||
fs::Unmount(ReportStoragePath);
|
||||
R_ABORT_UNLESS(fs::DeleteSystemSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, fs::InvalidUserId));
|
||||
|
||||
R_ABORT_UNLESS(MountSystemSaveData());
|
||||
}
|
||||
} else{
|
||||
/* Pre 21.0.0, Nintendo just calls restore and ignores the result. */
|
||||
Journal::Restore();
|
||||
}
|
||||
|
||||
Reporter::UpdatePowerOnTime();
|
||||
@@ -128,8 +212,8 @@ namespace ams::erpt::srv {
|
||||
R_RETURN(InitializeService());
|
||||
}
|
||||
|
||||
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) {
|
||||
R_RETURN(Reporter::SetSerialNumberAndOsVersion(sn, sn_len, os, os_len, os_priv, os_priv_len));
|
||||
Result SetSerialNumber(const char *sn, u32 sn_len) {
|
||||
R_RETURN(Reporter::SetSerialNumber(sn, sn_len));
|
||||
}
|
||||
|
||||
Result SetProductModel(const char *model, u32 model_len) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <stratosphere.hpp>
|
||||
#include "erpt_srv_manager_impl.hpp"
|
||||
#include "erpt_srv_journal.hpp"
|
||||
#include "erpt_srv_recent_report.hpp"
|
||||
|
||||
namespace ams::erpt::srv {
|
||||
|
||||
@@ -59,6 +60,7 @@ namespace ams::erpt::srv {
|
||||
Result ManagerImpl::CleanupReports() {
|
||||
Journal::CleanupReports();
|
||||
Journal::CleanupAttachments();
|
||||
RecentReport::Clear();
|
||||
R_RETURN(Journal::Commit());
|
||||
}
|
||||
|
||||
@@ -99,9 +101,15 @@ namespace ams::erpt::srv {
|
||||
|
||||
Result ManagerImpl::GetReportSizeMax(ams::sf::Out<u32> out) {
|
||||
/* TODO: Where is this size defined? */
|
||||
constexpr size_t ReportSizeMax = 0x3FF4F;
|
||||
constexpr size_t ReportSizeMax = 0x35D3D;
|
||||
*out = ReportSizeMax;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ManagerImpl::GetRecentReportSummary(ams::sf::Out<RecentReportSummary> out) {
|
||||
RecentReport::GetSummary(out.GetPointer());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ams::erpt::srv {
|
||||
Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out);
|
||||
Result GetAttachmentListDeprecated(const ams::sf::OutBuffer &out_buf, const ReportId &report_id);
|
||||
Result GetAttachmentList(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const ReportId &report_id);
|
||||
Result GetRecentReportSummary(ams::sf::Out<RecentReportSummary> out);
|
||||
Result GetReportSizeMax(ams::sf::Out<u32> out);
|
||||
};
|
||||
static_assert(erpt::sf::IsIManager<ManagerImpl>);
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
#include "erpt_srv_recent_report.hpp"
|
||||
|
||||
namespace ams::erpt::srv {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t MaxEntriesPerType = 25;
|
||||
|
||||
struct RecentReportState {
|
||||
u32 report_counts[ReportType_Count];
|
||||
RecentReportEntry report_entries[ReportType_Count][MaxEntriesPerType];
|
||||
os::Tick last_tick;
|
||||
u32 consecutive_count;
|
||||
};
|
||||
|
||||
constinit RecentReportState g_state = {
|
||||
.report_counts = {},
|
||||
.report_entries = {},
|
||||
.last_tick = os::Tick{},
|
||||
.consecutive_count = 0,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void RecentReport::PushEntry(const char *error_code, const char *program_id, ReportType type, bool is_system_abort, bool is_application_abort) {
|
||||
u32 &count = g_state.report_counts[type];
|
||||
RecentReportEntry *entries = g_state.report_entries[type];
|
||||
|
||||
/* If we're full, shift the oldest entry out. */
|
||||
if (count >= MaxEntriesPerType) {
|
||||
std::memmove(entries, entries + 1, sizeof(RecentReportEntry) * (MaxEntriesPerType - 1));
|
||||
count = MaxEntriesPerType - 1;
|
||||
}
|
||||
|
||||
/* Fill the new entry. */
|
||||
RecentReportEntry &entry = entries[count];
|
||||
util::Strlcpy(entry.error_code, error_code, sizeof(entry.error_code));
|
||||
util::Strlcpy(entry.program_id, program_id, sizeof(entry.program_id));
|
||||
entry.is_visible = (type == ReportType_Visible);
|
||||
entry.is_system_abort = is_system_abort;
|
||||
entry.is_application_abort = is_application_abort;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
void RecentReport::GetSummary(RecentReportSummary *out) {
|
||||
/* Fill basic info from lazily-initialized system info. */
|
||||
const auto &sys_info = srv::GetSystemInfo();
|
||||
util::Strlcpy(out->firmware_display_version, sys_info.os_version, sizeof(out->firmware_display_version));
|
||||
util::Strlcpy(out->private_os_version, sys_info.private_os_version, sizeof(out->private_os_version));
|
||||
util::Strlcpy(out->product_model, sys_info.product_model, sizeof(out->product_model));
|
||||
util::Strlcpy(out->region_code, sys_info.region, sizeof(out->region_code));
|
||||
|
||||
u32 total_count = 0;
|
||||
|
||||
/* Copy entries. */
|
||||
for (u32 i = 0; i < ReportType_Count; i++) {
|
||||
if (g_state.report_counts[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
std::memcpy(out->entries + total_count, g_state.report_entries[i], sizeof(RecentReportEntry) * g_state.report_counts[i]);
|
||||
total_count += g_state.report_counts[i];
|
||||
|
||||
/* Reset count (destructive read). */
|
||||
g_state.report_counts[i] = 0;
|
||||
}
|
||||
|
||||
out->entry_count = total_count;
|
||||
}
|
||||
|
||||
void RecentReport::Clear() {
|
||||
for (u32 i = 0; i < ReportType_Count; i++) {
|
||||
g_state.report_counts[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::erpt::srv {
|
||||
|
||||
class RecentReport {
|
||||
public:
|
||||
static void PushEntry(const char *error_code, const char *program_id, ReportType type, bool is_system_abort, bool is_application_abort);
|
||||
static void GetSummary(RecentReportSummary *out);
|
||||
static void Clear();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -20,13 +20,12 @@
|
||||
#include "erpt_srv_context_record.hpp"
|
||||
#include "erpt_srv_context.hpp"
|
||||
#include "erpt_srv_fs_info.hpp"
|
||||
#include "erpt_srv_recent_report.hpp"
|
||||
|
||||
namespace ams::erpt::srv {
|
||||
|
||||
constinit bool Reporter::s_redirect_new_reports = true;
|
||||
constinit char Reporter::s_serial_number[24] = "Unknown";
|
||||
constinit char Reporter::s_os_version[24] = "Unknown";
|
||||
constinit char Reporter::s_private_os_version[96] = "Unknown";
|
||||
constinit util::optional<os::Tick> Reporter::s_application_launch_time;
|
||||
constinit util::optional<os::Tick> Reporter::s_awake_time;
|
||||
constinit util::optional<os::Tick> Reporter::s_power_on_time;
|
||||
@@ -212,18 +211,83 @@ namespace ams::erpt::srv {
|
||||
}
|
||||
#endif
|
||||
|
||||
Result ValidateCreateReportContext(const ContextEntry *ctx) {
|
||||
Result ValidateAndGetErrorCode(const ContextEntry *ctx, char *out_error_code) {
|
||||
R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
|
||||
R_UNLESS(ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
|
||||
|
||||
const bool found_error_code = util::range::any_of(MakeSpan(ctx->fields, ctx->field_count), [] (const FieldEntry &entry) {
|
||||
return entry.id == FieldId_ErrorCode;
|
||||
});
|
||||
R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing());
|
||||
const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
|
||||
const u8 *array_data = static_cast<const u8 *>(ctx->array_buffer);
|
||||
|
||||
const FieldEntry *error_code_field = nullptr;
|
||||
|
||||
for (const auto &field : fields_span) {
|
||||
if (field.id != FieldId_ErrorCode){
|
||||
continue;
|
||||
}
|
||||
error_code_field = &field;
|
||||
break;
|
||||
}
|
||||
|
||||
R_UNLESS(error_code_field != nullptr, erpt::ResultRequiredFieldMissing());
|
||||
R_UNLESS(error_code_field->type == FieldType_String, erpt::ResultFieldTypeMismatch());
|
||||
R_UNLESS(error_code_field->value_array.size <= ErrorCodeSizeMax, erpt::ResultArrayFieldTooLarge());
|
||||
|
||||
const char *error_code = reinterpret_cast<const char *>(array_data + error_code_field->value_array.start_idx);
|
||||
util::Strlcpy(out_error_code, error_code, ErrorCodeSizeMax);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ThrottleState {
|
||||
TimeSpan throttle_time_span;
|
||||
char last_error_code[ErrorCodeSizeMax];
|
||||
u32 consecutive_count;
|
||||
os::Tick last_tick;
|
||||
};
|
||||
constinit ThrottleState g_throttle_state = {
|
||||
.throttle_time_span = TimeSpan{},
|
||||
.last_error_code = {},
|
||||
.consecutive_count = 0,
|
||||
.last_tick = os::Tick{},
|
||||
};
|
||||
};
|
||||
bool IsThrottledReport(const ContextEntry *ctx, ReportType type, const char *error_code) {
|
||||
if (hos::GetVersion() < hos::Version_22_0_0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
|
||||
bool is_crash_report = false;
|
||||
|
||||
for (const auto &field : fields_span) {
|
||||
if (field.id != FieldId_CrashReportFlag){
|
||||
continue;
|
||||
}
|
||||
is_crash_report = field.value_bool;
|
||||
break;
|
||||
}
|
||||
|
||||
if(type == ReportType_Visible || is_crash_report){
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto now = os::GetSystemTick();
|
||||
const TimeSpan elapsed = (now - g_throttle_state.last_tick).ToTimeSpan();
|
||||
|
||||
if (std::strcmp(g_throttle_state.last_error_code, error_code) == 0 && elapsed < g_throttle_state.throttle_time_span) {
|
||||
if (g_throttle_state.consecutive_count >= 5) {
|
||||
return true;
|
||||
}
|
||||
g_throttle_state.consecutive_count++;
|
||||
} else {
|
||||
util::Strlcpy(g_throttle_state.last_error_code, error_code, sizeof(g_throttle_state.last_error_code));
|
||||
g_throttle_state.last_tick = now;
|
||||
g_throttle_state.consecutive_count = 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Result SubmitReportDefaults(const ContextEntry *ctx) {
|
||||
AMS_ASSERT(ctx->category == CategoryId_ErrorInfo);
|
||||
|
||||
@@ -381,6 +445,9 @@ namespace ams::erpt::srv {
|
||||
|
||||
}
|
||||
|
||||
void Reporter::SetThrottleTimeSpan(TimeSpan time_span) {
|
||||
g_throttle_state.throttle_time_span = time_span;
|
||||
}
|
||||
Result Reporter::RegisterRunningApplet(ncm::ProgramId program_id) {
|
||||
g_applet_active_time_info_list.Register(program_id);
|
||||
R_SUCCEED();
|
||||
@@ -427,12 +494,51 @@ namespace ams::erpt::srv {
|
||||
/* Get the context entry pointer. */
|
||||
const ContextEntry *ctx = record->GetContextEntryPtr();
|
||||
|
||||
/* Validate the context. */
|
||||
R_TRY(ValidateCreateReportContext(ctx));
|
||||
/* Validate the context and retrieve the error code. */
|
||||
char error_code[ErrorCodeSizeMax];
|
||||
R_TRY(ValidateAndGetErrorCode(ctx, error_code));
|
||||
|
||||
if (hos::GetVersion() >= hos::Version_22_0_0) {
|
||||
/* Check if we should throttle the report. */
|
||||
if (IsThrottledReport(ctx, type, error_code)) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
/* Submit report defaults. */
|
||||
R_TRY(SubmitReportDefaults(ctx));
|
||||
|
||||
/* Push to recent reports. */
|
||||
if (hos::GetVersion() >= hos::Version_22_0_0) {
|
||||
const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
|
||||
const u8 *array_data = static_cast<const u8 *>(ctx->array_buffer);
|
||||
|
||||
char program_id[ProgramIdSizeMax] = {};
|
||||
bool is_system_abort = false;
|
||||
bool is_application_abort = false;
|
||||
|
||||
for (const auto &field : fields_span) {
|
||||
switch (field.id) {
|
||||
case FieldId_ProgramId:
|
||||
if(field.type != FieldType_String){
|
||||
break;
|
||||
}
|
||||
util::Strlcpy(program_id, reinterpret_cast<const char *>(array_data + field.value_array.start_idx), sizeof(program_id));
|
||||
break;
|
||||
case FieldId_SystemAbortFlag:
|
||||
is_system_abort = field.value_bool;
|
||||
break;
|
||||
case FieldId_ApplicationAbortFlag:
|
||||
is_application_abort = field.value_bool;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RecentReport::PushEntry(error_code, program_id, type, is_system_abort, is_application_abort);
|
||||
}
|
||||
|
||||
/* Generate report id. */
|
||||
const ReportId report_id = specified_report_id ? *specified_report_id : ReportId{ .uuid = util::GenerateUuid() };
|
||||
|
||||
@@ -480,8 +586,9 @@ namespace ams::erpt::srv {
|
||||
R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(steady_clock_current_timepoint)));
|
||||
|
||||
/* Add automatic fields. */
|
||||
static_cast<void>(auto_record->Add(FieldId_OsVersion, s_os_version, util::Strnlen(s_os_version, sizeof(s_os_version))));
|
||||
static_cast<void>(auto_record->Add(FieldId_PrivateOsVersion, s_private_os_version, util::Strnlen(s_private_os_version, sizeof(s_private_os_version))));
|
||||
const auto &sys_info = srv::GetSystemInfo();
|
||||
static_cast<void>(auto_record->Add(FieldId_OsVersion, sys_info.os_version, util::Strnlen(sys_info.os_version, sizeof(sys_info.os_version))));
|
||||
static_cast<void>(auto_record->Add(FieldId_PrivateOsVersion, sys_info.private_os_version, util::Strnlen(sys_info.private_os_version, sizeof(sys_info.private_os_version))));
|
||||
static_cast<void>(auto_record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number))));
|
||||
static_cast<void>(auto_record->Add(FieldId_ReportIdentifier, identifier_str, util::Strnlen(identifier_str, sizeof(identifier_str))));
|
||||
static_cast<void>(auto_record->Add(FieldId_OccurrenceTimestamp, timestamp_user.value));
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace ams::erpt::srv {
|
||||
private:
|
||||
static bool s_redirect_new_reports;
|
||||
static char s_serial_number[24];
|
||||
static char s_os_version[24];
|
||||
static char s_private_os_version[96];
|
||||
static util::optional<os::Tick> s_application_launch_time;
|
||||
static util::optional<os::Tick> s_awake_time;
|
||||
static util::optional<os::Tick> s_power_on_time;
|
||||
@@ -39,14 +37,11 @@ namespace ams::erpt::srv {
|
||||
static void UpdateAwakeTime() { s_awake_time = os::GetSystemTick(); }
|
||||
static void UpdatePowerOnTime() { s_power_on_time = os::GetSystemTick(); }
|
||||
|
||||
static Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) {
|
||||
R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument());
|
||||
R_UNLESS(os_len <= sizeof(s_os_version), erpt::ResultInvalidArgument());
|
||||
R_UNLESS(os_priv_len <= sizeof(s_private_os_version), erpt::ResultInvalidArgument());
|
||||
static void SetThrottleTimeSpan(TimeSpan time_span);
|
||||
|
||||
static Result SetSerialNumber(const char *sn, u32 sn_len) {
|
||||
R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument());
|
||||
std::memcpy(s_serial_number, sn, sn_len);
|
||||
std::memcpy(s_os_version, os, os_len);
|
||||
std::memcpy(s_private_os_version, os_priv, os_priv_len);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ namespace ams::fs {
|
||||
}
|
||||
|
||||
void DisableAutoSaveDataCreation() {
|
||||
if (hos::GetVersion() >= hos::Version_22_0_0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto fsp = impl::GetFileSystemProxyServiceObject();
|
||||
AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation());
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace ams::fs::impl {
|
||||
#define ADD_ENUM_CASE(v) case v: return #v
|
||||
|
||||
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
|
||||
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_21_0_0);
|
||||
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_22_0_0);
|
||||
switch (id) {
|
||||
using enum pkg1::KeyGeneration;
|
||||
case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
|
||||
@@ -44,7 +44,8 @@ namespace ams::fs::impl {
|
||||
case KeyGeneration_18_0_0: return "18.0.0-18.1.0";
|
||||
case KeyGeneration_19_0_0: return "19.0.0-19.0.1";
|
||||
case KeyGeneration_20_0_0: return "20.0.0-20.5.0";
|
||||
case KeyGeneration_21_0_0: return "21.0.0-";
|
||||
case KeyGeneration_21_0_0: return "21.0.0-21.2.0";
|
||||
case KeyGeneration_22_0_0: return "22.0.0";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "pinmux_pad_index.hpp"
|
||||
#include "pinmux_board_driver_api.hpp"
|
||||
#include "pinmux_platform_pads.hpp"
|
||||
#include "pinmux_build_config.hpp"
|
||||
|
||||
namespace ams::pinmux::driver::board::nintendo::nx {
|
||||
|
||||
@@ -99,6 +100,31 @@ namespace ams::pinmux::driver::board::nintendo::nx {
|
||||
UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat6, 0x2000, 0x2000 });
|
||||
UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat7, 0x2000, 0x2000 });
|
||||
}
|
||||
|
||||
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART)
|
||||
UpdateSinglePinmuxPad({
|
||||
.index = PinmuxPadIndex_Uart2Tx,
|
||||
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
|
||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
||||
});
|
||||
UpdateSinglePinmuxPad({
|
||||
.index = PinmuxPadIndex_Uart2Cts,
|
||||
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
|
||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
||||
});
|
||||
#endif
|
||||
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART)
|
||||
UpdateSinglePinmuxPad({
|
||||
.index = PinmuxPadIndex_Uart3Tx,
|
||||
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
|
||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
||||
});
|
||||
UpdateSinglePinmuxPad({
|
||||
.index = PinmuxPadIndex_Uart3Cts,
|
||||
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
|
||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetInitialDrivePadConfig() {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere.hpp>
|
||||
|
||||
// #define AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART
|
||||
// #define AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART
|
||||
@@ -16,11 +16,11 @@
|
||||
#pragma once
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 10
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 21
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 22
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||
|
||||
@@ -98,8 +98,9 @@
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_21_0_1 ATMOSPHERE_TARGET_FIRMWARE(21, 0, 1)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_21_1_0 ATMOSPHERE_TARGET_FIRMWARE(21, 1, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_21_2_0 ATMOSPHERE_TARGET_FIRMWARE(21, 2, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_22_0_0 ATMOSPHERE_TARGET_FIRMWARE(22, 0, 0)
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_21_2_0
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_0_0
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||
@@ -190,6 +191,7 @@ namespace ams {
|
||||
TargetFirmware_21_0_1 = ATMOSPHERE_TARGET_FIRMWARE_21_0_1,
|
||||
TargetFirmware_21_1_0 = ATMOSPHERE_TARGET_FIRMWARE_21_1_0,
|
||||
TargetFirmware_21_2_0 = ATMOSPHERE_TARGET_FIRMWARE_21_2_0,
|
||||
TargetFirmware_22_0_0 = ATMOSPHERE_TARGET_FIRMWARE_22_0_0,
|
||||
|
||||
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
||||
|
||||
|
||||
@@ -40,5 +40,6 @@ namespace ams::erpt {
|
||||
R_DEFINE_ERROR_RESULT(InvalidPowerState, 17);
|
||||
R_DEFINE_ERROR_RESULT(ArrayFieldTooLarge, 18);
|
||||
R_DEFINE_ERROR_RESULT(AlreadyOwned, 19);
|
||||
R_DEFINE_ERROR_RESULT(TooManyOutAttachments, 51);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@ namespace ams::svc::arch::arm {
|
||||
volatile u16 interrupt_flag;
|
||||
volatile u8 cache_maintenance_flag;
|
||||
volatile s64 thread_cpu_time;
|
||||
volatile ams::svc::Handle thread_handle;
|
||||
/* TODO: Should we bother adding the Nintendo aarch32 thread local context here? */
|
||||
uintptr_t TODO[(0x200 - 0x110) / sizeof(uintptr_t)];
|
||||
uintptr_t TODO[(0x200 - 0x114) / sizeof(uintptr_t)];
|
||||
};
|
||||
|
||||
ALWAYS_INLINE ThreadLocalRegion *GetThreadLocalRegion() {
|
||||
|
||||
@@ -27,8 +27,9 @@ namespace ams::svc::arch::arm64 {
|
||||
volatile u16 interrupt_flag;
|
||||
volatile u8 cache_maintenance_flag;
|
||||
volatile s64 thread_cpu_time;
|
||||
volatile ams::svc::Handle thread_handle;
|
||||
/* TODO: How should we handle libnx vs Nintendo user thread local space? */
|
||||
uintptr_t TODO[(0x200 - 0x110) / sizeof(uintptr_t)];
|
||||
uintptr_t TODO[(0x200 - 0x114) / sizeof(uintptr_t)];
|
||||
};
|
||||
static_assert(__builtin_offsetof(ThreadLocalRegion, disable_count) == 0x100);
|
||||
static_assert(__builtin_offsetof(ThreadLocalRegion, interrupt_flag) == 0x102);
|
||||
|
||||
@@ -57,8 +57,8 @@ namespace ams::svc {
|
||||
|
||||
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
|
||||
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
|
||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(20);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 5);
|
||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2);
|
||||
|
||||
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||
|
||||
|
||||
@@ -26,26 +26,6 @@ namespace ams {
|
||||
|
||||
}
|
||||
|
||||
int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) {
|
||||
switch (model) {
|
||||
case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast<int>(dst_size));
|
||||
case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast<int>(dst_size));
|
||||
default: return util::SNPrintf(dst, dst_size, "%d", static_cast<int>(model));
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetRegionString(settings::system::RegionCode code) {
|
||||
switch (code) {
|
||||
case settings::system::RegionCode_Japan: return "Japan";
|
||||
case settings::system::RegionCode_Usa: return "Usa";
|
||||
case settings::system::RegionCode_Europe: return "Europe";
|
||||
case settings::system::RegionCode_Australia: return "Australia";
|
||||
case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea";
|
||||
case settings::system::RegionCode_China: return "China";
|
||||
default: return "RegionUnknown";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace init {
|
||||
@@ -94,42 +74,19 @@ namespace ams {
|
||||
/* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */
|
||||
erpt::srv::SetRedirectNewReportsToSdCard(true);
|
||||
|
||||
/* Configure the OS version. */
|
||||
/* Configure the serial number, OS version, product model, and region. */
|
||||
{
|
||||
settings::system::FirmwareVersion firmware_version = {};
|
||||
const auto &sys_info = erpt::srv::GetSystemInfo();
|
||||
|
||||
settings::system::SerialNumber serial_number = {};
|
||||
settings::system::GetFirmwareVersion(std::addressof(firmware_version));
|
||||
settings::system::GetSerialNumber(std::addressof(serial_number));
|
||||
|
||||
char os_private[0x60];
|
||||
const auto os_priv_len = util::SNPrintf(os_private, sizeof(os_private), "%s (%.8s)", firmware_version.display_name, firmware_version.revision);
|
||||
AMS_ASSERT(static_cast<size_t>(os_priv_len) < sizeof(os_private));
|
||||
AMS_UNUSED(os_priv_len);
|
||||
R_ABORT_UNLESS(erpt::srv::SetSerialNumber(serial_number.str,
|
||||
strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1));
|
||||
|
||||
R_ABORT_UNLESS(erpt::srv::SetSerialNumberAndOsVersion(serial_number.str,
|
||||
strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1,
|
||||
firmware_version.display_version,
|
||||
strnlen(firmware_version.display_version, sizeof(firmware_version.display_version) - 1) + 1,
|
||||
os_private,
|
||||
strnlen(os_private, sizeof(os_private) - 1) + 1));
|
||||
}
|
||||
R_ABORT_UNLESS(erpt::srv::SetProductModel(sys_info.product_model, static_cast<u32>(std::strlen(sys_info.product_model))));
|
||||
|
||||
/* Configure the product model. */
|
||||
{
|
||||
char product_model[0x10];
|
||||
const auto pm_len = erpt::MakeProductModelString(product_model, sizeof(product_model), settings::system::GetProductModel());
|
||||
AMS_ASSERT(static_cast<size_t>(pm_len) < sizeof(product_model));
|
||||
AMS_UNUSED(pm_len);
|
||||
|
||||
R_ABORT_UNLESS(erpt::srv::SetProductModel(product_model, static_cast<u32>(std::strlen(product_model))));
|
||||
}
|
||||
|
||||
/* Configure the region. */
|
||||
{
|
||||
settings::system::RegionCode code;
|
||||
settings::system::GetRegionCode(std::addressof(code));
|
||||
const char *region_str = erpt::GetRegionString(code);
|
||||
R_ABORT_UNLESS(erpt::srv::SetRegionSetting(region_str, static_cast<u32>(std::strlen(region_str))));
|
||||
R_ABORT_UNLESS(erpt::srv::SetRegionSetting(sys_info.region, static_cast<u32>(std::strlen(sys_info.region))));
|
||||
}
|
||||
|
||||
/* Start the erpt server. */
|
||||
|
||||
Reference in New Issue
Block a user