From 4bce7efec739552c58694956eb7d6ee2a95cc3de Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 8 Oct 2024 11:50:32 -0700 Subject: [PATCH 01/14] fusee/exo/ams: update with new keydata/version enums --- .../program/source/boot/secmon_boot_key_data.s | 9 +++++++-- .../program/source/boot/secmon_package2.cpp | 2 +- fusee/program/source/fusee_key_derivation.cpp | 11 ++++++++--- fusee/program/source/fusee_package2.cpp | 2 +- fusee/program/source/fusee_setup_horizon.cpp | 2 ++ fusee/program/source/fusee_stratosphere.cpp | 16 ++++++++++++++++ .../exosphere/pkg1/pkg1_key_generation.hpp | 1 + .../libexosphere/include/exosphere/pkg2.hpp | 2 +- libraries/libexosphere/source/fuse/fuse_api.cpp | 1 + .../fs/impl/fs_id_string_impl.os.generic.cpp | 5 +++-- .../include/vapours/ams/ams_api_version.h | 8 ++++---- .../include/vapours/ams/ams_target_firmware.h | 4 +++- 12 files changed, 48 insertions(+), 15 deletions(-) diff --git a/exosphere/program/source/boot/secmon_boot_key_data.s b/exosphere/program/source/boot/secmon_boot_key_data.s index b745114f1..826441314 100644 --- a/exosphere/program/source/boot/secmon_boot_key_data.s +++ b/exosphere/program/source/boot/secmon_boot_key_data.s @@ -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 0xE4, 0x45, 0xD0, 0x14, 0xA0, 0xE5, 0xE9, 0x4B, 0xFE, 0x76, 0xF4, 0x29, 0x41, 0xBB, 0x64, 0xED +.byte 0x65, 0x7B, 0x11, 0x46, 0x0E, 0xC2, 0x22, 0x5D, 0xB9, 0xF1, 0xF5, 0x00, 0xF9, 0x3E, 0x1F, 0x70 /* Mariko Production Master Kek Source. */ -.byte 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 +.byte 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 /* 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. */ @@ -109,6 +109,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE: .byte 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 /* Master key 0E encrypted with Master key 0F. */ .byte 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 /* Master key 0F encrypted with Master key 10. */ .byte 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 /* Master key 10 encrypted with Master key 11. */ +.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. */ /* 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. */ @@ -129,6 +130,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE: .byte 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 /* Master key 0E encrypted with Master key 0F. */ .byte 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD /* Master key 0F encrypted with Master key 10. */ .byte 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 /* Master key 10 encrypted with Master key 11. */ +.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. */ /* 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. */ @@ -146,6 +148,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE: .byte 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C /* 16.0.0 Device Master Key Source Source. */ .byte 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 /* 17.0.0 Device Master Key Source Source. */ .byte 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 /* 18.0.0 Device Master Key Source Source. */ +.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. */ /* 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. */ @@ -163,6 +166,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE: .byte 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F /* 16.0.0 Device Master Kek Source. */ .byte 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 /* 17.0.0 Device Master Kek Source. */ .byte 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF /* 18.0.0 Device Master Kek Source. */ +.byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.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. */ @@ -180,3 +184,4 @@ _ZN3ams6secmon4boot15VolatileKeyDataE: .byte 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F /* 16.0.0 Device Master Kek Source. */ .byte 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E /* 17.0.0 Device Master Kek Source. */ .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. */ diff --git a/exosphere/program/source/boot/secmon_package2.cpp b/exosphere/program/source/boot/secmon_package2.cpp index a51e1a712..2d6b8948e 100644 --- a/exosphere/program/source/boot/secmon_package2.cpp +++ b/exosphere/program/source/boot/secmon_package2.cpp @@ -94,7 +94,7 @@ namespace ams::secmon::boot { } /* Check that the key generation is one that we can use. */ - static_assert(pkg1::KeyGeneration_Count == 18); + static_assert(pkg1::KeyGeneration_Count == 19); if (key_generation >= pkg1::KeyGeneration_Count) { return false; } diff --git a/fusee/program/source/fusee_key_derivation.cpp b/fusee/program/source/fusee_key_derivation.cpp index cad7ca589..3d8eb31bf 100644 --- a/fusee/program/source/fusee_key_derivation.cpp +++ b/fusee/program/source/fusee_key_derivation.cpp @@ -23,17 +23,17 @@ namespace ams::nxboot { alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ - 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 + 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }; alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ - 0xE4, 0x45, 0xD0, 0x14, 0xA0, 0xE5, 0xE9, 0x4B, 0xFE, 0x76, 0xF4, 0x29, 0x41, 0xBB, 0x64, 0xED + 0x65, 0x7B, 0x11, 0x46, 0x0E, 0xC2, 0x22, 0x5D, 0xB9, 0xF1, 0xF5, 0x00, 0xF9, 0x3E, 0x1F, 0x70 }; alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ - 0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1 + 0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3 }; alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = { @@ -72,6 +72,7 @@ namespace ams::nxboot { { 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, /* 16.0.0 Device Master Key Source Source. */ { 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, /* 17.0.0 Device Master Key Source Source. */ { 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, /* 18.0.0 Device Master Key Source Source. */ + { 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { @@ -90,6 +91,7 @@ namespace ams::nxboot { { 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, /* 16.0.0 Device Master Kek Source. */ { 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, /* 17.0.0 Device Master Kek Source. */ { 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, /* 18.0.0 Device Master Kek Source. */ + { 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { @@ -108,6 +110,7 @@ namespace ams::nxboot { { 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F }, /* 16.0.0 Device Master Kek Source. */ { 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 }, /* 17.0.0 Device Master Kek Source. */ { 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF }, /* 18.0.0 Device Master Kek Source. */ + { 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = { @@ -129,6 +132,7 @@ namespace ams::nxboot { { 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, /* Master key 0E encrypted with Master key 0F. */ { 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, /* Master key 0F encrypted with Master key 10. */ { 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, /* Master key 10 encrypted with Master key 11. */ + { 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */ }; alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = { @@ -150,6 +154,7 @@ namespace ams::nxboot { { 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, /* Master key 0E encrypted with Master key 0F. */ { 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 }, /* Master key 0F encrypted with Master key 10. */ { 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 }, /* Master key 10 encrypted with Master key 11. */ + { 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */ }; alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {}; diff --git a/fusee/program/source/fusee_package2.cpp b/fusee/program/source/fusee_package2.cpp index 535f0f68d..9735b0f0b 100644 --- a/fusee/program/source/fusee_package2.cpp +++ b/fusee/program/source/fusee_package2.cpp @@ -80,7 +80,7 @@ namespace ams::nxboot { } /* Check that the key generation is one that we can use. */ - static_assert(pkg1::KeyGeneration_Count == 18); + static_assert(pkg1::KeyGeneration_Count == 19); if (key_generation >= pkg1::KeyGeneration_Count) { return false; } diff --git a/fusee/program/source/fusee_setup_horizon.cpp b/fusee/program/source/fusee_setup_horizon.cpp index 78c40b216..6d0d6a384 100644 --- a/fusee/program/source/fusee_setup_horizon.cpp +++ b/fusee/program/source/fusee_setup_horizon.cpp @@ -261,6 +261,8 @@ namespace ams::nxboot { return ams::TargetFirmware_17_0_0; } else if (std::memcmp(package1 + 0x10, "20240207", 8) == 0) { return ams::TargetFirmware_18_0_0; + } else if (std::memcmp(package1 + 0x10, "20240808", 8) == 0) { + return ams::TargetFirmware_19_0_0; } break; default: diff --git a/fusee/program/source/fusee_stratosphere.cpp b/fusee/program/source/fusee_stratosphere.cpp index a7a380d97..99fea38bd 100644 --- a/fusee/program/source/fusee_stratosphere.cpp +++ b/fusee/program/source/fusee_stratosphere.cpp @@ -177,6 +177,9 @@ namespace ams::nxboot { FsVersion_18_1_0, FsVersion_18_1_0_Exfat, + FsVersion_19_0_0, + FsVersion_19_0_0_Exfat, + FsVersion_Count, }; @@ -266,6 +269,9 @@ namespace ams::nxboot { { 0xA3, 0x39, 0xF0, 0x1C, 0x95, 0xBF, 0xA7, 0x68 }, /* FsVersion_18_1_0 */ { 0x20, 0x4C, 0xBA, 0x86, 0xDE, 0x08, 0x44, 0x6A }, /* FsVersion_18_1_0_Exfat */ + + { 0xD9, 0x4C, 0x68, 0x15, 0xF8, 0xF5, 0x0A, 0x20 }, /* FsVersion_19_0_0 */ + { 0xED, 0xA8, 0x78, 0x68, 0xA4, 0x49, 0x07, 0x50 }, /* FsVersion_19_0_0_Exfat */ }; const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) { @@ -645,6 +651,16 @@ namespace ams::nxboot { AddPatch(fs_meta, 0x195FD9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16FBE0, NogcPatch1, sizeof(NogcPatch1)); break; + case FsVersion_19_0_0: + AddPatch(fs_meta, 0x195C75, NogcPatch0, sizeof(NogcPatch0)); + AddPatch(fs_meta, 0x195E75, NogcPatch0, sizeof(NogcPatch0)); + AddPatch(fs_meta, 0x16F170, NogcPatch1, sizeof(NogcPatch1)); + break; + case FsVersion_19_0_0_Exfat: + AddPatch(fs_meta, 0x1A14A5, NogcPatch0, sizeof(NogcPatch0)); + AddPatch(fs_meta, 0x1A16A5, NogcPatch0, sizeof(NogcPatch0)); + AddPatch(fs_meta, 0x17A9A0, NogcPatch1, sizeof(NogcPatch1)); + break; default: break; } diff --git a/libraries/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp b/libraries/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp index 0cfc43633..92aea986e 100644 --- a/libraries/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp +++ b/libraries/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp @@ -38,6 +38,7 @@ namespace ams::pkg1 { KeyGeneration_16_0_0 = 0x0F, KeyGeneration_17_0_0 = 0x10, KeyGeneration_18_0_0 = 0x11, + KeyGeneration_19_0_0 = 0x12, KeyGeneration_Count, diff --git a/libraries/libexosphere/include/exosphere/pkg2.hpp b/libraries/libexosphere/include/exosphere/pkg2.hpp index 8775d2ed9..d72ce1f03 100644 --- a/libraries/libexosphere/include/exosphere/pkg2.hpp +++ b/libraries/libexosphere/include/exosphere/pkg2.hpp @@ -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 = 0x15; + constexpr inline int CurrentBootloaderVersion = 0x16; struct Package2Meta { using Magic = util::FourCC<'P','K','2','1'>; diff --git a/libraries/libexosphere/source/fuse/fuse_api.cpp b/libraries/libexosphere/source/fuse/fuse_api.cpp index 95c316d68..e20dddcc0 100644 --- a/libraries/libexosphere/source/fuse/fuse_api.cpp +++ b/libraries/libexosphere/source/fuse/fuse_api.cpp @@ -177,6 +177,7 @@ namespace ams::fuse { } constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = { + TargetFirmware_19_0_0, TargetFirmware_17_0_0, TargetFirmware_16_0_0, TargetFirmware_15_0_0, diff --git a/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp b/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp index 091b19d3a..5e2d9b60f 100644 --- a/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp +++ b/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp @@ -21,7 +21,7 @@ namespace ams::fs::impl { #define ADD_ENUM_CASE(v) case v: return #v template<> const char *IdString::ToString(pkg1::KeyGeneration id) { - static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_18_0_0); + static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_19_0_0); switch (id) { using enum pkg1::KeyGeneration; case KeyGeneration_1_0_0: return "1.0.0-2.3.0"; @@ -41,7 +41,8 @@ namespace ams::fs::impl { case KeyGeneration_15_0_0: return "15.0.0-15.0.1"; case KeyGeneration_16_0_0: return "16.0.0-16.0.3"; case KeyGeneration_17_0_0: return "17.0.0-17.0.1"; - case KeyGeneration_18_0_0: return "18.0.0-"; + case KeyGeneration_18_0_0: return "18.0.0-18.1.0"; + case KeyGeneration_19_0_0: return "19.0.0-"; default: return "Unknown"; } } diff --git a/libraries/libvapours/include/vapours/ams/ams_api_version.h b/libraries/libvapours/include/vapours/ams/ams_api_version.h index 0e06af0fb..978b1622e 100644 --- a/libraries/libvapours/include/vapours/ams/ams_api_version.h +++ b/libraries/libvapours/include/vapours/ams/ams_api_version.h @@ -16,11 +16,11 @@ #pragma once #define ATMOSPHERE_RELEASE_VERSION_MAJOR 1 -#define ATMOSPHERE_RELEASE_VERSION_MINOR 7 -#define ATMOSPHERE_RELEASE_VERSION_MICRO 1 +#define ATMOSPHERE_RELEASE_VERSION_MINOR 8 +#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 18 -#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 19 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 diff --git a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h index 0dde6da81..484f76f8b 100644 --- a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h +++ b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h @@ -82,8 +82,9 @@ #define ATMOSPHERE_TARGET_FIRMWARE_17_0_1 ATMOSPHERE_TARGET_FIRMWARE(17, 0, 1) #define ATMOSPHERE_TARGET_FIRMWARE_18_0_0 ATMOSPHERE_TARGET_FIRMWARE(18, 0, 0) #define ATMOSPHERE_TARGET_FIRMWARE_18_1_0 ATMOSPHERE_TARGET_FIRMWARE(18, 1, 0) +#define ATMOSPHERE_TARGET_FIRMWARE_19_0_0 ATMOSPHERE_TARGET_FIRMWARE(19, 0, 0) -#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_18_1_0 +#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_19_0_0 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0) #define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT @@ -158,6 +159,7 @@ namespace ams { TargetFirmware_17_0_1 = ATMOSPHERE_TARGET_FIRMWARE_17_0_1, TargetFirmware_18_0_0 = ATMOSPHERE_TARGET_FIRMWARE_18_0_0, TargetFirmware_18_1_0 = ATMOSPHERE_TARGET_FIRMWARE_18_1_0, + TargetFirmware_19_0_0 = ATMOSPHERE_TARGET_FIRMWARE_19_0_0, TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT, From 4793ba2caaf70c5ebc3f62f6aa0808115244c6ae Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 8 Oct 2024 12:24:41 -0700 Subject: [PATCH 02/14] erpt: add new IDs/categories --- .../stratosphere/erpt/erpt_ids.autogen.hpp | 80 +++++++++++++------ utilities/erpt.py | 3 + 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/erpt/erpt_ids.autogen.hpp b/libraries/libstratosphere/include/stratosphere/erpt/erpt_ids.autogen.hpp index 92d6db7dc..c7e5eef6b 100644 --- a/libraries/libstratosphere/include/stratosphere/erpt/erpt_ids.autogen.hpp +++ b/libraries/libstratosphere/include/stratosphere/erpt/erpt_ids.autogen.hpp @@ -81,8 +81,8 @@ HANDLER(NetworkErrorInfo, 40 ) \ HANDLER(FileAccessPathInfo, 41 ) \ HANDLER(GameCardCIDInfo, 42 ) \ - HANDLER(NANDCIDInfo, 43 ) \ - HANDLER(MicroSDCIDInfo, 44 ) \ + HANDLER(NANDCIDInfoDeprecated, 43 ) \ + HANDLER(MicroSDCIDInfoDeprecated, 44 ) \ HANDLER(NANDSpeedModeInfo, 45 ) \ HANDLER(MicroSDSpeedModeInfo, 46 ) \ HANDLER(GameCardSpeedModeInfo, 47 ) \ @@ -112,7 +112,7 @@ HANDLER(FocusedAppletHistoryInfo, 71 ) \ HANDLER(CompositorInfo, 72 ) \ HANDLER(BatteryChargeInfo, 73 ) \ - HANDLER(NANDExtendedCsd, 74 ) \ + HANDLER(NANDExtendedCsdDeprecated, 74 ) \ HANDLER(NANDPatrolInfo, 75 ) \ HANDLER(NANDErrorInfo, 76 ) \ HANDLER(NANDDriverLog, 77 ) \ @@ -178,9 +178,12 @@ HANDLER(BuiltInWirelessOUIInfo, 137 ) \ HANDLER(WirelessAPOUIInfo, 138 ) \ HANDLER(EthernetAdapterOUIInfo, 139 ) \ - HANDLER(NANDTypeInfo, 140 ) \ + HANDLER(NANDTypeInfoDeprecated, 140 ) \ HANDLER(MicroSDTypeInfo, 141 ) \ - HANDLER(TestNx, 1000) + HANDLER(AttachmentFileInfo, 142 ) \ + HANDLER(TestNx, 1000) \ + HANDLER(NANDTypeInfo, 1001) \ + HANDLER(NANDExtendedCsd, 1002) \ #define AMS_ERPT_FOREACH_FIELD(HANDLER) \ HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \ @@ -280,8 +283,8 @@ HANDLER(CDNContentPath, 94, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(FileAccessPath, 95, FileAccessPathInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardCID, 96, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \ - HANDLER(NANDCID, 97, NANDCIDInfo, FieldType_U8Array, FieldFlag_None ) \ - HANDLER(MicroSDCID, 98, MicroSDCIDInfo, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(NANDCIDDeprecated, 97, NANDCIDInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(MicroSDCIDDeprecated, 98, MicroSDCIDInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NANDSpeedMode, 99, NANDSpeedModeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(MicroSDSpeedMode, 100, MicroSDSpeedModeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardSpeedMode, 101, GameCardSpeedModeInfo, FieldType_String, FieldFlag_None ) \ @@ -373,9 +376,9 @@ HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ControllerPowerSupplyAcquiredDeprecated, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(OtgRequestedDeprecated, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ - HANDLER(NANDPreEolInfo, 190, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ - HANDLER(NANDDeviceLifeTimeEstTypA, 191, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ - HANDLER(NANDDeviceLifeTimeEstTypB, 192, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(NANDPreEolInfoDeprecated, 190, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(NANDDeviceLifeTimeEstTypADeprecated, 191, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(NANDDeviceLifeTimeEstTypBDeprecated, 192, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDPatrolCount, 193, NANDPatrolInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumActivationFailures, 194, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumActivationErrorCorrections, 195, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ @@ -446,21 +449,21 @@ HANDLER(AdspExceptionStackDumpDeprecated, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionReasonDeprecated, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(OscillatorClock, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \ - HANDLER(CpuDvfsTableClocks, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ - HANDLER(CpuDvfsTableVoltages, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ - HANDLER(GpuDvfsTableClocks, 265, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ - HANDLER(GpuDvfsTableVoltages, 266, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ - HANDLER(EmcDvfsTableClocks, 267, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ - HANDLER(EmcDvfsTableVoltages, 268, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(CpuDvfsTableClocksDeprecated, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(CpuDvfsTableVoltagesDeprecated, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(GpuDvfsTableClocksDeprecated, 265, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(GpuDvfsTableVoltagesDeprecated, 266, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(EmcDvfsTableClocksDeprecated, 267, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(EmcDvfsTableVoltagesDeprecated, 268, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(ModuleClockFrequencies, 269, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(ModuleClockEnableFlags, 270, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModulePowerEnableFlags, 271, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModuleResetAssertFlags, 272, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModuleMinimumVoltageClockRates, 273, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ - HANDLER(PowerDomainEnableFlags, 274, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ - HANDLER(PowerDomainVoltages, 275, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(PowerDomainEnableFlagsDeprecated, 274, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(PowerDomainVoltagesDeprecated, 275, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(AccessPointRssi, 276, RadioStrengthInfo, FieldType_NumericI32, FieldFlag_None ) \ - HANDLER(FuseInfo, 277, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(FuseInfoDeprecated, 277, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(VideoLog, 278, VideoInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardDeviceId, 279, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardAsicReinitializeCount, 280, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ @@ -830,9 +833,9 @@ HANDLER(RuntimeLimitedApplicationLicenseUpgrade, 644, RunningApplicationInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(ServiceProfileRevisionKey, 645, ServiceProfileInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(BluetoothAudioConnectionCount, 646, BluetoothAudioInfo, FieldType_NumericU8, FieldFlag_None ) \ - HANDLER(BluetoothHidPairingInfoCount, 647, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ - HANDLER(BluetoothAudioPairingInfoCount, 648, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ - HANDLER(BluetoothLePairingInfoCount, 649, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(BluetoothHidPairingInfoCountDeprecated, 647, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(BluetoothAudioPairingInfoCountDeprecated, 648, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(BluetoothLePairingInfoCountDeprecated, 649, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatFsBisSystemFilePeakOpenCount, 650, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisSystemDirectoryPeakOpenCount, 651, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisUserFilePeakOpenCount, 652, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ @@ -860,11 +863,24 @@ HANDLER(FatFsBisUserFatErrorNumber, 674, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsBisUserFatSafeErrorNumber, 675, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(GpuCrashDump2, 676, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \ - HANDLER(NANDType, 677, NANDTypeInfo, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(NANDTypeDeprecated, 677, NANDTypeInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ HANDLER(MicroSDType, 678, MicroSDTypeInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardLastDeactivateReasonResult, 679, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLastDeactivateReason, 680, GameCardErrorInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(InvalidErrorCode, 681, ErrorInfo, FieldType_String, FieldFlag_None ) \ + HANDLER(AppletId, 682, ApplicationInfo, FieldType_NumericI32, FieldFlag_None ) \ + HANDLER(PrevReportIdentifier, 683, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ + HANDLER(SyslogStartupTimeBase, 684, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ + HANDLER(NxdmpIsAttached, 685, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ + HANDLER(ScreenshotIsAttached, 686, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ + HANDLER(SyslogIsAttached, 687, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ + HANDLER(SaveSyslogResult, 688, AttachmentFileInfo, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(EncryptionKeyGeneration, 689, ErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ + HANDLER(FsBufferManagerNonBlockingRetriedCount, 690, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ + HANDLER(FsPooledBufferNonBlockingRetriedCount, 691, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ + HANDLER(LastConnectionTestDownloadSpeed64, 692, ConnectionInfo, FieldType_NumericU64, FieldFlag_None ) \ + HANDLER(LastConnectionTestUploadSpeed64, 693, ConnectionInfo, FieldType_NumericU64, FieldFlag_None ) \ + HANDLER(EncryptionKeyV1, 694, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \ HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ @@ -877,5 +893,21 @@ HANDLER(AdspExceptionArmModeRegisters, 1009, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionStackAddress, 1010, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionStackDump, 1011, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ - HANDLER(AdspExceptionReason, 1012, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) + HANDLER(AdspExceptionReason, 1012, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(CpuDvfsTableClocks, 1013, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(CpuDvfsTableVoltages, 1014, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(GpuDvfsTableClocks, 1015, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(GpuDvfsTableVoltages, 1016, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(EmcDvfsTableClocks, 1017, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(EmcDvfsTableVoltages, 1018, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(PowerDomainEnableFlags, 1019, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(PowerDomainVoltages, 1020, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ + HANDLER(FuseInfo, 1021, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ + HANDLER(NANDType, 1022, NANDTypeInfo, FieldType_U8Array, FieldFlag_None ) \ + HANDLER(BluetoothHidPairingInfoCount, 1023, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(BluetoothAudioPairingInfoCount, 1024, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(BluetoothLePairingInfoCount, 1025, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ + HANDLER(NANDPreEolInfo, 1026, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(NANDDeviceLifeTimeEstTypA, 1027, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ + HANDLER(NANDDeviceLifeTimeEstTypB, 1028, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) diff --git a/utilities/erpt.py b/utilities/erpt.py index 94d0919cd..fb697cb13 100644 --- a/utilities/erpt.py +++ b/utilities/erpt.py @@ -238,7 +238,10 @@ CATEGORIES = { 139 : 'EthernetAdapterOUIInfo', 140 : 'NANDTypeInfo', 141 : 'MicroSDTypeInfo', + 142 : 'AttachmentFileInfo', 1000 : 'TestNx', + 1001 : 'NANDTypeInfo', + 1002 : 'NANDExtendedCsd', } FIELD_TYPES = { From 34e27ee97dc0b52e80a9a4f0c4d3c2e8bd0d0f2c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 8 Oct 2024 16:12:56 -0700 Subject: [PATCH 03/14] emummc: update for 19.0.0 --- emummc/README.md | 2 +- emummc/source/FS/FS_offsets.c | 8 ++++ emummc/source/FS/FS_versions.h | 3 ++ emummc/source/FS/offsets/1900.h | 59 +++++++++++++++++++++++++++ emummc/source/FS/offsets/1900_exfat.h | 59 +++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 emummc/source/FS/offsets/1900.h create mode 100644 emummc/source/FS/offsets/1900_exfat.h diff --git a/emummc/README.md b/emummc/README.md index f01783ba5..cada2cdb5 100644 --- a/emummc/README.md +++ b/emummc/README.md @@ -2,7 +2,7 @@ *A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw*** ### Supported Horizon Versions -**1.0.0 - 18.1.0** +**1.0.0 - 19.0.0** ## Features * Arbitrary SDMMC backend selection diff --git a/emummc/source/FS/FS_offsets.c b/emummc/source/FS/FS_offsets.c index b2059c092..64ac34562 100644 --- a/emummc/source/FS/FS_offsets.c +++ b/emummc/source/FS/FS_offsets.c @@ -73,6 +73,8 @@ #include "offsets/1800_exfat.h" #include "offsets/1810.h" #include "offsets/1810_exfat.h" +#include "offsets/1900.h" +#include "offsets/1900_exfat.h" #include "../utils/fatal.h" #define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers @@ -157,6 +159,8 @@ DEFINE_OFFSET_STRUCT(_1800); DEFINE_OFFSET_STRUCT(_1800_EXFAT); DEFINE_OFFSET_STRUCT(_1810); DEFINE_OFFSET_STRUCT(_1810_EXFAT); +DEFINE_OFFSET_STRUCT(_1900); +DEFINE_OFFSET_STRUCT(_1900_EXFAT); const fs_offsets_t *get_fs_offsets(enum FS_VER version) { switch (version) { @@ -274,6 +278,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) { return &(GET_OFFSET_STRUCT_NAME(_1810)); case FS_VER_18_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1810_EXFAT)); + case FS_VER_19_0_0: + return &(GET_OFFSET_STRUCT_NAME(_1900)); + case FS_VER_19_0_0_EXFAT: + return &(GET_OFFSET_STRUCT_NAME(_1900_EXFAT)); default: fatal_abort(Fatal_UnknownVersion); } diff --git a/emummc/source/FS/FS_versions.h b/emummc/source/FS/FS_versions.h index ec4f9ecf8..6eebac186 100644 --- a/emummc/source/FS/FS_versions.h +++ b/emummc/source/FS/FS_versions.h @@ -107,6 +107,9 @@ enum FS_VER FS_VER_18_1_0, FS_VER_18_1_0_EXFAT, + FS_VER_19_0_0, + FS_VER_19_0_0_EXFAT, + FS_VER_MAX, }; diff --git a/emummc/source/FS/offsets/1900.h b/emummc/source/FS/offsets/1900.h new file mode 100644 index 000000000..82ffd0f94 --- /dev/null +++ b/emummc/source/FS/offsets/1900.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-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 . + */ +#ifndef __FS_1900_H__ +#define __FS_1900_H__ + +// Accessor vtable getters +#define FS_OFFSET_1900_SDMMC_ACCESSOR_GC 0x195C00 +#define FS_OFFSET_1900_SDMMC_ACCESSOR_SD 0x197F80 +#define FS_OFFSET_1900_SDMMC_ACCESSOR_NAND 0x1963B0 + +// Hooks +#define FS_OFFSET_1900_SDMMC_WRAPPER_READ 0x191A70 +#define FS_OFFSET_1900_SDMMC_WRAPPER_WRITE 0x191AD0 +#define FS_OFFSET_1900_RTLD 0x275F0 +#define FS_OFFSET_1900_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x50))) + +#define FS_OFFSET_1900_CLKRST_SET_MIN_V_CLK_RATE 0x1B3880 + +// Misc funcs +#define FS_OFFSET_1900_LOCK_MUTEX 0x18AC20 +#define FS_OFFSET_1900_UNLOCK_MUTEX 0x18AC70 + +#define FS_OFFSET_1900_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191A30 +#define FS_OFFSET_1900_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191A50 + +// Misc Data +#define FS_OFFSET_1900_SD_MUTEX 0xFE1408 +#define FS_OFFSET_1900_NAND_MUTEX 0xFDCB60 +#define FS_OFFSET_1900_ACTIVE_PARTITION 0xFDCBA0 +#define FS_OFFSET_1900_SDMMC_DAS_HANDLE 0xFC1908 + +// NOPs +#define FS_OFFSET_1900_SD_DAS_INIT 0x260C4 + +// Nintendo Paths +#define FS_OFFSET_1900_NINTENDO_PATHS \ +{ \ + {.opcode_reg = 3, .adrp_offset = 0x00067FC8, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 3, .adrp_offset = 0x00075D6C, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 4, .adrp_offset = 0x0007D1E8, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 4, .adrp_offset = 0x00092818, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ +} + +#endif // __FS_1900_H__ diff --git a/emummc/source/FS/offsets/1900_exfat.h b/emummc/source/FS/offsets/1900_exfat.h new file mode 100644 index 000000000..2bbf0c899 --- /dev/null +++ b/emummc/source/FS/offsets/1900_exfat.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-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 . + */ +#ifndef __FS_1900_EXFAT_H__ +#define __FS_1900_EXFAT_H__ + +// Accessor vtable getters +#define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_GC 0x1A1430 +#define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_SD 0x1A37B0 +#define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_NAND 0x1A1BE0 + +// Hooks +#define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_READ 0x19D2A0 +#define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_WRITE 0x19D300 +#define FS_OFFSET_1900_EXFAT_RTLD 0x275F0 +#define FS_OFFSET_1900_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x50))) + +#define FS_OFFSET_1900_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1BF0B0 + +// Misc funcs +#define FS_OFFSET_1900_EXFAT_LOCK_MUTEX 0x196450 +#define FS_OFFSET_1900_EXFAT_UNLOCK_MUTEX 0x1964A0 + +#define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x19D260 +#define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x19D280 + +// Misc Data +#define FS_OFFSET_1900_EXFAT_SD_MUTEX 0xFF4408 +#define FS_OFFSET_1900_EXFAT_NAND_MUTEX 0xFEFB60 +#define FS_OFFSET_1900_EXFAT_ACTIVE_PARTITION 0xFEFBA0 +#define FS_OFFSET_1900_EXFAT_SDMMC_DAS_HANDLE 0xFCF908 + +// NOPs +#define FS_OFFSET_1900_EXFAT_SD_DAS_INIT 0x260C4 + +// Nintendo Paths +#define FS_OFFSET_1900_EXFAT_NINTENDO_PATHS \ +{ \ + {.opcode_reg = 3, .adrp_offset = 0x00067FC8, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 3, .adrp_offset = 0x00075D6C, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 4, .adrp_offset = 0x0007D1E8, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 4, .adrp_offset = 0x00092818, .add_rel_offset = 0x00000004}, \ + {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ +} + +#endif // __FS_1900_EXFAT_H__ From 483d06ac0e2229776c0e3a48dffe5469e6432e99 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 11:04:43 -0700 Subject: [PATCH 04/14] kern: add InfoType_TransferMemoryHint --- .../mesosphere/kern_k_transfer_memory.hpp | 16 ++++++++++++++++ .../libmesosphere/source/svc/kern_svc_info.cpp | 13 +++++++++++++ .../include/vapours/svc/svc_types_common.hpp | 2 ++ 3 files changed, 31 insertions(+) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_transfer_memory.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_transfer_memory.hpp index cd88f3abf..c34ceb8c3 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_transfer_memory.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_transfer_memory.hpp @@ -48,6 +48,22 @@ namespace ams::kern { KProcess *GetOwner() const { return m_owner; } KProcessAddress GetSourceAddress() { return m_address; } size_t GetSize() const { return m_is_initialized ? GetReference(m_page_group).GetNumPages() * PageSize : 0; } + + constexpr uintptr_t GetHint() const { + /* Get memory size. */ + const size_t size = this->GetSize(); + + /* TODO: Is this architecture specific? */ + if (size >= 2_MB) { + return GetInteger(m_address) & (2_MB - 1); + } else if (size >= 64_KB) { + return GetInteger(m_address) & (64_KB - 1); + } else if (size >= 4_KB) { + return GetInteger(m_address) & (4_KB - 1); + } else { + return 0; + } + } }; } diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index e9153edbb..ec41ef59a 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -314,6 +314,19 @@ namespace ams::kern::svc { *out = io_region->GetHint(); } break; + case ams::svc::InfoType_TransferMemoryHint: + { + /* Verify the sub-type is valid. */ + R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); + + /* Get the transfer memory from its handle. */ + KScopedAutoObject transfer_memory = GetCurrentProcess().GetHandleTable().GetObject(handle); + R_UNLESS(transfer_memory.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the transfer memory's address hint. */ + *out = transfer_memory->GetHint(); + } + break; case ams::svc::InfoType_MesosphereMeta: { /* Verify the handle is invalid. */ diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 5668cd2dd..0247f59b9 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -191,6 +191,8 @@ namespace ams::svc { InfoType_IsSvcPermitted = 26, InfoType_IoRegionHint = 27, InfoType_AliasRegionExtraSize = 28, + /* ... */ + InfoType_TransferMemoryHint = 34, InfoType_MesosphereMeta = 65000, InfoType_MesosphereCurrentProcess = 65001, From 456b88ed9a9d2a84f36ed3a21867fc6b4b281f49 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 11:36:17 -0700 Subject: [PATCH 05/14] kern/svc: update WaitForAddress to support 64-bit WaitIfEqual --- .../arm64/kern_userspace_memory_access.hpp | 1 + .../mesosphere/kern_k_address_arbiter.hpp | 11 +-- .../include/mesosphere/kern_k_process.hpp | 2 +- .../arm64/kern_userspace_memory_access_asm.s | 14 ++++ .../arm64/svc/kern_svc_address_arbiter_asm.s | 67 +++++++++++++++++++ .../source/arch/arm64/svc/kern_svc_tables.cpp | 8 +++ .../source/kern_k_address_arbiter.cpp | 51 ++++++++++++++ .../source/svc/kern_svc_address_arbiter.cpp | 17 +++-- .../svc/svc_stratosphere_shims.hpp | 2 +- .../vapours/svc/svc_definition_macro.hpp | 2 +- .../include/vapours/svc/svc_types_common.hpp | 1 + 11 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 libraries/libmesosphere/source/arch/arm64/svc/kern_svc_address_arbiter_asm.s diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp index 202be5f51..9e0c1844e 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp @@ -25,6 +25,7 @@ namespace ams::kern::arch::arm64 { static bool CopyMemoryFromUser(void *dst, const void *src, size_t size); static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size); static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size); + static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src); static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src); static s32 CopyStringFromUser(void *dst, const void *src, size_t size); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_arbiter.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_arbiter.hpp index 4066de80d..f4ef74e6b 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_address_arbiter.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_arbiter.hpp @@ -39,14 +39,16 @@ namespace ams::kern { } } - Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s32 value, s64 timeout) { + Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s64 value, s64 timeout) { switch (type) { case ams::svc::ArbitrationType_WaitIfLessThan: - R_RETURN(this->WaitIfLessThan(addr, value, false, timeout)); + R_RETURN(this->WaitIfLessThan(addr, static_cast(value), false, timeout)); case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan: - R_RETURN(this->WaitIfLessThan(addr, value, true, timeout)); + R_RETURN(this->WaitIfLessThan(addr, static_cast(value), true, timeout)); case ams::svc::ArbitrationType_WaitIfEqual: - R_RETURN(this->WaitIfEqual(addr, value, timeout)); + R_RETURN(this->WaitIfEqual(addr, static_cast(value), timeout)); + case ams::svc::ArbitrationType_WaitIfEqual64: + R_RETURN(this->WaitIfEqual64(addr, value, timeout)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } @@ -56,6 +58,7 @@ namespace ams::kern { Result SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count); Result WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout); Result WaitIfEqual(uintptr_t addr, s32 value, s64 timeout); + Result WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout); }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 3258d41e2..5a37e3a6b 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -360,7 +360,7 @@ namespace ams::kern { R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count)); } - Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s32 value, s64 timeout) { + Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s64 value, s64 timeout) { R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout)); } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s b/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s index 5b1fd4a51..e697fde3c 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s +++ b/libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s @@ -126,6 +126,20 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm: mov x0, #1 ret +/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */ +.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits +.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv +.type _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, %function +.balign 0x10 +_ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv: + /* Just load and store a u64. */ + ldtr x2, [x1] + str x2, [x0] + + /* We're done. */ + mov x0, #1 + ret + /* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_address_arbiter_asm.s b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_address_arbiter_asm.s new file mode 100644 index 000000000..f82db4454 --- /dev/null +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_address_arbiter_asm.s @@ -0,0 +1,67 @@ +/* + * 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 . + */ + +/* ams::kern::svc::CallWaitForAddress64From32() */ +.section .text._ZN3ams4kern3svc26CallWaitForAddress64From32Ev, "ax", %progbits +.global _ZN3ams4kern3svc26CallWaitForAddress64From32Ev +.type _ZN3ams4kern3svc26CallWaitForAddress64From32Ev, %function +_ZN3ams4kern3svc26CallWaitForAddress64From32Ev: + /* Save LR + callee-save registers. */ + str x30, [sp, #-16]! + stp x6, x7, [sp, #-16]! + + /* Gather the arguments into correct registers. */ + /* NOTE: This has to be manually implemented via asm, */ + /* in order to avoid breaking ABI with pre-19.0.0. */ + orr x2, x2, x5, lsl#32 + orr x3, x3, x4, lsl#32 + + /* Invoke the svc handler. */ + bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll + + /* Clean up registers. */ + mov x1, xzr + mov x2, xzr + mov x3, xzr + mov x4, xzr + mov x5, xzr + + ldp x6, x7, [sp], #0x10 + ldr x30, [sp], #0x10 + ret + +/* ams::kern::svc::CallWaitForAddress64() */ +.section .text._ZN3ams4kern3svc20CallWaitForAddress64Ev, "ax", %progbits +.global _ZN3ams4kern3svc20CallWaitForAddress64Ev +.type _ZN3ams4kern3svc20CallWaitForAddress64Ev, %function +_ZN3ams4kern3svc20CallWaitForAddress64Ev: + /* Save LR + FP. */ + stp x29, x30, [sp, #-16]! + + /* Invoke the svc handler. */ + bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll + + /* Clean up registers. */ + mov x1, xzr + mov x2, xzr + mov x3, xzr + mov x4, xzr + mov x5, xzr + mov x6, xzr + mov x7, xzr + + ldp x29, x30, [sp], #0x10 + ret diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp index cb9151823..cfc0cb7c5 100644 --- a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp @@ -36,6 +36,10 @@ namespace ams::kern::svc { /* Declare special prototype for (unsupported) CallCallSecureMonitor64From32. */ void CallCallSecureMonitor64From32(); + /* Declare special prototypes for WaitForAddress. */ + void CallWaitForAddress64(); + void CallWaitForAddress64From32(); + namespace { #ifndef MESOSPHERE_USE_STUBBED_SVC_TABLES @@ -81,6 +85,8 @@ namespace ams::kern::svc { table[svc::SvcId_CallSecureMonitor] = CallCallSecureMonitor64From32; + table[svc::SvcId_WaitForAddress] = CallWaitForAddress64From32; + return table; }(); @@ -97,6 +103,8 @@ namespace ams::kern::svc { table[svc::SvcId_ReturnFromException] = CallReturnFromException64; + table[svc::SvcId_WaitForAddress] = CallWaitForAddress64; + return table; }(); diff --git a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp index c084c9053..66c0c1645 100644 --- a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp +++ b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp @@ -23,6 +23,10 @@ namespace ams::kern { return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address)); } + ALWAYS_INLINE bool ReadFromUser(s64 *out, KProcessAddress address) { + return UserspaceAccess::CopyMemoryFromUserSize64Bit(out, GetVoidPointer(address)); + } + ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) { /* NOTE: If scheduler lock is not held here, interrupt disable is required. */ /* KScopedInterruptDisable di; */ @@ -279,4 +283,51 @@ namespace ams::kern { R_RETURN(cur_thread->GetWaitResult()); } + Result KAddressArbiter::WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout) { + /* Prepare to wait. */ + KThread *cur_thread = GetCurrentThreadPointer(); + KHardwareTimer *timer; + ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree)); + + { + KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); + + /* Check that the thread isn't terminating. */ + if (cur_thread->IsTerminationRequested()) { + slp.CancelSleep(); + R_THROW(svc::ResultTerminationRequested()); + } + + /* Read the value from userspace. */ + s64 user_value; + if (!ReadFromUser(std::addressof(user_value), addr)) { + slp.CancelSleep(); + R_THROW(svc::ResultInvalidCurrentMemory()); + } + + /* Check that the value is equal. */ + if (value != user_value) { + slp.CancelSleep(); + R_THROW(svc::ResultInvalidState()); + } + + /* Check that the timeout is non-zero. */ + if (timeout == 0) { + slp.CancelSleep(); + R_THROW(svc::ResultTimedOut()); + } + + /* Set the arbiter. */ + cur_thread->SetAddressArbiter(std::addressof(m_tree), addr); + m_tree.insert(*cur_thread); + + /* Wait for the thread to finish. */ + wait_queue.SetHardwareTimer(timer); + cur_thread->BeginWait(std::addressof(wait_queue)); + } + + /* Get the wait result. */ + R_RETURN(cur_thread->GetWaitResult()); + } + } diff --git a/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp b/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp index 68eb61e84..2b495ad45 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp @@ -41,17 +41,22 @@ namespace ams::kern::svc { case ams::svc::ArbitrationType_WaitIfLessThan: case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan: case ams::svc::ArbitrationType_WaitIfEqual: + case ams::svc::ArbitrationType_WaitIfEqual64: return true; default: return false; } } - Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) { + Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { /* Validate input. */ - R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); - R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); - R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue()); + R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); + if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) { + R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress()); + } else { + R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); + } + R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue()); /* Convert timeout from nanoseconds to ticks. */ s64 timeout; @@ -85,7 +90,7 @@ namespace ams::kern::svc { /* ============================= 64 ABI ============================= */ - Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) { + Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns)); } @@ -95,7 +100,7 @@ namespace ams::kern::svc { /* ============================= 64From32 ABI ============================= */ - Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) { + Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns)); } diff --git a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp index b724ce5f1..d68a56f33 100644 --- a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp +++ b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp @@ -231,7 +231,7 @@ R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle)); } - ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) { + ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(::svcWaitForAddress(reinterpret_cast(static_cast(address)), arb_type, value, timeout_ns)); } diff --git a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp index 0f1c57783..7e4121aa3 100644 --- a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp @@ -67,7 +67,7 @@ HANDLER(0x31, Result, GetResourceLimitCurrentValue, OUTPUT(int64_t, out_current_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \ HANDLER(0x32, Result, SetThreadActivity, INPUT(::ams::svc::Handle, thread_handle), INPUT(::ams::svc::ThreadActivity, thread_activity)) \ HANDLER(0x33, Result, GetThreadContext3, OUTPTR(::ams::svc::ThreadContext, out_context), INPUT(::ams::svc::Handle, thread_handle)) \ - HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int32_t, value), INPUT(int64_t, timeout_ns)) \ + HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int64_t, value), INPUT(int64_t, timeout_ns)) \ HANDLER(0x35, Result, SignalToAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::SignalType, signal_type), INPUT(int32_t, value), INPUT(int32_t, count)) \ HANDLER(0x36, void, SynchronizePreemptionState) \ HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \ diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 0247f59b9..21ab685d0 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -263,6 +263,7 @@ namespace ams::svc { ArbitrationType_WaitIfLessThan = 0, ArbitrationType_DecrementAndWaitIfLessThan = 1, ArbitrationType_WaitIfEqual = 2, + ArbitrationType_WaitIfEqual64 = 3, }; enum YieldType : s64 { From 93d4656d0b07f951852b5ed0fcc9fec37bf634db Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 12:03:21 -0700 Subject: [PATCH 06/14] kern: KAddressSpaceInfo now takes CreateProcessFlags in getters --- .../mesosphere/kern_k_address_space_info.hpp | 4 +-- .../source/kern_k_address_space_info.cpp | 26 +++++++++++--- .../source/kern_k_initial_process_reader.cpp | 35 ++++++++++--------- .../source/kern_k_page_table_base.cpp | 4 +-- .../source/svc/kern_svc_process.cpp | 14 ++++---- 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp index 9e20dd254..8af8404cc 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp @@ -37,8 +37,8 @@ namespace ams::kern { size_t m_size; Type m_type; public: - static uintptr_t GetAddressSpaceStart(size_t width, Type type); - static size_t GetAddressSpaceSize(size_t width, Type type); + static uintptr_t GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, Type type); + static size_t GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, Type type); static void SetAddressSpaceSize(size_t width, Type type, size_t size); diff --git a/libraries/libmesosphere/source/kern_k_address_space_info.cpp b/libraries/libmesosphere/source/kern_k_address_space_info.cpp index ef585eba8..b23f6e929 100644 --- a/libraries/libmesosphere/source/kern_k_address_space_info.cpp +++ b/libraries/libmesosphere/source/kern_k_address_space_info.cpp @@ -37,6 +37,24 @@ namespace ams::kern { { 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, }, }; + constexpr u8 FlagsToAddressSpaceWidthTable[4] = { + 32, 36, 32, 39 + }; + + constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) { + /* Convert the input flags to an array index. */ + const size_t idx = (flags & ams::svc::CreateProcessFlag_AddressSpaceMask) >> ams::svc::CreateProcessFlag_AddressSpaceShift; + MESOSPHERE_ABORT_UNLESS(idx < sizeof(FlagsToAddressSpaceWidthTable)); + + /* Return the width. */ + return FlagsToAddressSpaceWidthTable[idx]; + } + + static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32Bit) == 32); + static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36); + static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32); + static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39); + KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { for (auto &info : AddressSpaceInfos) { if (info.GetWidth() == width && info.GetType() == type) { @@ -48,12 +66,12 @@ namespace ams::kern { } - uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { - return GetAddressSpaceInfo(width, type).GetAddress(); + uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) { + return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetAddress(); } - size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { - return GetAddressSpaceInfo(width, type).GetSize(); + size_t KAddressSpaceInfo::GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) { + return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetSize(); } void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) { diff --git a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp index c5ef13ac5..9c91889f9 100644 --- a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp +++ b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp @@ -193,40 +193,25 @@ namespace ams::kern { R_UNLESS(this->Is64Bit(), svc::ResultInvalidCombination()); } - using ASType = KAddressSpaceInfo::Type; - const uintptr_t start_address = rx_address; const uintptr_t end_address = bss_size > 0 ? bss_address + bss_size : rw_address + rw_size; - const size_t as_width = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? 39 : 36) : 32; - const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; - const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(as_width, as_type); - const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(as_width, as_type); - const uintptr_t map_end = map_start + map_size; MESOSPHERE_ABORT_UNLESS(start_address == 0); /* Default fields in parameter to zero. */ *out = {}; /* Set fields in parameter. */ - out->code_address = map_start + start_address; + out->code_address = 0; out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize; out->program_id = m_kip_header.GetProgramId(); out->version = m_kip_header.GetVersion(); out->flags = 0; out->reslimit = ams::svc::InvalidHandle; out->system_resource_num_pages = 0; - MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize)); /* Copy name field. */ m_kip_header.GetName(out->name, sizeof(out->name)); - /* Apply ASLR, if needed. */ - if (enable_aslr) { - const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment); - out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment; - out->flags |= ams::svc::CreateProcessFlag_EnableAslr; - } - /* Apply other flags. */ if (this->Is64Bit()) { out->flags |= ams::svc::CreateProcessFlag_Is64Bit; @@ -236,10 +221,28 @@ namespace ams::kern { } else { out->flags |= ams::svc::CreateProcessFlag_AddressSpace32Bit; } + if (enable_aslr) { + out->flags |= ams::svc::CreateProcessFlag_EnableAslr; + } /* All initial processes should disable device address space merge. */ out->flags |= ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge; + /* Set and check code address. */ + using ASType = KAddressSpaceInfo::Type; + const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; + const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(out->flags), as_type); + const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(out->flags), as_type); + const uintptr_t map_end = map_start + map_size; + out->code_address = map_start + start_address; + MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize)); + + /* Apply ASLR, if needed. */ + if (enable_aslr) { + const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment); + out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment; + } + R_SUCCEED(); } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 2e90d924e..613dc0dbb 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -141,10 +141,10 @@ namespace ams::kern { /* Define helpers. */ auto GetSpaceStart = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA { - return KAddressSpaceInfo::GetAddressSpaceStart(m_address_space_width, type); + return KAddressSpaceInfo::GetAddressSpaceStart(flags, type); }; auto GetSpaceSize = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA { - return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type); + return KAddressSpaceInfo::GetAddressSpaceSize(flags, type); }; /* Default to zero alias region extra size. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 76e36302b..5141a2c31 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -110,8 +110,8 @@ namespace ams::kern::svc { case ams::svc::CreateProcessFlag_AddressSpace32Bit: case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias: { - map_start = KAddressSpaceInfo::GetAddressSpaceStart(32, KAddressSpaceInfo::Type_MapSmall); - map_size = KAddressSpaceInfo::GetAddressSpaceSize(32, KAddressSpaceInfo::Type_MapSmall); + map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(params.flags), KAddressSpaceInfo::Type_MapSmall); + map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_MapSmall); map_end = map_start + map_size; } break; @@ -120,8 +120,8 @@ namespace ams::kern::svc { /* 64-bit address space requires 64-bit process. */ R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); - map_start = KAddressSpaceInfo::GetAddressSpaceStart(36, KAddressSpaceInfo::Type_MapSmall); - map_size = KAddressSpaceInfo::GetAddressSpaceSize(36, KAddressSpaceInfo::Type_MapSmall); + map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(params.flags), KAddressSpaceInfo::Type_MapSmall); + map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_MapSmall); map_end = map_start + map_size; } break; @@ -130,10 +130,10 @@ namespace ams::kern::svc { /* 64-bit address space requires 64-bit process. */ R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); - map_start = KAddressSpaceInfo::GetAddressSpaceStart(39, KAddressSpaceInfo::Type_Map39Bit); - map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Map39Bit); + map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(params.flags), KAddressSpaceInfo::Type_Map39Bit); + map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_Map39Bit); - map_size = KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap); + map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_Heap); } break; default: From e3ee4cb544993dba4d0a9543a80d26bd641dfc85 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 12:44:11 -0700 Subject: [PATCH 07/14] kern: eliminate use of KMemoryInfo, shuffle KMemoryBlock fields --- .../mesosphere/kern_k_memory_block.hpp | 27 +- .../mesosphere/kern_k_page_table_base.hpp | 2 +- .../source/kern_k_memory_block_manager.cpp | 130 ++++---- .../source/kern_k_page_table_base.cpp | 296 ++++++++---------- 4 files changed, 196 insertions(+), 259 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp index f021391e0..2847de337 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp @@ -200,7 +200,8 @@ namespace ams::kern { KMemoryBlockDisableMergeAttribute_DeviceLeft = (1u << 1), KMemoryBlockDisableMergeAttribute_IpcLeft = (1u << 2), KMemoryBlockDisableMergeAttribute_Locked = (1u << 3), - KMemoryBlockDisableMergeAttribute_DeviceRight = (1u << 4), + /* ... */ + KMemoryBlockDisableMergeAttribute_DeviceRight = (1u << 5), KMemoryBlockDisableMergeAttribute_AllLeft = KMemoryBlockDisableMergeAttribute_Normal | KMemoryBlockDisableMergeAttribute_DeviceLeft | KMemoryBlockDisableMergeAttribute_IpcLeft | KMemoryBlockDisableMergeAttribute_Locked, KMemoryBlockDisableMergeAttribute_AllRight = KMemoryBlockDisableMergeAttribute_DeviceRight, @@ -288,18 +289,18 @@ namespace ams::kern { class KMemoryBlock : public util::IntrusiveRedBlackTreeBaseNode { private: - u16 m_device_disable_merge_left_count; - u16 m_device_disable_merge_right_count; - KProcessAddress m_address; - size_t m_num_pages; - KMemoryState m_memory_state; - u16 m_ipc_lock_count; - u16 m_device_use_count; - u16 m_ipc_disable_merge_count; KMemoryPermission m_permission; KMemoryPermission m_original_permission; KMemoryAttribute m_attribute; KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; + KProcessAddress m_address; + u32 m_num_pages; + KMemoryState m_memory_state; + u16 m_ipc_lock_count; + u16 m_ipc_disable_merge_count; + u16 m_device_use_count; + u16 m_device_disable_merge_left_count; + u16 m_device_disable_merge_right_count; public: static constexpr ALWAYS_INLINE int Compare(const KMemoryBlock &lhs, const KMemoryBlock &rhs) { if (lhs.GetAddress() < rhs.GetAddress()) { @@ -343,6 +344,10 @@ namespace ams::kern { return m_ipc_disable_merge_count; } + constexpr u16 GetDeviceUseCount() const { + return m_device_use_count; + } + constexpr KMemoryPermission GetPermission() const { return m_permission; } @@ -374,7 +379,7 @@ namespace ams::kern { public: explicit KMemoryBlock() { /* ... */ } - constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) + constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) : util::IntrusiveRedBlackTreeBaseNode(util::ConstantInitialize), m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), m_original_permission(KMemoryPermission_None), @@ -383,7 +388,7 @@ namespace ams::kern { /* ... */ } - constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) { + constexpr void Initialize(KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) { MESOSPHERE_ASSERT_THIS(); m_device_disable_merge_left_count = 0; m_device_disable_merge_right_count = 0; diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 99a27c6f9..8da4311df 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -318,7 +318,7 @@ namespace ams::kern { R_RETURN(this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr)); } - Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const; + Result CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const; Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const; Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const; Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const { diff --git a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp index 4ba4a566a..2c5bd962d 100644 --- a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp @@ -54,11 +54,11 @@ namespace ams::kern { return "Unknown "; } - constexpr const char *GetMemoryPermissionString(const KMemoryInfo &info) { - if (info.m_state == KMemoryState_Free) { + constexpr const char *GetMemoryPermissionString(const KMemoryBlock &block) { + if (block.GetState() == KMemoryState_Free) { return " "; } else { - switch (info.m_permission) { + switch (block.GetPermission()) { case KMemoryPermission_UserReadExecute: return "r-x"; case KMemoryPermission_UserRead: @@ -71,19 +71,19 @@ namespace ams::kern { } } - void DumpMemoryInfo(const KMemoryInfo &info) { - const char *state = GetMemoryStateName(info.m_state); - const char *perm = GetMemoryPermissionString(info); - const uintptr_t start = info.GetAddress(); - const uintptr_t end = info.GetLastAddress(); - const size_t kb = info.GetSize() / 1_KB; + void DumpMemoryBlock(const KMemoryBlock &block) { + const char *state = GetMemoryStateName(block.GetState()); + const char *perm = GetMemoryPermissionString(block); + const uintptr_t start = GetInteger(block.GetAddress()); + const uintptr_t end = GetInteger(block.GetLastAddress()); + const size_t kb = block.GetSize() / 1_KB; - const char l = (info.m_attribute & KMemoryAttribute_Locked) ? 'L' : '-'; - const char i = (info.m_attribute & KMemoryAttribute_IpcLocked) ? 'I' : '-'; - const char d = (info.m_attribute & KMemoryAttribute_DeviceShared) ? 'D' : '-'; - const char u = (info.m_attribute & KMemoryAttribute_Uncached) ? 'U' : '-'; + const char l = (block.GetAttribute() & KMemoryAttribute_Locked) ? 'L' : '-'; + const char i = (block.GetAttribute() & KMemoryAttribute_IpcLocked) ? 'I' : '-'; + const char d = (block.GetAttribute() & KMemoryAttribute_DeviceShared) ? 'D' : '-'; + const char u = (block.GetAttribute() & KMemoryAttribute_Uncached) ? 'U' : '-'; - MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.m_ipc_lock_count, info.m_device_use_count); + MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, block.GetIpcLockCount(), block.GetDeviceUseCount()); } } @@ -123,15 +123,14 @@ namespace ams::kern { const KProcessAddress region_end = region_start + region_num_pages * PageSize; const KProcessAddress region_last = region_end - 1; for (const_iterator it = this->FindIterator(region_start); it != m_memory_block_tree.cend(); it++) { - const KMemoryInfo info = it->GetMemoryInfo(); - if (region_last < info.GetAddress()) { + if (region_last < it->GetAddress()) { break; } - if (info.m_state != KMemoryState_Free) { + if (it->GetState() != KMemoryState_Free) { continue; } - KProcessAddress area = (info.GetAddress() <= GetInteger(region_start)) ? region_start : info.GetAddress(); + KProcessAddress area = (it->GetAddress() <= GetInteger(region_start)) ? region_start : it->GetAddress(); area += guard_pages * PageSize; const KProcessAddress offset_area = util::AlignDown(GetInteger(area), alignment) + offset; @@ -140,7 +139,7 @@ namespace ams::kern { const KProcessAddress area_end = area + num_pages * PageSize + guard_pages * PageSize; const KProcessAddress area_last = area_end - 1; - if (info.GetAddress() <= GetInteger(area) && area < area_last && area_last <= region_last && GetInteger(area_last) <= info.GetLastAddress()) { + if (GetInteger(it->GetAddress()) <= GetInteger(area) && area < area_last && area_last <= region_last && GetInteger(area_last) <= GetInteger(it->GetLastAddress())) { return area; } } @@ -171,7 +170,7 @@ namespace ams::kern { it = prev; } - if (address + num_pages * PageSize < it->GetMemoryInfo().GetEndAddress()) { + if (address + num_pages * PageSize < it->GetEndAddress()) { break; } } @@ -189,43 +188,39 @@ namespace ams::kern { while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; - KMemoryInfo cur_info = it->GetMemoryInfo(); if (it->HasProperties(state, perm, attr)) { /* If we already have the right properties, just advance. */ - if (cur_address + remaining_size < cur_info.GetEndAddress()) { + if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { - remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize; - cur_address = cur_info.GetEndAddress(); + remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; + cur_address = it->GetEndAddress(); } } else { /* If we need to, create a new block before and insert it. */ - if (cur_info.GetAddress() != GetInteger(cur_address)) { + if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; - cur_info = it->GetMemoryInfo(); - cur_address = cur_info.GetAddress(); + cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ - if (cur_info.GetSize() > remaining_size) { + if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); - - cur_info = it->GetMemoryInfo(); } /* Update block state. */ it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr); - cur_address += cur_info.GetSize(); - remaining_pages -= cur_info.GetNumPages(); + cur_address += it->GetSize(); + remaining_pages -= it->GetNumPages(); } it++; } @@ -245,42 +240,38 @@ namespace ams::kern { while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; - KMemoryInfo cur_info = it->GetMemoryInfo(); if (it->HasProperties(test_state, test_perm, test_attr) && !it->HasProperties(state, perm, attr)) { /* If we need to, create a new block before and insert it. */ - if (cur_info.GetAddress() != GetInteger(cur_address)) { + if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; - cur_info = it->GetMemoryInfo(); - cur_address = cur_info.GetAddress(); + cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ - if (cur_info.GetSize() > remaining_size) { + if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); - - cur_info = it->GetMemoryInfo(); } /* Update block state. */ it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr); - cur_address += cur_info.GetSize(); - remaining_pages -= cur_info.GetNumPages(); + cur_address += it->GetSize(); + remaining_pages -= it->GetNumPages(); } else { /* If we already have the right properties, just advance. */ - if (cur_address + remaining_size < cur_info.GetEndAddress()) { + if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { - remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize; - cur_address = cur_info.GetEndAddress(); + remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; + cur_address = it->GetEndAddress(); } } it++; @@ -302,34 +293,30 @@ namespace ams::kern { while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; - KMemoryInfo cur_info = it->GetMemoryInfo(); /* If we need to, create a new block before and insert it. */ - if (cur_info.m_address != GetInteger(cur_address)) { + if (it->GetAddress() != cur_address) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; - cur_info = it->GetMemoryInfo(); - cur_address = cur_info.GetAddress(); + cur_address = it->GetAddress(); } - if (cur_info.GetSize() > remaining_size) { + if (it->GetSize() > remaining_size) { /* If we need to, create a new block after and insert it. */ KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); - - cur_info = it->GetMemoryInfo(); } /* Call the locked update function. */ - (std::addressof(*it)->*lock_func)(perm, cur_info.GetAddress() == address, cur_info.GetEndAddress() == end_address); - cur_address += cur_info.GetSize(); - remaining_pages -= cur_info.GetNumPages(); + (std::addressof(*it)->*lock_func)(perm, it->GetAddress() == address, it->GetEndAddress() == end_address); + cur_address += it->GetSize(); + remaining_pages -= it->GetNumPages(); it++; } @@ -347,43 +334,39 @@ namespace ams::kern { while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; - KMemoryInfo cur_info = it->GetMemoryInfo(); if ((it->GetAttribute() & mask) != attr) { /* If we need to, create a new block before and insert it. */ - if (cur_info.GetAddress() != GetInteger(cur_address)) { + if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; - cur_info = it->GetMemoryInfo(); - cur_address = cur_info.GetAddress(); + cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ - if (cur_info.GetSize() > remaining_size) { + if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); - - cur_info = it->GetMemoryInfo(); } /* Update block state. */ it->UpdateAttribute(mask, attr); - cur_address += cur_info.GetSize(); - remaining_pages -= cur_info.GetNumPages(); + cur_address += it->GetSize(); + remaining_pages -= it->GetNumPages(); } else { /* If we already have the right attributes, just advance. */ - if (cur_address + remaining_size < cur_info.GetEndAddress()) { + if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { - remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize; - cur_address = cur_info.GetEndAddress(); + remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; + cur_address = it->GetEndAddress(); } } it++; @@ -401,8 +384,6 @@ namespace ams::kern { auto it = m_memory_block_tree.cbegin(); auto prev = it++; while (it != m_memory_block_tree.cend()) { - const KMemoryInfo prev_info = prev->GetMemoryInfo(); - const KMemoryInfo cur_info = it->GetMemoryInfo(); /* Sequential blocks which can be merged should be merged. */ if (prev->CanMergeWith(*it)) { @@ -410,17 +391,17 @@ namespace ams::kern { } /* Sequential blocks should be sequential. */ - if (prev_info.GetEndAddress() != cur_info.GetAddress()) { + if (prev->GetEndAddress() != it->GetAddress()) { return false; } /* If the block is ipc locked, it must have a count. */ - if ((cur_info.m_attribute & KMemoryAttribute_IpcLocked) != 0 && cur_info.m_ipc_lock_count == 0) { + if ((it->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && it->GetIpcLockCount() == 0) { return false; } /* If the block is device shared, it must have a count. */ - if ((cur_info.m_attribute & KMemoryAttribute_DeviceShared) != 0 && cur_info.m_device_use_count == 0) { + if ((it->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && it->GetDeviceUseCount() == 0) { return false; } @@ -430,14 +411,13 @@ namespace ams::kern { /* Our loop will miss checking the last block, potentially, so check it. */ if (prev != m_memory_block_tree.cend()) { - const KMemoryInfo prev_info = prev->GetMemoryInfo(); /* If the block is ipc locked, it must have a count. */ - if ((prev_info.m_attribute & KMemoryAttribute_IpcLocked) != 0 && prev_info.m_ipc_lock_count == 0) { + if ((prev->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && prev->GetIpcLockCount() == 0) { return false; } /* If the block is device shared, it must have a count. */ - if ((prev_info.m_attribute & KMemoryAttribute_DeviceShared) != 0 && prev_info.m_device_use_count == 0) { + if ((prev->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && prev->GetDeviceUseCount() == 0) { return false; } } @@ -450,7 +430,7 @@ namespace ams::kern { void KMemoryBlockManager::DumpBlocks() const { /* Dump each block. */ for (const auto &block : m_memory_block_tree) { - DumpMemoryInfo(block.GetMemoryInfo()); + DumpMemoryBlock(block); } } } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 613dc0dbb..95bc983ca 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -664,11 +664,11 @@ namespace ams::kern { } } - Result KPageTableBase::CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const { + Result KPageTableBase::CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const { /* Validate the states match expectation. */ - R_UNLESS((info.m_state & state_mask) == state, svc::ResultInvalidCurrentMemory()); - R_UNLESS((info.m_permission & perm_mask) == perm, svc::ResultInvalidCurrentMemory()); - R_UNLESS((info.m_attribute & attr_mask) == attr, svc::ResultInvalidCurrentMemory()); + R_UNLESS((it->GetState() & state_mask) == state, svc::ResultInvalidCurrentMemory()); + R_UNLESS((it->GetPermission() & perm_mask) == perm, svc::ResultInvalidCurrentMemory()); + R_UNLESS((it->GetAttribute() & attr_mask) == attr, svc::ResultInvalidCurrentMemory()); R_SUCCEED(); } @@ -679,28 +679,26 @@ namespace ams::kern { /* Get information about the first block. */ const KProcessAddress last_addr = addr + size - 1; KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr); - KMemoryInfo info = it->GetMemoryInfo(); /* If the start address isn't aligned, we need a block. */ - const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0; + const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) ? 1 : 0; while (true) { /* Validate against the provided masks. */ - R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); + R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr)); /* Break once we're done. */ - if (last_addr <= info.GetLastAddress()) { + if (last_addr <= it->GetLastAddress()) { break; } /* Advance our iterator. */ it++; MESOSPHERE_ASSERT(it != m_memory_block_manager.cend()); - info = it->GetMemoryInfo(); } /* If the end address isn't aligned, we need a block. */ - const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0; + const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != it->GetEndAddress()) ? 1 : 0; if (out_blocks_needed != nullptr) { *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; @@ -712,31 +710,27 @@ namespace ams::kern { Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); - /* Get information about the first block. */ - KMemoryInfo info = it->GetMemoryInfo(); - /* Validate all blocks in the range have correct state. */ - const KMemoryState first_state = info.m_state; - const KMemoryPermission first_perm = info.m_permission; - const KMemoryAttribute first_attr = info.m_attribute; + const KMemoryState first_state = it->GetState(); + const KMemoryPermission first_perm = it->GetPermission(); + const KMemoryAttribute first_attr = it->GetAttribute(); while (true) { /* Validate the current block. */ - R_UNLESS(info.m_state == first_state, svc::ResultInvalidCurrentMemory()); - R_UNLESS(info.m_permission == first_perm, svc::ResultInvalidCurrentMemory()); - R_UNLESS((info.m_attribute | ignore_attr) == (first_attr | ignore_attr), svc::ResultInvalidCurrentMemory()); + R_UNLESS(it->GetState() == first_state, svc::ResultInvalidCurrentMemory()); + R_UNLESS(it->GetPermission() == first_perm, svc::ResultInvalidCurrentMemory()); + R_UNLESS((it->GetAttribute() | ignore_attr) == (first_attr | ignore_attr), svc::ResultInvalidCurrentMemory()); /* Validate against the provided masks. */ - R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); + R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr)); /* Break once we're done. */ - if (last_addr <= info.GetLastAddress()) { + if (last_addr <= it->GetLastAddress()) { break; } /* Advance our iterator. */ it++; MESOSPHERE_ASSERT(it != m_memory_block_manager.cend()); - info = it->GetMemoryInfo(); } /* Write output state. */ @@ -752,7 +746,7 @@ namespace ams::kern { /* If the end address isn't aligned, we need a block. */ if (out_blocks_needed != nullptr) { - const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress()) ? 1 : 0; + const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != it->GetEndAddress()) ? 1 : 0; *out_blocks_needed = blocks_for_end_align; } @@ -1176,17 +1170,14 @@ namespace ams::kern { { KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(dst_address); while (true) { - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* Check if the memory has code flag. */ - if ((info.GetState() & KMemoryState_FlagCode) != 0) { + if ((it->GetState() & KMemoryState_FlagCode) != 0) { any_code_pages = true; break; } /* Check if we're done. */ - if (dst_address + size - 1 <= info.GetLastAddress()) { + if (dst_address + size - 1 <= it->GetLastAddress()) { break; } @@ -1355,14 +1346,13 @@ namespace ams::kern { const size_t random_offset = KSystemControl::GenerateRandomRange(0, (region_num_pages - num_pages - guard_pages) * PageSize / alignment) * alignment; const KProcessAddress candidate = util::AlignDown(GetInteger(region_start + random_offset), alignment) + offset; - KMemoryInfo info; - ams::svc::PageInfo page_info; - MESOSPHERE_R_ABORT_UNLESS(this->QueryInfoImpl(std::addressof(info), std::addressof(page_info), candidate)); + KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(candidate); + MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end()); - if (info.m_state != KMemoryState_Free) { continue; } + if (it->GetState() != KMemoryState_Free) { continue; } if (!(region_start <= candidate)) { continue; } - if (!(info.GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; } - if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= info.GetLastAddress())) { continue; } + if (!(it->GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; } + if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= it->GetLastAddress())) { continue; } if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= region_start + region_num_pages * PageSize - 1)) { continue; } address = candidate; @@ -1393,10 +1383,8 @@ namespace ams::kern { /* Iterate, counting blocks with the desired state. */ size_t total_size = 0; for (KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(m_address_space_start); it != m_memory_block_manager.end(); ++it) { - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - if (info.GetState() == state) { - total_size += info.GetSize(); + if (it->GetState() == state) { + total_size += it->GetSize(); } } @@ -1488,17 +1476,14 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* Determine the range to map. */ - KProcessAddress map_address = std::max(info.GetAddress(), GetInteger(start_address)); - const KProcessAddress map_end_address = std::min(info.GetEndAddress(), GetInteger(end_address)); + KProcessAddress map_address = std::max(GetInteger(it->GetAddress()), GetInteger(start_address)); + const KProcessAddress map_end_address = std::min(GetInteger(it->GetEndAddress()), GetInteger(end_address)); MESOSPHERE_ABORT_UNLESS(map_end_address != map_address); /* Determine if we should disable head merge. */ - const bool disable_head_merge = info.GetAddress() >= GetInteger(start_address) && (info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Normal) != 0; - const KPageProperties map_properties = { info.GetPermission(), false, false, disable_head_merge ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; + const bool disable_head_merge = it->GetAddress() >= GetInteger(start_address) && (it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Normal) != 0; + const KPageProperties map_properties = { it->GetPermission(), false, false, disable_head_merge ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; /* While we have pages to map, map them. */ size_t map_pages = (map_end_address - map_address) / PageSize; @@ -1527,7 +1512,7 @@ namespace ams::kern { } /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { + if (last_address <= it->GetLastAddress()) { break; } @@ -2032,19 +2017,18 @@ namespace ams::kern { address = util::AlignDown(GetInteger(address), PageSize); /* Verify that we can query the address. */ - KMemoryInfo info; - ams::svc::PageInfo page_info; - R_TRY(this->QueryInfoImpl(std::addressof(info), std::addressof(page_info), address)); + KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address); + R_UNLESS(it != m_memory_block_manager.end(), svc::ResultInvalidCurrentMemory()); /* Check the memory state. */ - R_TRY(this->CheckMemoryState(info, KMemoryState_FlagCanQueryPhysical, KMemoryState_FlagCanQueryPhysical, KMemoryPermission_UserReadExecute, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); + R_TRY(this->CheckMemoryState(it, KMemoryState_FlagCanQueryPhysical, KMemoryState_FlagCanQueryPhysical, KMemoryPermission_UserReadExecute, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); /* Prepare to traverse. */ KPhysicalAddress phys_addr; size_t phys_size; - KProcessAddress virt_addr = info.GetAddress(); - KProcessAddress end_addr = info.GetEndAddress(); + KProcessAddress virt_addr = it->GetAddress(); + KProcessAddress end_addr = it->GetEndAddress(); /* Perform traversal. */ { @@ -3854,27 +3838,25 @@ namespace ams::kern { /* Iterate, mapping as needed. */ KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(aligned_src_start); while (true) { - const KMemoryInfo info = it->GetMemoryInfo(); - /* Validate the current block. */ - R_TRY(this->CheckMemoryState(info, test_state, test_state, test_perm, test_perm, test_attr_mask, KMemoryAttribute_None)); + R_TRY(this->CheckMemoryState(it, test_state, test_state, test_perm, test_perm, test_attr_mask, KMemoryAttribute_None)); - if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < info.GetEndAddress() && info.GetAddress() < GetInteger(mapping_src_end)) { - const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start) ? info.GetAddress() : GetInteger(mapping_src_start); - const auto cur_end = mapping_src_last >= info.GetLastAddress() ? info.GetEndAddress() : GetInteger(mapping_src_end); + if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < GetInteger(it->GetEndAddress()) && GetInteger(it->GetAddress()) < GetInteger(mapping_src_end)) { + const auto cur_start = it->GetAddress() >= GetInteger(mapping_src_start) ? GetInteger(it->GetAddress()) : GetInteger(mapping_src_start); + const auto cur_end = mapping_src_last >= GetInteger(it->GetLastAddress()) ? GetInteger(it->GetEndAddress()) : GetInteger(mapping_src_end); const size_t cur_size = cur_end - cur_start; - if (info.GetAddress() < GetInteger(mapping_src_start)) { + if (GetInteger(it->GetAddress()) < GetInteger(mapping_src_start)) { ++blocks_needed; } - if (mapping_src_last < info.GetLastAddress()) { + if (mapping_src_last < GetInteger(it->GetLastAddress())) { ++blocks_needed; } /* Set the permissions on the block, if we need to. */ - if ((info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) { - const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= info.GetAddress()) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None; - const DisableMergeAttribute tail_attr = (cur_end == GetInteger(mapping_src_end)) ? DisableMergeAttribute_DisableTail : DisableMergeAttribute_None; + if ((it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) { + const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= GetInteger(it->GetAddress())) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None; + const DisableMergeAttribute tail_attr = (cur_end == GetInteger(mapping_src_end)) ? DisableMergeAttribute_DisableTail : DisableMergeAttribute_None; const KPageProperties properties = { src_perm, false, false, static_cast(head_body_attr | tail_attr) }; R_TRY(this->Operate(page_list, cur_start, cur_size / PageSize, Null, false, properties, OperationType_ChangePermissions, false)); } @@ -3884,7 +3866,7 @@ namespace ams::kern { } /* If the block is at the end, we're done. */ - if (aligned_src_last <= info.GetLastAddress()) { + if (aligned_src_last <= GetInteger(it->GetLastAddress())) { break; } @@ -4248,56 +4230,50 @@ namespace ams::kern { const auto mapped_last = mapped_end - 1; /* Get current and next iterators. */ - KMemoryBlockManager::const_iterator start_it = m_memory_block_manager.FindIterator(mapping_start); - KMemoryBlockManager::const_iterator next_it = start_it; + KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start); + KMemoryBlockManager::const_iterator next_it = cur_it; ++next_it; - /* Get the current block info. */ - KMemoryInfo cur_info = start_it->GetMemoryInfo(); - /* Create tracking variables. */ - KProcessAddress cur_address = cur_info.GetAddress(); - size_t cur_size = cur_info.GetSize(); - bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission(); - bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1; - bool first = cur_info.GetIpcDisableMergeCount() == 1 && (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; + KProcessAddress cur_address = cur_it->GetAddress(); + size_t cur_size = cur_it->GetSize(); + bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission(); + bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1; + bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; while ((GetInteger(cur_address) + cur_size - 1) < mapped_last) { /* Check that we have a next block. */ MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end()); - /* Get the next info. */ - const KMemoryInfo next_info = next_it->GetMemoryInfo(); - /* Check if we can consolidate the next block's permission set with the current one. */ - const bool next_perm_eq = next_info.GetPermission() == next_info.GetOriginalPermission(); - const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1; - if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) { + const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission(); + const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1; + if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) { /* We can consolidate the reprotection for the current and next block into a single call. */ - cur_size += next_info.GetSize(); + cur_size += next_it->GetSize(); } else { /* We have to operate on the current block. */ if ((cur_needs_set_perm || first) && !cur_perm_eq) { - const KPageProperties properties = { cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; + const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null, false, properties, OperationType_ChangePermissions, true)); } /* Advance. */ - cur_address = next_info.GetAddress(); - cur_size = next_info.GetSize(); + cur_address = next_it->GetAddress(); + cur_size = next_it->GetSize(); first = false; } /* Advance. */ - cur_info = next_info; cur_perm_eq = next_perm_eq; cur_needs_set_perm = next_needs_set_perm; - ++next_it; + + cur_it = next_it++; } /* Process the last block. */ if ((first || cur_needs_set_perm) && !cur_perm_eq) { - const KPageProperties properties = { cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; + const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null, false, properties, OperationType_ChangePermissions, true)); } } @@ -4306,41 +4282,37 @@ namespace ams::kern { /* Iterate, reprotecting as needed. */ { /* Get current and next iterators. */ - KMemoryBlockManager::const_iterator start_it = m_memory_block_manager.FindIterator(mapping_start); - KMemoryBlockManager::const_iterator next_it = start_it; + KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start); + KMemoryBlockManager::const_iterator next_it = cur_it; ++next_it; /* Validate the current block. */ - KMemoryInfo cur_info = start_it->GetMemoryInfo(); - MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(cur_info, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); + MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(cur_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); /* Create tracking variables. */ - KProcessAddress cur_address = cur_info.GetAddress(); - size_t cur_size = cur_info.GetSize(); - bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission(); - bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1; - bool first = cur_info.GetIpcDisableMergeCount() == 1 && (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; + KProcessAddress cur_address = cur_it->GetAddress(); + size_t cur_size = cur_it->GetSize(); + bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission(); + bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1; + bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; while ((cur_address + cur_size - 1) < mapping_last) { /* Check that we have a next block. */ MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end()); - /* Get the next info. */ - const KMemoryInfo next_info = next_it->GetMemoryInfo(); - /* Validate the next block. */ - MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(next_info, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); + MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(next_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); /* Check if we can consolidate the next block's permission set with the current one. */ - const bool next_perm_eq = next_info.GetPermission() == next_info.GetOriginalPermission(); - const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1; - if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) { + const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission(); + const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1; + if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) { /* We can consolidate the reprotection for the current and next block into a single call. */ - cur_size += next_info.GetSize(); + cur_size += next_it->GetSize(); } else { /* We have to operate on the current block. */ if ((cur_needs_set_perm || first) && !cur_perm_eq) { - const KPageProperties properties = { cur_needs_set_perm ? cur_info.GetOriginalPermission() : cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None }; + const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null, false, properties, OperationType_ChangePermissions, false)); } @@ -4348,24 +4320,24 @@ namespace ams::kern { mapped_size += cur_size; /* Advance. */ - cur_address = next_info.GetAddress(); - cur_size = next_info.GetSize(); + cur_address = next_it->GetAddress(); + cur_size = next_it->GetSize(); first = false; } /* Advance. */ - cur_info = next_info; cur_perm_eq = next_perm_eq; cur_needs_set_perm = next_needs_set_perm; - ++next_it; + + cur_it = next_it++; } /* Process the last block. */ - const auto lock_count = cur_info.GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); + const auto lock_count = cur_it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); if ((first || cur_needs_set_perm || (lock_count == 1)) && !cur_perm_eq) { const DisableMergeAttribute head_body_attr = first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None; const DisableMergeAttribute tail_attr = lock_count == 1 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None; - const KPageProperties properties = { cur_needs_set_perm ? cur_info.GetOriginalPermission() : cur_info.GetPermission(), false, false, static_cast(head_body_attr | tail_attr) }; + const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, static_cast(head_body_attr | tail_attr) }; R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null, false, properties, OperationType_ChangePermissions, false)); } } @@ -4398,38 +4370,36 @@ namespace ams::kern { /* Iterate over blocks, fixing permissions. */ KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address); while (true) { - const KMemoryInfo info = it->GetMemoryInfo(); - - const auto cur_start = info.GetAddress() >= GetInteger(src_map_start) ? info.GetAddress() : GetInteger(src_map_start); - const auto cur_end = src_map_last <= info.GetLastAddress() ? src_map_end : info.GetEndAddress(); + const auto cur_start = it->GetAddress() >= GetInteger(src_map_start) ? it->GetAddress() : GetInteger(src_map_start); + const auto cur_end = src_map_last <= it->GetLastAddress() ? src_map_end : it->GetEndAddress(); /* If we can, fix the protections on the block. */ - if ((info.GetIpcLockCount() == 0 && (info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) || - (info.GetIpcLockCount() != 0 && (info.GetOriginalPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm)) + if ((it->GetIpcLockCount() == 0 && (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) || + (it->GetIpcLockCount() != 0 && (it->GetOriginalPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm)) { /* Check if we actually need to fix the protections on the block. */ - if (cur_end == src_map_end || info.GetAddress() <= GetInteger(src_map_start) || (info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) { - const bool start_nc = (info.GetAddress() == GetInteger(src_map_start)) ? ((info.GetDisableMergeAttribute() & (KMemoryBlockDisableMergeAttribute_Locked | KMemoryBlockDisableMergeAttribute_IpcLeft)) == 0) : info.GetAddress() <= GetInteger(src_map_start); + if (cur_end == src_map_end || it->GetAddress() <= GetInteger(src_map_start) || (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) { + const bool start_nc = (it->GetAddress() == GetInteger(src_map_start)) ? ((it->GetDisableMergeAttribute() & (KMemoryBlockDisableMergeAttribute_Locked | KMemoryBlockDisableMergeAttribute_IpcLeft)) == 0) : it->GetAddress() <= GetInteger(src_map_start); const DisableMergeAttribute head_body_attr = start_nc ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None; DisableMergeAttribute tail_attr; - if (cur_end == src_map_end && info.GetEndAddress() == src_map_end) { + if (cur_end == src_map_end && it->GetEndAddress() == src_map_end) { auto next_it = it; ++next_it; - const auto lock_count = info.GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); + const auto lock_count = it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); tail_attr = lock_count == 0 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None; } else { tail_attr = DisableMergeAttribute_None; } - const KPageProperties properties = { info.GetPermission(), false, false, static_cast(head_body_attr | tail_attr) }; + const KPageProperties properties = { it->GetPermission(), false, false, static_cast(head_body_attr | tail_attr) }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(page_list, cur_start, (cur_end - cur_start) / PageSize, Null, false, properties, OperationType_ChangePermissions, true)); } } /* If we're past the end of the region, we're done. */ - if (src_map_last <= info.GetLastAddress()) { + if (src_map_last <= it->GetLastAddress()) { break; } @@ -4468,24 +4438,21 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { - if (info.GetState() != KMemoryState_Free) { + if (last_address <= it->GetLastAddress()) { + if (it->GetState() != KMemoryState_Free) { mapped_size += (last_address + 1 - cur_address); } break; } /* Track the memory if it's mapped. */ - if (info.GetState() != KMemoryState_Free) { - mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address; + if (it->GetState() != KMemoryState_Free) { + mapped_size += it->GetEndAddress() - cur_address; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } @@ -4527,21 +4494,18 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - - const bool is_free = info.GetState() == KMemoryState_Free; + const bool is_free = it->GetState() == KMemoryState_Free; if (is_free) { - if (info.GetAddress() < GetInteger(address)) { + if (it->GetAddress() < GetInteger(address)) { ++num_allocator_blocks; } - if (last_address < info.GetLastAddress()) { + if (last_address < it->GetLastAddress()) { ++num_allocator_blocks; } } /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { + if (last_address <= it->GetLastAddress()) { if (!is_free) { checked_mapped_size += (last_address + 1 - cur_address); } @@ -4550,11 +4514,11 @@ namespace ams::kern { /* Track the memory if it's mapped. */ if (!is_free) { - checked_mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address; + checked_mapped_size += it->GetEndAddress() - cur_address; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } @@ -4594,26 +4558,23 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* If the memory state is free, we mapped it and need to unmap it. */ - if (info.GetState() == KMemoryState_Free) { + if (it->GetState() == KMemoryState_Free) { /* Determine the range to unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; - const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_unmap_address + 1 - cur_address) / PageSize; + const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_unmap_address + 1 - cur_address) / PageSize; /* Unmap. */ MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null, false, unmap_properties, OperationType_Unmap, true)); } /* Check if we're done. */ - if (last_unmap_address <= info.GetLastAddress()) { + if (last_unmap_address <= it->GetLastAddress()) { break; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } } @@ -4632,14 +4593,11 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* If it's unmapped, we need to map it. */ - if (info.GetState() == KMemoryState_Free) { + if (it->GetState() == KMemoryState_Free) { /* Determine the range to map. */ const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, cur_address == this->GetAliasRegionStart() ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; - size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize; + size_t map_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize; /* While we have pages to map, map them. */ { @@ -4680,12 +4638,12 @@ namespace ams::kern { } /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { + if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } @@ -4737,26 +4695,23 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* Verify the memory's state. */ - const bool is_normal = info.GetState() == KMemoryState_Normal && info.GetAttribute() == 0; - const bool is_free = info.GetState() == KMemoryState_Free; + const bool is_normal = it->GetState() == KMemoryState_Normal && it->GetAttribute() == 0; + const bool is_free = it->GetState() == KMemoryState_Free; R_UNLESS(is_normal || is_free, svc::ResultInvalidCurrentMemory()); if (is_normal) { - R_UNLESS(info.GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory()); + R_UNLESS(it->GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory()); if (map_start_address == Null) { map_start_address = cur_address; } - map_last_address = (last_address >= info.GetLastAddress()) ? info.GetLastAddress() : last_address; + map_last_address = (last_address >= it->GetLastAddress()) ? it->GetLastAddress() : last_address; - if (info.GetAddress() < GetInteger(address)) { + if (it->GetAddress() < GetInteger(address)) { ++num_allocator_blocks; } - if (last_address < info.GetLastAddress()) { + if (last_address < it->GetLastAddress()) { ++num_allocator_blocks; } @@ -4764,12 +4719,12 @@ namespace ams::kern { } /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { + if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } @@ -4802,26 +4757,23 @@ namespace ams::kern { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); - /* Get the memory info. */ - const KMemoryInfo info = it->GetMemoryInfo(); - /* If the memory state is normal, we need to unmap it. */ - if (info.GetState() == KMemoryState_Normal) { + if (it->GetState() == KMemoryState_Normal) { /* Determine the range to unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; - const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize; + const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize; /* Unmap. */ MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null, false, unmap_properties, OperationType_Unmap, false)); } /* Check if we're done. */ - if (last_address <= info.GetLastAddress()) { + if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ - cur_address = info.GetEndAddress(); + cur_address = it->GetEndAddress(); ++it; } From 3d178950e86769fca40204b663334bd9723f598e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 12:51:49 -0700 Subject: [PATCH 08/14] kern: fix KMemoryBlock ctor reorder warn --- .../include/mesosphere/kern_k_memory_block.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp index 2847de337..57876fbcb 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp @@ -380,10 +380,9 @@ namespace ams::kern { explicit KMemoryBlock() { /* ... */ } constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) - : util::IntrusiveRedBlackTreeBaseNode(util::ConstantInitialize), m_device_disable_merge_left_count(), - m_device_disable_merge_right_count(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), - m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), m_original_permission(KMemoryPermission_None), - m_attribute(attr), m_disable_merge_attribute() + : util::IntrusiveRedBlackTreeBaseNode(util::ConstantInitialize), m_permission(p), m_original_permission(KMemoryPermission_None), + m_attribute(attr), m_disable_merge_attribute(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), + m_ipc_disable_merge_count(), m_device_use_count(0), m_device_disable_merge_left_count(), m_device_disable_merge_right_count() { /* ... */ } From c6b26921683505802e6dbce7c78d715853680286 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 12:52:07 -0700 Subject: [PATCH 09/14] kern: clear gicd/gicc pointers in KInterruptController::Finalize --- .../source/arch/arm/kern_generic_interrupt_controller.inc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/libmesosphere/source/arch/arm/kern_generic_interrupt_controller.inc b/libraries/libmesosphere/source/arch/arm/kern_generic_interrupt_controller.inc index 864da44a5..ef363c0cf 100644 --- a/libraries/libmesosphere/source/arch/arm/kern_generic_interrupt_controller.inc +++ b/libraries/libmesosphere/source/arch/arm/kern_generic_interrupt_controller.inc @@ -79,6 +79,12 @@ namespace ams::kern::arch::arm { /* Setup all interrupt lines. */ SetupInterruptLines(core_id); + + /* Clear pointers, if needed. */ + if (core_id == 0) { + m_gicd = nullptr; + m_gicc = nullptr; + } } void KInterruptController::SaveCoreLocal(LocalState *state) const { From c8e73003f30d703796bc4ad265d7fad607bf7215 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 14:04:15 -0700 Subject: [PATCH 10/14] kern: allocate all TTBR0 pages during init, use procidx as asid --- .../arch/arm64/kern_k_page_table.hpp | 25 ++++- .../arch/arm64/kern_k_process_page_table.hpp | 8 +- .../arm64/kern_k_supervisor_page_table.hpp | 3 +- .../include/mesosphere/kern_k_process.hpp | 2 +- .../source/arch/arm64/kern_k_page_table.cpp | 103 ++---------------- .../nintendo/nx/kern_k_sleep_manager.cpp | 4 +- .../libmesosphere/source/kern_k_process.cpp | 4 +- mesosphere/kernel/kernel.ld | 2 + .../source/arch/arm64/init/kern_init_core.cpp | 31 ++++++ 9 files changed, 72 insertions(+), 110 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index 14aba9913..370211b2b 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -93,9 +93,13 @@ namespace ams::kern::arch::arm64 { MESOSPHERE_ASSERT(alignment < L1BlockSize); return KPageTable::GetBlockSize(static_cast(KPageTable::GetBlockType(alignment) + 1)); } + public: + /* TODO: How should this size be determined. Does the KProcess slab count need to go in a header as a define? */ + static constexpr size_t NumTtbr0Entries = 81; + private: + static constinit inline const volatile u64 s_ttbr0_entries[NumTtbr0Entries] = {}; private: KPageTableManager *m_manager; - u64 m_ttbr; u8 m_asid; protected: Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll); @@ -168,17 +172,28 @@ namespace ams::kern::arch::arm64 { return entry; } public: - constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_ttbr(), m_asid() { /* ... */ } + constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_asid() { /* ... */ } explicit KPageTable() { /* ... */ } static NOINLINE void Initialize(s32 core_id); - ALWAYS_INLINE void Activate(u32 proc_id) { - cpu::SwitchProcess(m_ttbr, proc_id); + static const volatile u64 &GetTtbr0Entry(size_t index) { return s_ttbr0_entries[index]; } + + static ALWAYS_INLINE u64 GetKernelTtbr0() { + return s_ttbr0_entries[0]; + } + + static ALWAYS_INLINE void ActivateKernel() { + /* Activate, using asid 0 and process id = 0xFFFFFFFF */ + cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF); + } + + static ALWAYS_INLINE void ActivateProcess(size_t proc_idx, u32 proc_id) { + cpu::SwitchProcess(s_ttbr0_entries[proc_idx + 1], proc_id); } NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end); - NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); + NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index); Result Finalize(); private: Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 640b9e5e5..3ad3c96a1 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -23,13 +23,13 @@ namespace ams::kern::arch::arm64 { private: KPageTable m_page_table; public: - void Activate(u64 id) { + void Activate(size_t process_index, u64 id) { /* Activate the page table with the specified contextidr. */ - m_page_table.Activate(id); + m_page_table.ActivateProcess(process_index, id); } - Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { - R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit)); + Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { + R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit, process_index)); } void Finalize() { m_page_table.Finalize(); } diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index 73d886d84..0c0602289 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -29,8 +29,7 @@ namespace ams::kern::arch::arm64 { NOINLINE void Initialize(s32 core_id); void Activate() { - /* Activate, using process id = 0xFFFFFFFF */ - m_page_table.Activate(0xFFFFFFFF); + m_page_table.ActivateKernel(); } void ActivateForInit() { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 5a37e3a6b..c4ab7f2a5 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -374,7 +374,7 @@ namespace ams::kern { /* Update the current page table. */ if (next_process) { - next_process->GetPageTable().Activate(next_process->GetProcessId()); + next_process->GetPageTable().Activate(next_process->GetSlabIndex(), next_process->GetProcessId()); } else { Kernel::GetKernelPageTable().Activate(); } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp index 55e4fc52b..c1b0c76b4 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp @@ -85,77 +85,6 @@ namespace ams::kern::arch::arm64 { return (static_cast(asid) << 48) | (static_cast(GetInteger(table))); } - class KPageTableAsidManager { - private: - using WordType = u32; - static constexpr u8 ReservedAsids[] = { 0 }; - static constexpr size_t NumReservedAsids = util::size(ReservedAsids); - static constexpr size_t BitsPerWord = BITSIZEOF(WordType); - static constexpr size_t AsidCount = 0x100; - static constexpr size_t NumWords = AsidCount / BitsPerWord; - static constexpr WordType FullWord = ~WordType(0u); - private: - WordType m_state[NumWords]; - KLightLock m_lock; - u8 m_hint; - private: - constexpr bool TestImpl(u8 asid) const { - return m_state[asid / BitsPerWord] & (1u << (asid % BitsPerWord)); - } - constexpr void ReserveImpl(u8 asid) { - MESOSPHERE_ASSERT(!this->TestImpl(asid)); - m_state[asid / BitsPerWord] |= (1u << (asid % BitsPerWord)); - } - - constexpr void ReleaseImpl(u8 asid) { - MESOSPHERE_ASSERT(this->TestImpl(asid)); - m_state[asid / BitsPerWord] &= ~(1u << (asid % BitsPerWord)); - } - - constexpr u8 FindAvailable() const { - for (size_t i = 0; i < util::size(m_state); i++) { - if (m_state[i] == FullWord) { - continue; - } - const WordType clear_bit = (m_state[i] + 1) ^ (m_state[i]); - return BitsPerWord * i + BitsPerWord - 1 - ClearLeadingZero(clear_bit); - } - if (m_state[util::size(m_state)-1] == FullWord) { - MESOSPHERE_PANIC("Unable to reserve ASID"); - } - __builtin_unreachable(); - } - - static constexpr ALWAYS_INLINE WordType ClearLeadingZero(WordType value) { - return __builtin_clzll(value) - (BITSIZEOF(unsigned long long) - BITSIZEOF(WordType)); - } - public: - constexpr KPageTableAsidManager() : m_state(), m_lock(), m_hint() { - for (size_t i = 0; i < NumReservedAsids; i++) { - this->ReserveImpl(ReservedAsids[i]); - } - } - - u8 Reserve() { - KScopedLightLock lk(m_lock); - - if (this->TestImpl(m_hint)) { - m_hint = this->FindAvailable(); - } - - this->ReserveImpl(m_hint); - - return m_hint++; - } - - void Release(u8 asid) { - KScopedLightLock lk(m_lock); - this->ReleaseImpl(asid); - } - }; - - KPageTableAsidManager g_asid_manager; - } ALWAYS_INLINE void KPageTable::NoteUpdated() const { @@ -184,6 +113,7 @@ namespace ams::kern::arch::arm64 { this->OnKernelTableSinglePageUpdated(virt_addr); } + void KPageTable::Initialize(s32 core_id) { /* Nothing actually needed here. */ MESOSPHERE_UNUSED(core_id); @@ -194,38 +124,29 @@ namespace ams::kern::arch::arm64 { m_asid = 0; m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer(); - /* Allocate a page for ttbr. */ - /* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */ - const u64 asid_tag = (static_cast(m_asid) << 48ul); - const KVirtualAddress page = m_manager->Allocate(); - MESOSPHERE_ASSERT(page != Null); - m_ttbr = GetInteger(KPageTableBase::GetLinearMappedPhysicalAddress(page)) | asid_tag; - /* Initialize the base page table. */ MESOSPHERE_R_ABORT_UNLESS(KPageTableBase::InitializeForKernel(true, table, start, end)); R_SUCCEED(); } - Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { - /* Get an ASID */ - m_asid = g_asid_manager.Reserve(); - ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); }; + Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { + /* Determine our ASID */ + m_asid = process_index + 1; + MESOSPHERE_ABORT_UNLESS(0 < m_asid && m_asid < util::size(s_ttbr0_entries)); /* Set our manager. */ m_manager = system_resource->GetPageTableManagerPointer(); - /* Allocate a new table, and set our ttbr value. */ - const KVirtualAddress new_table = m_manager->Allocate(); - R_UNLESS(new_table != Null, svc::ResultOutOfResource()); - m_ttbr = EncodeTtbr(GetPageTablePhysicalAddress(new_table), m_asid); - ON_RESULT_FAILURE_2 { m_manager->Free(new_table); }; + /* Get the virtual address of our L1 table. */ + const KPhysicalAddress ttbr0_phys = KPhysicalAddress(s_ttbr0_entries[m_asid] & UINT64_C(0xFFFFFFFFFFFE)); + const KVirtualAddress ttbr0_virt = KMemoryLayout::GetLinearVirtualAddress(ttbr0_phys); /* Initialize our base table. */ const size_t as_width = GetAddressSpaceWidth(flags); const KProcessAddress as_start = 0; const KProcessAddress as_end = (1ul << as_width); - R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit)); + R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(ttbr0_virt), as_start, as_end, code_address, code_size, system_resource, resource_limit)); /* Note that we've updated the table (since we created it). */ this->NoteUpdated(); @@ -329,20 +250,16 @@ namespace ams::kern::arch::arm64 { } } - /* Free the L1 table. */ + /* Clear the L1 table. */ { const KVirtualAddress l1_table = reinterpret_cast(impl.Finalize()); ClearPageTable(l1_table); - this->GetPageTableManager().Free(l1_table); } /* Perform inherited finalization. */ KPageTableBase::Finalize(); } - /* Release our asid. */ - g_asid_manager.Release(m_asid); - R_SUCCEED(); } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp index bb782d390..5e5983c86 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp @@ -31,7 +31,6 @@ namespace ams::kern::board::nintendo::nx { /* Struct representing registers saved on wake/sleep. */ class SavedSystemRegisters { private: - u64 ttbr0_el1; u64 elr_el1; u64 sp_el0; u64 spsr_el1; @@ -90,7 +89,6 @@ namespace ams::kern::board::nintendo::nx { void SavedSystemRegisters::Save() { /* Save system registers. */ - this->ttbr0_el1 = cpu::GetTtbr0El1(); this->tpidr_el0 = cpu::GetTpidrEl0(); this->elr_el1 = cpu::GetElrEl1(); this->sp_el0 = cpu::GetSpEl0(); @@ -405,7 +403,7 @@ namespace ams::kern::board::nintendo::nx { cpu::EnsureInstructionConsistency(); /* Restore system registers. */ - cpu::SetTtbr0El1 (this->ttbr0_el1); + cpu::SetTtbr0El1 (KPageTable::GetKernelTtbr0()); cpu::SetTpidrEl0 (this->tpidr_el0); cpu::SetElrEl1 (this->elr_el1); cpu::SetSpEl0 (this->sp_el0); diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 789bdbc09..96d82f975 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -299,7 +299,7 @@ namespace ams::kern { /* Setup page table. */ { const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0; - R_TRY(m_page_table.Initialize(static_cast(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit)); + R_TRY(m_page_table.Initialize(static_cast(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit, this->GetSlabIndex())); } ON_RESULT_FAILURE_2 { m_page_table.Finalize(); }; @@ -378,7 +378,7 @@ namespace ams::kern { /* Setup page table. */ { const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0; - R_TRY(m_page_table.Initialize(static_cast(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit)); + R_TRY(m_page_table.Initialize(static_cast(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit, this->GetSlabIndex())); } ON_RESULT_FAILURE_2 { m_page_table.Finalize(); }; diff --git a/mesosphere/kernel/kernel.ld b/mesosphere/kernel/kernel.ld index 779488a35..bcd658572 100644 --- a/mesosphere/kernel/kernel.ld +++ b/mesosphere/kernel/kernel.ld @@ -125,6 +125,8 @@ SECTIONS .gnu.version_r : { *(.gnu.version_r) } :rodata .note.gnu.build-id : { *(.note.gnu.build-id) } :rodata + __rodata_end = .; + /* =========== DATA section =========== */ . = ALIGN(0x1000); __data_start = . ; diff --git a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp index faf34576d..10a000c6d 100644 --- a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp +++ b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp @@ -15,6 +15,9 @@ */ #include +extern "C" void __rodata_start(); +extern "C" void __rodata_end(); + extern "C" void __bin_start__(); extern "C" void __bin_end__(); @@ -220,6 +223,31 @@ namespace ams::kern::init { }; static_assert(kern::arch::arm64::init::IsInitialPageAllocator); + void SetupAllTtbr0Entries(KInitialPageTable &init_pt, KInitialPageAllocator &allocator) { + /* Validate that the ttbr0 array is in rodata. */ + const uintptr_t rodata_start = reinterpret_cast(__rodata_start); + const uintptr_t rodata_end = reinterpret_cast(__rodata_end); + MESOSPHERE_INIT_ABORT_UNLESS(rodata_start < rodata_end); + MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast(std::addressof(KPageTable::GetTtbr0Entry(0)))); + MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumTtbr0Entries))) < rodata_end); + + /* Allocate pages for all ttbr0 entries. */ + for (size_t i = 0; i < KPageTable::NumTtbr0Entries; ++i) { + /* Allocate a page. */ + KPhysicalAddress page = allocator.Allocate(PageSize); + MESOSPHERE_INIT_ABORT_UNLESS(page != Null); + + /* Check that the page is allowed to be a ttbr0 entry. */ + MESOSPHERE_INIT_ABORT_UNLESS((GetInteger(page) & UINT64_C(0xFFFF000000000001)) == 0); + + /* Get the physical address of the ttbr0 entry. */ + const auto ttbr0_phys_ptr = init_pt.GetPhysicalAddress(KVirtualAddress(std::addressof(KPageTable::GetTtbr0Entry(i)))); + + /* Set the entry to the newly allocated page. */ + *reinterpret_cast(GetInteger(ttbr0_phys_ptr)) = (static_cast(i) << 48) | GetInteger(page); + } + } + void FinalizeIdentityMapping(KInitialPageTable &init_pt, KInitialPageAllocator &allocator, u64 phys_to_virt_offset) { /* Create an allocator for identity mapping finalization. */ KInitialPageAllocatorForFinalizeIdentityMapping finalize_allocator(allocator, phys_to_virt_offset); @@ -591,6 +619,9 @@ namespace ams::kern::init { /* Create page table object for use during remaining initialization. */ KInitialPageTable init_pt; + /* Setup all ttbr0 pages. */ + SetupAllTtbr0Entries(init_pt, g_initial_page_allocator); + /* Unmap the identity mapping. */ FinalizeIdentityMapping(init_pt, g_initial_page_allocator, g_phase2_linear_region_phys_to_virt_diff); From 117da7ff37e9b4ca7d4326f4d67a15afb6069850 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 15:12:25 -0700 Subject: [PATCH 11/14] kern: fix debug build --- .../source/arch/arm64/kern_k_debug.cpp | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp index 89587597b..87d7bf307 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp @@ -15,6 +15,28 @@ */ #include +/* */ +namespace ams::rocrt { + + constexpr inline const u32 ModuleHeaderVersion = util::FourCC<'M','O','D','0'>::Code; + + struct ModuleHeader { + u32 signature; + u32 dynamic_offset; + u32 bss_start_offset; + u32 bss_end_offset; + u32 exception_info_start_offset; + u32 exception_info_end_offset; + u32 module_offset; + }; + + struct ModuleHeaderLocation { + u32 pad; + u32 header_offset; + }; + +} + namespace ams::kern::arch::arm64 { namespace { @@ -657,7 +679,7 @@ namespace ams::kern::arch::arm64 { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - dyn_address = module.start_address + mod_offset + temp_32; + dyn_address = base_address + mod_offset + temp_32; } /* Locate tables inside .dyn. */ From e200dfb48c138e2346f31a0656b92ac7097dafc2 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 15:12:46 -0700 Subject: [PATCH 12/14] kern: move KTargetSystem into .rodata, split init/verify --- .../nintendo/nx/kern_k_system_control.hpp | 1 + .../mesosphere/kern_k_system_control_base.hpp | 1 + .../mesosphere/kern_k_target_system.hpp | 49 +++++++++-------- .../nintendo/nx/kern_k_system_control.cpp | 53 +++++++++++++++---- .../source/kern_k_system_control_base.cpp | 29 +++------- .../source/kern_kernel_instantiations.cpp | 4 ++ 6 files changed, 83 insertions(+), 54 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index a0cfce5a1..8e1829849 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -45,6 +45,7 @@ namespace ams::kern::board::nintendo::nx { }; public: /* Initialization. */ + static NOINLINE void ConfigureKTargetSystem(); static NOINLINE void InitializePhase1(); static NOINLINE void InitializePhase2(); static NOINLINE u32 GetCreateProcessMemoryPool(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp index bb1c1ff0f..ab3a18c5b 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp @@ -69,6 +69,7 @@ namespace ams::kern { static NOINLINE void InitializePhase1Base(u64 seed); public: /* Initialization. */ + static NOINLINE void ConfigureKTargetSystem(); static NOINLINE void InitializePhase1(); static NOINLINE void InitializePhase2(); static NOINLINE u32 GetCreateProcessMemoryPool(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp index 87b72c0fa..24220bed0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp @@ -24,29 +24,36 @@ namespace ams::kern { friend class KSystemControlBase; friend class KSystemControl; private: - static inline constinit bool s_is_debug_mode; - static inline constinit bool s_enable_debug_logging; - static inline constinit bool s_enable_user_exception_handlers; - static inline constinit bool s_enable_debug_memory_fill; - static inline constinit bool s_enable_user_pmu_access; - static inline constinit bool s_enable_kernel_debugging; - static inline constinit bool s_enable_dynamic_resource_limits; + struct KTargetSystemData { + bool is_debug_mode; + bool enable_debug_logging; + bool enable_user_exception_handlers; + bool enable_debug_memory_fill; + bool enable_user_pmu_access; + bool enable_kernel_debugging; + bool enable_dynamic_resource_limits; + }; private: - static ALWAYS_INLINE void SetIsDebugMode(bool en) { s_is_debug_mode = en; } - static ALWAYS_INLINE void EnableDebugLogging(bool en) { s_enable_debug_logging = en; } - static ALWAYS_INLINE void EnableUserExceptionHandlers(bool en) { s_enable_user_exception_handlers = en; } - static ALWAYS_INLINE void EnableDebugMemoryFill(bool en) { s_enable_debug_memory_fill = en; } - static ALWAYS_INLINE void EnableUserPmuAccess(bool en) { s_enable_user_pmu_access = en; } - static ALWAYS_INLINE void EnableKernelDebugging(bool en) { s_enable_kernel_debugging = en; } - static ALWAYS_INLINE void EnableDynamicResourceLimits(bool en) { s_enable_dynamic_resource_limits = en; } + static inline constinit bool s_is_initialized = false; + static inline constinit const volatile KTargetSystemData s_data = { + .is_debug_mode = true, + .enable_debug_logging = true, + .enable_user_exception_handlers = true, + .enable_debug_memory_fill = true, + .enable_user_pmu_access = true, + .enable_kernel_debugging = true, + .enable_dynamic_resource_limits = false, + }; + private: + static ALWAYS_INLINE void SetInitialized() { s_is_initialized = true; } public: - static ALWAYS_INLINE bool IsDebugMode() { return s_is_debug_mode; } - static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_enable_debug_logging; } - static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_enable_user_exception_handlers; } - static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_enable_debug_memory_fill; } - static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_enable_user_pmu_access; } - static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_enable_kernel_debugging; } - static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_enable_dynamic_resource_limits; } + static ALWAYS_INLINE bool IsDebugMode() { return s_is_initialized && s_data.is_debug_mode; } + static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_is_initialized && s_data.enable_debug_logging; } + static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_is_initialized && s_data.enable_user_exception_handlers; } + static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_is_initialized && s_data.enable_debug_memory_fill; } + static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_is_initialized && s_data.enable_user_pmu_access; } + static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_is_initialized && s_data.enable_kernel_debugging; } + static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_is_initialized && s_data.enable_dynamic_resource_limits; } }; } \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index 52a894d1c..8050f78e0 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -26,7 +26,7 @@ namespace ams::kern::board::nintendo::nx { constexpr size_t SecureSizeMax = util::AlignDown(512_MB - 1, SecureAlignment); /* Global variables for panic. */ - constinit bool g_call_smc_on_panic; + constinit const volatile bool g_call_smc_on_panic = false; /* Global variables for secure memory. */ constinit KSpinLock g_secure_applet_lock; @@ -401,34 +401,67 @@ namespace ams::kern::board::nintendo::nx { } /* System Initialization. */ - void KSystemControl::InitializePhase1() { + void KSystemControl::ConfigureKTargetSystem() { /* Configure KTargetSystem. */ + volatile auto *ts = const_cast(std::addressof(KTargetSystem::s_data)); { /* Set IsDebugMode. */ { - KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); + ts->is_debug_mode = GetConfigBool(smc::ConfigItem::IsDebugMode); /* If debug mode, we want to initialize uart logging. */ - KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode()); + ts->enable_debug_logging = ts->is_debug_mode; } /* Set Kernel Configuration. */ { const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; - KTargetSystem::EnableDebugMemoryFill(kernel_config.Get()); - KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get()); - KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get()); - KTargetSystem::EnableUserPmuAccess(kernel_config.Get()); + ts->enable_debug_memory_fill = kernel_config.Get(); + ts->enable_user_exception_handlers = kernel_config.Get(); + ts->enable_dynamic_resource_limits = !kernel_config.Get(); + ts->enable_user_pmu_access = kernel_config.Get(); - g_call_smc_on_panic = kernel_config.Get(); + /* Configure call smc on panic. */ + *const_cast(std::addressof(g_call_smc_on_panic)) = kernel_config.Get(); } /* Set Kernel Debugging. */ { /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ - KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification)); + ts->enable_kernel_debugging = GetConfigBool(smc::ConfigItem::DisableProgramVerification); + } + } + } + + void KSystemControl::InitializePhase1() { + /* Enable KTargetSystem. */ + KTargetSystem::SetInitialized(); + + /* Check KTargetSystem was configured correctly. */ + { + /* Check IsDebugMode. */ + { + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMode() == GetConfigBool(smc::ConfigItem::IsDebugMode)); + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugLoggingEnabled() == GetConfigBool(smc::ConfigItem::IsDebugMode)); + } + + /* Check Kernel Configuration. */ + { + const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; + + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMemoryFillEnabled() == kernel_config.Get()); + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserExceptionHandlersEnabled() == kernel_config.Get()); + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled() == !kernel_config.Get()); + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserPmuAccessEnabled() == kernel_config.Get()); + + MESOSPHERE_ABORT_UNLESS(g_call_smc_on_panic == kernel_config.Get()); + } + + /* Check Kernel Debugging. */ + { + MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsKernelDebuggingEnabled() == GetConfigBool(smc::ConfigItem::DisableProgramVerification)); } } diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp index fe0b56996..025ec4f9c 100644 --- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp +++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp @@ -124,31 +124,14 @@ namespace ams::kern { } /* System Initialization. */ + void KSystemControlBase::ConfigureKTargetSystem() { + /* By default, use the default config set in the KTargetSystem header. */ + } + void KSystemControlBase::InitializePhase1() { - /* Configure KTargetSystem. */ + /* Enable KTargetSystem. */ { - /* Set IsDebugMode. */ - { - KTargetSystem::SetIsDebugMode(true); - - /* If debug mode, we want to initialize uart logging. */ - KTargetSystem::EnableDebugLogging(true); - } - - /* Set Kernel Configuration. */ - { - KTargetSystem::EnableDebugMemoryFill(false); - KTargetSystem::EnableUserExceptionHandlers(true); - KTargetSystem::EnableDynamicResourceLimits(true); - KTargetSystem::EnableUserPmuAccess(false); - } - - /* Set Kernel Debugging. */ - { - /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ - /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ - KTargetSystem::EnableKernelDebugging(true); - } + KTargetSystem::SetInitialized(); } /* Initialize random and resource limit. */ diff --git a/mesosphere/kernel/source/kern_kernel_instantiations.cpp b/mesosphere/kernel/source/kern_kernel_instantiations.cpp index 6adff0754..d01ddd151 100644 --- a/mesosphere/kernel/source/kern_kernel_instantiations.cpp +++ b/mesosphere/kernel/source/kern_kernel_instantiations.cpp @@ -111,4 +111,8 @@ namespace ams::kern { KThread &Kernel::GetMainThread(s32 core_id) { return g_main_threads.m_arr[core_id]; } KThread &Kernel::GetIdleThread(s32 core_id) { return g_idle_threads.m_arr[core_id]; } + __attribute__((constructor)) void ConfigureKTargetSystem() { + KSystemControl::ConfigureKTargetSystem(); + } + } From 52bc54205bfadb3e76a4cc52dc031839414c46d1 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 15:20:32 -0700 Subject: [PATCH 13/14] kern: simplify KProcess max memory calculation --- libraries/libmesosphere/source/kern_k_process.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 96d82f975..24c6baef5 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -220,18 +220,8 @@ namespace ams::kern { m_running_thread_switch_counts[i] = 0; } - /* Set max memory based on address space type. */ - switch ((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask)) { - case ams::svc::CreateProcessFlag_AddressSpace32Bit: - case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated: - case ams::svc::CreateProcessFlag_AddressSpace64Bit: - m_max_process_memory = m_page_table.GetHeapRegionSize(); - break; - case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias: - m_max_process_memory = m_page_table.GetHeapRegionSize() + m_page_table.GetAliasRegionSize(); - break; - MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); - } + /* Set max memory. */ + m_max_process_memory = m_page_table.GetHeapRegionSize(); /* Generate random entropy. */ KSystemControl::GenerateRandom(m_entropy, util::size(m_entropy)); From dfff4508fa3fc8d4c3b441a3aeb8b32bcb598e04 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Oct 2024 16:50:20 -0700 Subject: [PATCH 14/14] kern/strat: update for new DebugFlags capability semantics --- config_templates/exosphere.ini | 2 +- .../arch/arm64/kern_k_process_page_table.hpp | 4 +- .../mesosphere/kern_k_capabilities.hpp | 11 ++- .../include/mesosphere/kern_k_debug_base.hpp | 5 ++ .../mesosphere/kern_k_page_table_base.hpp | 4 +- .../include/mesosphere/kern_k_process.hpp | 4 + .../source/kern_k_capabilities.cpp | 7 ++ .../source/kern_k_debug_base.cpp | 81 ++++--------------- .../source/kern_k_page_table_base.cpp | 38 ++++++--- .../source/svc/kern_svc_debug.cpp | 23 +++++- .../source/svc/kern_svc_process.cpp | 3 + .../source/svc/kern_svc_thread.cpp | 47 ++++++----- stratosphere/creport/creport.json | 1 + stratosphere/dmnt.gen2/dmnt.gen2.json | 1 + stratosphere/fatal/fatal.json | 1 + .../loader/source/ldr_capabilities.cpp | 19 ++++- stratosphere/pm/pm.json | 1 + 17 files changed, 142 insertions(+), 110 deletions(-) diff --git a/config_templates/exosphere.ini b/config_templates/exosphere.ini index e8dc82377..8df772ccf 100644 --- a/config_templates/exosphere.ini +++ b/config_templates/exosphere.ini @@ -1,6 +1,6 @@ # Key: debugmode, default: 1. # Desc: Controls whether kernel is debug mode. -# Disabling this may break Atmosphere's debugger in a future release. +# Disabling this will break Atmosphere. # Key: debugmode_user, default: 0. # Desc: Controls whether userland is debug mode. diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 3ad3c96a1..e18a6fbc8 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -154,8 +154,8 @@ namespace ams::kern::arch::arm64 { R_RETURN(m_page_table.InvalidateCurrentProcessDataCache(address, size)); } - Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) { - R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size)); + Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) { + R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size, force_debug_prod)); } Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp index 7c2f5dbcd..2c74b835c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp @@ -168,9 +168,10 @@ namespace ams::kern { struct DebugFlags { using IdBits = Field<0, CapabilityId + 1>; - DEFINE_FIELD(AllowDebug, IdBits, 1, bool); - DEFINE_FIELD(ForceDebug, AllowDebug, 1, bool); - DEFINE_FIELD(Reserved, ForceDebug, 13); + DEFINE_FIELD(AllowDebug, IdBits, 1, bool); + DEFINE_FIELD(ForceDebugProd, AllowDebug, 1, bool); + DEFINE_FIELD(ForceDebug, ForceDebugProd, 1, bool); + DEFINE_FIELD(Reserved, ForceDebug, 12); }; #undef DEFINE_FIELD @@ -255,6 +256,10 @@ namespace ams::kern { return m_debug_capabilities.Get(); } + constexpr bool CanForceDebugProd() const { + return m_debug_capabilities.Get(); + } + constexpr bool CanForceDebug() const { return m_debug_capabilities.Get(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp index 6c8fe54f7..6978b9152 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp @@ -32,6 +32,7 @@ namespace ams::kern { KLightLock m_lock; KProcess::State m_old_process_state; bool m_is_attached; + bool m_is_force_debug_prod; public: explicit KDebugBase() { /* ... */ } protected: @@ -62,6 +63,10 @@ namespace ams::kern { return m_is_attached; } + ALWAYS_INLINE bool IsForceDebugProd() const { + return m_is_force_debug_prod; + } + ALWAYS_INLINE bool OpenProcess() { return m_process_holder.Open(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 8da4311df..7b2c722e1 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -328,6 +328,8 @@ namespace ams::kern { R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr)); } + bool CanReadWriteDebugMemory(KProcessAddress addr, size_t size, bool force_debug_prod); + Result LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr); Result UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg); @@ -421,7 +423,7 @@ namespace ams::kern { Result InvalidateProcessDataCache(KProcessAddress address, size_t size); Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size); - Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size); + Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod); Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state); Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index c4ab7f2a5..849f73dab 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -206,6 +206,10 @@ namespace ams::kern { return m_capabilities.IsPermittedDebug(); } + constexpr bool CanForceDebugProd() const { + return m_capabilities.CanForceDebugProd(); + } + constexpr bool CanForceDebug() const { return m_capabilities.CanForceDebug(); } diff --git a/libraries/libmesosphere/source/kern_k_capabilities.cpp b/libraries/libmesosphere/source/kern_k_capabilities.cpp index feb245eda..ba0359262 100644 --- a/libraries/libmesosphere/source/kern_k_capabilities.cpp +++ b/libraries/libmesosphere/source/kern_k_capabilities.cpp @@ -262,7 +262,14 @@ namespace ams::kern { /* Validate. */ R_UNLESS(cap.Get() == 0, svc::ResultReservedUsed()); + u32 total = 0; + if (cap.Get()) { ++total; } + if (cap.Get()) { ++total; } + if (cap.Get()) { ++total; } + R_UNLESS(total <= 1, svc::ResultInvalidCombination()); + m_debug_capabilities.Set(cap.Get()); + m_debug_capabilities.Set(cap.Get()); m_debug_capabilities.Set(cap.Get()); R_SUCCEED(); } diff --git a/libraries/libmesosphere/source/kern_k_debug_base.cpp b/libraries/libmesosphere/source/kern_k_debug_base.cpp index 418d804f3..635673cd2 100644 --- a/libraries/libmesosphere/source/kern_k_debug_base.cpp +++ b/libraries/libmesosphere/source/kern_k_debug_base.cpp @@ -27,7 +27,8 @@ namespace ams::kern { void KDebugBase::Initialize() { /* Clear the continue flags. */ - m_continue_flags = 0; + m_continue_flags = 0; + m_is_force_debug_prod = GetCurrentProcess().CanForceDebugProd(); } bool KDebugBase::Is64Bit() const { @@ -120,8 +121,11 @@ namespace ams::kern { /* Read the memory. */ if (info.GetSvcState() != ams::svc::MemoryState_Io) { /* The memory is normal memory. */ - R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size)); + R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size, this->IsForceDebugProd())); } else { + /* Only allow IO memory to be read if not force debug prod. */ + R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidCurrentMemory()); + /* The memory is IO memory. */ R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size, info.GetState())); } @@ -269,6 +273,9 @@ namespace ams::kern { switch (state) { case KProcess::State_Created: case KProcess::State_Running: + /* Created and running processes can only be debugged if the debugger is not ForceDebugProd. */ + R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidState()); + break; case KProcess::State_Crashed: break; case KProcess::State_CreatedAttached: @@ -408,69 +415,6 @@ namespace ams::kern { /* Get the process pointer. */ KProcess * const target = this->GetProcessUnsafe(); - /* Detach from the process. */ - { - /* Lock both ourselves and the target process. */ - KScopedLightLock state_lk(target->GetStateLock()); - KScopedLightLock list_lk(target->GetListLock()); - KScopedLightLock this_lk(m_lock); - - /* Check that we're still attached. */ - if (this->IsAttached()) { - /* Lock the scheduler. */ - KScopedSchedulerLock sl; - - /* Get the process's state. */ - const KProcess::State state = target->GetState(); - - /* Check that the process is in a state where we can terminate it. */ - R_UNLESS(state != KProcess::State_Created, svc::ResultInvalidState()); - R_UNLESS(state != KProcess::State_CreatedAttached, svc::ResultInvalidState()); - - /* Decide on a new state for the process. */ - KProcess::State new_state; - if (state == KProcess::State_RunningAttached) { - /* If the process is running, transition it accordingly. */ - new_state = KProcess::State_Running; - } else if (state == KProcess::State_DebugBreak) { - /* If the process is debug breaked, transition it accordingly. */ - new_state = KProcess::State_Crashed; - - /* Suspend all the threads in the process. */ - { - auto end = target->GetThreadList().end(); - for (auto it = target->GetThreadList().begin(); it != end; ++it) { - /* Request that we suspend the thread. */ - it->RequestSuspend(KThread::SuspendType_Debug); - } - } - } else { - /* Otherwise, don't transition. */ - new_state = state; - } - - #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) - /* Clear single step on all threads. */ - { - auto end = target->GetThreadList().end(); - for (auto it = target->GetThreadList().begin(); it != end; ++it) { - it->ClearHardwareSingleStep(); - } - } - #endif - - /* Detach from the process. */ - target->ClearDebugObject(new_state); - m_is_attached = false; - - /* Close the initial reference opened to our process. */ - this->CloseProcess(); - - /* Clear our continue flags. */ - m_continue_flags = 0; - } - } - /* Terminate the process. */ target->Terminate(); @@ -962,7 +906,12 @@ namespace ams::kern { case ams::svc::DebugException_UndefinedInstruction: { MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 1); - out->info.exception.specific.undefined_instruction.insn = info->info.exception.exception_data[0]; + /* Only save the instruction if the caller is not force debug prod. */ + if (this->IsForceDebugProd()) { + out->info.exception.specific.undefined_instruction.insn = 0; + } else { + out->info.exception.specific.undefined_instruction.insn = info->info.exception.exception_data[0]; + } } break; case ams::svc::DebugException_BreakPoint: diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 95bc983ca..2a9402ecc 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -2695,18 +2695,37 @@ namespace ams::kern { R_RETURN(cpu::InvalidateDataCache(GetVoidPointer(address), size)); } - Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) { + bool KPageTableBase::CanReadWriteDebugMemory(KProcessAddress address, size_t size, bool force_debug_prod) { + /* Check pre-conditions. */ + MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); + + /* If the memory is debuggable and user-readable, we can perform the access. */ + if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { + return true; + } + + /* If we're in debug mode, and the process isn't force debug prod, check if the memory is debuggable and kernel-readable and user-executable. */ + if (KTargetSystem::IsDebugMode() && !force_debug_prod) { + if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryAttribute_None, KMemoryAttribute_None))) { + return true; + } + } + + /* If neither of the above checks passed, we can't access the memory. */ + return false; + } + + Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) { /* Lightly validate the region is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); - /* Require that the memory either be user readable or debuggable. */ - const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); + /* Require that the memory either be user-readable-and-mapped or debug-accessible. */ + const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); if (!can_read) { - const bool can_debug = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); - R_UNLESS(can_debug, svc::ResultInvalidCurrentMemory()); + R_UNLESS(this->CanReadWriteDebugMemory(address, size, force_debug_prod), svc::ResultInvalidCurrentMemory()); } /* Get the impl. */ @@ -2788,11 +2807,10 @@ namespace ams::kern { /* Lock the table. */ KScopedLightLock lk(m_general_lock); - /* Require that the memory either be user writable or debuggable. */ - const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None)); - if (!can_read) { - const bool can_debug = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); - R_UNLESS(can_debug, svc::ResultInvalidCurrentMemory()); + /* Require that the memory either be user-writable-and-mapped or debug-accessible. */ + const bool can_write = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None)); + if (!can_write) { + R_UNLESS(this->CanReadWriteDebugMemory(address, size, false), svc::ResultInvalidCurrentMemory()); } /* Get the impl. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp index 369885355..986654ce4 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp @@ -24,6 +24,9 @@ namespace ams::kern::svc { constexpr inline int32_t MaximumDebuggableThreadCount = 0x60; Result DebugActiveProcess(ams::svc::Handle *out_handle, uint64_t process_id) { + /* Check that the SVC can be used. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Get the process from its id. */ KProcess *process = KProcess::GetProcessFromId(process_id); R_UNLESS(process != nullptr, svc::ResultInvalidProcessId()); @@ -32,9 +35,8 @@ namespace ams::kern::svc { ON_SCOPE_EXIT { process->Close(); }; /* Check that the debugging is allowed. */ - if (!process->IsPermittedDebug()) { - R_UNLESS(GetCurrentProcess().CanForceDebug(), svc::ResultInvalidState()); - } + const bool allowable = process->IsPermittedDebug() || GetCurrentProcess().CanForceDebug() || GetCurrentProcess().CanForceDebugProd(); + R_UNLESS(allowable, svc::ResultInvalidState()); /* Disallow debugging one's own processs, to prevent softlocks. */ R_UNLESS(process != GetCurrentProcessPointer(), svc::ResultInvalidState()); @@ -92,6 +94,9 @@ namespace ams::kern::svc { template Result GetDebugEvent(KUserPointer out_info, ams::svc::Handle debug_handle) { + /* Only allow invoking the svc on development hardware or if force debug prod. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); @@ -164,6 +169,9 @@ namespace ams::kern::svc { } Result GetDebugThreadContext(KUserPointer out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { + /* Only allow invoking the svc on development hardware or if force debug prod. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Validate the context flags. */ R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue()); @@ -220,6 +228,9 @@ namespace ams::kern::svc { } Result QueryDebugProcessMemory(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uintptr_t address) { + /* Only allow invoking the svc on development hardware or if force debug prod. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); @@ -261,6 +272,9 @@ namespace ams::kern::svc { } Result ReadDebugProcessMemory(uintptr_t buffer, ams::svc::Handle debug_handle, uintptr_t address, size_t size) { + /* Only allow invoking the svc on development hardware or if force debug prod. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Validate address / size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); @@ -306,6 +320,9 @@ namespace ams::kern::svc { } Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { + /* Only allow invoking the svc on development hardware or if force debug prod. */ + R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 5141a2c31..98c8740f2 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -71,6 +71,9 @@ namespace ams::kern::svc { } Result GetProcessList(int32_t *out_num_processes, KUserPointer out_process_ids, int32_t max_out_count) { + /* Only allow invoking the svc on development hardware. */ + R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); + /* Validate that the out count is valid. */ R_UNLESS((0 <= max_out_count && max_out_count <= static_cast(std::numeric_limits::max() / sizeof(u64))), svc::ResultOutOfRange()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp index 99c8c37a8..6f74dd145 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp @@ -217,6 +217,9 @@ namespace ams::kern::svc { } Result GetThreadList(int32_t *out_num_threads, KUserPointer out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { + /* Only allow invoking the svc on development hardware. */ + R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); + /* Validate that the out count is valid. */ R_UNLESS((0 <= max_out_count && max_out_count <= static_cast(std::numeric_limits::max() / sizeof(u64))), svc::ResultOutOfRange()); @@ -225,30 +228,34 @@ namespace ams::kern::svc { R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); } - if (debug_handle == ams::svc::InvalidHandle) { - /* If passed invalid handle, we should return the global thread list. */ - R_TRY(KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count)); + /* Get the handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Try to get as a debug object. */ + KScopedAutoObject debug = handle_table.GetObject(debug_handle); + if (debug.IsNotNull()) { + /* Check that the debug object has a process. */ + R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); + R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); + ON_SCOPE_EXIT { debug->CloseProcess(); }; + + /* Get the thread list. */ + R_TRY(debug->GetProcessUnsafe()->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); } else { - /* Get the handle table. */ - auto &handle_table = GetCurrentProcess().GetHandleTable(); - - /* Try to get as a debug object. */ - KScopedAutoObject debug = handle_table.GetObject(debug_handle); - if (debug.IsNotNull()) { - /* Check that the debug object has a process. */ - R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); - R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); - ON_SCOPE_EXIT { debug->CloseProcess(); }; - - /* Get the thread list. */ - R_TRY(debug->GetProcessUnsafe()->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); - } else { - /* Try to get as a process. */ - KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle(debug_handle); - R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); + /* Only allow getting as a process (or global) if the caller does not have ForceDebugProd. */ + R_UNLESS(!GetCurrentProcess().CanForceDebugProd(), svc::ResultInvalidHandle()); + /* Try to get as a process. */ + KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle(debug_handle); + if (process.IsNotNull()) { /* Get the thread list. */ R_TRY(process->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); + } else { + /* If the object is not a process, the caller may want the global thread list. */ + R_UNLESS(debug_handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); + + /* If passed invalid handle, we should return the global thread list. */ + R_TRY(KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count)); } } diff --git a/stratosphere/creport/creport.json b/stratosphere/creport/creport.json index cdd28371d..99859c3d2 100644 --- a/stratosphere/creport/creport.json +++ b/stratosphere/creport/creport.json @@ -110,6 +110,7 @@ "type": "debug_flags", "value": { "allow_debug": false, + "force_debug_prod": false, "force_debug": true } } diff --git a/stratosphere/dmnt.gen2/dmnt.gen2.json b/stratosphere/dmnt.gen2/dmnt.gen2.json index 918f1262c..e0d970789 100644 --- a/stratosphere/dmnt.gen2/dmnt.gen2.json +++ b/stratosphere/dmnt.gen2/dmnt.gen2.json @@ -105,6 +105,7 @@ "type": "debug_flags", "value": { "allow_debug": false, + "force_debug_prod": false, "force_debug": true } }] diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json index 45b718089..aef307a68 100644 --- a/stratosphere/fatal/fatal.json +++ b/stratosphere/fatal/fatal.json @@ -104,6 +104,7 @@ "type": "debug_flags", "value": { "allow_debug": false, + "force_debug_prod": false, "force_debug": true } }] diff --git a/stratosphere/loader/source/ldr_capabilities.cpp b/stratosphere/loader/source/ldr_capabilities.cpp index 6835267b3..cd93d855f 100644 --- a/stratosphere/loader/source/ldr_capabilities.cpp +++ b/stratosphere/loader/source/ldr_capabilities.cpp @@ -308,10 +308,19 @@ namespace ams::ldr { ); DEFINE_CAPABILITY_CLASS(DebugFlags, - DEFINE_CAPABILITY_FIELD(AllowDebug, IdBits, 1, bool); - DEFINE_CAPABILITY_FIELD(ForceDebug, AllowDebug, 1, bool); + DEFINE_CAPABILITY_FIELD(AllowDebug, IdBits, 1, bool); + DEFINE_CAPABILITY_FIELD(ForceDebugProd, AllowDebug, 1, bool); + DEFINE_CAPABILITY_FIELD(ForceDebug, ForceDebugProd, 1, bool); bool IsValid(const util::BitPack32 *kac, size_t kac_count) const { + u32 total = 0; + if (this->GetAllowDebug()) { ++total; } + if (this->GetForceDebugProd()) { ++total; } + if (this->GetForceDebug()) { ++total; } + if (total > 1) { + return false; + } + for (size_t i = 0; i < kac_count; i++) { if (GetCapabilityId(kac[i]) == Id) { const auto restriction = Decode(kac[i]); @@ -319,12 +328,14 @@ namespace ams::ldr { return (restriction.GetValue() & this->GetValue()) == this->GetValue(); } } + return false; } - static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug) { + static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug_prod, bool force_debug) { util::BitPack32 encoded{IdBitsValue}; encoded.Set(allow_debug); + encoded.Set(force_debug_prod); encoded.Set(force_debug); return encoded; } @@ -406,7 +417,7 @@ namespace ams::ldr { kac[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask); break; case CapabilityId::DebugFlags: - kac[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cap).GetForceDebug()); + kac[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cap).GetForceDebugProd(), CapabilityDebugFlags::Decode(cap).GetForceDebug()); break; default: break; diff --git a/stratosphere/pm/pm.json b/stratosphere/pm/pm.json index 005504b72..4ffe5e94e 100644 --- a/stratosphere/pm/pm.json +++ b/stratosphere/pm/pm.json @@ -85,6 +85,7 @@ "type": "debug_flags", "value": { "allow_debug": false, + "force_debug_prod": false, "force_debug": true } }