#include "lib.h" #include "ncch.h" #include "exheader.h" #include "titleid.h" #include "polarssl/base64.h" #ifndef RETAIL_FSIGN #include "accessdesc_sig.h" // For AccessDesc Presets #endif /* Prototypes */ void init_ExHeaderSettings(exheader_settings *exhdrset); void free_ExHeaderSettings(exheader_settings *exhdrset); int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings *ncchset); int get_ExHeaderSettingsFromYaml(exheader_settings *exhdrset); void AdjustBooleans(rsf_settings *yaml); int get_ExHeaderCodeSetInfo(exhdr_CodeSetInfo *CodeSetInfo, rsf_settings *yaml); int get_ExHeaderDependencyList(u8 *DependencyList, rsf_settings *yaml); int get_ExHeaderSystemInfo(exhdr_SystemInfo *SystemInfo, rsf_settings *yaml); int get_ExHeaderARM11SystemLocalInfo(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int GetAppType(int *AppType, rsf_settings *yaml); int SetARM11ResLimitDesc(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11StorageInfo(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11StorageInfoSystemSaveDataId(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11StorageInfoExtSaveDataId(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11StorageInfoOtherUserSaveData(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); bool CheckCondiditionsForNewAccessibleSaveDataIds(rsf_settings *yaml); int SetARM11StorageInfoAccessibleSaveDataIds(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int SetARM11ServiceAccessControl(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml); int get_ExHeaderARM11KernelInfo(exhdr_ARM11KernelCapabilities *arm11, rsf_settings *yaml); int SetARM11KernelDescSysCallControl(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int GetARM11SysCalls(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); void EnableSystemCall(ARM11KernelCapabilityDescriptor *desc, int SysCall); void DisableSystemCall(ARM11KernelCapabilityDescriptor *desc, int SysCall); int SetARM11KernelDescInteruptNumList(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int GetARM11Interupts(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); void EnableInterupt(ARM11KernelCapabilityDescriptor *desc, int Interrupt, int i); int SetARM11KernelDescAddressMapping(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int GetARM11IOMappings(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int GetARM11StaticMappings(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); bool IsEndAddress(u32 Address); bool IsStartAddress(u32 Address); u32 GetIOMappingDesc(u32 Address); u32 GetStaticMappingDesc(u32 Address, bool IsReadOnly); u32 GetMappingDesc(u32 Address, u32 PrefixVal, s32 numPrefixBits, bool IsRO); int SetARM11KernelDescOtherCapabilities(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int SetARM11KernelDescHandleTableSize(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); int SetARM11KernelDescReleaseKernelVersion(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml); void SetARM11KernelDescValue(ARM11KernelCapabilityDescriptor *desc, u16 Index, u32 Value); void SetARM11KernelDescBitmask(ARM11KernelCapabilityDescriptor *desc, u32 Bitmask); void AllocateARM11KernelDescMemory(ARM11KernelCapabilityDescriptor *desc, u16 Num); u32 GetDescPrefixMask(int numPrefixBits); u32 GetDescPrefixBits(int numPrefixBits, u32 PrefixVal); int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_settings *yaml); int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset); /* ExHeader Signature Functions */ int SignAccessDesc(ExtendedHeader_Struct *ExHdr, keys_struct *keys) { u8 *AccessDesc = (u8*) &ExHdr->AccessDescriptor.ncchpubkeymodulus; u8 *Signature = (u8*) &ExHdr->AccessDescriptor.signature; return ctr_sig(AccessDesc,0x300,Signature,keys->rsa.AccessDesc_Pub,keys->rsa.AccessDesc_Priv,RSA_2048_SHA256,CTR_RSA_SIGN); } int CheckAccessDescSignature(ExtendedHeader_Struct *ExHdr, keys_struct *keys) { u8 *AccessDesc = (u8*) &ExHdr->AccessDescriptor.ncchpubkeymodulus; u8 *Signature = (u8*) &ExHdr->AccessDescriptor.signature; return ctr_sig(AccessDesc,0x300,Signature,keys->rsa.AccessDesc_Pub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); } /* ExHeader Build Functions */ int BuildExHeader(ncch_settings *ncchset) { int result = 0; exheader_settings *exhdrset = malloc(sizeof(exheader_settings)); if(!exhdrset) {fprintf(stderr,"[EXHEADER ERROR] MEM ERROR\n"); return MEM_ERROR;} init_ExHeaderSettings(exhdrset); // Get Settings result = get_ExHeaderSettingsFromNcchset(exhdrset,ncchset); if(result) goto finish; result = get_ExHeaderSettingsFromYaml(exhdrset); if(result) goto finish; result = set_AccessDesc(exhdrset,ncchset); if(result) goto finish; exhdrset->ExHdr->AccessDescriptor.ARM11SystemLocalCapabilities.Flags[6] = 5; finish: if(result) fprintf(stderr,"[EXHEADER ERROR] Failed to create ExHeader\n"); free_ExHeaderSettings(exhdrset); return result; } void init_ExHeaderSettings(exheader_settings *exhdrset) { memset(exhdrset,0,sizeof(exheader_settings)); } void free_ExHeaderSettings(exheader_settings *exhdrset) { free(exhdrset); } int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings *ncchset) { /* Transfer settings */ exhdrset->keys = ncchset->keys; exhdrset->yaml = ncchset->yaml_set; /* Creating Output Buffer */ ncchset->Sections.ExHeader.size = 0x800; ncchset->Sections.ExHeader.buffer = malloc(ncchset->Sections.ExHeader.size); if(!ncchset->Sections.ExHeader.buffer) {fprintf(stderr,"[EXHEADER ERROR] MEM ERROR\n"); return MEM_ERROR;} memset(ncchset->Sections.ExHeader.buffer,0,ncchset->Sections.ExHeader.size); /* Import ExHeader template */ if(ncchset->ComponentFilePtrs.exheader_size){ u32 import_size = min_u64(0x40,ncchset->ComponentFilePtrs.exheader_size); ReadFile_64(ncchset->Sections.ExHeader.buffer,import_size,0,ncchset->ComponentFilePtrs.exheader); } /* Create ExHeader Struct for output */ exhdrset->ExHdr = (ExtendedHeader_Struct*)ncchset->Sections.ExHeader.buffer; /* Set Code Info if Code Section was built not imported */ if(ncchset->Options.IsBuildingCodeSection){ /* BSS Size */ u32_to_u8(exhdrset->ExHdr->CodeSetInfo.BssSize,ncchset->CodeDetails.BSS_Size,LE); /* Data */ u32_to_u8(exhdrset->ExHdr->CodeSetInfo.DataSectionInfo.Address,ncchset->CodeDetails.DataAddress,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.DataSectionInfo.CodeSize,ncchset->CodeDetails.DataSize,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.DataSectionInfo.NumMaxPages,ncchset->CodeDetails.DataMaxPages,LE); /* RO */ u32_to_u8(exhdrset->ExHdr->CodeSetInfo.ReadOnlySectionInfo.Address,ncchset->CodeDetails.ROAddress,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.ReadOnlySectionInfo.CodeSize,ncchset->CodeDetails.ROSize,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.ReadOnlySectionInfo.NumMaxPages,ncchset->CodeDetails.ROMaxPages,LE); /* Text */ u32_to_u8(exhdrset->ExHdr->CodeSetInfo.TextSectionInfo.Address,ncchset->CodeDetails.TextAddress,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.TextSectionInfo.CodeSize,ncchset->CodeDetails.TextSize,LE); u32_to_u8(exhdrset->ExHdr->CodeSetInfo.TextSectionInfo.NumMaxPages,ncchset->CodeDetails.TextMaxPages,LE); } /* Set Simple Flags */ if(ncchset->Options.CompressCode) exhdrset->ExHdr->CodeSetInfo.Flags.flag |= ExeFsCodeCompress; if(ncchset->Options.UseOnSD) exhdrset->ExHdr->CodeSetInfo.Flags.flag |= RetailSDAppFlag; if(!ncchset->Options.UseRomFS) // Move this later exhdrset->ExHdr->ARM11SystemLocalCapabilities.StorageInfo.OtherAttributes |= 1 << attribute_NOT_USE_ROMFS; return 0; } int get_ExHeaderSettingsFromYaml(exheader_settings *exhdrset) { AdjustBooleans(exhdrset->yaml); int result = 0; result = get_ExHeaderCodeSetInfo(&exhdrset->ExHdr->CodeSetInfo, exhdrset->yaml); if(result) goto finish; result = get_ExHeaderDependencyList((u8*)&exhdrset->ExHdr->DependencyList[0], exhdrset->yaml); if(result) goto finish; result = get_ExHeaderSystemInfo(&exhdrset->ExHdr->SystemInfo, exhdrset->yaml); if(result) goto finish; result = get_ExHeaderARM11SystemLocalInfo(&exhdrset->ExHdr->ARM11SystemLocalCapabilities, exhdrset->yaml); if(result) goto finish; result = get_ExHeaderARM11KernelInfo(&exhdrset->ExHdr->ARM11KernelCapabilities, exhdrset->yaml); if(result) goto finish; result = get_ExHeaderARM9AccessControlInfo(&exhdrset->ExHdr->ARM9AccessControlInfo, exhdrset->yaml); if(result) goto finish; finish: return result; } void AdjustBooleans(rsf_settings *yaml) { if(yaml->AccessControlInfo.DisableDebug == -1) yaml->AccessControlInfo.DisableDebug = 0; if(yaml->AccessControlInfo.EnableForceDebug == -1) yaml->AccessControlInfo.EnableForceDebug = 0; if(yaml->AccessControlInfo.CanWriteSharedPage == -1) yaml->AccessControlInfo.CanWriteSharedPage = 0; if(yaml->AccessControlInfo.CanUsePrivilegedPriority == -1) yaml->AccessControlInfo.CanUsePrivilegedPriority = 0; if(yaml->AccessControlInfo.CanUseNonAlphabetAndNumber == -1) yaml->AccessControlInfo.CanUseNonAlphabetAndNumber = 0; if(yaml->AccessControlInfo.PermitMainFunctionArgument == -1) yaml->AccessControlInfo.PermitMainFunctionArgument = 0; if(yaml->AccessControlInfo.CanShareDeviceMemory == -1) yaml->AccessControlInfo.CanShareDeviceMemory = 0; if(yaml->AccessControlInfo.UseOtherVariationSaveData == -1) yaml->AccessControlInfo.UseOtherVariationSaveData = 0; if(yaml->AccessControlInfo.UseExtSaveData == -1) yaml->AccessControlInfo.UseExtSaveData = 0; if(yaml->AccessControlInfo.UseExtendedSaveDataAccessControl == -1) yaml->AccessControlInfo.UseExtendedSaveDataAccessControl = 0; if(yaml->AccessControlInfo.RunnableOnSleep == -1) yaml->AccessControlInfo.RunnableOnSleep = 0; if(yaml->AccessControlInfo.SpecialMemoryArrange == -1) yaml->AccessControlInfo.SpecialMemoryArrange = 0; } int get_ExHeaderCodeSetInfo(exhdr_CodeSetInfo *CodeSetInfo, rsf_settings *yaml) { /* Name */ if(yaml->BasicInfo.Title){ if(strlen(yaml->BasicInfo.Title) > 8){ fprintf(stderr,"[EXHEADER ERROR] Parameter Too Long 'BasicInfo/Title'\n"); return EXHDR_BAD_YAML_OPT; } strcpy((char*)CodeSetInfo->Name,yaml->BasicInfo.Title); } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'BasicInfo/Title'\n"); return EXHDR_BAD_YAML_OPT; } /* Stack Size */ if(yaml->SystemControlInfo.StackSize){ u32 StackSize = strtoul(yaml->SystemControlInfo.StackSize,NULL,0); u32_to_u8(CodeSetInfo->StackSize,StackSize,LE); } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'SystemControlInfo/StackSize'\n"); return EXHDR_BAD_YAML_OPT; } /* Remaster Version */ if(yaml->SystemControlInfo.RemasterVersion){ u16 RemasterVersion = strtol(yaml->SystemControlInfo.RemasterVersion,NULL,0); u16_to_u8(CodeSetInfo->Flags.remasterVersion,RemasterVersion,LE); } else{ u16_to_u8(CodeSetInfo->Flags.remasterVersion,0,LE); } return 0; } int get_ExHeaderDependencyList(u8 *DependencyList, rsf_settings *yaml) { if(yaml->SystemControlInfo.DependencyNum > 0x30){ fprintf(stderr,"[EXHEADER ERROR] Too Many Dependency IDs\n"); return EXHDR_BAD_YAML_OPT; } for(int i = 0; i < yaml->SystemControlInfo.DependencyNum; i++){ u8 *pos = (DependencyList + 0x8*i); u64 TitleID = strtoull(yaml->SystemControlInfo.Dependency[i],NULL,0); u64_to_u8(pos,TitleID,LE); } return 0; } int get_ExHeaderSystemInfo(exhdr_SystemInfo *SystemInfo, rsf_settings *yaml) { /* SaveDataSize */ if(yaml->Rom.SaveDataSize){ u64 SaveDataSize = strtoull(yaml->Rom.SaveDataSize,NULL,10); if(strstr(yaml->Rom.SaveDataSize,"K")){ char *str = strstr(yaml->Rom.SaveDataSize,"K"); if(strcmp(str,"K") == 0 || strcmp(str,"KB") == 0 ){ SaveDataSize = SaveDataSize*KB; } } else if(strstr(yaml->Rom.SaveDataSize,"M")){ char *str = strstr(yaml->Rom.SaveDataSize,"M"); if(strcmp(str,"M") == 0 || strcmp(str,"MB") == 0 ){ SaveDataSize = SaveDataSize*MB; } } else if(strstr(yaml->Rom.SaveDataSize,"G")){ char *str = strstr(yaml->Rom.SaveDataSize,"G"); if(strcmp(str,"G") == 0 || strcmp(str,"GB") == 0 ){ SaveDataSize = SaveDataSize*GB; } } else{ fprintf(stderr,"[EXHEADER ERROR] Invalid save data size format.\n"); return EXHDR_BAD_YAML_OPT; } if((SaveDataSize & 65536) != 0){ fprintf(stderr,"[EXHEADER ERROR] Save data size must be aligned to 64K.\n"); return EXHDR_BAD_YAML_OPT; } u64_to_u8(SystemInfo->SaveDataSize,SaveDataSize,LE); } else{ u64_to_u8(SystemInfo->SaveDataSize,0,LE); } /* Jump Id */ if(yaml->SystemControlInfo.JumpId){ u64 JumpId = strtoull(yaml->SystemControlInfo.JumpId,NULL,0); u64_to_u8(SystemInfo->JumpId,JumpId,LE); } else{ u64 JumpId = 0; int result = GetProgramID(&JumpId,yaml,false); if(result) return result; u64_to_u8(SystemInfo->JumpId,JumpId,LE); } return 0; } int get_ExHeaderARM11SystemLocalInfo(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { /* Program Id */ u64 ProgramId = 0; int result = GetProgramID(&ProgramId,yaml,true); if(result) return result; u64_to_u8(arm11->ProgramId,ProgramId,LE); /* Flags */ result = SetARM11SystemLocalInfoFlags(arm11, yaml); if(result) return result; /* Resource Limit Descriptors */ result = SetARM11ResLimitDesc(arm11, yaml); if(result) return result; /* Storage Info */ result = SetARM11StorageInfo(arm11, yaml); if(result) return result; /* Service Access Control */ result = SetARM11ServiceAccessControl(arm11, yaml); if(result) return result; /* Resource Limit Category */ if(yaml->AccessControlInfo.ResourceLimitCategory){ if(strcasecmp(yaml->AccessControlInfo.ResourceLimitCategory,"application") == 0) arm11->ResourceLimitCategory = resrc_limit_APPLICATION; else if(strcasecmp(yaml->AccessControlInfo.ResourceLimitCategory,"sysapplet") == 0) arm11->ResourceLimitCategory = resrc_limit_SYS_APPLET; else if(strcasecmp(yaml->AccessControlInfo.ResourceLimitCategory,"libapplet") == 0) arm11->ResourceLimitCategory = resrc_limit_LIB_APPLET; else if(strcasecmp(yaml->AccessControlInfo.ResourceLimitCategory,"other") == 0) arm11->ResourceLimitCategory = resrc_limit_OTHER; } /* Finish */ return 0; } int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { /* Core Version */ if(yaml->AccessControlInfo.CoreVersion){ u32 Version = strtoul(yaml->AccessControlInfo.CoreVersion,NULL,0); u32_to_u8(&arm11->Flags[0],Version,LE); } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'AccessControlInfo/CoreVersion'\n"); return EXHDR_BAD_YAML_OPT; } /* Byte[6] */ u8 AffinityMask = 0; u8 IdealProcessor = 0; u8 SystemMode = 0; if(yaml->AccessControlInfo.AffinityMask){ AffinityMask = strtol(yaml->AccessControlInfo.AffinityMask,NULL,0); if(AffinityMask != 0 && AffinityMask != 1){ fprintf(stderr,"[EXHEADER ERROR] Unexpected AffinityMask: %d. Expected range: 0x0 - 0x1\n",AffinityMask); return EXHDR_BAD_YAML_OPT; } } if(yaml->AccessControlInfo.IdealProcessor){ IdealProcessor = strtol(yaml->AccessControlInfo.IdealProcessor,NULL,0); if(IdealProcessor != 0 && IdealProcessor != 1){ fprintf(stderr,"[EXHEADER ERROR] Unexpected IdealProcessor: %d. Expected range: 0x0 - 0x1\n",IdealProcessor); return EXHDR_BAD_YAML_OPT; } } if(yaml->AccessControlInfo.SystemMode){ SystemMode = strtol(yaml->AccessControlInfo.SystemMode,NULL,0); if(SystemMode > 15){ fprintf(stderr,"[EXHEADER ERROR] Unexpected SystemMode: 0x%x. Expected range: 0x0 - 0xf\n",SystemMode); return EXHDR_BAD_YAML_OPT; } } arm11->Flags[6] = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); /* Thread Priority */ if(yaml->AccessControlInfo.Priority){ u8 Priority = strtoul(yaml->AccessControlInfo.Priority,NULL,0); int ProccessType = 0; GetAppType(&ProccessType,yaml); if(ProccessType == processtype_APPLICATION || ProccessType == processtype_DEFAULT){ Priority += 32; } if(Priority > 127){ fprintf(stderr,"[EXHEADER ERROR] Invalid Priority: %d\n",Priority); return EXHDR_BAD_YAML_OPT; } arm11->Flags[7] = Priority; } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'AccessControlInfo/Priority'\n"); return EXHDR_BAD_YAML_OPT; } return 0; } int GetAppType(int *AppType, rsf_settings *yaml) { *AppType = processtype_DEFAULT; if(yaml->SystemControlInfo.AppType){ if(strcasecmp(yaml->SystemControlInfo.AppType,"application") == 0) *AppType = processtype_APPLICATION; else if(strcasecmp(yaml->SystemControlInfo.AppType,"system") == 0) *AppType = processtype_SYSTEM; } return 0; } int SetARM11ResLimitDesc(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { for(int i = 0; i < 16; i++){ if(i == 0){ /* MaxCpu */ // N's makerom actually reads this from the pre-made accessdesc. Damn cheaters. But we can improvise if(yaml->AccessControlInfo.MaxCpu){ arm11->ResourceLimitDescriptor[i][0] = strtol(yaml->AccessControlInfo.MaxCpu,NULL,0); } } } return 0; } int SetARM11StorageInfo(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { if(yaml->AccessControlInfo.UseExtendedSaveDataAccessControl || yaml->AccessControlInfo.AccessibleSaveDataIds){ /* Accessible SaveData IDs */ if(!CheckCondiditionsForNewAccessibleSaveDataIds(yaml)) return EXHDR_BAD_YAML_OPT; SetARM11StorageInfoAccessibleSaveDataIds(arm11,yaml); } else{ /* Extdata Id */ int ret = SetARM11StorageInfoExtSaveDataId(arm11,yaml); if(ret) return ret; /* OtherUserSaveData */ SetARM11StorageInfoOtherUserSaveData(arm11,yaml); } /* System Savedata Id */ SetARM11StorageInfoSystemSaveDataId(arm11,yaml); /* FileSystem Access Info */ u32 AccessInfo = 0; for(int i = 0; i < yaml->AccessControlInfo.FileSystemAccessNum; i++){ if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CategorySystemApplication") == 0) AccessInfo |= 1 << fsaccess_CATEGORY_SYSTEM_APPLICATION; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CategoryHardwareCheck") == 0) AccessInfo |= 1 << fsaccess_CATEGORY_HARDWARE_CHECK; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CategoryFileSystemTool") == 0) AccessInfo |= 1 << fsaccess_CATEGORY_FILE_SYSTEM_TOOL; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"Debug") == 0) AccessInfo |= 1 << fsaccess_DEBUG; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"TwlCardBackup") == 0) AccessInfo |= 1 << fsaccess_TWL_CARD_BACKUP; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"TwlNandData") == 0) AccessInfo |= 1 << fsaccess_TWL_NAND_DATA; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"Boss") == 0) AccessInfo |= 1 << fsaccess_BOSS; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"DirectSdmc") == 0) AccessInfo |= 1 << fsaccess_DIRECT_SDMC; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"Core") == 0) AccessInfo |= 1 << fsaccess_CORE; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CtrNandRo") == 0) AccessInfo |= 1 << fsaccess_CTR_NAND_RO; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CtrNandRw") == 0) AccessInfo |= 1 << fsaccess_CTR_NAND_RW; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CtrNandRoWrite") == 0) AccessInfo |= 1 << fsaccess_CTR_NAND_RO_WRITE; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CategorySystemSettings") == 0) AccessInfo |= 1 << fsaccess_CATEGORY_SYSTEM_SETTINGS; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CardBoard") == 0) AccessInfo |= 1 << fsaccess_CARD_BOARD; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"ExportImportIvs") == 0) AccessInfo |= 1 << fsaccess_EXPORT_IMPORT_IVS; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"DirectSdmcWrite") == 0) AccessInfo |= 1 << fsaccess_DIRECT_SDMC_WRITE; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"SwitchCleanup") == 0) AccessInfo |= 1 << fsaccess_SWITCH_CLEANUP; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"SaveDataMove") == 0) AccessInfo |= 1 << fsaccess_SAVE_DATA_MOVE; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"Shop") == 0) AccessInfo |= 1 << fsaccess_SHOP; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"Shell") == 0) AccessInfo |= 1 << fsaccess_SHELL; else if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"CategoryHomeMenu") == 0) AccessInfo |= 1 << fsaccess_CATEGORY_HOME_MENU; else{ fprintf(stderr,"[EXHEADER ERROR] Invalid FileSystemAccess Name: '%s'\n",yaml->AccessControlInfo.FileSystemAccess[i]); return EXHDR_BAD_YAML_OPT; } } u32_to_u8(arm11->StorageInfo.AccessInfo,AccessInfo,LE); return 0; } int SetARM11StorageInfoSystemSaveDataId(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { if(yaml->AccessControlInfo.SystemSaveDataId1){ u32 SaveId = strtoul(yaml->AccessControlInfo.SystemSaveDataId1,NULL,0); u32_to_u8(arm11->StorageInfo.SystemSaveDataId,SaveId,LE); } if(yaml->AccessControlInfo.SystemSaveDataId2){ u32 SaveId = strtoul(yaml->AccessControlInfo.SystemSaveDataId2,NULL,0); u32_to_u8(&arm11->StorageInfo.SystemSaveDataId[4],SaveId,LE); } return 0; } int SetARM11StorageInfoExtSaveDataId(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { if(yaml->AccessControlInfo.ExtSaveDataId){ if(!yaml->AccessControlInfo.UseExtSaveData){ fprintf(stderr,"[EXHEADER ERROR] Failed to set ExtSaveDataId. UseExtSaveData must be true.\n"); return EXHDR_BAD_YAML_OPT; } u32 ExtdataIdLow = strtoul(yaml->AccessControlInfo.ExtSaveDataId,NULL,0); u32_to_u8(arm11->StorageInfo.ExtSaveDataId,ExtdataIdLow,LE); } return 0; } int SetARM11StorageInfoOtherUserSaveData(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { u64 Value = 0; if(yaml->AccessControlInfo.OtherUserSaveDataId1) Value = 0xffffff & strtoul(yaml->AccessControlInfo.OtherUserSaveDataId1,NULL,0); Value = Value << 20; if(yaml->AccessControlInfo.OtherUserSaveDataId2) Value |= 0xffffff & strtoul(yaml->AccessControlInfo.OtherUserSaveDataId2,NULL,0); Value = Value << 20; if(yaml->AccessControlInfo.OtherUserSaveDataId3) Value |= 0xffffff & strtoul(yaml->AccessControlInfo.OtherUserSaveDataId3,NULL,0); /* UseOtherVariationSaveData Flag */ if(yaml->AccessControlInfo.UseOtherVariationSaveData){ Value |= 0x1000000000000000; } u64_to_u8(arm11->StorageInfo.StorageAccessableUniqueIds,Value,LE); return 0; } bool CheckCondiditionsForNewAccessibleSaveDataIds(rsf_settings *yaml) { if(!yaml->AccessControlInfo.UseExtendedSaveDataAccessControl){ if(yaml->AccessControlInfo.AccessibleSaveDataIds) fprintf(stderr,"[EXHEADER ERROR] AccessibleSaveDataIds is unavailable if UseExtendedSaveDataAccessControl is false.\n"); return false; } if(yaml->AccessControlInfo.AccessibleSaveDataIdsNum > 6){ fprintf(stderr,"[EXHEADER ERROR] Too many UniqueId in \"AccessibleSaveDataIds\".\n"); return false; } if(yaml->AccessControlInfo.UseExtSaveData){ fprintf(stderr,"[EXHEADER ERROR] UseExtSaveData must be false if AccessibleSaveDataIds is specified.\n"); return false; } if (yaml->AccessControlInfo.ExtSaveDataId){ fprintf(stderr,"[EXHEADER ERROR] ExtSaveDataId is unavailable if AccessibleSaveDataIds is specified.\n"); return false; } if (yaml->AccessControlInfo.OtherUserSaveDataId1){ if(strtoul(yaml->AccessControlInfo.OtherUserSaveDataId1,NULL,0) > 0){ fprintf(stderr,"[EXHEADER ERROR] OtherUserSaveDataId1 must be 0 if AccessibleSaveDataIds is specified.\n"); return false; } } if (yaml->AccessControlInfo.OtherUserSaveDataId2){ if(strtoul(yaml->AccessControlInfo.OtherUserSaveDataId2,NULL,0) > 0){ fprintf(stderr,"[EXHEADER ERROR] OtherUserSaveDataId2 must be 0 if AccessibleSaveDataIds is specified.\n"); return false; } } if (yaml->AccessControlInfo.OtherUserSaveDataId3){ if(strtoul(yaml->AccessControlInfo.OtherUserSaveDataId3,NULL,0) > 0){ fprintf(stderr,"[EXHEADER ERROR] OtherUserSaveDataId3 must be 0 if AccessibleSaveDataIds is specified.\n"); return false; } } return true; } int SetARM11StorageInfoAccessibleSaveDataIds(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { u64 RegionExtSaveDataId = 0; u64 RegionOtherUseSaveData = 0; if(yaml->AccessControlInfo.AccessibleSaveDataIdsNum > 0){ u32 Max = yaml->AccessControlInfo.AccessibleSaveDataIdsNum < 3 ? yaml->AccessControlInfo.AccessibleSaveDataIdsNum : 3; for(int i = 0; i < Max; i++){ u32 UniqueID = 0xffffff & strtoul(yaml->AccessControlInfo.AccessibleSaveDataIds[i],NULL,0); RegionOtherUseSaveData = RegionOtherUseSaveData << 20; RegionOtherUseSaveData |= UniqueID; } } if(yaml->AccessControlInfo.AccessibleSaveDataIdsNum > 3){ for(int i = 3; i < yaml->AccessControlInfo.AccessibleSaveDataIdsNum; i++){ u32 UniqueID = 0xffffff & strtoul(yaml->AccessControlInfo.AccessibleSaveDataIds[i],NULL,0); RegionExtSaveDataId = RegionExtSaveDataId << 20; RegionExtSaveDataId |= UniqueID; } } arm11->StorageInfo.OtherAttributes |= 1 << attribute_USE_EXTENDED_SAVEDATA_ACCESS_CONTROL; /* UseOtherVariationSaveData Flag */ if(yaml->AccessControlInfo.UseOtherVariationSaveData){ RegionOtherUseSaveData |= 0x1000000000000000; } u64_to_u8(arm11->StorageInfo.ExtSaveDataId,RegionExtSaveDataId,LE); u64_to_u8(arm11->StorageInfo.StorageAccessableUniqueIds,RegionOtherUseSaveData,LE); return 0; } int SetARM11ServiceAccessControl(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_settings *yaml) { if(yaml->AccessControlInfo.ServiceAccessControl){ if(yaml->AccessControlInfo.ServiceAccessControlNum > 32){ fprintf(stderr,"[EXHEADER ERROR] Too Many SVC Handles, maximum is 32\n"); return EXHDR_BAD_YAML_OPT; } for(int i = 0; i < yaml->AccessControlInfo.ServiceAccessControlNum; i++){ int svc_handle_len = strlen(yaml->AccessControlInfo.ServiceAccessControl[i]); if(svc_handle_len > 8){ fprintf(stderr,"[EXHEADER ERROR] SVC Handle: '%s' is too long\n",yaml->AccessControlInfo.ServiceAccessControl[i]); return EXHDR_BAD_YAML_OPT; } memcpy(arm11->ServiceAccessControl[i],yaml->AccessControlInfo.ServiceAccessControl[i],svc_handle_len); } } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'AccessControlInfo/ServiceAccessControl'\n"); return EXHDR_BAD_YAML_OPT; } return 0; } int get_ExHeaderARM11KernelInfo(exhdr_ARM11KernelCapabilities *arm11, rsf_settings *yaml) { int result = 0; ARM11KernelCapabilityDescriptor desc[6]; memset(&desc,0,sizeof(ARM11KernelCapabilityDescriptor)*6); /* Get Descriptors */ result = SetARM11KernelDescSysCallControl(&desc[0],yaml); if(result) goto finish; result = SetARM11KernelDescInteruptNumList(&desc[1],yaml); if(result) goto finish; result = SetARM11KernelDescAddressMapping(&desc[2],yaml); if(result) goto finish; result = SetARM11KernelDescOtherCapabilities(&desc[3],yaml); if(result) goto finish; result = SetARM11KernelDescHandleTableSize(&desc[4],yaml); if(result) goto finish; result = SetARM11KernelDescReleaseKernelVersion(&desc[5],yaml); /* Write Descriptors To Exheader */ u16 TotalDesc = 0; for(int i = 0; i < 6; i++){ TotalDesc += desc[i].num; } if(TotalDesc >= 28){ fprintf(stderr,"[EXHEADER ERROR] Too many Kernel Capabilities.\n"); result = EXHDR_BAD_YAML_OPT; goto finish; } u16 DescIndex = 0; for(int i = 0; i < 6; i++){ for(int j = 0; j < desc[i].num; j++){ u32_to_u8(arm11->descriptors[DescIndex],desc[i].Data[j],LE); DescIndex++; } } /* Fill Remaining Descriptors with 0xffffffff */ for(int i = DescIndex; i < 28; i++){ u32_to_u8(arm11->descriptors[i],0xffffffff,LE); } finish: for(int i = 0; i < 6; i++){ free(desc[i].Data); } return result; } int SetARM11KernelDescSysCallControl(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { int ret = 0; // Create Temporary Descriptor ARM11KernelCapabilityDescriptor tmp; memset(&tmp,0,sizeof(ARM11KernelCapabilityDescriptor)); AllocateARM11KernelDescMemory(&tmp,8); for(int i = 0; i < 8; i++) SetARM11KernelDescValue(&tmp,i,desc_SysCallControl | (i << 24)); // Get SysCalls ret = GetARM11SysCalls(&tmp,yaml); if(ret) goto finish; // Count Active Syscall Descs u16 ActiveSysCallDesc = 0; for(int i = 0; i < 8; i++) if((tmp.Data[i] & 0x00ffffff) != 0) ActiveSysCallDesc++; // Transfer Active Syscall Descs to out Descriptor AllocateARM11KernelDescMemory(desc,ActiveSysCallDesc); u16 SysCallDescPos = 0; for(int i = 0; i < 8; i++){ if((tmp.Data[i] & 0x00ffffff) != 0) { SetARM11KernelDescValue(desc,SysCallDescPos,tmp.Data[i]); SysCallDescPos++; } } finish: // Free data in Temporary Descriptor free(tmp.Data); return ret; } int GetARM11SysCalls(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(!yaml->AccessControlInfo.SystemCallAccess){ fprintf(stderr,"[EXHEADER ERROR] Parameter not found: 'AccessControlInfo/SystemCallAccess'\n"); return EXHDR_BAD_YAML_OPT; } for(int i = 0; i < yaml->AccessControlInfo.SystemCallAccessNum; i++){ int SysCall = strtoul(yaml->AccessControlInfo.SystemCallAccess[i],NULL,0); if(SysCall > 184){ fprintf(stderr,"[EXHEADER ERROR] Unexpected Syscall: 0x%02x. Expected Range: 0x00 - 0xB8\n",SysCall); return EXHDR_BAD_YAML_OPT; } EnableSystemCall(desc,SysCall); } return 0; } void EnableSystemCall(ARM11KernelCapabilityDescriptor *desc, int SysCall) { int num = SysCall / 24; int num1 = SysCall % 24; desc->Data[num] |= 1 << (num1 & 31); } void DisableSystemCall(ARM11KernelCapabilityDescriptor *desc, int SysCall) { int num = SysCall / 24; int num1 = SysCall % 24; desc->Data[num] = desc->Data[num] & ~(1 << (num1 & 31)); } int SetARM11KernelDescInteruptNumList(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { int ret = 0; // Create Temporary Descriptor ARM11KernelCapabilityDescriptor tmp; memset(&tmp,0,sizeof(ARM11KernelCapabilityDescriptor)); AllocateARM11KernelDescMemory(&tmp,8); // Get Interupts ret = GetARM11Interupts(&tmp,yaml); if(ret) goto finish; // Count Active Interupt Descs u16 ActiveInteruptDesc = 0; for(int i = 0; i < 8; i++) if(tmp.Data[i]) ActiveInteruptDesc++; // Transfer Active Interupt Descs to output Descriptor AllocateARM11KernelDescMemory(desc,ActiveInteruptDesc); u16 InteruptDescPos = 0; for(int i = 0; i < 8; i++){ if(tmp.Data[i]) { SetARM11KernelDescValue(desc,InteruptDescPos,(tmp.Data[i] & 0x0fffffff) | desc_InteruptNumList); InteruptDescPos++; } } finish: // Free data in Temporary Descriptor free(tmp.Data); return ret; } int GetARM11Interupts(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(!yaml->AccessControlInfo.InterruptNumbers){ return 0; } if(yaml->AccessControlInfo.InterruptNumbersNum > 32){ fprintf(stderr,"[EXHEADER ERROR] Too many Interupts. Maximum is 32\n"); return EXHDR_BAD_YAML_OPT; } for(int i = 0; i < yaml->AccessControlInfo.InterruptNumbersNum; i++){ int Interrupt = strtoul(yaml->AccessControlInfo.InterruptNumbers[i],NULL,0); if(Interrupt > 0x7f){ fprintf(stderr,"[EXHEADER ERROR] Unexpected Interupt: 0x%02x. Expected Range: 0x00 - 0x7f\n",Interrupt); return EXHDR_BAD_YAML_OPT; } EnableInterupt(desc,Interrupt,i); } return 0; } void EnableInterupt(ARM11KernelCapabilityDescriptor *desc, int Interrupt, int i) { int num = i / 4; if(num*4 == i) desc->Data[num] |= 0xffffffff; desc->Data[num] = desc->Data[num] << 7; desc->Data[num] |= Interrupt; } int SetARM11KernelDescAddressMapping(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { int ret = 0; // Create Temporary Descriptors ARM11KernelCapabilityDescriptor io_tmp; memset(&io_tmp,0,sizeof(ARM11KernelCapabilityDescriptor)); ARM11KernelCapabilityDescriptor static_tmp; memset(&static_tmp,0,sizeof(ARM11KernelCapabilityDescriptor)); // Getting IO Mapping ret = GetARM11IOMappings(&io_tmp,yaml); if(ret) goto finish; // Getting Static Mapping ret = GetARM11StaticMappings(&static_tmp,yaml); if(ret) goto finish; // Creating Output Descriptor and Combining the two MemMap Descriptors AllocateARM11KernelDescMemory(desc,io_tmp.num+static_tmp.num); u16 MemMapDescPos = 0; for(int i = 0; i < io_tmp.num; i++){ SetARM11KernelDescValue(desc,MemMapDescPos,io_tmp.Data[i]); MemMapDescPos++; } for(int i = 0; i < static_tmp.num; i++){ SetARM11KernelDescValue(desc,MemMapDescPos,static_tmp.Data[i]); MemMapDescPos++; } finish: free(io_tmp.Data); free(static_tmp.Data); return ret; } int GetARM11IOMappings(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(!yaml->AccessControlInfo.IORegisterMapping) return 0; AllocateARM11KernelDescMemory(desc,yaml->AccessControlInfo.IORegisterMappingNum*2); u16 DescUsed = 0; for(int i = 0; i < yaml->AccessControlInfo.IORegisterMappingNum; i++){ if(strlen(yaml->AccessControlInfo.IORegisterMapping[i])){ char *AddressStartStr = yaml->AccessControlInfo.IORegisterMapping[i]; char *AddressEndStr = strstr(AddressStartStr,"-"); if(AddressEndStr){ if(strlen(AddressEndStr) > 1) AddressEndStr = (AddressEndStr+1); else AddressEndStr = NULL; } u32 AddressStart = strtoul(AddressStartStr,NULL,16); if(!IsStartAddress(AddressStart)){ fprintf(stderr,"[EXHEADER ERROR] Address 0x%x is not valid mapping start address.\n",AddressStart); return EXHDR_BAD_YAML_OPT; } if(!AddressEndStr){ // No End Addr Was Specified SetARM11KernelDescValue(desc,DescUsed,GetIOMappingDesc(AddressStart)); DescUsed++; goto skip; } u32 AddressEnd = strtoul(AddressEndStr,NULL,16); if(!IsEndAddress(AddressEnd)){ fprintf(stderr,"[EXHEADER ERROR] Address 0x%x is not valid mapping end address.\n",AddressEnd); return EXHDR_BAD_YAML_OPT; } u32 DescStartAddr = GetStaticMappingDesc(AddressStart,false); u32 DescEndAddr = GetStaticMappingDesc(AddressEnd+0x1000,false); if(DescStartAddr != DescEndAddr){ SetARM11KernelDescValue(desc,DescUsed,DescStartAddr); SetARM11KernelDescValue(desc,DescUsed+1,DescEndAddr); DescUsed += 2; goto skip; } else{ SetARM11KernelDescValue(desc,DescUsed,GetIOMappingDesc(AddressStart)); DescUsed++; goto skip; } } skip: ; } desc->num = DescUsed; return 0; } int GetARM11StaticMappings(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(!yaml->AccessControlInfo.MemoryMapping) return 0; AllocateARM11KernelDescMemory(desc,yaml->AccessControlInfo.MemoryMappingNum*2); u16 DescUsed = 0; for(int i = 0; i < yaml->AccessControlInfo.MemoryMappingNum; i++){ if(strlen(yaml->AccessControlInfo.MemoryMapping[i])){ char *AddressStartStr = yaml->AccessControlInfo.MemoryMapping[i]; char *AddressEndStr = strstr(AddressStartStr,"-"); char *ROFlagStr = strstr(AddressStartStr,":"); bool IsRO = false; if(ROFlagStr) IsRO = strcasecmp(ROFlagStr,":r") == 0 ? true : false; if(AddressEndStr){ if(strlen(AddressEndStr) > 1) { AddressEndStr = (AddressEndStr+1); if(AddressEndStr == ROFlagStr) AddressEndStr = NULL; } else AddressEndStr = NULL; } u32 AddressStart = strtoul(AddressStartStr,NULL,16); if(!IsStartAddress(AddressStart)){ fprintf(stderr,"[EXHEADER ERROR] Address 0x%x (%s) is not valid mapping start address.\n",AddressStart,AddressStartStr); return EXHDR_BAD_YAML_OPT; } if(!AddressEndStr){ // No End Addr Was Specified SetARM11KernelDescValue(desc,DescUsed,GetStaticMappingDesc(AddressStart,IsRO)); SetARM11KernelDescValue(desc,DescUsed+1,GetStaticMappingDesc(AddressStart+0x1000, true)); DescUsed += 2; goto skip; } u32 AddressEnd = strtoul(AddressEndStr,NULL,16); if(!IsEndAddress(AddressEnd)){ fprintf(stderr,"[EXHEADER ERROR] Address 0x%x (%s) is not valid mapping end address.\n",AddressEnd,AddressEndStr); return EXHDR_BAD_YAML_OPT; } u32 DescStartAddr = GetStaticMappingDesc(AddressStart,IsRO); u32 DescEndAddr = GetStaticMappingDesc(AddressEnd+0x1000,true); if(DescStartAddr != DescEndAddr){ SetARM11KernelDescValue(desc,DescUsed,DescStartAddr); SetARM11KernelDescValue(desc,DescUsed+1,DescEndAddr); DescUsed += 2; goto skip; } else{ SetARM11KernelDescValue(desc,DescUsed,GetStaticMappingDesc(AddressStart,IsRO)); SetARM11KernelDescValue(desc,DescUsed+1,GetStaticMappingDesc(AddressStart+0x1000, true)); DescUsed += 2; goto skip; } } skip: ; } desc->num = DescUsed; return 0; } bool IsEndAddress(u32 Address) { return (Address & 0xfff) == 0xfff; } bool IsStartAddress(u32 Address) { return (Address & 0xfff) == 0; } u32 GetIOMappingDesc(u32 Address) { return GetMappingDesc(Address,0xFFE,0xC,false); } u32 GetStaticMappingDesc(u32 Address, bool IsReadOnly) { return GetMappingDesc(Address,0x7FC,0xB,IsReadOnly); } u32 GetMappingDesc(u32 Address, u32 PrefixVal, s32 numPrefixBits, bool IsRO) { u32 PrefixMask = GetDescPrefixMask(numPrefixBits); u32 PrefixBits = GetDescPrefixBits(numPrefixBits,PrefixVal); u32 Desc = (Address >> 12 & ~PrefixMask) | PrefixBits; if (IsRO) Desc |= 0x100000; return Desc; } int SetARM11KernelDescOtherCapabilities(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { u32 OtherCapabilities = 0; if(!yaml->AccessControlInfo.DisableDebug) OtherCapabilities |= 1 << othcap_PERMIT_DEBUG; if(yaml->AccessControlInfo.EnableForceDebug) OtherCapabilities |= 1 << othcap_FORCE_DEBUG; if(yaml->AccessControlInfo.CanUseNonAlphabetAndNumber) OtherCapabilities |= 1 << othcap_CAN_USE_NON_ALPHABET_AND_NUMBER; if(yaml->AccessControlInfo.CanWriteSharedPage) OtherCapabilities |= 1 << othcap_CAN_WRITE_SHARED_PAGE; if(yaml->AccessControlInfo.CanUsePrivilegedPriority) OtherCapabilities |= 1 << othcap_CAN_USE_PRIVILEGE_PRIORITY; if(yaml->AccessControlInfo.PermitMainFunctionArgument) OtherCapabilities |= 1 << othcap_PERMIT_MAIN_FUNCTION_ARGUMENT; if(yaml->AccessControlInfo.CanShareDeviceMemory) OtherCapabilities |= 1 << othcap_CAN_SHARE_DEVICE_MEMORY; if(yaml->AccessControlInfo.RunnableOnSleep) OtherCapabilities |= 1 << othcap_RUNNABLE_ON_SLEEP; if(yaml->AccessControlInfo.SpecialMemoryArrange) OtherCapabilities |= 1 << othcap_SPECIAL_MEMORY_ARRANGE; if(yaml->AccessControlInfo.MemoryType){ u32 MemType = 0; if(strcasecmp(yaml->AccessControlInfo.MemoryType,"application") == 0) MemType = memtype_APPLICATION; else if(strcasecmp(yaml->AccessControlInfo.MemoryType,"system") == 0) MemType = memtype_SYSTEM; else if(strcasecmp(yaml->AccessControlInfo.MemoryType,"base") == 0) MemType = memtype_BASE; else{ fprintf(stderr,"[EXHEADER ERROR] Invalid memory type: '%s'\n",yaml->AccessControlInfo.MemoryType); return EXHDR_BAD_YAML_OPT; } OtherCapabilities = (OtherCapabilities & -3841) | MemType << 8; } if(OtherCapabilities){ AllocateARM11KernelDescMemory(desc,1); SetARM11KernelDescBitmask(desc,desc_OtherCapabilities); SetARM11KernelDescValue(desc,0,OtherCapabilities); } return 0; } int SetARM11KernelDescHandleTableSize(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(yaml->AccessControlInfo.HandleTableSize){ u16 HandleTableSize = strtoul(yaml->AccessControlInfo.HandleTableSize,NULL,0); if(HandleTableSize > 1023){ fprintf(stderr,"[EXHEADER ERROR] Too large handle table size\n"); return EXHDR_BAD_YAML_OPT; } AllocateARM11KernelDescMemory(desc,1); SetARM11KernelDescBitmask(desc,desc_HandleTableSize); SetARM11KernelDescValue(desc,0,HandleTableSize); } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'AccessControlInfo/HandleTableSize'\n"); return EXHDR_BAD_YAML_OPT; } return 0; } int SetARM11KernelDescReleaseKernelVersion(ARM11KernelCapabilityDescriptor *desc, rsf_settings *yaml) { if(yaml->AccessControlInfo.ReleaseKernelMajor && yaml->AccessControlInfo.ReleaseKernelMinor){ u32 releaseKernelMajor = strtoul(yaml->AccessControlInfo.ReleaseKernelMajor,NULL,0); u32 releaseKernelMinor = strtoul(yaml->AccessControlInfo.ReleaseKernelMinor,NULL,0); if (releaseKernelMajor > 255 || releaseKernelMinor > 255){ fprintf(stderr,"[EXHEADER ERROR] Invalid release kernel version"); } AllocateARM11KernelDescMemory(desc,1); SetARM11KernelDescBitmask(desc,desc_KernelReleaseVersion); SetARM11KernelDescValue(desc,0,(releaseKernelMajor << 8 | releaseKernelMinor)); } return 0; } void SetARM11KernelDescValue(ARM11KernelCapabilityDescriptor *desc, u16 Index, u32 Value) { if(Index >= desc->num) return; desc->Data[Index] |= Value; } void SetARM11KernelDescBitmask(ARM11KernelCapabilityDescriptor *desc, u32 Bitmask) { for(int i = 0; i < desc->num; i++) SetARM11KernelDescValue(desc,i,Bitmask); } void AllocateARM11KernelDescMemory(ARM11KernelCapabilityDescriptor *desc, u16 Num) { if(Num == 0) return; desc->num = Num; desc->Data = malloc(sizeof(u32)*Num); memset(desc->Data,0,sizeof(u32)*Num); return; } u32 GetDescPrefixMask(int numPrefixBits) { return (u32)(~((1 << (32 - (numPrefixBits & 31))) - 1)); } u32 GetDescPrefixBits(int numPrefixBits, u32 PrefixVal) { return PrefixVal << (32 - (numPrefixBits & 31)); } int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_settings *yaml) { u32 Arm9AccessControl = 0; for(int i = 0; i < yaml->AccessControlInfo.IoAccessControlNum; i++){ if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"FsMountNand") == 0) Arm9AccessControl |= 1 << arm9cap_FS_MOUNT_NAND; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"FsMountNandRoWrite") == 0) Arm9AccessControl |= 1 << arm9cap_FS_MOUNT_NAND_RO_WRITE; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"FsMountTwln") == 0) Arm9AccessControl |= 1 << arm9cap_FS_MOUNT_TWLN; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"FsMountWnand") == 0) Arm9AccessControl |= 1 << arm9cap_FS_MOUNT_WNAND; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"FsMountCardSpi") == 0) Arm9AccessControl |= 1 << arm9cap_FS_MOUNT_CARD_SPI; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"UseSdif3") == 0) Arm9AccessControl |= 1 << arm9cap_USE_SDIF3; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"CreateSeed") == 0) Arm9AccessControl |= 1 << arm9cap_CREATE_SEED; else if(strcmp(yaml->AccessControlInfo.IoAccessControl[i],"UseCardSpi") == 0) Arm9AccessControl |= 1 << arm9cap_USE_CARD_SPI; else{ fprintf(stderr,"[EXHEADER ERROR] Invalid IoAccessControl Name: '%s'\n",yaml->AccessControlInfo.IoAccessControl[i]); return EXHDR_BAD_YAML_OPT; } } for(int i = 0; i < yaml->AccessControlInfo.FileSystemAccessNum; i++){ if(strcmp(yaml->AccessControlInfo.FileSystemAccess[i],"DirectSdmc") == 0) Arm9AccessControl |= 1 << arm9cap_USE_DIRECT_SDMC; } if(yaml->Option.UseOnSD) Arm9AccessControl |= 1 << arm9cap_SD_APPLICATION; u32_to_u8(arm9->descriptors,Arm9AccessControl,LE); if(yaml->AccessControlInfo.DescVersion){ arm9->descriptors[15] = strtol(yaml->AccessControlInfo.DescVersion,NULL,0); } else{ fprintf(stderr,"[EXHEADER ERROR] Parameter Not Found: 'AccessControlInfo/DescVersion'\n"); return EXHDR_BAD_YAML_OPT; } return 0; } int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset) { switch(ncchset->Options.accessdesc){ case auto_gen : /* Set RSA Keys */ memcpy(ncchset->CxiRsaKey.PrivK,exhdrset->keys->rsa.CFA_Priv,0x100); memcpy(ncchset->CxiRsaKey.PubK,exhdrset->keys->rsa.CFA_Pub,0x100); memcpy(&exhdrset->ExHdr->AccessDescriptor.ncchpubkeymodulus,exhdrset->keys->rsa.CFA_Pub,0x100); /* Copy Data From ExHeader */ memcpy(&exhdrset->ExHdr->AccessDescriptor.ARM11SystemLocalCapabilities,&exhdrset->ExHdr->ARM11SystemLocalCapabilities,sizeof(exhdr_ARM11SystemLocalCapabilities)); memcpy(&exhdrset->ExHdr->AccessDescriptor.ARM11KernelCapabilities,&exhdrset->ExHdr->ARM11KernelCapabilities,sizeof(exhdr_ARM11KernelCapabilities)); memcpy(&exhdrset->ExHdr->AccessDescriptor.ARM9AccessControlInfo,&exhdrset->ExHdr->ARM9AccessControlInfo,sizeof(exhdr_ARM9AccessControlInfo)); /* Sign AccessDesc */ return SignAccessDesc(exhdrset->ExHdr,exhdrset->keys); case use_spec_file: /* Yaml Option Sanity Checks */ if(!exhdrset->yaml->CommonHeaderKey.Found){ fprintf(stderr,"[EXHEADER ERROR] RSF Section 'CommonHeaderKey' not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } if(!exhdrset->yaml->CommonHeaderKey.D){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/D' not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } if(strlen(exhdrset->yaml->CommonHeaderKey.D) != 350){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/D' has invalid length (%d)\n",strlen(exhdrset->yaml->CommonHeaderKey.D)); return COMMON_HEADER_KEY_NOT_FOUND; } if(!exhdrset->yaml->CommonHeaderKey.Modulus){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Modulus' not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } if(strlen(exhdrset->yaml->CommonHeaderKey.Modulus) != 350){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Modulus' has invalid length (%d)\n",strlen(exhdrset->yaml->CommonHeaderKey.Modulus)); return COMMON_HEADER_KEY_NOT_FOUND; } if(!exhdrset->yaml->CommonHeaderKey.AccCtlDescSign){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Signature' not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } if(strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescSign) != 350){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Signature' has invalid length (%d)\n",strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescSign)); return COMMON_HEADER_KEY_NOT_FOUND; } if(!exhdrset->yaml->CommonHeaderKey.AccCtlDescBin){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Descriptor' not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } if(strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescBin) != 695){ fprintf(stderr,"[EXHEADER ERROR] 'CommonHeaderKey/Descriptor' has invalid length (%d)\n",strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescBin)); return COMMON_HEADER_KEY_NOT_FOUND; } /* Set RSA Keys */ int result = 0; u32 out = 0x500; u8 *tmp = malloc(0x500); result = base64_decode(tmp,&out,(const u8*)exhdrset->yaml->CommonHeaderKey.Modulus,strlen(exhdrset->yaml->CommonHeaderKey.Modulus)); if(result) goto finish; memcpy(ncchset->CxiRsaKey.PubK,tmp,0x100); out = 0x500; result = base64_decode(tmp,&out,(const u8*)exhdrset->yaml->CommonHeaderKey.D,strlen(exhdrset->yaml->CommonHeaderKey.D)); if(result) goto finish; memcpy(ncchset->CxiRsaKey.PrivK,tmp,0x100); /* Set AccessDesc */ out = 0x500; result = base64_decode(tmp,&out,(const u8*)exhdrset->yaml->CommonHeaderKey.AccCtlDescSign,strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescSign)); if(result) goto finish; memcpy(exhdrset->ExHdr->AccessDescriptor.signature,tmp,0x100); memcpy(exhdrset->ExHdr->AccessDescriptor.ncchpubkeymodulus,ncchset->CxiRsaKey.PubK,0x100); out = 0x500; result = base64_decode(tmp,&out,(const u8*)exhdrset->yaml->CommonHeaderKey.AccCtlDescBin,strlen(exhdrset->yaml->CommonHeaderKey.AccCtlDescBin)); if(result) goto finish; memcpy(&exhdrset->ExHdr->AccessDescriptor.ARM11SystemLocalCapabilities,tmp,0x200); finish: free(tmp); return result; #ifndef RETAIL_FSIGN case app : memcpy(ncchset->CxiRsaKey.PrivK,(u8*)App_sdk5_HdrPrivK,0x100); memcpy(ncchset->CxiRsaKey.PubK,(u8*)App_sdk5_HdrPubK,0x100); memcpy(&exhdrset->ExHdr->AccessDescriptor.signature,(u8*)App_sdk5_AcexData,0x400); return 0; case demo : memcpy(ncchset->CxiRsaKey.PrivK,(u8*)Demo_sdk5_HdrPrivK,0x100); memcpy(ncchset->CxiRsaKey.PubK,(u8*)Demo_sdk5_HdrPubK,0x100); memcpy(&exhdrset->ExHdr->AccessDescriptor.signature,(u8*)Demo_sdk5_AcexData,0x400); return 0; case dlp : memcpy(ncchset->CxiRsaKey.PrivK,(u8*)Dlp_sdk5_HdrPrivK,0x100); memcpy(ncchset->CxiRsaKey.PubK,(u8*)Dlp_sdk5_HdrPubK,0x100); memcpy(&exhdrset->ExHdr->AccessDescriptor.signature,(u8*)Dlp_sdk5_AcexData,0x400); return 0; #endif } return 0; } /* ExHeader Binary Print Functions */ void exhdr_Print_ServiceAccessControl(ExtendedHeader_Struct *hdr) { printf("[+] Service Access Control\n"); for(int i = 0; i < 32; i ++){ char *SVC_Handle = (char*)hdr->ARM11SystemLocalCapabilities.ServiceAccessControl[i]; if(SVC_Handle[0] == 0) break; printf("%.8s\n",hdr->ARM11SystemLocalCapabilities.ServiceAccessControl[i]); } } /* ExHeader Binary Read Functions */ u8* GetAccessDescSig_frm_exhdr(ExtendedHeader_Struct *hdr) { if(!hdr) return NULL; return hdr->AccessDescriptor.signature ; } u8* GetNcchHdrPubKey_frm_exhdr(ExtendedHeader_Struct *hdr) { if(!hdr) return NULL; return hdr->AccessDescriptor.ncchpubkeymodulus; } u8* GetAccessDesc_frm_exhdr(ExtendedHeader_Struct *hdr) { if(!hdr) return NULL; return hdr->AccessDescriptor.ncchpubkeymodulus; } u16 GetRemasterVersion_frm_exhdr(ExtendedHeader_Struct *hdr) { return u8_to_u16(hdr->CodeSetInfo.Flags.remasterVersion,LE); } u64 GetSaveDataSize_frm_exhdr(ExtendedHeader_Struct *hdr) { return u8_to_u64(hdr->SystemInfo.SaveDataSize,LE); } int GetCoreVersion_frm_exhdr(u8 *Dest, ExtendedHeader_Struct *hdr) { return (int) memcpy(Dest,hdr->ARM11SystemLocalCapabilities.Flags,4); } int GetDependancyList_frm_exhdr(u8 *Dest,ExtendedHeader_Struct *hdr) { if(!Dest) return -1; for(int i = 0; i < 0x30; i++){ memcpy(Dest,hdr->DependencyList,0x30*8); } return 0; } /* ExHeader Settings Read from Yaml */ int GetSaveDataSize_yaml(u64 *SaveDataSize, user_settings *usrset) { if(usrset->yaml_set.Rom.SaveDataSize){ *SaveDataSize = strtoull(usrset->yaml_set.Rom.SaveDataSize,NULL,10); if(strstr(usrset->yaml_set.Rom.SaveDataSize,"K")){ char *str = strstr(usrset->yaml_set.Rom.SaveDataSize,"K"); if(strcmp(str,"K") == 0 || strcmp(str,"KB") == 0 ){ *SaveDataSize = *SaveDataSize*KB; } } else if(strstr(usrset->yaml_set.Rom.SaveDataSize,"M")){ char *str = strstr(usrset->yaml_set.Rom.SaveDataSize,"M"); if(strcmp(str,"M") == 0 || strcmp(str,"MB") == 0 ){ *SaveDataSize = *SaveDataSize*MB; } } else if(strstr(usrset->yaml_set.Rom.SaveDataSize,"G")){ char *str = strstr(usrset->yaml_set.Rom.SaveDataSize,"G"); if(strcmp(str,"G") == 0 || strcmp(str,"GB") == 0 ){ *SaveDataSize = *SaveDataSize*GB; } } else{ fprintf(stderr,"[EXHEADER ERROR] Invalid save data size format.\n"); return EXHDR_BAD_YAML_OPT; } if((*SaveDataSize & 65536) != 0){ fprintf(stderr,"[EXHEADER ERROR] Save data size must be aligned to 64K.\n"); return EXHDR_BAD_YAML_OPT; } } else{ *SaveDataSize = 0; } return 0; } int GetRemasterVersion_yaml(u16 *RemasterVersion, user_settings *usrset) { char *Str = usrset->yaml_set.SystemControlInfo.RemasterVersion; if(!Str){ *RemasterVersion = 0; return 0; } *RemasterVersion = strtol(Str,NULL,0); return 0; }