1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 04:02:11 +00:00

*FormattedStringToBuffer: relax input validation

Affects both utilsAppendFormattedStringToBuffer() and logWriteFormattedStringToBuffer(). Fixes logging issues within both the exception handler and memory debugging code.

Other changes include:

* bfttf: rename BfttfFontType_Total -> BfttfFontType_Count.
* config: rename "append_authoringtool_data" -> "generate_authoringtool_data".
* fs_ext: update FsGameCardCertificate struct
* gamecard: fix gamecardReadLotusAsicFirmwareBlob() not returning false if FS .data segment memory couldn't be retrieved; update GameCardInfo struct to reflect a recently discovered area that's not zeroed out.
* mem: expand MemoryProgramSegmentType enum; define extra macros for PID buffer size and memory page type checks; force empty memory page attribute and R/X permission checks while looking for the last FS .text segment; make memory page filtering code more readable.
* npdm: rename KernelCapability enums; rename entry_value -> bitmask in all KernelCapability descriptor structs.
* tik: force byte-for-byte memory lookup while dumping volatile tickets.
* libs: update libusbhsfs to latest commit.
* codebase: add missing comments to some enums; add missing "None" and "Count" elements to some enums. "Count" entries from enums with bitmasks will only reflect the number of available bitmask values. Enums with hex values remain unchanged.
* PoC builds: use EXIT_SUCCESS and EXIT_FAILURE as return values.
* nxdt_rw_poc: move "end" jump label within main() to avoid a crash if utilsInitializeResources() fails; reflect changes in config.c.
This commit is contained in:
Pablo Curiel 2023-07-17 01:03:05 +02:00
parent 51b17f35fe
commit 8f75b6b923
34 changed files with 387 additions and 289 deletions

View file

@ -257,8 +257,8 @@ static void setNspEnableVideoCaptureOption(u32 idx);
static u32 getNspDisableHdcpOption(void); static u32 getNspDisableHdcpOption(void);
static void setNspDisableHdcpOption(u32 idx); static void setNspDisableHdcpOption(u32 idx);
static u32 getNspAppendAuthoringToolDataOption(void); static u32 getNspGenerateAuthoringToolDataOption(void);
static void setNspAppendAuthoringToolDataOption(u32 idx); static void setNspGenerateAuthoringToolDataOption(u32 idx);
static u32 getTicketRemoveConsoleDataOption(void); static u32 getTicketRemoveConsoleDataOption(void);
static void setTicketRemoveConsoleDataOption(u32 idx); static void setTicketRemoveConsoleDataOption(u32 idx);
@ -589,13 +589,13 @@ static MenuElement *g_nspMenuElements[] = {
.userdata = NULL .userdata = NULL
}, },
&(MenuElement){ &(MenuElement){
.str = "nsp: append authoringtool data", .str = "nsp: generate authoringtool data",
.child_menu = NULL, .child_menu = NULL,
.task_func = NULL, .task_func = NULL,
.element_options = &(MenuElementOption){ .element_options = &(MenuElementOption){
.selected = 1, .selected = 1,
.getter_func = &getNspAppendAuthoringToolDataOption, .getter_func = &getNspGenerateAuthoringToolDataOption,
.setter_func = &setNspAppendAuthoringToolDataOption, .setter_func = &setNspGenerateAuthoringToolDataOption,
.options = g_noYesStrings .options = g_noYesStrings
}, },
.userdata = NULL .userdata = NULL
@ -876,11 +876,11 @@ static char path[FS_MAX_PATH] = {0};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret = 0; int ret = EXIT_SUCCESS;
if (!utilsInitializeResources(argc, (const char**)argv)) if (!utilsInitializeResources(argc, (const char**)argv))
{ {
ret = -1; ret = EXIT_FAILURE;
goto end; goto end;
} }
@ -1356,7 +1356,6 @@ int main(int argc, char *argv[])
if (btn_held & (HidNpadButton_StickLDown | HidNpadButton_StickRDown | HidNpadButton_StickLUp | HidNpadButton_StickRUp | HidNpadButton_ZL | HidNpadButton_ZR)) svcSleepThread(40000000); // 40 ms if (btn_held & (HidNpadButton_StickLDown | HidNpadButton_StickRDown | HidNpadButton_StickLUp | HidNpadButton_StickRUp | HidNpadButton_ZL | HidNpadButton_ZR)) svcSleepThread(40000000); // 40 ms
} }
end:
freeNcaFsSectionsList(); freeNcaFsSectionsList();
freeNcaList(); freeNcaList();
@ -1367,6 +1366,7 @@ end:
titleFreeUserApplicationData(&user_app_data); titleFreeUserApplicationData(&user_app_data);
end:
utilsCloseResources(); utilsCloseResources();
consoleExit(NULL); consoleExit(NULL);
@ -4716,7 +4716,7 @@ static void nspThreadFunc(void *arg)
bool patch_screenshot = (bool)getNspEnableScreenshotsOption(); bool patch_screenshot = (bool)getNspEnableScreenshotsOption();
bool patch_video_capture = (bool)getNspEnableVideoCaptureOption(); bool patch_video_capture = (bool)getNspEnableVideoCaptureOption();
bool patch_hdcp = (bool)getNspDisableHdcpOption(); bool patch_hdcp = (bool)getNspDisableHdcpOption();
bool append_authoringtool_data = (bool)getNspAppendAuthoringToolDataOption(); bool generate_authoringtool_data = (bool)getNspGenerateAuthoringToolDataOption();
bool success = false; bool success = false;
u64 free_space = 0; u64 free_space = 0;
@ -4783,7 +4783,7 @@ static void nspThreadFunc(void *arg)
} }
// determine if we should initialize programinfo ctx // determine if we should initialize programinfo ctx
if (append_authoringtool_data) if (generate_authoringtool_data)
{ {
program_count = titleGetContentCountByType(title_info, NcmContentType_Program); program_count = titleGetContentCountByType(title_info, NcmContentType_Program);
if (program_count && !(program_info_ctx = calloc(program_count, sizeof(ProgramInfoContext)))) if (program_count && !(program_info_ctx = calloc(program_count, sizeof(ProgramInfoContext))))
@ -4794,7 +4794,7 @@ static void nspThreadFunc(void *arg)
} }
// determine if we should initialize nacp ctx // determine if we should initialize nacp ctx
if (patch_sua || patch_screenshot || patch_video_capture || patch_hdcp || append_authoringtool_data) if (patch_sua || patch_screenshot || patch_video_capture || patch_hdcp || generate_authoringtool_data)
{ {
control_count = titleGetContentCountByType(title_info, NcmContentType_Control); control_count = titleGetContentCountByType(title_info, NcmContentType_Control);
if (control_count && !(nacp_ctx = calloc(control_count, sizeof(NacpContext)))) if (control_count && !(nacp_ctx = calloc(control_count, sizeof(NacpContext))))
@ -4805,7 +4805,7 @@ static void nspThreadFunc(void *arg)
} }
// determine if we should initialize legalinfo ctx // determine if we should initialize legalinfo ctx
if (append_authoringtool_data) if (generate_authoringtool_data)
{ {
legal_info_count = titleGetContentCountByType(title_info, NcmContentType_LegalInformation); legal_info_count = titleGetContentCountByType(title_info, NcmContentType_LegalInformation);
if (legal_info_count && !(legal_info_ctx = calloc(legal_info_count, sizeof(LegalInfoContext)))) if (legal_info_count && !(legal_info_ctx = calloc(legal_info_count, sizeof(LegalInfoContext))))
@ -4923,7 +4923,7 @@ static void nspThreadFunc(void *arg)
goto end; goto end;
} }
if (append_authoringtool_data && !nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx))) if (generate_authoringtool_data && !nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx)))
{ {
consolePrint("nacp xml failed (%s)\n", cur_nca_ctx->content_id_str); consolePrint("nacp xml failed (%s)\n", cur_nca_ctx->content_id_str);
goto end; goto end;
@ -4972,7 +4972,7 @@ static void nspThreadFunc(void *arg)
// generate cnmt xml right away even though we don't yet have all the data we need // generate cnmt xml right away even though we don't yet have all the data we need
// This is because we need its size to calculate the full nsp size // This is because we need its size to calculate the full nsp size
if (append_authoringtool_data && !cnmtGenerateAuthoringToolXml(&cnmt_ctx, nca_ctx, title_info->content_count)) if (generate_authoringtool_data && !cnmtGenerateAuthoringToolXml(&cnmt_ctx, nca_ctx, title_info->content_count))
{ {
consolePrint("cnmt xml #1 failed\n"); consolePrint("cnmt xml #1 failed\n");
goto end; goto end;
@ -5019,7 +5019,7 @@ static void nspThreadFunc(void *arg)
} }
// add cnmt xml info // add cnmt xml info
if (append_authoringtool_data) if (generate_authoringtool_data)
{ {
sprintf(entry_name, "%s.cnmt.xml", meta_nca_ctx->content_id_str); sprintf(entry_name, "%s.cnmt.xml", meta_nca_ctx->content_id_str);
if (!pfsAddEntryInformationToFileContext(&pfs_file_ctx, entry_name, cnmt_ctx.authoring_tool_xml_size, &(meta_nca_ctx->content_type_ctx_data_idx))) if (!pfsAddEntryInformationToFileContext(&pfs_file_ctx, entry_name, cnmt_ctx.authoring_tool_xml_size, &(meta_nca_ctx->content_type_ctx_data_idx)))
@ -5030,7 +5030,7 @@ static void nspThreadFunc(void *arg)
} }
// add content type ctx data info // add content type ctx data info
u32 limit = append_authoringtool_data ? (title_info->content_count - 1) : 0; u32 limit = generate_authoringtool_data ? (title_info->content_count - 1) : 0;
for(u32 i = 0; i < limit; i++) for(u32 i = 0; i < limit; i++)
{ {
bool ret = false; bool ret = false;
@ -5275,7 +5275,7 @@ static void nspThreadFunc(void *arg)
} }
} }
if (append_authoringtool_data) if (generate_authoringtool_data)
{ {
// regenerate cnmt xml // regenerate cnmt xml
if (!cnmtGenerateAuthoringToolXml(&cnmt_ctx, nca_ctx, title_info->content_count)) if (!cnmtGenerateAuthoringToolXml(&cnmt_ctx, nca_ctx, title_info->content_count))
@ -5643,14 +5643,14 @@ static void setNspDisableHdcpOption(u32 idx)
configSetBoolean("nsp/disable_hdcp", (bool)idx); configSetBoolean("nsp/disable_hdcp", (bool)idx);
} }
static u32 getNspAppendAuthoringToolDataOption(void) static u32 getNspGenerateAuthoringToolDataOption(void)
{ {
return (u32)configGetBoolean("nsp/append_authoringtool_data"); return (u32)configGetBoolean("nsp/generate_authoringtool_data");
} }
static void setNspAppendAuthoringToolDataOption(u32 idx) static void setNspGenerateAuthoringToolDataOption(u32 idx)
{ {
configSetBoolean("nsp/append_authoringtool_data", (bool)idx); configSetBoolean("nsp/generate_authoringtool_data", (bool)idx);
} }
static u32 getTicketRemoveConsoleDataOption(void) static u32 getTicketRemoveConsoleDataOption(void)

View file

@ -262,11 +262,11 @@ static void dumpFsSection(TitleInfo *info, NcaFsSectionContext *nca_fs_ctx)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret = 0; int ret = EXIT_SUCCESS;
if (!utilsInitializeResources(argc, (const char**)argv)) if (!utilsInitializeResources(argc, (const char**)argv))
{ {
ret = -1; ret = EXIT_FAILURE;
goto out; goto out;
} }

View file

@ -81,11 +81,11 @@ static void writeFile(void *buf, size_t buf_size, const char *path)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret = 0; int ret = EXIT_SUCCESS;
if (!utilsInitializeResources(argc, (const char**)argv)) if (!utilsInitializeResources(argc, (const char**)argv))
{ {
ret = -1; ret = EXIT_FAILURE;
goto out; goto out;
} }

View file

@ -37,7 +37,7 @@ typedef enum {
BfttfFontType_ChineseSimplified = 3, ///< Simplified Chinese. BfttfFontType_ChineseSimplified = 3, ///< Simplified Chinese.
BfttfFontType_ExtChineseSimplified = 4, ///< Extended Simplified Chinese. BfttfFontType_ExtChineseSimplified = 4, ///< Extended Simplified Chinese.
BfttfFontType_ChineseTraditional = 5, ///< Traditional Chinese. BfttfFontType_ChineseTraditional = 5, ///< Traditional Chinese.
BfttfFontType_Total = 6 ///< Total fonts supported by this enum. BfttfFontType_Count = 6 ///< Total fonts supported by this enum.
} BfttfFontType; } BfttfFontType;
/// Loosely based on PlFontData. /// Loosely based on PlFontData.

View file

@ -70,7 +70,8 @@ NXDT_ASSERT(BucketTreeOffsetNode, BKTR_NODE_SIZE);
/// IndirectStorage-related elements. /// IndirectStorage-related elements.
typedef enum { typedef enum {
BucketTreeIndirectStorageIndex_Original = 0, BucketTreeIndirectStorageIndex_Original = 0,
BucketTreeIndirectStorageIndex_Patch = 1 BucketTreeIndirectStorageIndex_Patch = 1,
BucketTreeIndirectStorageIndex_Count = 2 ///< Total values supported by this enum.
} BucketTreeIndirectStorageIndex; } BucketTreeIndirectStorageIndex;
#pragma pack(push, 1) #pragma pack(push, 1)
@ -86,7 +87,8 @@ NXDT_ASSERT(BucketTreeIndirectStorageEntry, BKTR_INDIRECT_ENTRY_SIZE);
/// AesCtrExStorage-related elements. /// AesCtrExStorage-related elements.
typedef enum { typedef enum {
BucketTreeAesCtrExStorageEncryption_Enabled = 0, BucketTreeAesCtrExStorageEncryption_Enabled = 0,
BucketTreeAesCtrExStorageEncryption_Disabled = 1 BucketTreeAesCtrExStorageEncryption_Disabled = 1,
BucketTreeAesCtrExStorageEncryption_Count = 2 ///< Total values supported by this enum.
} BucketTreeAesCtrExStorageEncryption; } BucketTreeAesCtrExStorageEncryption;
typedef struct { typedef struct {
@ -100,10 +102,11 @@ NXDT_ASSERT(BucketTreeAesCtrExStorageEntry, BKTR_AES_CTR_EX_ENTRY_SIZE);
/// CompressedStorage-related elements. /// CompressedStorage-related elements.
typedef enum { typedef enum {
BucketTreeCompressedStorageCompressionType_None = 0, BucketTreeCompressedStorageCompressionType_None = 0,
BucketTreeCompressedStorageCompressionType_Zero = 1, BucketTreeCompressedStorageCompressionType_Zero = 1,
BucketTreeCompressedStorageCompressionType_2 = 2, BucketTreeCompressedStorageCompressionType_2 = 2,
BucketTreeCompressedStorageCompressionType_LZ4 = 3 BucketTreeCompressedStorageCompressionType_LZ4 = 3,
BucketTreeCompressedStorageCompressionType_Count = 4 ///< Total values supported by this enum.
} BucketTreeCompressedStorageCompressionType; } BucketTreeCompressedStorageCompressionType;
typedef struct { typedef struct {

View file

@ -46,7 +46,8 @@ NXDT_ASSERT(CertSig##sigtype##PubKey##pubkeytype, certsize);
typedef enum { typedef enum {
CertPubKeyType_Rsa4096 = 0, CertPubKeyType_Rsa4096 = 0,
CertPubKeyType_Rsa2048 = 1, CertPubKeyType_Rsa2048 = 1,
CertPubKeyType_Ecc480 = 2 CertPubKeyType_Ecc480 = 2,
CertPubKeyType_Count = 3 ///< Total values supported by this enum.
} CertPubKeyType; } CertPubKeyType;
/// Placed after the certificate signature block. /// Placed after the certificate signature block.
@ -121,7 +122,8 @@ typedef enum {
CertType_SigEcc480_PubKeyEcc480 = 9, CertType_SigEcc480_PubKeyEcc480 = 9,
CertType_SigHmac160_PubKeyRsa4096 = 10, CertType_SigHmac160_PubKeyRsa4096 = 10,
CertType_SigHmac160_PubKeyRsa2048 = 11, CertType_SigHmac160_PubKeyRsa2048 = 11,
CertType_SigHmac160_PubKeyEcc480 = 12 CertType_SigHmac160_PubKeyEcc480 = 12,
CertType_Count = 13 ///< Total values supported by this enum.
} CertType; } CertType;
/// Used to store certificate type, size and raw data. /// Used to store certificate type, size and raw data.

View file

@ -34,6 +34,7 @@ extern "C" {
/// Equivalent to NcmContentMetaAttribute. /// Equivalent to NcmContentMetaAttribute.
typedef enum { typedef enum {
ContentMetaAttribute_None = 0,
ContentMetaAttribute_IncludesExFatDriver = BIT(0), ContentMetaAttribute_IncludesExFatDriver = BIT(0),
ContentMetaAttribute_Rebootless = BIT(1), ContentMetaAttribute_Rebootless = BIT(1),
ContentMetaAttribute_Compacted = BIT(2), ///< One or more NCAs use SparseInfo data. ContentMetaAttribute_Compacted = BIT(2), ///< One or more NCAs use SparseInfo data.
@ -41,6 +42,7 @@ typedef enum {
} ContentMetaAttribute; } ContentMetaAttribute;
typedef enum { typedef enum {
ContentMetaInstallState_None = 0,
ContentMetaInstallState_Committed = BIT(0), ContentMetaInstallState_Committed = BIT(0),
ContentMetaInstallState_Count = 1 ///< Total values supported by this enum. ContentMetaInstallState_Count = 1 ///< Total values supported by this enum.
} ContentMetaInstallState; } ContentMetaInstallState;
@ -98,6 +100,7 @@ typedef struct {
NXDT_ASSERT(ContentMetaPatchMetaExtendedHeader, 0x18); NXDT_ASSERT(ContentMetaPatchMetaExtendedHeader, 0x18);
typedef enum { typedef enum {
ContentMetaContentAccessibility_None = 0,
ContentMetaContentAccessibility_Individual = BIT(0), ContentMetaContentAccessibility_Individual = BIT(0),
ContentMetaContentAccessibility_Count = 1 ///< Total values supported by this enum. ContentMetaContentAccessibility_Count = 1 ///< Total values supported by this enum.
} ContentMetaContentAccessibility; } ContentMetaContentAccessibility;
@ -149,7 +152,8 @@ typedef enum {
ContentMetaFirmwareVariationVersion_Invalid = 0, ContentMetaFirmwareVariationVersion_Invalid = 0,
ContentMetaFirmwareVariationVersion_V1 = 1, ContentMetaFirmwareVariationVersion_V1 = 1,
ContentMetaFirmwareVariationVersion_V2 = 2, ContentMetaFirmwareVariationVersion_V2 = 2,
ContentMetaFirmwareVariationVersion_Unknown = 3 ContentMetaFirmwareVariationVersion_Unknown = 3,
ContentMetaFirmwareVariationVersion_Count = 4 ///< Total values supported by this enum.
} ContentMetaFirmwareVariationVersion; } ContentMetaFirmwareVariationVersion;
/// Header for the extended data region in the SystemUpdate title, pointed to by the extended header. /// Header for the extended data region in the SystemUpdate title, pointed to by the extended header.
@ -240,7 +244,8 @@ NXDT_ASSERT(ContentMetaPatchDeltaHeader, 0x28);
typedef enum { typedef enum {
ContentMetaUpdateType_ApplyAsDelta = 0, ContentMetaUpdateType_ApplyAsDelta = 0,
ContentMetaUpdateType_Overwrite = 1, ContentMetaUpdateType_Overwrite = 1,
ContentMetaUpdateType_Create = 2 ContentMetaUpdateType_Create = 2,
ContentMetaUpdateType_Count = 3 ///< Total values supported by this enum.
} ContentMetaUpdateType; } ContentMetaUpdateType;
#pragma pack(push, 1) #pragma pack(push, 1)

View file

@ -33,14 +33,14 @@ extern "C" {
typedef enum { typedef enum {
ConfigOutputStorage_SdCard = 0, ConfigOutputStorage_SdCard = 0,
ConfigOutputStorage_UsbHost = 1, ConfigOutputStorage_UsbHost = 1,
ConfigOutputStorage_Count = 2 ConfigOutputStorage_Count = 2 ///< Total values supported by this enum.
} ConfigOutputStorage; } ConfigOutputStorage;
typedef enum { typedef enum {
ConfigChecksumLookupMethod_None = 0, ConfigChecksumLookupMethod_None = 0,
ConfigChecksumLookupMethod_NSWDB = 1, ConfigChecksumLookupMethod_NSWDB = 1,
ConfigChecksumLookupMethod_NoIntro = 2, ConfigChecksumLookupMethod_NoIntro = 2,
ConfigChecksumLookupMethod_Count = 3 ConfigChecksumLookupMethod_Count = 3 ///< Total values supported by this enum.
} ConfigChecksumLookupMethod; } ConfigChecksumLookupMethod;
/// Initializes the configuration interface. /// Initializes the configuration interface.

View file

@ -32,14 +32,15 @@ extern "C" {
/// Located at offset 0x7000 in the gamecard image. /// Located at offset 0x7000 in the gamecard image.
typedef struct { typedef struct {
u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the data. u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the data.
u32 magic; ///< "CERT". u32 magic; ///< "CERT".
u32 version; u32 version;
u8 kek_index; u8 kek_index;
u8 reserved[0x7]; u8 reserved[0x7];
u8 device_id[0x10]; u8 t1_card_device_id[0x10];
u8 iv[0x10]; u8 iv[0x10];
u8 data[0xD0]; ///< Encrypted using the IV from this struct and an unknown key. u8 hw_key[0x10]; ///< Encrypted.
u8 data[0xC0]; ///< Encrypted.
} FsGameCardCertificate; } FsGameCardCertificate;
NXDT_ASSERT(FsGameCardCertificate, 0x200); NXDT_ASSERT(FsGameCardCertificate, 0x200);

View file

@ -40,20 +40,6 @@ extern "C" {
#define GAMECARD_CERTIFICATE_OFFSET 0x7000 #define GAMECARD_CERTIFICATE_OFFSET 0x7000
/// Plaintext area. Dumped from FS program memory.
/// Overall structure may change with each new LAFW version.
typedef struct {
u32 asic_security_mode; ///< Determines how the Lotus ASIC initialised the gamecard security mode. Usually 0xFFFFFFF9.
u32 asic_status; ///< Bitmask of the internal gamecard interface status. Usually 0x20000000.
FsCardId1 card_id1;
FsCardId2 card_id2;
u8 card_uid[0x40];
u8 reserved[0x190];
u8 asic_session_hash[0x20]; ///< Changes with each gamecard (re)insertion.
} GameCardSpecificData;
NXDT_ASSERT(GameCardSpecificData, 0x200);
/// Encrypted using AES-128-ECB with the common titlekek generator key (stored in the .rodata segment from the Lotus firmware). /// Encrypted using AES-128-ECB with the common titlekek generator key (stored in the .rodata segment from the Lotus firmware).
typedef struct { typedef struct {
union { union {
@ -78,18 +64,6 @@ typedef struct {
NXDT_ASSERT(GameCardInitialData, 0x200); NXDT_ASSERT(GameCardInitialData, 0x200);
/// Plaintext area. Dumped from FS program memory.
/// This struct is returned by Lotus command "ChangeToSecureMode" (0xF). This means it is only available *after* the gamecard secure area has been mounted.
/// A copy of the gamecard header without the RSA-2048 signature and a plaintext GameCardInfo precedes this struct in FS program memory.
typedef struct {
GameCardSpecificData specific_data;
FsGameCardCertificate certificate;
u8 reserved[0x200];
GameCardInitialData initial_data;
} GameCardSecurityInformation;
NXDT_ASSERT(GameCardSecurityInformation, 0x800);
/// Encrypted using AES-128-CTR with the key and IV/counter from the `GameCardTitleKeyAreaEncryption` section. Assumed to be all zeroes in retail gamecards. /// Encrypted using AES-128-CTR with the key and IV/counter from the `GameCardTitleKeyAreaEncryption` section. Assumed to be all zeroes in retail gamecards.
typedef struct { typedef struct {
u8 titlekey[0x10]; ///< Decrypted titlekey from the `GameCardInitialData` section. u8 titlekey[0x10]; ///< Decrypted titlekey from the `GameCardInitialData` section.
@ -117,9 +91,36 @@ typedef struct {
NXDT_ASSERT(GameCardKeyArea, 0x1000); NXDT_ASSERT(GameCardKeyArea, 0x1000);
/// Plaintext area. Dumped from FS program memory.
/// Overall structure may change with each new LAFW version.
typedef struct {
u32 asic_security_mode; ///< Determines how the Lotus ASIC initialised the gamecard security mode. Usually 0xFFFFFFF9.
u32 asic_status; ///< Bitmask of the internal gamecard interface status. Usually 0x20000000.
FsCardId1 card_id1;
FsCardId2 card_id2;
u8 card_uid[0x40];
u8 reserved[0x190];
u8 asic_session_hash[0x20]; ///< Changes with each gamecard (re)insertion.
} GameCardSpecificData;
NXDT_ASSERT(GameCardSpecificData, 0x200);
/// Plaintext area. Dumped from FS program memory.
/// This struct is returned by Lotus command "ChangeToSecureMode" (0xF). This means it is only available *after* the gamecard secure area has been mounted.
/// A copy of the gamecard header without the RSA-2048 signature and a plaintext GameCardInfo precedes this struct in FS program memory.
typedef struct {
GameCardSpecificData specific_data;
FsGameCardCertificate certificate;
u8 reserved[0x200];
GameCardInitialData initial_data;
} GameCardSecurityInformation;
NXDT_ASSERT(GameCardSecurityInformation, 0x800);
typedef enum { typedef enum {
GameCardKekIndex_Version0 = 0, GameCardKekIndex_Version0 = 0,
GameCardKekIndex_VersionForDev = 1 GameCardKekIndex_VersionForDev = 1,
GameCardKekIndex_Count = 2 ///< Total values supported by this enum.
} GameCardKekIndex; } GameCardKekIndex;
typedef struct { typedef struct {
@ -139,17 +140,20 @@ typedef enum {
} GameCardRomSize; } GameCardRomSize;
typedef enum { typedef enum {
GameCardFlags_None = 0,
GameCardFlags_AutoBoot = BIT(0), GameCardFlags_AutoBoot = BIT(0),
GameCardFlags_HistoryErase = BIT(1), GameCardFlags_HistoryErase = BIT(1),
GameCardFlags_RepairTool = BIT(2), GameCardFlags_RepairTool = BIT(2),
GameCardFlags_DifferentRegionCupToTerraDevice = BIT(3), GameCardFlags_DifferentRegionCupToTerraDevice = BIT(3),
GameCardFlags_DifferentRegionCupToGlobalDevice = BIT(4), GameCardFlags_DifferentRegionCupToGlobalDevice = BIT(4),
GameCardFlags_HasCa10Certificate = BIT(7) GameCardFlags_HasCa10Certificate = BIT(7),
GameCardFlags_Count = 6 ///< Total values supported by this enum.
} GameCardFlags; } GameCardFlags;
typedef enum { typedef enum {
GameCardSelSec_ForT1 = 1, GameCardSelSec_ForT1 = 1,
GameCardSelSec_ForT2 = 2 GameCardSelSec_ForT2 = 2,
GameCardSelSec_Count = 2 ///< Total values supported by this enum.
} GameCardSelSec; } GameCardSelSec;
typedef enum { typedef enum {
@ -159,7 +163,7 @@ typedef enum {
GameCardFwVersion_Since900NUP = 3, ///< upp_version >= 603979776 (9.0.0-0.0) in GameCardInfo. Seems to be unused. GameCardFwVersion_Since900NUP = 3, ///< upp_version >= 603979776 (9.0.0-0.0) in GameCardInfo. Seems to be unused.
GameCardFwVersion_Since1100NUP = 4, ///< upp_version >= 738197504 (11.0.0-0.0) in GameCardInfo. GameCardFwVersion_Since1100NUP = 4, ///< upp_version >= 738197504 (11.0.0-0.0) in GameCardInfo.
GameCardFwVersion_Since1200NUP = 5, ///< upp_version >= 805306368 (12.0.0-0.0) in GameCardInfo. GameCardFwVersion_Since1200NUP = 5, ///< upp_version >= 805306368 (12.0.0-0.0) in GameCardInfo.
GameCardFwVersion_Count = 6 GameCardFwVersion_Count = 6 ///< Total values supported by this enum.
} GameCardFwVersion; } GameCardFwVersion;
typedef enum { typedef enum {
@ -170,7 +174,7 @@ typedef enum {
typedef enum { typedef enum {
GameCardCompatibilityType_Normal = 0, GameCardCompatibilityType_Normal = 0,
GameCardCompatibilityType_Terra = 1, GameCardCompatibilityType_Terra = 1,
GameCardCompatibilityType_Count = 2 GameCardCompatibilityType_Count = 2 ///< Total values supported by this enum.
} GameCardCompatibilityType; } GameCardCompatibilityType;
/// Encrypted using AES-128-CBC with the XCI header key (found in FS program memory under HOS 9.0.0+) and the IV from `GameCardHeader`. /// Encrypted using AES-128-CBC with the XCI header key (found in FS program memory under HOS 9.0.0+) and the IV from `GameCardHeader`.
@ -187,7 +191,8 @@ typedef struct {
u8 reserved_1[0x3]; u8 reserved_1[0x3];
u64 upp_hash; ///< Checksum for the update partition. The exact way it's calculated is currently unknown. u64 upp_hash; ///< Checksum for the update partition. The exact way it's calculated is currently unknown.
u64 upp_id; ///< Must match GAMECARD_UPDATE_TID. u64 upp_id; ///< Must match GAMECARD_UPDATE_TID.
u8 reserved_2[0x38]; u8 reserved_2[0x28];
u8 unknown[0x10]; ///< Unknown purpose. It's not zeroed out in recent (2021+?) gamecards.
} GameCardInfo; } GameCardInfo;
NXDT_ASSERT(GameCardInfo, 0x70); NXDT_ASSERT(GameCardInfo, 0x70);
@ -227,7 +232,8 @@ typedef enum {
GameCardStatus_LotusAsicFirmwareUpdateRequired = 3, ///< A gamecard has been inserted, but a LAFW update is needed before being able to read the secure storage area. GameCardStatus_LotusAsicFirmwareUpdateRequired = 3, ///< A gamecard has been inserted, but a LAFW update is needed before being able to read the secure storage area.
///< Operations on the normal storage area are still possible, though. ///< Operations on the normal storage area are still possible, though.
GameCardStatus_InsertedAndInfoNotLoaded = 4, ///< A gamecard has been inserted, but an unexpected error unrelated to both "nogc" patch and LAFW version occurred. GameCardStatus_InsertedAndInfoNotLoaded = 4, ///< A gamecard has been inserted, but an unexpected error unrelated to both "nogc" patch and LAFW version occurred.
GameCardStatus_InsertedAndInfoLoaded = 5 ///< A gamecard has been inserted and all required information could be successfully retrieved from it. GameCardStatus_InsertedAndInfoLoaded = 5, ///< A gamecard has been inserted and all required information could be successfully retrieved from it.
GameCardStatus_Count = 6 ///< Total values supported by this enum.
} GameCardStatus; } GameCardStatus;
typedef enum { typedef enum {
@ -242,7 +248,7 @@ typedef enum {
LotusAsicDeviceType_Dev = 1, LotusAsicDeviceType_Dev = 1,
LotusAsicDeviceType_Prod = 2, LotusAsicDeviceType_Prod = 2,
LotusAsicDeviceType_Prod2Dev = 3, LotusAsicDeviceType_Prod2Dev = 3,
LotusAsicDeviceType_Count = 4 ///< Not a real value. LotusAsicDeviceType_Count = 4 ///< Total values supported by this enum.
} LotusAsicDeviceType; } LotusAsicDeviceType;
/// Plaintext Lotus ASIC firmware (LAFW) blob. Dumped from FS program memory. /// Plaintext Lotus ASIC firmware (LAFW) blob. Dumped from FS program memory.

View file

@ -30,9 +30,12 @@ extern "C" {
#endif #endif
typedef enum { typedef enum {
MemoryProgramSegmentType_None = 0,
MemoryProgramSegmentType_Text = BIT(0), MemoryProgramSegmentType_Text = BIT(0),
MemoryProgramSegmentType_Rodata = BIT(1), MemoryProgramSegmentType_Rodata = BIT(1),
MemoryProgramSegmentType_Data = BIT(2) MemoryProgramSegmentType_Data = BIT(2),
MemoryProgramSegmentType_All = (MemoryProgramSegmentType_Data | MemoryProgramSegmentType_Rodata | MemoryProgramSegmentType_Text),
MemoryProgramSegmentType_Limit = (MemoryProgramSegmentType_All + 1) ///< Placed here for convenience.
} MemoryProgramSegmentType; } MemoryProgramSegmentType;
typedef struct { typedef struct {
@ -43,7 +46,7 @@ typedef struct {
} MemoryLocation; } MemoryLocation;
/// Retrieves memory segment (.text, .rodata, .data) data from a running program. /// Retrieves memory segment (.text, .rodata, .data) data from a running program.
/// These are memory pages with read permission (Perm_R) enabled and type MemType_CodeStatic or MemType_CodeMutable. /// These are memory pages with read permission (Perm_R) enabled, with type MemType_CodeStatic or MemType_CodeMutable and no MemoryAttribute flag set.
bool memRetrieveProgramMemorySegment(MemoryLocation *location); bool memRetrieveProgramMemorySegment(MemoryLocation *location);
/// Retrieves full memory data from a running program. /// Retrieves full memory data from a running program.

View file

@ -64,6 +64,7 @@ typedef enum {
} NacpAddOnContentRegistrationType; } NacpAddOnContentRegistrationType;
typedef enum { typedef enum {
NacpAttribute_None = 0,
NacpAttribute_Demo = BIT(0), NacpAttribute_Demo = BIT(0),
NacpAttribute_RetailInteractiveDisplay = BIT(1), NacpAttribute_RetailInteractiveDisplay = BIT(1),
NacpAttribute_DownloadPlay = BIT(2), ///< Removed. NacpAttribute_DownloadPlay = BIT(2), ///< Removed.
@ -96,23 +97,24 @@ typedef enum {
} NacpLanguage; } NacpLanguage;
typedef enum { typedef enum {
NacpSupportedLanguage_AmericanEnglish = BIT(0), NacpSupportedLanguage_None = 0,
NacpSupportedLanguage_BritishEnglish = BIT(1), NacpSupportedLanguage_AmericanEnglish = BIT(NacpLanguage_AmericanEnglish),
NacpSupportedLanguage_Japanese = BIT(2), NacpSupportedLanguage_BritishEnglish = BIT(NacpLanguage_BritishEnglish),
NacpSupportedLanguage_French = BIT(3), NacpSupportedLanguage_Japanese = BIT(NacpLanguage_Japanese),
NacpSupportedLanguage_German = BIT(4), NacpSupportedLanguage_French = BIT(NacpLanguage_French),
NacpSupportedLanguage_LatinAmericanSpanish = BIT(5), NacpSupportedLanguage_German = BIT(NacpLanguage_German),
NacpSupportedLanguage_Spanish = BIT(6), NacpSupportedLanguage_LatinAmericanSpanish = BIT(NacpLanguage_LatinAmericanSpanish),
NacpSupportedLanguage_Italian = BIT(7), NacpSupportedLanguage_Spanish = BIT(NacpLanguage_Spanish),
NacpSupportedLanguage_Dutch = BIT(8), NacpSupportedLanguage_Italian = BIT(NacpLanguage_Italian),
NacpSupportedLanguage_CanadianFrench = BIT(9), NacpSupportedLanguage_Dutch = BIT(NacpLanguage_Dutch),
NacpSupportedLanguage_Portuguese = BIT(10), NacpSupportedLanguage_CanadianFrench = BIT(NacpLanguage_CanadianFrench),
NacpSupportedLanguage_Russian = BIT(11), NacpSupportedLanguage_Portuguese = BIT(NacpLanguage_Portuguese),
NacpSupportedLanguage_Korean = BIT(12), NacpSupportedLanguage_Russian = BIT(NacpLanguage_Russian),
NacpSupportedLanguage_TraditionalChinese = BIT(13), NacpSupportedLanguage_Korean = BIT(NacpLanguage_Korean),
NacpSupportedLanguage_SimplifiedChinese = BIT(14), NacpSupportedLanguage_TraditionalChinese = BIT(NacpLanguage_TraditionalChinese),
NacpSupportedLanguage_BrazilianPortuguese = BIT(15), NacpSupportedLanguage_SimplifiedChinese = BIT(NacpLanguage_SimplifiedChinese),
NacpSupportedLanguage_Count = 16, ///< Total values supported by this enum. Should always match NacpLanguage_Count. NacpSupportedLanguage_BrazilianPortuguese = BIT(NacpLanguage_BrazilianPortuguese),
NacpSupportedLanguage_Count = NacpLanguage_Count, ///< Total values supported by this enum.
///< Old. ///< Old.
NacpSupportedLanguage_Taiwanese = NacpSupportedLanguage_TraditionalChinese, NacpSupportedLanguage_Taiwanese = NacpSupportedLanguage_TraditionalChinese,
@ -120,6 +122,7 @@ typedef enum {
} NacpSupportedLanguage; } NacpSupportedLanguage;
typedef enum { typedef enum {
NacpParentalControl_None = 0,
NacpParentalControl_FreeCommunication = BIT(0), NacpParentalControl_FreeCommunication = BIT(0),
NacpParentalControl_Count = 1 ///< Total values supported by this enum. NacpParentalControl_Count = 1 ///< Total values supported by this enum.
} NacpParentalControl; } NacpParentalControl;
@ -249,6 +252,7 @@ typedef enum {
} NacpHdcp; } NacpHdcp;
typedef enum { typedef enum {
NacpStartupUserAccountOption_None = 0,
NacpStartupUserAccountOption_IsOptional = BIT(0), NacpStartupUserAccountOption_IsOptional = BIT(0),
NacpStartupUserAccountOption_Count = 1 ///< Total values supported by this enum. NacpStartupUserAccountOption_Count = 1 ///< Total values supported by this enum.
} NacpStartupUserAccountOption; } NacpStartupUserAccountOption;
@ -260,6 +264,7 @@ typedef enum {
} NacpRuntimeUpgrade; } NacpRuntimeUpgrade;
typedef enum { typedef enum {
NacpSupportingLimitedApplicationLicenses_None = 0,
NacpSupportingLimitedApplicationLicenses_Demo = BIT(0), NacpSupportingLimitedApplicationLicenses_Demo = BIT(0),
NacpSupportingLimitedApplicationLicenses_Count = 1 ///< Total values supported by this enum. NacpSupportingLimitedApplicationLicenses_Count = 1 ///< Total values supported by this enum.
} NacpSupportingLimitedApplicationLicenses; } NacpSupportingLimitedApplicationLicenses;
@ -272,16 +277,19 @@ typedef enum {
} NacpPlayLogQueryCapability; } NacpPlayLogQueryCapability;
typedef enum { typedef enum {
NacpRepair_None = 0,
NacpRepair_SuppressGameCardAccess = BIT(0), NacpRepair_SuppressGameCardAccess = BIT(0),
NacpRepair_Count = 1 ///< Total values supported by this enum. NacpRepair_Count = 1 ///< Total values supported by this enum.
} NacpRepair; } NacpRepair;
typedef enum { typedef enum {
NacpRequiredNetworkServiceLicenseOnLaunch_None = 0,
NacpRequiredNetworkServiceLicenseOnLaunch_Common = BIT(0), NacpRequiredNetworkServiceLicenseOnLaunch_Common = BIT(0),
NacpRequiredNetworkServiceLicenseOnLaunch_Count = 1 ///< Total values supported by this enum. NacpRequiredNetworkServiceLicenseOnLaunch_Count = 1 ///< Total values supported by this enum.
} NacpRequiredNetworkServiceLicenseOnLaunch; } NacpRequiredNetworkServiceLicenseOnLaunch;
typedef enum { typedef enum {
NacpJitConfigurationFlag_None = 0,
NacpJitConfigurationFlag_Enabled = BITL(0), NacpJitConfigurationFlag_Enabled = BITL(0),
NacpJitConfigurationFlag_Count = 1 ///< Total values supported by this enum. NacpJitConfigurationFlag_Count = 1 ///< Total values supported by this enum.
} NacpJitConfigurationFlag; } NacpJitConfigurationFlag;
@ -295,7 +303,8 @@ NXDT_ASSERT(NacpJitConfiguration, 0x10);
typedef enum { typedef enum {
NacpRequiredAddOnContentsSetDescriptorFlag_None = 0, NacpRequiredAddOnContentsSetDescriptorFlag_None = 0,
NacpRequiredAddOnContentsSetDescriptorFlag_Continue = 1 NacpRequiredAddOnContentsSetDescriptorFlag_Continue = 1,
NacpRequiredAddOnContentsSetDescriptorFlag_Count = 2 ///< Total values supported by this enum.
} NacpRequiredAddOnContentsSetDescriptorFlag; } NacpRequiredAddOnContentsSetDescriptorFlag;
typedef struct { typedef struct {
@ -312,6 +321,7 @@ typedef struct {
NXDT_ASSERT(NacpRequiredAddOnContentsSetBinaryDescriptor, 0x40); NXDT_ASSERT(NacpRequiredAddOnContentsSetBinaryDescriptor, 0x40);
typedef enum { typedef enum {
NacpPlayReportPermission_None = 0,
NacpPlayReportPermission_TargetMarketing = BIT(0), NacpPlayReportPermission_TargetMarketing = BIT(0),
NacpPlayReportPermission_Count = 1 ///< Total values supported by this enum. NacpPlayReportPermission_Count = 1 ///< Total values supported by this enum.
} NacpPlayReportPermission; } NacpPlayReportPermission;

View file

@ -62,7 +62,8 @@ extern "C" {
typedef enum { typedef enum {
NcaDistributionType_Download = 0, NcaDistributionType_Download = 0,
NcaDistributionType_GameCard = 1 NcaDistributionType_GameCard = 1,
NcaDistributionType_Count = 2 ///< Total values supported by this enum.
} NcaDistributionType; } NcaDistributionType;
typedef enum { typedef enum {
@ -71,7 +72,8 @@ typedef enum {
NcaContentType_Control = 2, NcaContentType_Control = 2,
NcaContentType_Manual = 3, NcaContentType_Manual = 3,
NcaContentType_Data = 4, NcaContentType_Data = 4,
NcaContentType_PublicData = 5 NcaContentType_PublicData = 5,
NcaContentType_Count = 6 ///< Total values supported by this enum.
} NcaContentType; } NcaContentType;
/// 'NcaKeyGeneration_Current' will always point to the last known key generation value. /// 'NcaKeyGeneration_Current' will always point to the last known key generation value.
@ -101,7 +103,7 @@ typedef enum {
NcaKeyAreaEncryptionKeyIndex_Application = 0, NcaKeyAreaEncryptionKeyIndex_Application = 0,
NcaKeyAreaEncryptionKeyIndex_Ocean = 1, NcaKeyAreaEncryptionKeyIndex_Ocean = 1,
NcaKeyAreaEncryptionKeyIndex_System = 2, NcaKeyAreaEncryptionKeyIndex_System = 2,
NcaKeyAreaEncryptionKeyIndex_Count = 3 NcaKeyAreaEncryptionKeyIndex_Count = 3 ///< Total values supported by this enum.
} NcaKeyAreaEncryptionKeyIndex; } NcaKeyAreaEncryptionKeyIndex;
/// 'NcaSignatureKeyGeneration_Current' will always point to the last known key generation value. /// 'NcaSignatureKeyGeneration_Current' will always point to the last known key generation value.
@ -172,7 +174,8 @@ NXDT_ASSERT(NcaHeader, 0x400);
typedef enum { typedef enum {
NcaFsType_RomFs = 0, NcaFsType_RomFs = 0,
NcaFsType_PartitionFs = 1 NcaFsType_PartitionFs = 1,
NcaFsType_Count = 2 ///< Total values supported by this enum.
} NcaFsType; } NcaFsType;
typedef enum { typedef enum {
@ -182,7 +185,8 @@ typedef enum {
NcaHashType_HierarchicalIntegrity = 3, ///< Used by NcaFsType_RomFs. NcaHashType_HierarchicalIntegrity = 3, ///< Used by NcaFsType_RomFs.
NcaHashType_AutoSha3 = 4, NcaHashType_AutoSha3 = 4,
NcaHashType_HierarchicalSha3256 = 5, ///< Used by NcaFsType_PartitionFs. NcaHashType_HierarchicalSha3256 = 5, ///< Used by NcaFsType_PartitionFs.
NcaHashType_HierarchicalIntegritySha3 = 6 ///< Used by NcaFsType_RomFs. NcaHashType_HierarchicalIntegritySha3 = 6, ///< Used by NcaFsType_RomFs.
NcaHashType_Count = 7 ///< Total values supported by this enum.
} NcaHashType; } NcaHashType;
typedef enum { typedef enum {
@ -192,13 +196,15 @@ typedef enum {
NcaEncryptionType_AesCtr = 3, NcaEncryptionType_AesCtr = 3,
NcaEncryptionType_AesCtrEx = 4, NcaEncryptionType_AesCtrEx = 4,
NcaEncryptionType_AesCtrSkipLayerHash = 5, NcaEncryptionType_AesCtrSkipLayerHash = 5,
NcaEncryptionType_AesCtrExSkipLayerHash = 6 NcaEncryptionType_AesCtrExSkipLayerHash = 6,
NcaEncryptionType_Count = 7 ///< Total values supported by this enum.
} NcaEncryptionType; } NcaEncryptionType;
typedef enum { typedef enum {
NcaMetaDataHashType_None = 0, NcaMetaDataHashType_None = 0,
NcaMetaDataHashType_HierarchicalIntegrity = 1, NcaMetaDataHashType_HierarchicalIntegrity = 1,
NcaMetaDataHashType_HierarchicalIntegritySha3 = 2 NcaMetaDataHashType_HierarchicalIntegritySha3 = 2,
NcaMetaDataHashType_Count = 3 ///< Total values supported by this enum.
} NcaMetaDataHashType; } NcaMetaDataHashType;
typedef struct { typedef struct {
@ -408,9 +414,10 @@ typedef struct {
} NcaFsSectionContext; } NcaFsSectionContext;
typedef enum { typedef enum {
NcaVersion_Nca0 = 0, NcaVersion_Nca0 = 0,
NcaVersion_Nca2 = 2, NcaVersion_Nca2 = 1,
NcaVersion_Nca3 = 3 NcaVersion_Nca3 = 2,
NcaVersion_Count = 3 ///< Total values supported by this enum.
} NcaVersion; } NcaVersion;
typedef struct { typedef struct {

View file

@ -31,11 +31,12 @@ extern "C" {
#endif #endif
typedef enum { typedef enum {
NcaStorageBaseStorageType_Invalid = 0, /* Placeholder. */ NcaStorageBaseStorageType_Invalid = 0, ///< Placeholder.
NcaStorageBaseStorageType_Regular = 1, NcaStorageBaseStorageType_Regular = 1,
NcaStorageBaseStorageType_Sparse = 2, NcaStorageBaseStorageType_Sparse = 2,
NcaStorageBaseStorageType_Indirect = 3, NcaStorageBaseStorageType_Indirect = 3,
NcaStorageBaseStorageType_Compressed = 4 NcaStorageBaseStorageType_Compressed = 4,
NcaStorageBaseStorageType_Count = 5 ///< Total values supported by this enum.
} NcaStorageBaseStorageType; } NcaStorageBaseStorageType;
/// Used to perform multi-layered reads within a single NCA FS section. /// Used to perform multi-layered reads within a single NCA FS section.

View file

@ -52,7 +52,8 @@ typedef enum {
NpdmProcessAddressSpace_AddressSpace32Bit = 0, NpdmProcessAddressSpace_AddressSpace32Bit = 0,
NpdmProcessAddressSpace_AddressSpace64BitOld = 1, NpdmProcessAddressSpace_AddressSpace64BitOld = 1,
NpdmProcessAddressSpace_AddressSpace32BitNoReserved = 2, NpdmProcessAddressSpace_AddressSpace32BitNoReserved = 2,
NpdmProcessAddressSpace_AddressSpace64Bit = 3 NpdmProcessAddressSpace_AddressSpace64Bit = 3,
NpdmProcessAddressSpace_Count = 4 ///< Total values supported by this enum.
} NpdmProcessAddressSpace; } NpdmProcessAddressSpace;
typedef struct { typedef struct {
@ -95,6 +96,7 @@ typedef enum {
NpdmMemoryRegion_Applet = 1, NpdmMemoryRegion_Applet = 1,
NpdmMemoryRegion_SecureSystem = 2, NpdmMemoryRegion_SecureSystem = 2,
NpdmMemoryRegion_NonSecureSystem = 3, NpdmMemoryRegion_NonSecureSystem = 3,
NpdmMemoryRegion_Count = 4, ///< Total values supported by this enum.
/// Old. /// Old.
NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application, NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application,
@ -153,6 +155,7 @@ typedef struct {
NXDT_ASSERT(NpdmAciHeader, 0x40); NXDT_ASSERT(NpdmAciHeader, 0x40);
typedef enum { typedef enum {
NpdmFsAccessControlFlags_None = 0,
NpdmFsAccessControlFlags_ApplicationInfo = BITL(0), NpdmFsAccessControlFlags_ApplicationInfo = BITL(0),
NpdmFsAccessControlFlags_BootModeControl = BITL(1), NpdmFsAccessControlFlags_BootModeControl = BITL(1),
NpdmFsAccessControlFlags_Calibration = BITL(2), NpdmFsAccessControlFlags_Calibration = BITL(2),
@ -193,7 +196,8 @@ typedef enum {
NpdmFsAccessControlFlags_DeviceTreeBlob = BITL(37), NpdmFsAccessControlFlags_DeviceTreeBlob = BITL(37),
NpdmFsAccessControlFlags_NotifyErrorContextServiceReady = BITL(38), NpdmFsAccessControlFlags_NotifyErrorContextServiceReady = BITL(38),
NpdmFsAccessControlFlags_Debug = BITL(62), NpdmFsAccessControlFlags_Debug = BITL(62),
NpdmFsAccessControlFlags_FullPermission = BITL(63) NpdmFsAccessControlFlags_FullPermission = BITL(63),
NpdmFsAccessControlFlags_Count = 64 ///< Total values supported by this enum.
} NpdmFsAccessControlFlags; } NpdmFsAccessControlFlags;
/// FsAccessControl descriptor. Part of the ACID section body. /// FsAccessControl descriptor. Part of the ACID section body.
@ -246,9 +250,11 @@ typedef struct {
NXDT_ASSERT(NpdmFsAccessControlDataContentOwnerBlock, 0x4); NXDT_ASSERT(NpdmFsAccessControlDataContentOwnerBlock, 0x4);
typedef enum { typedef enum {
NpdmAccessibility_None = 0,
NpdmAccessibility_Read = BIT(0), NpdmAccessibility_Read = BIT(0),
NpdmAccessibility_Write = BIT(1), NpdmAccessibility_Write = BIT(1),
NpdmAccessibility_ReadWrite = NpdmAccessibility_Read | NpdmAccessibility_Write NpdmAccessibility_ReadWrite = (NpdmAccessibility_Read | NpdmAccessibility_Write),
NpdmAccessibility_Count = 3 ///< Total values supported by this enum.
} NpdmAccessibility; } NpdmAccessibility;
/// Placed after NpdmFsAccessControlData / NpdmFsAccessControlDataContentOwnerBlock if the 'save_data_owner_info_size' member from NpdmFsAccessControlData is greater than zero. /// Placed after NpdmFsAccessControlData / NpdmFsAccessControlDataContentOwnerBlock if the 'save_data_owner_info_size' member from NpdmFsAccessControlData is greater than zero.
@ -273,35 +279,35 @@ typedef struct {
NXDT_ASSERT(NpdmSrvAccessControlDescriptorEntry, 0x1); NXDT_ASSERT(NpdmSrvAccessControlDescriptorEntry, 0x1);
typedef enum { typedef enum {
NpdmKernelCapabilityEntryNumber_ThreadInfo = 3, NpdmKernelCapabilityEntryBitmaskSize_ThreadInfo = 3,
NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4, NpdmKernelCapabilityEntryBitmaskSize_EnableSystemCalls = 4,
NpdmKernelCapabilityEntryNumber_MemoryMap = 6, NpdmKernelCapabilityEntryBitmaskSize_MemoryMap = 6,
NpdmKernelCapabilityEntryNumber_IoMemoryMap = 7, NpdmKernelCapabilityEntryBitmaskSize_IoMemoryMap = 7,
NpdmKernelCapabilityEntryNumber_MemoryRegionMap = 10, NpdmKernelCapabilityEntryBitmaskSize_MemoryRegionMap = 10,
NpdmKernelCapabilityEntryNumber_EnableInterrupts = 11, NpdmKernelCapabilityEntryBitmaskSize_EnableInterrupts = 11,
NpdmKernelCapabilityEntryNumber_MiscParams = 13, NpdmKernelCapabilityEntryBitmaskSize_MiscParams = 13,
NpdmKernelCapabilityEntryNumber_KernelVersion = 14, NpdmKernelCapabilityEntryBitmaskSize_KernelVersion = 14,
NpdmKernelCapabilityEntryNumber_HandleTableSize = 15, NpdmKernelCapabilityEntryBitmaskSize_HandleTableSize = 15,
NpdmKernelCapabilityEntryNumber_MiscFlags = 16 NpdmKernelCapabilityEntryBitmaskSize_MiscFlags = 16
} NpdmKernelCapabilityEntryNumber; } NpdmKernelCapabilityEntryBitmaskSize;
typedef enum { typedef enum {
NpdmKernelCapabilityEntryValue_ThreadInfo = BIT(NpdmKernelCapabilityEntryNumber_ThreadInfo) - 1, NpdmKernelCapabilityEntryBitmaskPattern_ThreadInfo = BIT(NpdmKernelCapabilityEntryBitmaskSize_ThreadInfo) - 1,
NpdmKernelCapabilityEntryValue_EnableSystemCalls = BIT(NpdmKernelCapabilityEntryNumber_EnableSystemCalls) - 1, NpdmKernelCapabilityEntryBitmaskPattern_EnableSystemCalls = BIT(NpdmKernelCapabilityEntryBitmaskSize_EnableSystemCalls) - 1,
NpdmKernelCapabilityEntryValue_MemoryMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryMap) - 1, NpdmKernelCapabilityEntryBitmaskPattern_MemoryMap = BIT(NpdmKernelCapabilityEntryBitmaskSize_MemoryMap) - 1,
NpdmKernelCapabilityEntryValue_IoMemoryMap = BIT(NpdmKernelCapabilityEntryNumber_IoMemoryMap) - 1, NpdmKernelCapabilityEntryBitmaskPattern_IoMemoryMap = BIT(NpdmKernelCapabilityEntryBitmaskSize_IoMemoryMap) - 1,
NpdmKernelCapabilityEntryValue_MemoryRegionMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryRegionMap) - 1, NpdmKernelCapabilityEntryBitmaskPattern_MemoryRegionMap = BIT(NpdmKernelCapabilityEntryBitmaskSize_MemoryRegionMap) - 1,
NpdmKernelCapabilityEntryValue_EnableInterrupts = BIT(NpdmKernelCapabilityEntryNumber_EnableInterrupts) - 1, NpdmKernelCapabilityEntryBitmaskPattern_EnableInterrupts = BIT(NpdmKernelCapabilityEntryBitmaskSize_EnableInterrupts) - 1,
NpdmKernelCapabilityEntryValue_MiscParams = BIT(NpdmKernelCapabilityEntryNumber_MiscParams) - 1, NpdmKernelCapabilityEntryBitmaskPattern_MiscParams = BIT(NpdmKernelCapabilityEntryBitmaskSize_MiscParams) - 1,
NpdmKernelCapabilityEntryValue_KernelVersion = BIT(NpdmKernelCapabilityEntryNumber_KernelVersion) - 1, NpdmKernelCapabilityEntryBitmaskPattern_KernelVersion = BIT(NpdmKernelCapabilityEntryBitmaskSize_KernelVersion) - 1,
NpdmKernelCapabilityEntryValue_HandleTableSize = BIT(NpdmKernelCapabilityEntryNumber_HandleTableSize) - 1, NpdmKernelCapabilityEntryBitmaskPattern_HandleTableSize = BIT(NpdmKernelCapabilityEntryBitmaskSize_HandleTableSize) - 1,
NpdmKernelCapabilityEntryValue_MiscFlags = BIT(NpdmKernelCapabilityEntryNumber_MiscFlags) - 1 NpdmKernelCapabilityEntryBitmaskPattern_MiscFlags = BIT(NpdmKernelCapabilityEntryBitmaskSize_MiscFlags) - 1
} NpdmKernelCapabilityEntryValue; } NpdmKernelCapabilityEntryBitmaskPattern;
/// ThreadInfo entry for the KernelCapability descriptor. /// ThreadInfo entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_ThreadInfo; ///< Always set to NpdmKernelCapabilityEntryValue_ThreadInfo. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_ThreadInfo; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_ThreadInfo.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 lowest_priority : 6; u32 lowest_priority : 6;
u32 highest_priority : 6; u32 highest_priority : 6;
u32 min_core_number : 8; u32 min_core_number : 8;
@ -312,6 +318,8 @@ NXDT_ASSERT(NpdmThreadInfo, 0x4);
/// System call table. /// System call table.
typedef enum { typedef enum {
NpdmSystemCallId_None = 0,
///< System calls for index 0. ///< System calls for index 0.
NpdmSystemCallId_Reserved1 = BIT(0), ///< SVC 0x00. NpdmSystemCallId_Reserved1 = BIT(0), ///< SVC 0x00.
NpdmSystemCallId_SetHeapSize = BIT(1), ///< SVC 0x01. NpdmSystemCallId_SetHeapSize = BIT(1), ///< SVC 0x01.
@ -525,39 +533,41 @@ typedef enum {
/// EnableSystemCalls entry for the KernelCapability descriptor. /// EnableSystemCalls entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableSystemCalls; ///< Always set to NpdmKernelCapabilityEntryValue_EnableSystemCalls. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_EnableSystemCalls; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_EnableSystemCalls.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 system_call_ids : 24; ///< NpdmSystemCallId. u32 system_call_ids : 24; ///< NpdmSystemCallId.
u32 index : 3; ///< System calls index. u32 index : 3; ///< System calls index.
} NpdmEnableSystemCalls; } NpdmEnableSystemCalls;
NXDT_ASSERT(NpdmEnableSystemCalls, 0x4); NXDT_ASSERT(NpdmEnableSystemCalls, 0x4);
typedef enum { typedef enum {
NpdmPermissionType_RW = 0, NpdmPermissionType_RW = 0,
NpdmPermissionType_RO = 1 NpdmPermissionType_RO = 1,
NpdmPermissionType_Count = 2 ///< Total values supported by this enum.
} NpdmPermissionType; } NpdmPermissionType;
typedef enum { typedef enum {
NpdmMappingType_Io = 0, NpdmMappingType_Io = 0,
NpdmMappingType_Static = 1 NpdmMappingType_Static = 1,
NpdmMappingType_Count = 2 ///< Total values supported by this enum.
} NpdmMappingType; } NpdmMappingType;
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_MemoryMap.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 begin_address : 24; ///< begin_address << 12. u32 begin_address : 24; ///< begin_address << 12.
u32 permission_type : 1; ///< NpdmPermissionType. u32 permission_type : 1; ///< NpdmPermissionType.
} NpdmMemoryMapType1; } NpdmMemoryMapType1;
NXDT_ASSERT(NpdmMemoryMapType1, 0x4); NXDT_ASSERT(NpdmMemoryMapType1, 0x4);
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_MemoryMap.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 size : 20; ///< size << 12. u32 size : 20; ///< size << 12.
u32 reserved : 4; u32 reserved : 4;
u32 mapping_type : 1; ///< NpdmMappingType. u32 mapping_type : 1; ///< NpdmMappingType.
} NpdmMemoryMapType2; } NpdmMemoryMapType2;
NXDT_ASSERT(NpdmMemoryMapType2, 0x4); NXDT_ASSERT(NpdmMemoryMapType2, 0x4);
@ -575,9 +585,9 @@ NXDT_ASSERT(NpdmMemoryMap, 0x4);
/// IoMemoryMap entry for the KernelCapability descriptor. /// IoMemoryMap entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_IoMemoryMap.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 begin_address : 24; ///< begin_address << 12. u32 begin_address : 24; ///< begin_address << 12.
} NpdmIoMemoryMap; } NpdmIoMemoryMap;
NXDT_ASSERT(NpdmIoMemoryMap, 0x4); NXDT_ASSERT(NpdmIoMemoryMap, 0x4);
@ -586,29 +596,30 @@ typedef enum {
NpdmRegionType_NoMapping = 0, NpdmRegionType_NoMapping = 0,
NpdmRegionType_KernelTraceBuffer = 1, NpdmRegionType_KernelTraceBuffer = 1,
NpdmRegionType_OnMemoryBootImage = 2, NpdmRegionType_OnMemoryBootImage = 2,
NpdmRegionType_DTB = 3 NpdmRegionType_DTB = 3,
NpdmRegionType_Count = 4 ///< Total values supported by this enum.
} NpdmRegionType; } NpdmRegionType;
/// MemoryRegionMap entry for the KernelCapability descriptor. /// MemoryRegionMap entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryRegionMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryRegionMap. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_MemoryRegionMap; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_MemoryRegionMap.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 region_type_0 : 6; ///< NpdmRegionType. u32 region_type_0 : 6; ///< NpdmRegionType.
u32 permission_type_0 : 1; ///< NpdmPermissionType. u32 permission_type_0 : 1; ///< NpdmPermissionType.
u32 region_type_1 : 6; ///< NpdmRegionType. u32 region_type_1 : 6; ///< NpdmRegionType.
u32 permission_type_1 : 1; ///< NpdmPermissionType. u32 permission_type_1 : 1; ///< NpdmPermissionType.
u32 region_type_2 : 6; ///< NpdmRegionType. u32 region_type_2 : 6; ///< NpdmRegionType.
u32 permission_type_2 : 1; ///< NpdmPermissionType. u32 permission_type_2 : 1; ///< NpdmPermissionType.
} NpdmMemoryRegionMap; } NpdmMemoryRegionMap;
NXDT_ASSERT(NpdmMemoryRegionMap, 0x4); NXDT_ASSERT(NpdmMemoryRegionMap, 0x4);
/// EnableInterrupts entry for the KernelCapability descriptor. /// EnableInterrupts entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_EnableInterrupts.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 interrupt_number_0 : 10; ///< 0x3FF means empty. u32 interrupt_number_0 : 10; ///< 0x3FF means empty.
u32 interrupt_number_1 : 10; ///< 0x3FF means empty. u32 interrupt_number_1 : 10; ///< 0x3FF means empty.
} NpdmEnableInterrupts; } NpdmEnableInterrupts;
NXDT_ASSERT(NpdmEnableInterrupts, 0x4); NXDT_ASSERT(NpdmEnableInterrupts, 0x4);
@ -616,15 +627,16 @@ NXDT_ASSERT(NpdmEnableInterrupts, 0x4);
typedef enum { typedef enum {
NpdmProgramType_System = 0, NpdmProgramType_System = 0,
NpdmProgramType_Application = 1, NpdmProgramType_Application = 1,
NpdmProgramType_Applet = 2 NpdmProgramType_Applet = 2,
NpdmProgramType_Count = 3 ///< Total values supported by this enum.
} NpdmProgramType; } NpdmProgramType;
/// MiscParams entry for the KernelCapability descriptor. /// MiscParams entry for the KernelCapability descriptor.
/// Defaults to 0 if this entry doesn't exist. /// Defaults to 0 if this entry doesn't exist.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscParams; ///< Always set to NpdmKernelCapabilityEntryValue_MiscParams. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_MiscParams; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_MiscParams.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 program_type : 3; ///< NpdmProgramType. u32 program_type : 3; ///< NpdmProgramType.
u32 reserved : 15; u32 reserved : 15;
} NpdmMiscParams; } NpdmMiscParams;
@ -633,18 +645,18 @@ NXDT_ASSERT(NpdmMiscParams, 0x4);
/// KernelVersion entry for the KernelCapability descriptor. /// KernelVersion entry for the KernelCapability descriptor.
/// This is derived from/equivalent to SDK version. /// This is derived from/equivalent to SDK version.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_KernelVersion.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 minor_version : 4; ///< SDK minor version. u32 minor_version : 4; ///< SDK minor version.
u32 major_version : 13; ///< SDK major version + 4. u32 major_version : 13; ///< SDK major version + 4.
} NpdmKernelVersion; } NpdmKernelVersion;
NXDT_ASSERT(NpdmKernelVersion, 0x4); NXDT_ASSERT(NpdmKernelVersion, 0x4);
/// HandleTableSize entry for the KernelCapability descriptor. /// HandleTableSize entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_HandleTableSize.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 handle_table_size : 10; u32 handle_table_size : 10;
u32 reserved : 6; u32 reserved : 6;
} NpdmHandleTableSize; } NpdmHandleTableSize;
@ -653,8 +665,8 @@ NXDT_ASSERT(NpdmHandleTableSize, 0x4);
/// MiscFlags entry for the KernelCapability descriptor. /// MiscFlags entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags. u32 bitmask : NpdmKernelCapabilityEntryBitmaskSize_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryBitmaskPattern_MiscFlags.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
u32 enable_debug : 1; u32 enable_debug : 1;
u32 force_debug : 1; u32 force_debug : 1;
u32 reserved : 13; u32 reserved : 13;
@ -707,7 +719,8 @@ NX_INLINE bool npdmIsValidContext(NpdmContext *npdm_ctx)
((npdm_ctx->aci_header->kernel_capability_size && npdm_ctx->aci_kc_descriptor) || (!npdm_ctx->aci_header->kernel_capability_size && !npdm_ctx->aci_kc_descriptor))); ((npdm_ctx->aci_header->kernel_capability_size && npdm_ctx->aci_kc_descriptor) || (!npdm_ctx->aci_header->kernel_capability_size && !npdm_ctx->aci_kc_descriptor)));
} }
NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryValue(NpdmKernelCapabilityDescriptorEntry *entry) /// Returns a value that can be loooked up in the NpdmKernelCapabilityEntryBitmaskPattern enum.
NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryBitmaskPattern(NpdmKernelCapabilityDescriptorEntry *entry)
{ {
return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0); return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0);
} }

View file

@ -34,12 +34,14 @@ extern "C" {
#define NSO_MOD_MAGIC 0x4D4F4430 /* "MOD0". */ #define NSO_MOD_MAGIC 0x4D4F4430 /* "MOD0". */
typedef enum { typedef enum {
NsoFlags_None = 0,
NsoFlags_TextCompress = BIT(0), ///< Determines if .text segment is LZ4-compressed. NsoFlags_TextCompress = BIT(0), ///< Determines if .text segment is LZ4-compressed.
NsoFlags_RoCompress = BIT(1), ///< Determines if .rodata segment is LZ4-compressed. NsoFlags_RoCompress = BIT(1), ///< Determines if .rodata segment is LZ4-compressed.
NsoFlags_DataCompress = BIT(2), ///< Determines if .data segment is LZ4-compressed. NsoFlags_DataCompress = BIT(2), ///< Determines if .data segment is LZ4-compressed.
NsoFlags_TextHash = BIT(3), ///< Determines if .text segment hash must be checked during load. NsoFlags_TextHash = BIT(3), ///< Determines if .text segment hash must be checked during load.
NsoFlags_RoHash = BIT(4), ///< Determines if .rodata segment hash must be checked during load. NsoFlags_RoHash = BIT(4), ///< Determines if .rodata segment hash must be checked during load.
NsoFlags_DataHash = BIT(5) ///< Determines if .data segment hash must be checked during load. NsoFlags_DataHash = BIT(5), ///< Determines if .data segment hash must be checked during load.
NsoFlags_Count = 6 ///< Total values supported by this enum.
} NsoFlags; } NsoFlags;
typedef struct { typedef struct {

View file

@ -49,7 +49,8 @@ typedef enum {
UtilsCustomFirmwareType_Unknown = 0, UtilsCustomFirmwareType_Unknown = 0,
UtilsCustomFirmwareType_Atmosphere = 1, UtilsCustomFirmwareType_Atmosphere = 1,
UtilsCustomFirmwareType_SXOS = 2, UtilsCustomFirmwareType_SXOS = 2,
UtilsCustomFirmwareType_ReiNX = 3 UtilsCustomFirmwareType_ReiNX = 3,
UtilsCustomFirmwareType_Count = 4 ///< Total values supported by this enum.
} UtilsCustomFirmwareType; } UtilsCustomFirmwareType;
/// Used to handle parsed data from a GitHub release JSON. /// Used to handle parsed data from a GitHub release JSON.

View file

@ -134,7 +134,8 @@ typedef struct {
typedef enum { typedef enum {
RomFileSystemPathIllegalCharReplaceType_None = 0, RomFileSystemPathIllegalCharReplaceType_None = 0,
RomFileSystemPathIllegalCharReplaceType_IllegalFsChars = 1, RomFileSystemPathIllegalCharReplaceType_IllegalFsChars = 1,
RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly = 2 RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly = 2,
RomFileSystemPathIllegalCharReplaceType_Count = 3 ///< Total values supported by this enum.
} RomFileSystemPathIllegalCharReplaceType; } RomFileSystemPathIllegalCharReplaceType;
/// Initializes a RomFS or Patch RomFS context. /// Initializes a RomFS or Patch RomFS context.

View file

@ -34,7 +34,7 @@ typedef enum {
SmcKeyType_NormalOnly = 1, SmcKeyType_NormalOnly = 1,
SmcKeyType_RecoveryOnly = 2, SmcKeyType_RecoveryOnly = 2,
SmcKeyType_NormalAndRecovery = 3, SmcKeyType_NormalAndRecovery = 3,
SmcKeyType_Count = 4 SmcKeyType_Count = 4 ///< Total values supported by this enum.
} SmcKeyType; } SmcKeyType;
typedef enum { typedef enum {
@ -45,7 +45,7 @@ typedef enum {
SmcSealKey_ReencryptDeviceUniqueData = 4, SmcSealKey_ReencryptDeviceUniqueData = 4,
SmcSealKey_ImportSslKey = 5, SmcSealKey_ImportSslKey = 5,
SmcSealKey_ImportEsClientCertKey = 6, SmcSealKey_ImportEsClientCertKey = 6,
SmcSealKey_Count = 7 SmcSealKey_Count = 7 ///< Total values supported by this enum.
} SmcSealKey; } SmcSealKey;
typedef struct { typedef struct {

View file

@ -43,7 +43,8 @@ NXDT_ASSERT(TikSig##sigtype, tiksize);
typedef enum { typedef enum {
TikTitleKeyType_Common = 0, TikTitleKeyType_Common = 0,
TikTitleKeyType_Personalized = 1 TikTitleKeyType_Personalized = 1,
TikTitleKeyType_Count = 2 ///< Total values supported by this enum.
} TikTitleKeyType; } TikTitleKeyType;
typedef enum { typedef enum {
@ -52,16 +53,19 @@ typedef enum {
TikLicenseType_Trial = 2, TikLicenseType_Trial = 2,
TikLicenseType_Rental = 3, TikLicenseType_Rental = 3,
TikLicenseType_Subscription = 4, TikLicenseType_Subscription = 4,
TikLicenseType_Service = 5 TikLicenseType_Service = 5,
TikLicenseType_Count = 6 ///< Total values supported by this enum.
} TikLicenseType; } TikLicenseType;
typedef enum { typedef enum {
TikPropertyMask_None = 0,
TikPropertyMask_PreInstallation = BIT(0), TikPropertyMask_PreInstallation = BIT(0),
TikPropertyMask_SharedTitle = BIT(1), TikPropertyMask_SharedTitle = BIT(1),
TikPropertyMask_AllContents = BIT(2), TikPropertyMask_AllContents = BIT(2),
TikPropertyMask_DeviceLinkIndepedent = BIT(3), TikPropertyMask_DeviceLinkIndepedent = BIT(3),
TikPropertyMask_Volatile = BIT(4), ///< Used to determine if the ticket copy inside ticket.bin should be encrypted or not. TikPropertyMask_Volatile = BIT(4), ///< Used to determine if the ticket copy inside ticket.bin should be encrypted or not.
TikPropertyMask_ELicenseRequired = BIT(5) ///< Used to determine if the console should connect to the Internet to perform elicense verification. TikPropertyMask_ELicenseRequired = BIT(5), ///< Used to determine if the console should connect to the Internet to perform elicense verification.
TikPropertyMask_Count = 6 ///< Total values supported by this enum.
} TikPropertyMask; } TikPropertyMask;
/// Placed after the ticket signature block. /// Placed after the ticket signature block.
@ -92,12 +96,14 @@ NXDT_ASSERT(TikCommonBlock, 0x180);
/// Each ESV2 section record is followed by a 'record_count' number of ESV1 records, each one of 'record_size' size. /// Each ESV2 section record is followed by a 'record_count' number of ESV1 records, each one of 'record_size' size.
typedef enum { typedef enum {
TikSectionType_None = 0,
TikSectionType_Permanent = 1, TikSectionType_Permanent = 1,
TikSectionType_Subscription = 2, TikSectionType_Subscription = 2,
TikSectionType_Content = 3, TikSectionType_Content = 3,
TikSectionType_ContentConsumption = 4, TikSectionType_ContentConsumption = 4,
TikSectionType_AccessTitle = 5, TikSectionType_AccessTitle = 5,
TikSectionType_LimitedResource = 6 TikSectionType_LimitedResource = 6,
TikSectionType_Count = 7 ///< Total values supported by this enum.
} TikSectionType; } TikSectionType;
typedef struct { typedef struct {
@ -159,7 +165,8 @@ typedef enum {
TikType_SigRsa4096 = 1, TikType_SigRsa4096 = 1,
TikType_SigRsa2048 = 2, TikType_SigRsa2048 = 2,
TikType_SigEcc480 = 3, TikType_SigEcc480 = 3,
TikType_SigHmac160 = 4 TikType_SigHmac160 = 4,
TikType_Count = 5 ///< Total values supported by this enum.
} TikType; } TikType;
/// Used to store ticket type, size and raw data, as well as titlekey data. /// Used to store ticket type, size and raw data, as well as titlekey data.

View file

@ -77,13 +77,14 @@ typedef enum {
///< Gamecards: "{Name1} [{Id1}][v{Version1}] + ... + {NameN} [{IdN}][v{VersionN}]". ///< Gamecards: "{Name1} [{Id1}][v{Version1}] + ... + {NameN} [{IdN}][v{VersionN}]".
TitleNamingConvention_IdAndVersionOnly = 1, ///< Individual titles: "{Id}_v{Version}_{Type}". TitleNamingConvention_IdAndVersionOnly = 1, ///< Individual titles: "{Id}_v{Version}_{Type}".
///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}". ///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}".
TitleNamingConvention_Count = 2 TitleNamingConvention_Count = 2 ///< Total values supported by this enum.
} TitleNamingConvention; } TitleNamingConvention;
typedef enum { typedef enum {
TitleFileNameIllegalCharReplaceType_None = 0, TitleFileNameIllegalCharReplaceType_None = 0,
TitleFileNameIllegalCharReplaceType_IllegalFsChars = 1, TitleFileNameIllegalCharReplaceType_IllegalFsChars = 1,
TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly = 2 TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly = 2,
TitleFileNameIllegalCharReplaceType_Count = 3 ///< Total values supported by this enum.
} TitleFileNameIllegalCharReplaceType; } TitleFileNameIllegalCharReplaceType;
/// Initializes the title interface. /// Initializes the title interface.

View file

@ -38,7 +38,8 @@ typedef enum {
UsbHostSpeed_None = 0, UsbHostSpeed_None = 0,
UsbHostSpeed_FullSpeed = 1, ///< USB 1.x. UsbHostSpeed_FullSpeed = 1, ///< USB 1.x.
UsbHostSpeed_HighSpeed = 2, ///< USB 2.0. UsbHostSpeed_HighSpeed = 2, ///< USB 2.0.
UsbHostSpeed_SuperSpeed = 3 ///< USB 3.0. UsbHostSpeed_SuperSpeed = 3, ///< USB 3.0.
UsbHostSpeed_Count = 4 ///< Total values supported by this enum.
} UsbHostSpeed; } UsbHostSpeed;
/// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer. /// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer.

@ -1 +1 @@
Subproject commit 55f5a140770b10899e3c5e3a08243471fe8e9ba7 Subproject commit a11eb0d7083fba72aade29d3f9b35070d5510c3d

View file

@ -18,7 +18,7 @@
"enable_screenshots": false, "enable_screenshots": false,
"enable_video_capture": false, "enable_video_capture": false,
"disable_hdcp": false, "disable_hdcp": false,
"append_authoringtool_data": false, "generate_authoringtool_data": false,
"lookup_checksum": true "lookup_checksum": true
}, },
"ticket": { "ticket": {

View file

@ -208,7 +208,7 @@ void bfttfExit(void)
bool bfttfGetFontByType(BfttfFontData *font_data, u8 font_type) bool bfttfGetFontByType(BfttfFontData *font_data, u8 font_type)
{ {
if (!font_data || font_type >= BfttfFontType_Total) if (!font_data || font_type >= BfttfFontType_Count)
{ {
LOG_MSG_ERROR("Invalid parameters!"); LOG_MSG_ERROR("Invalid parameters!");
return false; return false;

View file

@ -240,7 +240,7 @@ static bool configValidateJsonNspObject(const struct json_object *obj)
{ {
bool ret = false, set_download_distribution_found = false, remove_console_data_found = false, remove_titlekey_crypto_found = false; bool ret = false, set_download_distribution_found = false, remove_console_data_found = false, remove_titlekey_crypto_found = false;
bool disable_linked_account_requirement_found = false, enable_screenshots_found = false, enable_video_capture_found = false, disable_hdcp_found = false; bool disable_linked_account_requirement_found = false, enable_screenshots_found = false, enable_video_capture_found = false, disable_hdcp_found = false;
bool append_authoringtool_data_found = false, lookup_checksum_found = false; bool generate_authoringtool_data_found = false, lookup_checksum_found = false;
if (!jsonValidateObject(obj)) goto end; if (!jsonValidateObject(obj)) goto end;
@ -254,12 +254,12 @@ static bool configValidateJsonNspObject(const struct json_object *obj)
CONFIG_VALIDATE_FIELD(Boolean, enable_video_capture); CONFIG_VALIDATE_FIELD(Boolean, enable_video_capture);
CONFIG_VALIDATE_FIELD(Boolean, disable_hdcp); CONFIG_VALIDATE_FIELD(Boolean, disable_hdcp);
CONFIG_VALIDATE_FIELD(Boolean, lookup_checksum); CONFIG_VALIDATE_FIELD(Boolean, lookup_checksum);
CONFIG_VALIDATE_FIELD(Boolean, append_authoringtool_data); CONFIG_VALIDATE_FIELD(Boolean, generate_authoringtool_data);
goto end; goto end;
} }
ret = (set_download_distribution_found && remove_console_data_found && remove_titlekey_crypto_found && disable_linked_account_requirement_found && \ ret = (set_download_distribution_found && remove_console_data_found && remove_titlekey_crypto_found && disable_linked_account_requirement_found && \
enable_screenshots_found && enable_video_capture_found && disable_hdcp_found && append_authoringtool_data_found && lookup_checksum_found); enable_screenshots_found && enable_video_capture_found && disable_hdcp_found && generate_authoringtool_data_found && lookup_checksum_found);
end: end:
return ret; return ret;

View file

@ -582,19 +582,14 @@ static bool gamecardReadLotusAsicFirmwareBlob(void)
/* Temporarily set the segment mask to .data. */ /* Temporarily set the segment mask to .data. */
g_fsProgramMemory.mask = MemoryProgramSegmentType_Data; g_fsProgramMemory.mask = MemoryProgramSegmentType_Data;
/* Retrieve full FS program memory dump. */ /* Retrieve FS .data segment memory dump. */
ret = memRetrieveProgramMemorySegment(&g_fsProgramMemory); if (!memRetrieveProgramMemorySegment(&g_fsProgramMemory))
/* Clear segment mask. */
g_fsProgramMemory.mask = 0;
if (!ret)
{ {
LOG_MSG_ERROR("Failed to retrieve FS .data segment dump!"); LOG_MSG_ERROR("Failed to retrieve FS .data segment dump!");
goto end; goto end;
} }
/* Look for the LAFW ReadFw blob in the FS .data memory dump. */ /* Look for the LAFW ReadFw blob in the FS .data segment memory dump. */
for(u64 offset = 0; offset < g_fsProgramMemory.data_size; offset++) for(u64 offset = 0; offset < g_fsProgramMemory.data_size; offset++)
{ {
if ((g_fsProgramMemory.data_size - offset) < sizeof(LotusAsicFirmwareBlob)) break; if ((g_fsProgramMemory.data_size - offset) < sizeof(LotusAsicFirmwareBlob)) break;
@ -635,6 +630,8 @@ static bool gamecardReadLotusAsicFirmwareBlob(void)
end: end:
memFreeMemoryLocation(&g_fsProgramMemory); memFreeMemoryLocation(&g_fsProgramMemory);
g_fsProgramMemory.mask = MemoryProgramSegmentType_None;
return ret; return ret;
} }
@ -953,6 +950,7 @@ static bool gamecardReadSecurityInformation(GameCardSecurityInformation *out)
if (memcmp(g_fsProgramMemory.data + offset, &(g_gameCardHeader.package_id), sizeof(g_gameCardHeader.package_id)) != 0) continue; if (memcmp(g_fsProgramMemory.data + offset, &(g_gameCardHeader.package_id), sizeof(g_gameCardHeader.package_id)) != 0) continue;
sha256CalculateHash(tmp_hash, g_fsProgramMemory.data + offset, sizeof(GameCardInitialData)); sha256CalculateHash(tmp_hash, g_fsProgramMemory.data + offset, sizeof(GameCardInitialData));
if (!memcmp(tmp_hash, g_gameCardHeader.initial_data_hash, SHA256_HASH_SIZE)) if (!memcmp(tmp_hash, g_gameCardHeader.initial_data_hash, SHA256_HASH_SIZE))
{ {
/* Jackpot. */ /* Jackpot. */

View file

@ -23,8 +23,14 @@
#include "nxdt_utils.h" #include "nxdt_utils.h"
#include "mem.h" #include "mem.h"
#define MEMLOG_DEBUG(fmt, ...) LOG_MSG_BUF_DEBUG(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__) #define MEMLOG_DEBUG(fmt, ...) LOG_MSG_BUF_DEBUG(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__)
#define MEMLOG_ERROR(fmt, ...) LOG_MSG_BUF_ERROR(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__) #define MEMLOG_ERROR(fmt, ...) LOG_MSG_BUF_ERROR(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__)
#define MEM_PID_BUF_SIZE 300
#define MEM_INVALID_SEGMENT_PAGE_TYPE(x) ((x) != MemType_CodeStatic && (x) != MemType_CodeMutable)
#define MEM_INVALID_FS_PAGE_TYPE(x) ((x) == MemType_Unmapped || (x) == MemType_Io || (x) == MemType_ThreadLocal || (x) == MemType_Reserved)
/* Global variables. */ /* Global variables. */
@ -43,7 +49,7 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id);
bool memRetrieveProgramMemorySegment(MemoryLocation *location) bool memRetrieveProgramMemorySegment(MemoryLocation *location)
{ {
if (!location || !location->program_id || !location->mask || location->mask >= BIT(3)) if (!location || !location->program_id || !location->mask || location->mask >= MemoryProgramSegmentType_Limit)
{ {
LOG_MSG_ERROR("Invalid parameters!"); LOG_MSG_ERROR("Invalid parameters!");
return false; return false;
@ -76,7 +82,7 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
u32 page_info = 0; u32 page_info = 0;
u64 addr = 0, last_text_addr = 0; u64 addr = 0, last_text_addr = 0;
u8 segment = 1, mem_type = 0; u8 segment = MemoryProgramSegmentType_Text, mem_type = 0;
u8 *tmp = NULL; u8 *tmp = NULL;
bool success = true; bool success = true;
@ -98,8 +104,9 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
#if LOG_LEVEL < LOG_LEVEL_NONE #if LOG_LEVEL < LOG_LEVEL_NONE
/* LOG_*() macros will be useless if the target program is the FS sysmodule. */ /* LOG_*() macros will be useless if the target program is the FS sysmodule. */
/* This is because any FS I/O operation *will* lock up the console while FS itself is being debugged. */ /* This is because any FS I/O operation *will* lock up the console while FS itself is being debugged. */
/* So we'll just temporarily log data to a char array using LOG_MSG_BUF_*() macros, then write it all out after calling svcCloseHandle(). */ /* So we'll just log data to a temporary buffer using LOG_MSG_BUF_*() macros, then write it all out to the logfile after calling svcCloseHandle(). */
/* However, we must prevent other threads from logging data as well in order to avoid a lock up, so we'll temporarily lock the logfile mutex. */ /* However, we must prevent other threads from logging data as well in order to avoid a lock up, so we'll temporarily lock the logfile mutex. */
/* We don't need to take care of manually (re)allocating memory for our buffer -- the log handler ABI takes care of that for us. */
logControlMutex(true); logControlMutex(true);
#endif #endif
@ -112,11 +119,12 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
if (is_segment && location->program_id == FS_SYSMODULE_TID) if (is_segment && location->program_id == FS_SYSMODULE_TID)
{ {
/* Only look for the FS .text segment address if we haven't previously retrieved it. */ /* Locate the "real" FS .text segment, since Atmosphère emuMMC has two. */
/* We'll only look for it if we haven't previously retrieved it, though. */
if (!g_fsTextSegmentAddr) if (!g_fsTextSegmentAddr)
{ {
/* Locate the "real" FS .text segment, since Atmosphère emuMMC has two. */
do { do {
/* Query memory page info. */
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr); rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
@ -125,27 +133,39 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
goto end; goto end;
} }
mem_type = (u8)(mem_info.type & MemState_Type);
addr = (mem_info.addr + mem_info.size);
/* Filter out unwanted memory pages. */
if (MEM_INVALID_SEGMENT_PAGE_TYPE(mem_type) || mem_info.attr || (mem_info.perm & Perm_Rx) != Perm_Rx) continue;
#if LOG_LEVEL == LOG_LEVEL_DEBUG #if LOG_LEVEL == LOG_LEVEL_DEBUG
MEMLOG_DEBUG("svcQueryDebugProcessMemory info (#1) (program %016lX, page 0x%X, debug handle 0x%X, address 0x%lX):\r\n" \ MEMLOG_DEBUG("svcQueryDebugProcessMemory info (FS .text segment lookup) (program %016lX, page 0x%X, debug handle 0x%X):\r\n" \
"- addr: 0x%lX\r\n- size: 0x%lX\r\n- type: 0x%X\r\n- attr: 0x%X\r\n- perm: 0x%X\r\n- ipc_refcount: 0x%X\r\n- device_refcount: 0x%X", \ "- addr: 0x%lX\r\n" \
location->program_id, page_info, debug_handle, addr, \ "- size: 0x%lX\r\n" \
mem_info.addr, mem_info.size, mem_info.type, mem_info.attr, mem_info.perm, mem_info.ipc_refcount, mem_info.device_refcount); "- type: 0x%X\r\n" \
"- attr: 0x%X\r\n" \
"- perm: 0x%X\r\n" \
"- ipc_refcount: 0x%X\r\n" \
"- device_refcount: 0x%X", \
location->program_id, page_info, debug_handle, mem_info.addr, mem_info.size, mem_info.type, mem_info.attr, mem_info.perm, \
mem_info.ipc_refcount, mem_info.device_refcount);
#endif #endif
mem_type = (u8)(mem_info.type & 0xFF); /* Update .text segment address. */
if ((mem_info.perm & Perm_X) && (mem_type == MemType_CodeStatic || mem_type == MemType_CodeMutable)) last_text_addr = mem_info.addr; last_text_addr = mem_info.addr;
addr = (mem_info.addr + mem_info.size);
} while(addr != 0); } while(addr != 0);
g_fsTextSegmentAddr = last_text_addr; g_fsTextSegmentAddr = last_text_addr;
MEMLOG_DEBUG("FS .text segment address: 0x%lX.", g_fsTextSegmentAddr); MEMLOG_DEBUG("FS .text segment address: 0x%lX.", g_fsTextSegmentAddr);
} }
/* Update variable so we can start reading data right from this address in the next steps. */
addr = g_fsTextSegmentAddr; addr = g_fsTextSegmentAddr;
} }
do { do {
/* Query memory page info. */
rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr); rc = svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
@ -154,45 +174,51 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
break; break;
} }
mem_type = (u8)(mem_info.type & MemState_Type);
addr = (mem_info.addr + mem_info.size);
/* Filter out unwanted memory pages. */
if (mem_info.attr || !(mem_info.perm & Perm_R) || \
(is_segment && (MEM_INVALID_SEGMENT_PAGE_TYPE(mem_type) || !(((segment <<= 1) >> 1) & location->mask))) || \
(!is_segment && location->program_id == FS_SYSMODULE_TID && MEM_INVALID_FS_PAGE_TYPE(mem_type))) continue;
#if LOG_LEVEL == LOG_LEVEL_DEBUG #if LOG_LEVEL == LOG_LEVEL_DEBUG
MEMLOG_DEBUG("svcQueryDebugProcessMemory info (#2) (program %016lX, page 0x%X, debug handle 0x%X, address 0x%lX):\r\n" \ MEMLOG_DEBUG("svcQueryDebugProcessMemory info (program %016lX, page 0x%X, debug handle 0x%X):\r\n" \
"- addr: 0x%lX\r\n- size: 0x%lX\r\n- type: 0x%X\r\n- attr: 0x%X\r\n- perm: 0x%X\r\n- ipc_refcount: 0x%X\r\n- device_refcount: 0x%X", \ "- addr: 0x%lX\r\n" \
location->program_id, page_info, debug_handle, addr, \ "- size: 0x%lX\r\n" \
mem_info.addr, mem_info.size, mem_info.type, mem_info.attr, mem_info.perm, mem_info.ipc_refcount, mem_info.device_refcount); "- type: 0x%X\r\n" \
"- attr: 0x%X\r\n" \
"- perm: 0x%X\r\n" \
"- ipc_refcount: 0x%X\r\n" \
"- device_refcount: 0x%X", \
location->program_id, page_info, debug_handle, mem_info.addr, mem_info.size, mem_info.type, mem_info.attr, mem_info.perm, \
mem_info.ipc_refcount, mem_info.device_refcount);
#endif #endif
mem_type = (u8)(mem_info.type & 0xFF); /* Reallocate data buffer. */
tmp = realloc(location->data, location->data_size + mem_info.size);
/* Code to allow for bitmasking segments. */ if (!tmp)
if ((mem_info.perm & Perm_R) && ((!is_segment && !mem_info.attr && (location->program_id != FS_SYSMODULE_TID || (location->program_id == FS_SYSMODULE_TID && mem_type != MemType_Unmapped && \
mem_type != MemType_Io && mem_type != MemType_ThreadLocal && mem_type != MemType_Reserved))) || (is_segment && (mem_type == MemType_CodeStatic || mem_type == MemType_CodeMutable) && \
(((segment <<= 1) >> 1) & location->mask))))
{ {
/* Reallocate data buffer. */ MEMLOG_ERROR("Failed to resize segment data buffer to 0x%lX bytes for program %016lX!", location->data_size + mem_info.size, location->program_id);
tmp = realloc(location->data, location->data_size + mem_info.size); success = false;
if (!tmp) break;
{
MEMLOG_ERROR("Failed to resize segment data buffer to 0x%lX bytes for program %016lX!", location->data_size + mem_info.size, location->program_id);
success = false;
break;
}
location->data = tmp;
tmp = NULL;
rc = svcReadDebugProcessMemory(location->data + location->data_size, debug_handle, mem_info.addr, mem_info.size);
if (R_FAILED(rc))
{
MEMLOG_ERROR("svcReadDebugProcessMemory failed for program %016lX! (0x%X).", location->program_id, rc);
success = false;
break;
}
location->data_size += mem_info.size;
} }
addr = (mem_info.addr + mem_info.size); location->data = tmp;
} while(addr != 0 && segment < BIT(3)); tmp = NULL;
/* Read memory page. */
rc = svcReadDebugProcessMemory(location->data + location->data_size, debug_handle, mem_info.addr, mem_info.size);
if (R_FAILED(rc))
{
MEMLOG_ERROR("svcReadDebugProcessMemory failed for program %016lX! (0x%X).", location->program_id, rc);
success = false;
break;
}
/* Increase data buffer size. */
location->data_size += mem_info.size;
} while(addr != 0 && segment < MemoryProgramSegmentType_Limit);
end: end:
/* Close debug handle. */ /* Close debug handle. */
@ -243,6 +269,8 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
u32 i = 0, num_processes = 0; u32 i = 0, num_processes = 0;
u64 *pids = NULL; u64 *pids = NULL;
bool success = false;
if (program_id > BOOT_SYSMODULE_TID && program_id != SPL_SYSMODULE_TID) if (program_id > BOOT_SYSMODULE_TID && program_id != SPL_SYSMODULE_TID)
{ {
/* If not a kernel process, get process ID from pm:dmnt. */ /* If not a kernel process, get process ID from pm:dmnt. */
@ -250,7 +278,7 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
MEMLOG_ERROR("pmdmntGetProcessId failed for program %016lX! (0x%X).", program_id, rc); MEMLOG_ERROR("pmdmntGetProcessId failed for program %016lX! (0x%X).", program_id, rc);
return false; goto end;
} }
MEMLOG_DEBUG("Process ID (%016lX): 0x%lX.", program_id, pid); MEMLOG_DEBUG("Process ID (%016lX): 0x%lX.", program_id, pid);
@ -260,27 +288,26 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
MEMLOG_ERROR("svcDebugActiveProcess failed for program %016lX! (0x%X).", program_id, rc); MEMLOG_ERROR("svcDebugActiveProcess failed for program %016lX! (0x%X).", program_id, rc);
return false; goto end;
} }
} else { } else {
/* Otherwise, query svc for the process list. */ /* Otherwise, query svc for the process list. */
pids = calloc(300, sizeof(u64)); pids = calloc(MEM_PID_BUF_SIZE, sizeof(u64));
if (!pids) if (!pids)
{ {
MEMLOG_ERROR("Failed to allocate memory for PID list!"); MEMLOG_ERROR("Failed to allocate memory for PID list!");
return false; goto end;
} }
MEMLOG_DEBUG("svcDebugActiveProcess returned %u process IDs.", num_processes); rc = svcGetProcessList((s32*)&num_processes, pids, MEM_PID_BUF_SIZE);
rc = svcGetProcessList((s32*)&num_processes, pids, 300);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
MEMLOG_ERROR("svcGetProcessList failed! (0x%X).", rc); MEMLOG_ERROR("svcGetProcessList failed! (0x%X).", rc);
free(pids); goto end;
return false;
} }
MEMLOG_DEBUG("svcGetProcessList returned %u process IDs.", num_processes);
/* Perform a lookup using the retrieved process list. */ /* Perform a lookup using the retrieved process list. */
for(i = 0; i < num_processes; i++) for(i = 0; i < num_processes; i++)
{ {
@ -295,7 +322,7 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
MEMLOG_DEBUG("Debug handle (process 0x%lX): 0x%X.", pids[i], debug_handle); MEMLOG_DEBUG("Debug handle (process 0x%lX): 0x%X.", pids[i], debug_handle);
/* Get debug event using the debug handle. */ /* Get debug event using the debug handle. */
/* This will let us know the program ID from the current process ID. */ /* This will let us know the program ID for the current process ID. */
rc = svcGetDebugEvent((u8*)&d, debug_handle); rc = svcGetDebugEvent((u8*)&d, debug_handle);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
{ {
@ -310,19 +337,23 @@ static bool memRetrieveDebugHandleFromProgramById(Handle *out, u64 program_id)
debug_handle = INVALID_HANDLE; debug_handle = INVALID_HANDLE;
} }
free(pids);
if (i == num_processes) if (i == num_processes)
{ {
MEMLOG_ERROR("Unable to find program %016lX in kernel process list! (0x%X).", program_id, rc); MEMLOG_ERROR("Unable to find program %016lX in kernel process list! (0x%X).", program_id, rc);
return false; goto end;
} }
} }
MEMLOG_DEBUG("Debug handle (%016lX): 0x%X.", program_id, debug_handle); MEMLOG_DEBUG("Output debug handle for program ID %016lX: 0x%X.", program_id, debug_handle);
/* Set output debug handle. */ /* Set output debug handle. */
*out = debug_handle; *out = debug_handle;
return true; /* Update output flag. */
success = true;
end:
if (pids) free(pids);
return success;
} }

View file

@ -856,7 +856,7 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
} }
} }
if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3 || fs_ctx->hash_type > NcaHashType_HierarchicalIntegritySha3) if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3 || fs_ctx->hash_type >= NcaHashType_Count)
{ {
LOG_MSG_ERROR("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", section_idx, nca_ctx->content_id_str, fs_ctx->hash_type); LOG_MSG_ERROR("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", section_idx, nca_ctx->content_id_str, fs_ctx->hash_type);
goto end; goto end;
@ -880,7 +880,7 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
} }
} }
if (fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type > NcaEncryptionType_AesCtrExSkipLayerHash) if (fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type >= NcaEncryptionType_Count)
{ {
LOG_MSG_ERROR("Invalid encryption type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", section_idx, nca_ctx->content_id_str, fs_ctx->encryption_type); LOG_MSG_ERROR("Invalid encryption type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", section_idx, nca_ctx->content_id_str, fs_ctx->encryption_type);
goto end; goto end;
@ -1017,7 +1017,7 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
/* Initialize crypto data. */ /* Initialize crypto data. */
if ((!nca_ctx->rights_id_available || (nca_ctx->rights_id_available && nca_ctx->titlekey_retrieved)) && fs_ctx->encryption_type > NcaEncryptionType_None && \ if ((!nca_ctx->rights_id_available || (nca_ctx->rights_id_available && nca_ctx->titlekey_retrieved)) && fs_ctx->encryption_type > NcaEncryptionType_None && \
fs_ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash) fs_ctx->encryption_type < NcaEncryptionType_Count)
{ {
/* Initialize the partial AES counter for this section. */ /* Initialize the partial AES counter for this section. */
aes128CtrInitializePartialCtr(fs_ctx->ctr, fs_ctx->header.aes_ctr_upper_iv.value, fs_ctx->section_offset); aes128CtrInitializePartialCtr(fs_ctx->ctr, fs_ctx->header.aes_ctr_upper_iv.value, fs_ctx->section_offset);
@ -1137,7 +1137,7 @@ static bool ncaFsSectionValidateHashDataBoundaries(NcaFsSectionContext *ctx)
static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset) static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset)
{ {
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_idx >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \ if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_idx >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type > NcaEncryptionType_AesCtrExSkipLayerHash || \ ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type >= NcaEncryptionType_Count || \
!out || !read_size || (offset + read_size) > ctx->section_size) !out || !read_size || (offset + read_size) > ctx->section_size)
{ {
LOG_MSG_ERROR("Invalid NCA FS section header parameters!"); LOG_MSG_ERROR("Invalid NCA FS section header parameters!");
@ -1685,7 +1685,7 @@ static void *ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
bool success = false; bool success = false;
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || ctx->has_sparse_layer || ctx->has_compression_layer || !ctx->nca_ctx || ctx->section_idx >= NCA_FS_HEADER_COUNT || \ if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || ctx->has_sparse_layer || ctx->has_compression_layer || !ctx->nca_ctx || ctx->section_idx >= NCA_FS_HEADER_COUNT || \
ctx->section_offset < sizeof(NcaHeader) || ctx->hash_type <= NcaHashType_None || ctx->hash_type == NcaHashType_AutoSha3 || ctx->hash_type > NcaHashType_HierarchicalIntegritySha3 || \ ctx->section_offset < sizeof(NcaHeader) || ctx->hash_type <= NcaHashType_None || ctx->hash_type == NcaHashType_AutoSha3 || ctx->hash_type >= NcaHashType_Count || \
ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type == NcaEncryptionType_AesCtrEx || ctx->encryption_type >= NcaEncryptionType_AesCtrExSkipLayerHash || \ ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type == NcaEncryptionType_AesCtrEx || ctx->encryption_type >= NcaEncryptionType_AesCtrExSkipLayerHash || \
ctx->section_type >= NcaFsSectionType_Invalid || !data || !data_size || (data_offset + data_size) > ctx->section_size || !out_block_size || !out_block_offset) ctx->section_type >= NcaFsSectionType_Invalid || !data || !data_size || (data_offset + data_size) > ctx->section_size || !out_block_size || !out_block_offset)
{ {

View file

@ -72,7 +72,7 @@ __attribute__((format(printf, 5, 6))) void logWriteFormattedStringToLogFile(u8 l
__attribute__((format(printf, 7, 8))) void logWriteFormattedStringToBuffer(char **dst, size_t *dst_size, u8 level, const char *file_name, int line, const char *func_name, const char *fmt, ...) __attribute__((format(printf, 7, 8))) void logWriteFormattedStringToBuffer(char **dst, size_t *dst_size, u8 level, const char *file_name, int line, const char *func_name, const char *fmt, ...)
{ {
if (!dst || !dst_size || (!*dst && *dst_size) || (*dst && !*dst_size) || level < LOG_LEVEL || !file_name || !*file_name || !func_name || !*func_name || !fmt || !*fmt) return; if (!dst || !dst_size || level < LOG_LEVEL || !file_name || !*file_name || !func_name || !*func_name || !fmt || !*fmt) return;
va_list args; va_list args;
@ -85,7 +85,8 @@ __attribute__((format(printf, 7, 8))) void logWriteFormattedStringToBuffer(char
struct tm ts = {0}; struct tm ts = {0};
struct timespec now = {0}; struct timespec now = {0};
if (dst_str_len >= dst_cur_size) return; /* Sanity check. */
if (dst_cur_size && dst_str_len >= dst_cur_size) return;
va_start(args, fmt); va_start(args, fmt);
@ -106,7 +107,7 @@ __attribute__((format(printf, 7, 8))) void logWriteFormattedStringToBuffer(char
log_str_len = (size_t)(str1_len + str2_len + 3); log_str_len = (size_t)(str1_len + str2_len + 3);
if (!dst_cur_size || log_str_len > (dst_cur_size - dst_str_len)) if (!dst_ptr || !dst_cur_size || log_str_len > (dst_cur_size - dst_str_len))
{ {
/* Update buffer size. */ /* Update buffer size. */
dst_cur_size = (dst_str_len + log_str_len); dst_cur_size = (dst_str_len + log_str_len);

View file

@ -501,7 +501,7 @@ void utilsJoinThread(Thread *thread)
__attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...) __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...)
{ {
if (!dst || !dst_size || (!*dst && *dst_size) || (*dst && !*dst_size) || !fmt || !*fmt) if (!dst || !dst_size || !fmt || !*fmt)
{ {
LOG_MSG_ERROR("Invalid parameters!"); LOG_MSG_ERROR("Invalid parameters!");
return false; return false;
@ -517,6 +517,7 @@ __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(ch
bool success = false; bool success = false;
/* Sanity check. */
if (dst_cur_size && dst_str_len >= dst_cur_size) if (dst_cur_size && dst_str_len >= dst_cur_size)
{ {
LOG_MSG_ERROR("String length is equal to or greater than the provided buffer size! (0x%lX >= 0x%lX).", dst_str_len, dst_cur_size); LOG_MSG_ERROR("String length is equal to or greater than the provided buffer size! (0x%lX >= 0x%lX).", dst_str_len, dst_cur_size);
@ -535,7 +536,7 @@ __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(ch
formatted_str_len_cast = (size_t)(formatted_str_len + 1); formatted_str_len_cast = (size_t)(formatted_str_len + 1);
if (!dst_cur_size || formatted_str_len_cast > (dst_cur_size - dst_str_len)) if (!dst_ptr || !dst_cur_size || formatted_str_len_cast > (dst_cur_size - dst_str_len))
{ {
/* Update buffer size. */ /* Update buffer size. */
dst_cur_size = (dst_str_len + formatted_str_len_cast); dst_cur_size = (dst_str_len + formatted_str_len_cast);
@ -561,6 +562,8 @@ __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(ch
/* Generate formatted string. */ /* Generate formatted string. */
vsprintf(dst_ptr + dst_str_len, fmt, args); vsprintf(dst_ptr + dst_str_len, fmt, args);
/* Update output flag. */
success = true; success = true;
end: end:

View file

@ -36,8 +36,6 @@
#define TIK_LIST_STORAGE_PATH "/ticket_list.bin" #define TIK_LIST_STORAGE_PATH "/ticket_list.bin"
#define TIK_DB_STORAGE_PATH "/ticket.bin" #define TIK_DB_STORAGE_PATH "/ticket.bin"
#define ES_CTRKEY_ENTRY_ALIGNMENT 0x8
/* Type definitions. */ /* Type definitions. */
/// Used to parse ticket_list.bin entries. /// Used to parse ticket_list.bin entries.
@ -52,7 +50,7 @@ NXDT_ASSERT(TikListEntry, 0x20);
/// 9.x+ CTR key entry in ES .data segment. Used to store CTR key/IV data for encrypted volatile tickets in ticket.bin and/or encrypted entries in ticket_list.bin. /// 9.x+ CTR key entry in ES .data segment. Used to store CTR key/IV data for encrypted volatile tickets in ticket.bin and/or encrypted entries in ticket_list.bin.
/// This is always stored in pairs. The first entry holds the key/IV for the encrypted volatile ticket, while the second entry holds the key/IV for the encrypted entry in ticket_list.bin. /// This is always stored in pairs. The first entry holds the key/IV for the encrypted volatile ticket, while the second entry holds the key/IV for the encrypted entry in ticket_list.bin.
/// First index in this list is always 0, and it's aligned to ES_CTRKEY_ENTRY_ALIGNMENT. /// First index in this list is always 0.
typedef struct { typedef struct {
u32 idx; ///< Entry index. u32 idx; ///< Entry index.
u8 key[AES_128_KEY_SIZE]; ///< AES-128-CTR key. u8 key[AES_128_KEY_SIZE]; ///< AES-128-CTR key.
@ -637,7 +635,7 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
} }
/* Retrieve the CTR key/IV from ES program memory in order to decrypt this ticket. */ /* Retrieve the CTR key/IV from ES program memory in order to decrypt this ticket. */
for(u64 i = 0; i < g_esMemoryLocation.data_size; i += ES_CTRKEY_ENTRY_ALIGNMENT) for(u64 i = 0; i < g_esMemoryLocation.data_size; i++)
{ {
if ((g_esMemoryLocation.data_size - i) < (sizeof(TikEsCtrKeyEntry9x) * 2)) break; if ((g_esMemoryLocation.data_size - i) < (sizeof(TikEsCtrKeyEntry9x) * 2)) break;

View file

@ -61,7 +61,8 @@ typedef enum {
UsbCommandType_SendFileProperties = 1, UsbCommandType_SendFileProperties = 1,
UsbCommandType_CancelFileTransfer = 2, UsbCommandType_CancelFileTransfer = 2,
UsbCommandType_SendNspHeader = 3, UsbCommandType_SendNspHeader = 3,
UsbCommandType_EndSession = 4 UsbCommandType_EndSession = 4,
UsbCommandType_Count = 5 ///< Total values supported by this enum.
} UsbCommandType; } UsbCommandType;
typedef struct { typedef struct {
@ -108,7 +109,9 @@ typedef enum {
UsbStatusType_UnsupportedCommand = 5, UsbStatusType_UnsupportedCommand = 5,
UsbStatusType_UnsupportedAbiVersion = 6, UsbStatusType_UnsupportedAbiVersion = 6,
UsbStatusType_MalformedCommand = 7, UsbStatusType_MalformedCommand = 7,
UsbStatusType_HostIoError = 8 UsbStatusType_HostIoError = 8,
UsbStatusType_Count = 9 ///< Total values supported by this enum.
} UsbStatusType; } UsbStatusType;
typedef struct { typedef struct {

View file

@ -61,7 +61,7 @@ namespace nxdt::utils {
if (R_FAILED(rc)) LOG_MSG_ERROR("svcQueryMemory failed! (0x%X).", rc); if (R_FAILED(rc)) LOG_MSG_ERROR("svcQueryMemory failed! (0x%X).", rc);
} }
#if LOG_LEVEL <= LOG_LEVEL_ERROR #if LOG_LEVEL < LOG_LEVEL_NONE
static bool UnwindStack(u64 *out_stack_trace, u32 *out_stack_trace_size, size_t max_stack_trace_size, u64 cur_fp) static bool UnwindStack(u64 *out_stack_trace, u32 *out_stack_trace_size, size_t max_stack_trace_size, u64 cur_fp)
{ {
if (!out_stack_trace || !out_stack_trace_size || !max_stack_trace_size || !cur_fp) if (!out_stack_trace || !out_stack_trace_size || !max_stack_trace_size || !cur_fp)
@ -90,7 +90,7 @@ namespace nxdt::utils {
return (*out_stack_trace_size > 0); return (*out_stack_trace_size > 0);
} }
#endif /* LOG_LEVEL <= LOG_LEVEL_ERROR */ #endif /* LOG_LEVEL < LOG_LEVEL_NONE */
static void NORETURN AbortProgramExecution(std::string str) static void NORETURN AbortProgramExecution(std::string str)
{ {
@ -164,7 +164,7 @@ extern "C" {
break; break;
} }
#if LOG_LEVEL <= LOG_LEVEL_ERROR #if LOG_LEVEL < LOG_LEVEL_NONE
char *exception_str = NULL; char *exception_str = NULL;
size_t exception_str_size = 0; size_t exception_str_size = 0;
@ -220,7 +220,7 @@ extern "C" {
/* Free exception info string. */ /* Free exception info string. */
if (exception_str) free(exception_str); if (exception_str) free(exception_str);
#endif /* LOG_LEVEL <= LOG_LEVEL_ERROR */ #endif /* LOG_LEVEL < LOG_LEVEL_NONE */
/* Abort program execution. */ /* Abort program execution. */
crash_str = (g_borealisInitialized ? i18n::getStr("generic/exception_triggered"_i18n, error_desc_str, ctx->error_desc) : \ crash_str = (g_borealisInitialized ? i18n::getStr("generic/exception_triggered"_i18n, error_desc_str, ctx->error_desc) : \