https://switchbrew.org/w/api.php?action=feedcontributions&user=Rajkosto&feedformat=atom
Nintendo Switch Brew - User contributions [en]
2024-03-29T08:41:49Z
User contributions
MediaWiki 1.35.8
https://switchbrew.org/w/index.php?title=Filesystem_services&diff=4928
Filesystem services
2018-08-16T14:36:12Z
<p>Rajkosto: correct parameters of OpenFileSystem</p>
<hr />
<div>= fsp-ldr =<br />
This is "nn::fssrv::sf::IFileSystemProxyForLoader".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || OpenCodeFileSystem || u64 TitleId + X descriptor [[#ContentPath]] || Returns an [[#IFileSystem]].<br />
|-<br />
| 1 || IsArchivedProgram || u64 ProcessId || Returns a bool (1 if code is mounted).<br />
|-<br />
| 2 || [4.0.0+] SetCurrentProcess || PID descriptor ||<br />
|}<br />
<br />
= fsp-pr =<br />
This is "nn::fssrv::sf::IProgramRegistry".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || [[#RegisterProgram]] ||<br />
|-<br />
| 1 || [[#UnregisterProgram]] ||<br />
|-<br />
| 2 || [4.0.0+] SetCurrentProcess ||<br />
|-<br />
| 256 || [[#SetEnabledProgramVerification]] ||<br />
|}<br />
<br />
== RegisterProgram ==<br />
Takes a storageID, a pid, a titleID, a 0x1C type-A buffer for the [[NPDM#FS_Access_Header| FS Access Header]], and a 0x2C type-A buffer for the [[NPDM#FS_Access_Control| FS Access Control]]<br />
<br />
Final FS permissions are stored as (ACI0_perms & ACID_perms). Will panic(svcBreak) when buffer sizes from ipc-rawdata are invalid.<br />
<br />
== UnregisterProgram ==<br />
Takes a pid. Removes registered FS permissions for that PID.<br />
<br />
== SetEnabledProgramVerification ==<br />
Seems to sets a global flag to inputval & 1.<br />
<br />
When the flag is zero, it will set ret=0 instead of ret={error} when verifying the fixed-key [[NPDM]] ACID signature fails. This also skips verifying the [[NCA_Format|NCA Header]] signature using the ACID key. Note that if verifying the fixed-key ACID signature is successful, and verifying the ACID-key NCA header signature fails, it will throw an error and abort.<br />
<br />
= fsp-srv =<br />
This is "nn::fssrv::sf::IFileSystemProxy".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [1.0.0] [[#OpenFileSystem]]<br />
|-<br />
| 1 || [[#SetCurrentProcess]]<br />
|-<br />
| 2 || OpenDataFileSystemByCurrentProcess<br />
|-<br />
| 7 || [2.0.0+] [[#OpenFileSystemWithPatch]]<br />
|-<br />
| 8 || [2.0.0+] [[#OpenFileSystemWithId]]<br />
|-<br />
| 9 || [3.0.0+] OpenDataFileSystemByApplicationId<br />
|-<br />
| 11 || [[#OpenBisFileSystem]]<br />
|-<br />
| 12 || [[#OpenBisStorage]]<br />
|-<br />
| 13 || InvalidateBisCache<br />
|-<br />
| 17 || OpenHostFileSystem<br />
|-<br />
| 18 || OpenSdCardFileSystem<br />
|-<br />
| 19 || [2.0.0+] FormatSdCardFileSystem<br />
|-<br />
| 21 || [[#DeleteSaveDataFileSystem]]<br />
|-<br />
| 22 || [[#CreateSaveDataFileSystem]]<br />
|-<br />
| 23 || [[#CreateSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 24 || RegisterSaveDataFileSystemAtomicDeletion<br />
|-<br />
| 25 || [2.0.0+] DeleteSaveDataFileSystemBySaveDataSpaceId<br />
|-<br />
| 26 || [2.0.0+] FormatSdCardDryRun<br />
|-<br />
| 27 || [2.0.0+] IsExFatSupported<br />
|-<br />
| 28 || [4.0.0+] DeleteSaveDataFileSystemBySaveDataAttribute<br />
|-<br />
| 30 || [[#OpenGameCardStorage]]<br />
|-<br />
| 31 || [[#OpenGameCardFileSystem]]<br />
|-<br />
| 32 || [3.0.0+] ExtendSaveDataFileSystem<br />
|-<br />
| 33 || [5.0.0+] DeleteCacheStorage<br />
|-<br />
| 34 || [5.0.0+] GetCacheStorageSize<br />
|-<br />
| 51 || [[#OpenSaveDataFileSystem]]<br />
|-<br />
| 52 || [[#OpenSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 53 || [2.0.0+] OpenReadOnlySaveDataFileSystem<br />
|-<br />
| 57 || [3.0.0+] ReadSaveDataFileSystemExtraDataBySaveDataSpaceId<br />
|-<br />
| 58 || ReadSaveDataFileSystemExtraData<br />
|-<br />
| 59 || [2.0.0+] WriteSaveDataFileSystemExtraData<br />
|-<br />
| 60 || [[#OpenSaveDataInfoReader]]<br />
|-<br />
| 61 || [[#OpenSaveDataInfoReaderBySaveDataSpaceId]]<br />
|-<br />
| 62 || [5.0.0+] OpenCacheStorageList<br />
|-<br />
| 64 || [5.0.0+] OpenSaveDataInternalStorageFileSystem<br />
|-<br />
| 65 || [5.0.0+] UpdateSaveDataMacForDebug<br />
|-<br />
| 66 || [5.0.0+] WriteSaveDataFileSystemExtraData2<br />
|-<br />
| 80 || OpenSaveDataMetaFile<br />
|-<br />
| 81 || [4.0.0+] OpenSaveDataTransferManager<br />
|-<br />
| 82 || [5.0.0+] OpenSaveDataTransferManagerVersion2<br />
|-<br />
| 100 || OpenImageDirectoryFileSystem<br />
|-<br />
| 110 || [[#OpenContentStorageFileSystem]]<br />
|-<br />
| 200 || OpenDataStorageByCurrentProcess<br />
|-<br />
| 201 || [3.0.0+] OpenDataStorageByProgramId<br />
|-<br />
| 202 || [[#OpenDataStorageByDataId]]<br />
|-<br />
| 203 || OpenPatchDataStorageByCurrentProcess<br />
|-<br />
| 400 || [[#OpenDeviceOperator]]<br />
|-<br />
| 500 || [[#OpenSdCardDetectionEventNotifier]]<br />
|-<br />
| 501 || [[#OpenGameCardDetectionEventNotifier]]<br />
|-<br />
| 510 || [5.0.0+] OpenSystemDataUpdateEventNotifier<br />
|-<br />
| 511 || [5.0.0+] NotifySystemDataUpdateEvent<br />
|-<br />
| 600 || [1.0.0-3.0.2] SetCurrentPosixTime<br />
|-<br />
| 601 || QuerySaveDataTotalSize<br />
|-<br />
| 602 || [[#VerifySaveDataFileSystem]]<br />
|-<br />
| 603 || CorruptSaveDataFileSystem<br />
|-<br />
| 604 || CreatePaddingFile<br />
|-<br />
| 605 || DeleteAllPaddingFiles<br />
|-<br />
| 606 || [2.0.0+] GetRightsId<br />
|-<br />
| 607 || [2.0.0+] RegisterExternalKey<br />
|-<br />
| 608 || [2.0.0+] UnregisterAllExternalKey<br />
|-<br />
| 609 || [2.0.0+] GetRightsIdByPath<br />
|-<br />
| 610 || [3.0.0+] GetRightsIdAndKeyGenerationByPath<br />
|-<br />
| 611 || [4.0.0+] SetCurrentPosixTimeWithTimeDifference<br />
|-<br />
| 612 || [4.0.0+] GetFreeSpaceSizeForSaveData<br />
|-<br />
| 613 || [4.0.0+] VerifySaveDataFileSystemBySaveDataSpaceId<br />
|-<br />
| 614 || [4.0.0+] CorruptSaveDataFileSystemBySaveDataSpaceId<br />
|-<br />
| 615 || [5.0.0+] QuerySaveDataInternalStorageTotalSize<br />
|-<br />
| 620 || [2.0.0+] [[#SetSdCardEncryptionSeed]]<br />
|-<br />
| 630 || [4.0.0+] SetSdCardAccessibility<br />
|-<br />
| 631 || [4.0.0+] IsSdCardAccessible<br />
|-<br />
| 640 || [4.0.0+] IsSignedSystemPartitionOnSdCardValid<br />
|-<br />
| 700 || [5.0.0+] OpenAccessFailureResolver<br />
|-<br />
| 701 || [5.0.0+] GetAccessFailureDetectionEvent<br />
|-<br />
| 702 || [5.0.0+] IsAccessFailureDetected<br />
|-<br />
| 710 || [5.0.0+] ResolveAccessFailure<br />
|-<br />
| 720 || [5.0.0+] AbandonAccessFailure<br />
|-<br />
| 800 || [2.0.0+] GetAndClearFileSystemProxyErrorInfo<br />
|-<br />
| 1000 || SetBisRootForHost<br />
|-<br />
| 1001 || SetSaveDataSize<br />
|-<br />
| 1002 || SetSaveDataRootPath<br />
|-<br />
| 1003 || DisableAutoSaveDataCreation<br />
|-<br />
| 1004 || [[#SetGlobalAccessLogMode]]<br />
|-<br />
| 1005 || [[#GetGlobalAccessLogMode]]<br />
|-<br />
| 1006 || [[#OutputAccessLogToSdCard]]<br />
|-<br />
| 1007 || [4.0.0+] RegisterUpdatePartition<br />
|-<br />
| 1008 || [4.0.0+] OpenRegisteredUpdatePartition<br />
|-<br />
| 1009 || [4.0.0+] GetAndClearMemoryReportInfo<br />
|-<br />
| 1010 || [5.1.0+]<br />
|-<br />
| 1100 || [4.0.0+] OverrideSaveDataTransferTokenSignVerificationKey<br />
|}<br />
<br />
== Permissions ==<br />
Every time permissions are checked, the process registration [[#fsp-pr]] is loaded using the session processID. The permission data is populated with data from the [[NPDM]].<br />
<br />
If the processID is <= 6 (which happens only for built-in sysmodules), it will use a hardcoded registration data. The default mask in this case is 0x8000000000000000.<br />
<br />
Note that the functions check whether or not at least one bit is set in the mask. This means that, you don't need to set 0xFFFFFFFFFFFFFFFF to get all permissions: it suffices to set 0x8000000000000000.<br />
<br />
If the code were to request an invalid input type, panic. But this never happens.<br />
<br />
=== RwPermissions ===<br />
{| class="wikitable" border="1"<br />
|-<br />
! Type(s) || Mask || Name || Value || Used by<br />
|-<br />
| 0x0 || 0x8000000000000801 || MountLogo || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x1 || 0x8000000000000801 || MountContentMeta || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x2 || 0x8000000000000801 || MountContentControl || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x3 || 0x8000000000000801 || MountContentManual || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x4 || 0x8000000000000801 || MountContentData || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x5 || 0x8000000000000801 || MountApplicationPackage || 1 || [[#OpenFileSystem]], [[#OpenFileSystemWithPatch]], [[#OpenFileSystemWithId]]<br />
|-<br />
| 0x6 || 0x8000000000000000 || || 3 ||<br />
|-<br />
| 0x7 || 0x8000000000000800 || ContentStorageAccess || 3 || [[#OpenContentStorageFileSystem]]<br />
|-<br />
| 0x8 || 0x8000000000001000 || ImageDirectoryAccess || 3 || [[#OpenImageDirectoryFileSystem]]<br />
|-<br />
| 0x9 || 0x8000000000000084 || OpenBisFileSystemType28, OpenBisFileSystemType32 || 3 || [[#OpenBisFileSystem]]<br />
|-<br />
| 0xA || 0x8000000000000080 || OpenBisFileSystemType29 || 3 || [[#OpenBisFileSystem]]<br />
|-<br />
| 0xB || 0x8000000000008080 || OpenBisFileSystemType30 || 3 || [[#OpenBisFileSystem]]<br />
|-<br />
| 0xC || 0x8000000000008080 || OpenBisFileSystemType31 || 3 || [[#OpenBisFileSystem]]<br />
|-<br />
| 0xD || 0x8000000000000080 || || 3 ||<br />
|-<br />
| 0xE || 0x8000000000000080 ([1.0.0-2.3.0] 0xC000000000200000) || OpenBisFileSystemType33 || 3 || [[#OpenBisFileSystem]]<br />
|-<br />
| 0xF || 0xC000000000200000 ([1.0.0-2.3.0] 0x8000000000000010) || SdCardAccess || 3 || [[#OpenSdCardFileSystem]]<br />
|-<br />
| 0x10 || 0x8000000000000010 ([1.0.0-2.3.0] 0x8000000000040020) || GameCardUser || 3 || [[#OpenGameCardFileSystem]]<br />
|-<br />
| 0x11 || 0x8000000000040020 ([1.0.0-2.3.0] 0x8000000000000028) || SaveDataAccess0 || 3 || [[#OpenSaveDataFileSystem]]<br />
|-<br />
| 0x12 || 0x8000000000000028 ([1.0.0-2.3.0] 0x8000000000000020) || SystemSaveDataAccess0 || 3 || [[#OpenSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 0x13 || 0x8000000000000020 || SaveDataAccess1 || 3 || [[#OpenSaveDataFileSystem]]<br />
|-<br />
| 0x14 || 0x8000000000000020 ([1.0.0-2.3.0] 0x8000000000010082) || SystemSaveDataAccess1 || 3 || [[#OpenSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 0x15 || 0x8000000000010082 ([1.0.0-2.3.0] 0x8000000000010080) || BisPartition0 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x16 || 0x8000000000010080 || BisPartition10 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x17 || 0x8000000000000080 ([1.0.0-2.3.0] 0x8000000000010080) || BisPartition20 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x18 || 0x8000000000010080 || BisPartition21 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x19 || 0x8000000000010080 || BisPartition22 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1A || 0x8000000000010080 || BisPartition23 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1B || 0x8000000000010080 || BisPartition24 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1C || 0x8000000000010080 || BisPartition25 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1D || 0x8000000000010080 ([1.0.0-2.3.0] 0x8000000000000084) || BisPartition26 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1E || 0x8000000000000084 || BisPartition27 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x1F || 0x8000000000000084 ([1.0.0-2.3.0] 0x8000000000000080) || BisPartition28 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x20 || 0x8000000000000080 || BisPartition29 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x21 || 0x8000000000000080 || BisPartition30 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x22 || 0x8000000000000080 || BisPartition31 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x23 || 0x8000000000000080 ([1.0.0-2.3.0] 0xC000000000200000) || BisPartition32 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x24 || 0x8000000000000080 ([1.0.0-2.3.0] 0x8000000000000100) || BisPartition33 || 3 || [[#OpenBisStorage]]<br />
|-<br />
| 0x25 || 0xC000000000200000 ([1.0.0-2.3.0] 0x8000000000100008) || || ||<br />
|-<br />
| 0x26 || 0x8000000000000100 ([1.0.0-2.3.0] 0xC000000000400000) || GameCard_System || 3 || [[#OpenGameCardStorage]], [[#EraseGameCard]] (bit1), [[#WriteToGameCard]] (bit1), [[#GetGameCardErrorInfo]] (bit1), [[#EraseAndWriteParamDirectly]] (bit1), [[#ReadParamDirectly]] (bit1), [[#ForceEraseGameCard]] (bit1)<br />
|-<br />
| [3.0.0+] 0x27 || 0x8000000000100008 || MountContent_System || 1 || [[#OpenFileSystem]], [[#OpenDataStorageByDataId]]<br />
|-<br />
| [3.0.0+] 0x28 || 0xC000000000400000 || HostAccess || 3 || [[#OpenHostFileSystem]]<br />
|-<br />
| [4.0.0+] 0x29 || 0x8000000000010000 || RegisteredUpdatePartitionAccess || 1 || [[#OpenRegisteredUpdatePartition]]<br />
|-<br />
| [5.0.0+] 0x2A || 0x8000000000000000 || SaveDataInternalStorageAccess || 3 || [[#OpenSaveDataInternalStorageFileSystem]]<br />
|}<br />
<br />
=== BoolPermissions ===<br />
{| class="wikitable" border="1"<br />
|-<br />
! Type(s) || Mask || Name || Used by<br />
|-<br />
| 0x0 || 0x8000000000000080 || BisCache || [[#InvalidateBisCache]]<br />
|-<br />
| 0x1 || 0x8000000000000080 || EraseMmc || [[#EraseMmc]]<br />
|-<br />
| 0x2 || 0x8000000000000010 || GameCardCertificate || [[#GetGameCardDeviceCertificate]]<br />
|-<br />
| 0x3 || 0x8000000000000010 || GameCardIdSet || [[#GetGameCardIdSet]]<br />
|-<br />
| 0x4 || 0x8000000000000200 || GameCardDriver || [[#FinalizeGameCardDriver]]<br />
|-<br />
| 0x5 || 0x8000000000000200 || GameCardAsic || [[#GetGameCardAsicInfo]]<br />
|-<br />
| 0x6 || 0x8000000000002020 || SaveDataCreate || [[#CreateSaveDataFileSystem]]<br />
|-<br />
| 0x7 || 0x8000000000000060 || SaveDataDelete0 || [[#DeleteSaveDataFileSystem]], [[#RegisterSaveDataFileSystemAtomicDeletion]]<br />
|-<br />
| 0x8 || 0x8000000000000028 || SystemSaveDataCreate0 || [[#CreateSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 0x9 || 0x8000000000000020 || SystemSaveDataCreate1 || [[#CreateSaveDataFileSystemBySystemSaveDataId]]<br />
|-<br />
| 0xA || 0x8000000000004028 || SaveDataDelete1 || [[#DeleteSaveDataFileSystem]], [[#RegisterSaveDataFileSystemAtomicDeletion]]<br />
|-<br />
| 0xB || 0x8000000000000060 || SaveDataInfoReader0 || [[#OpenSaveDataInfoReaderBySaveDataSpaceId]], [[#OpenSaveDataInfoReader]]<br />
|-<br />
| 0xC || 0x8000000000004020 || SaveDataInfoReader1 || [[#OpenSaveDataInfoReaderBySaveDataSpaceId]], [[#OpenSaveDataInfoReader]]<br />
|-<br />
| 0xD || 0x8000000000020000 || SaveDataMeta || [[#OpenSaveDataMetaFile]]<br />
|-<br />
| 0xE || 0x8000000000000400 || PosixTime || [[#SetCurrentPosixTime]], [[#SetCurrentPosixTimeWithTimeDifference]]<br />
|-<br />
| 0xF || 0x8000000000004060 || SaveDataExtraData_Read || [[#ReadSaveDataFileSystemExtraData]]<br />
|-<br />
| 0x10 || 0x8000000000080000 || GlobalAccessMode || [[#SetGlobalAccessMode]]<br />
|-<br />
| 0x11 || 0x8000000000080000 || SpeedEmulationMode || [[#SetSpeedEmulationMode]]<br />
|-<br />
| 0x12 || Invalid || || <br />
|-<br />
| 0x13 || 0xC000000000800000 || PaddingFiles || [[#CreatePaddingFile]], [[#DeleteAllPaddingFiles]] <br />
|-<br />
| 0x14 || 0xC000000001000000 || SaveDataCorrupt0 || [[#CorruptSaveDataFileSystem]], [[#CorruptSaveDataFileSystemBySaveDataSpaceId]]<br />
|-<br />
| 0x15 || 0x8000000001000060 ([1.0.0-4.1.0] 0xC000000002000000) || SaveDataCorrupt1 || [[#CorruptSaveDataFileSystem]], [[#CorruptSaveDataFileSystemBySaveDataSpaceId]]<br />
|-<br />
| [2.0.0+] 0x16 || 0x8000000000000060 ([1.0.0-4.1.0] 0x8000000004000000) || SaveDataVerify || [[#VerifySaveDataFileSystem]], [[#VerifySaveDataFileSystemBySaveDataSpaceId]]<br />
|-<br />
| [2.0.0+] 0x17 || 0xC000000002000000 ([1.0.0-4.1.0] 0x8000000008000000) || SaveData_SystemManagement || [[#CreateSaveDataFileSystem]], [[#OpenSaveDataFileSystem]], [[#SetSaveDataRootPath]]<br />
|-<br />
| [2.0.0+] 0x18 || 0x8000000004000000 ([1.0.0-4.1.0] 0x8000000010000000) || SdCardFormat || [[#FormatSdCardFileSystem]]<br />
|-<br />
| [2.0.0+] 0x19 || 0x8000000008000000 ([1.0.0-4.1.0] 0x8000000000000800) || RightsId || [[#GetRightsId]], [[#GetRightsIdAndKeyGenerationByPath]], [[#GetRightsIdByPath]]<br />
|-<br />
| [2.0.0+] 0x1A || 0x8000000010000000 ([1.0.0-4.1.0] 0x8000000000004020) || ExternalKey || [[#RegisterExternalKey]], [[#UnregisterAllExternalKey]]<br />
|-<br />
| [3.0.0+] 0x1B || 0x8000000000000800 ([1.0.0-4.1.0] 0x8000000000002020) || SdCardEncryptionSeed || [[#SetSdCardEncryptionSeed]]<br />
|-<br />
| [3.0.0+] 0x1C || 0x8000000000004020 ([1.0.0-4.1.0] 0x8000000000000028) || SaveDataExtraData_Write0 || [[#WriteSaveDataFileSystemExtraData]], [[#WriteSaveDataFileSystemExtraData2]]<br />
|-<br />
| [4.0.0+] 0x1D || 0x8000000000000000 ([1.0.0-4.1.0] 0x8000000020000000) || SaveDataExtraData_Write1 || [[#WriteSaveDataFileSystemExtraData]], [[#WriteSaveDataFileSystemExtraData2]]<br />
|-<br />
| [4.0.0+] 0x1E || 0x8000000000002020 ([1.0.0-4.1.0] 0x8000000040000000) || SaveDataExtend0 || [[#ExtendSaveDataFileSystem]]<br />
|-<br />
| [4.0.0+] 0x1F || 0x8000000000000028 ([1.0.0-4.1.0] 0x8000000000000000) || SaveDataExtend1 || [[#ExtendSaveDataFileSystem]]<br />
|-<br />
| [4.0.0+] 0x20 || 0x8000000020000000 ([1.0.0-4.1.0] 0x8000000000000000) || UpdatePartitionRegister || [[#RegisterUpdatePartition]]<br />
|-<br />
| [5.0.0+] 0x21 || 0x8000000040000000 || SaveDataTransfer || [[#OpenSaveDataTransferManager]]<br />
|-<br />
| [5.0.0+] 0x22 || 0x0000000080000002 || SaveDataTransferVersion2 || [[#OpenSaveDataTransferManagerVersion2]]<br />
|-<br />
| [5.0.0+] 0x23 || 0x8000000000000000 || MmcPatrol || [[#SuspendMmcPatrol]], [[#ResumeMmcPatrol]]<br />
|-<br />
| [5.0.0+] 0x24 || 0x8000000000000000 || SaveDataTransferKey || [[#OverrideSaveDataTransferTokenSignVerificationKey]]<br />
|-<br />
| [5.0.0+] 0x25 || 0x8000000080200000 || SdCardDetectionEventNotifier || [[#OpenSdCardDetectionEventNotifier]]<br />
|-<br />
| [5.0.0+] 0x26 || 0x8000000080000110 || GameCardDetectionEventNotifier || [[#OpenGameCardDetectionEventNotifier]]<br />
|-<br />
| [5.0.0+] 0x27 || 0x8000000000100008 || SystemDataUpdateEventNotifier || [[#OpenSystemDataUpdateEventNotifier]]<br />
|-<br />
| [5.0.0+] 0x28 || 0x8000000080010000 || SystemDataUpdateEventNotify || [[#NotifySystemDataUpdateEvent]]<br />
|-<br />
| [5.0.0+] 0x29 || 0x0000000080000001 || AccessFailureResolver || [[#OpenAccessFailureResolver]]<br />
|-<br />
| [5.0.0+] 0x2A || 0x0000000080000001 || AccessFailureDetectionEvent || [[#GetAccessFailureDetectionEvent]]<br />
|-<br />
| [5.0.0+] 0x2B || 0x0000000080000001 || AccessFailureDetected || [[#IsAccessFailureDetected]]<br />
|-<br />
| [5.0.0+] 0x2C || 0x0000000080000001 || AccessFailureResolve || [[#ResolveAccessFailure]]<br />
|-<br />
| [5.0.0+] 0x2D || 0x0000000080000001 || AccessFailureAbandon || [[#AbandonAccessFailure]]<br />
|-<br />
| [5.0.0+] 0x2E || 0x8000000040000000 || SaveDataInternalStorageTotalSize || [[#QuerySaveDataInternalStorageTotalSize]] <br />
|-<br />
| [5.0.0+] 0x2F || 0x8000000080200000 || SdCardAccessibility || [[#SetSdCardAccessibility]]<br />
|-<br />
| [5.1.0+] 0x30 || 0x8000000080080000 || || <br />
|}<br />
<br />
== OpenFileSystem ==<br />
Takes a type-0x19 input buffer (ContentPath) and a [[#FileSystemType]] as parameters. Returns an [[#IFileSystem]].<br />
<br />
[2.0.0+] This function was removed.<br />
<br />
== SetCurrentProcess ==<br />
Takes a pid-descriptor.<br />
<br />
== OpenFileSystemWithPatch ==<br />
Takes an input [[#FileSystemType]] and an u64 title-id. Returns an [[#IFileSystem]].<br />
<br />
Web-applet loads the [[#FileSystemType]] (which must be '''ContentManual''') from u32_table[inparam].<br />
<br />
Note: web-applet strings refer to both this cmd and [[#OpenFileSystemWithId]] as "MountContent", but official nn_sf_sync symbols use "OpenXX" names.<br />
<br />
== OpenFileSystemWithId ==<br />
Takes a type-0x19 input buffer, an [[#FileSystemType]] and an u64 title-id. Returns an [[#IFileSystem]].<br />
<br />
The [[#IFileSystem]] must be '''ContentMeta''' if the NCA type is 0 (control).<br />
<br />
The input buffer is the output string path from [[NS_Services#GetApplicationContentPath|GetApplicationContentPath]].<br />
<br />
May return errors when attempting to access NCA-paths for an update-title with a gamecard, when the gamecard isn't inserted. May return error 0x7D402 in some cases with update-titles. Non-val2 in32 values with NCA-type1 are unusable, even for normal titles.<br />
<br />
The official "MountApplicationPackage" func uses this with in64=0 and [[#FileSystemType]] '''ApplicationPackage'''.<br />
<br />
After the [[#FileSystemType]] specific permissions are checked, it then gets the func retval for permissions-type 0x25 and func0.<br />
<br />
When [[#FileSystemType]] is '''ContentMeta''', it uses in64=0xffffffffffffffff internally, otherwise it checks if in64 is set to 0xffffffffffffffff then throws an error if so. When the in64 used internally is not 0xffffffffffffffff, it's compared with the NCA titleID, then an error is thrown on mismatch.<br />
<br />
== OpenBisFileSystem ==<br />
Takes a type-0x19 input buffer string and a u32 [[Flash_Filesystem|Bis partitionID]]. Official user-process code sets instr[0] = 0 normally. Returns an [[#IFileSystem]].<br />
<br />
Only partitionIDs for FAT partitions are usable with this, otherwise error 0x2EE202 is returned. Seems to be about the same as [[#OpenBisStorage]] except this mounts the partition filesystem instead of allowing direct access to the partition sectors.<br />
<br />
== OpenBisStorage ==<br />
Takes a u32 partition ID, returns 0x2EE202 for partitions which do not exist, 0x320002 for partitions which cannot be opened and a valid [[#IStorage]] handle otherwise.<br />
<br />
== InvalidateBisCache ==<br />
Seems to invalidate the Bis cache for MBR/GPT after overwriting that data via the OpenBisStorage IStorage. Used by [[SystemInitializer]].<br />
<br />
== DeleteSaveDataFileSystem ==<br />
Takes an input u64.<br />
<br />
== CreateSaveDataFileSystem ==<br />
Takes a 0x40-byte Save-struct entry, a 0x40-byte SaveCreate-struct entry, and a 0x10-byte input struct.<br />
<br />
Only the first 0x5-bytes in the 0x10-byte struct are initialized: all-zero when automatically creating savedata during savecommon mount by official user-processes. In the dedicated save-creation code in official user-processes: +0 u32 = 0x40060, +4 u8 = 1.<br />
<br />
Creates regular savedata.<br />
<br />
== CreateSaveDataFileSystemBySystemSaveDataId ==<br />
Takes a 0x40-byte Save-struct entry and a 0x40-byte SaveCreate-struct entry.<br />
<br />
Creates savedata in the SYSTEM [[Flash_Filesystem|NAND]] partition.<br />
<br />
== OpenGameCardStorage ==<br />
Takes two input u32s (gamecard handle, partition ID), and returns an [[#IStorage]] for the [[Gamecard_Format|partition]].<br />
<br />
== OpenGameCardFileSystem ==<br />
Takes two input u32s, with the second u32 located at +4 in rawdata after the first u32. Returns an [[#IFileSystem]].<br />
<br />
Mounts a [[Gamecard_Partition|gamecard partition]].<br />
<br />
== OpenSaveDataFileSystem ==<br />
Takes an input u8 [[#SaveDataSpaceId]] and a 0x40-byte Save-struct entry. Official user-process code is only known to use value 1 for the u8.<br />
<br />
Returns an [[#IFileSystem]].<br />
<br />
Permissions aren't checked until the specified save is successfully found.<br />
<br />
Only one process (specifically only one [[#IFileSystem]] session) can mount a given savedata at any given time (this includes SystemSaveData).<br />
<br />
== OpenSaveDataFileSystemBySystemSaveDataId ==<br />
Takes an input u8 [[#SaveDataSpaceId]] and a 0x40-byte Save-struct entry. Web-applet only uses value0 for the input u8.<br />
<br />
Returns an [[#IFileSystem]].<br />
<br />
Mounts savedata in the SYSTEM [[Flash_Filesystem|NAND]] partition.<br />
<br />
== OpenSaveDataInfoReader ==<br />
No input, returns an output [[#ISaveDataInfoReader]].<br />
<br />
== OpenSaveDataInfoReaderBySaveDataSpaceId ==<br />
Takes an input u8 [[#SaveDataSpaceId]], returns an output [[#ISaveDataInfoReader]].<br />
<br />
== OpenContentStorageFileSystem ==<br />
Takes a [[#ContentStorageId]]. Invalid values return 0x2EE202.<br />
<br />
Returns an [[#IFileSystem]] with NCA files. The read data from these files is identical to the data read by [[Content_Manager_services#ReadEntryRaw]].<br />
<br />
== OpenDataStorageByDataId ==<br />
Takes a [[#StorageId]] and a TitleID.<br />
<br />
Returns a [[IPC_Marshalling#Domain_message|domain object ID]] implementing the [[#IStorage]] interface for data archives.<br />
<br />
== OpenDeviceOperator ==<br />
This command returns a session to a port implementing the [[#IDeviceOperator]] interface.<br />
<br />
== OpenSdCardDetectionEventNotifier ==<br />
This command returns a session to a port implementing the [[#IEventNotifier]] interface.<br />
<br />
== OpenGameCardDetectionEventNotifier ==<br />
This command returns a session to a port implementing the [[#IEventNotifier]] interface.<br />
<br />
== VerifySaveDataFileSystem ==<br />
Takes an unknown input u64 and a type-0x6 output buffer.<br />
<br />
The input u64 high-byte must be non-zero, otherwise an [[Error_codes|error]] is returned(0xE02).<br />
<br />
== SetSdCardEncryptionSeed ==<br />
Takes in the 0x10 byte SD card encryption seed, and loads it into FS-module state.<br />
<br />
[[NS_Services|NS]]-module reads the 0x10 bytes from SdCard:/Nintendo/Contents/private, and compares them to the first 0x10 bytes of the ns_appman:/private (in [[Flash_Filesystem#System_Savegames|system savedata]] 0x8000000000000043). If they match, NS calls this command using bytes 0x10-0x20 from ns_appman:/private. The rest of this file (0x1F0 bytes total) is (usually/always?) all-zero.<br />
<br />
== SetGlobalAccessLogMode ==<br />
Takes an input u32.<br />
<br />
== GetGlobalAccessLogMode ==<br />
Returns an output u32.<br />
<br />
GlobalAccessLogMode is normally 0.<br />
<br />
== OutputAccessLogToSdCard ==<br />
Takes a type-0x5 input buffer.<br />
<br />
The input buffer is the string to output to the log. User-processes normally include a newline at the end.<br />
<br />
User-processes only use this when the value previously loaded from [[#GetGlobalAccessLogMode]] has bit1 set.<br />
<br />
When bit1 in GlobalAccessLogMode is clear, FS-module will just return 0 for OutputAccessLogToSdCard. However even with that set the log doesn't show up SD, unknown why.<br />
<br />
The input buffer is written to the "$FsAccessLog:/FsAccessLog.txt" file, where "$FsAccessLog" is the SD-card mount-name. It's written to the current end of the file(appended).<br />
<br />
= IStorage =<br />
This is "nn::fssrv::sf::IStorage".<br />
<br />
This is the interface for a raw device, usually a block device.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments<br />
|-<br />
| 0 || Read || Takes a type-0x46 buffer, an offset and length <br />
|-<br />
| 1 || Write || Takes a type-0x45 buffer, an offset and length <br />
|-<br />
| 2 || Flush || None<br />
|-<br />
| 3 || SetSize || Takes a size<br />
|-<br />
| 4 || GetSize || None<br />
|-<br />
| 5 || [4.0.0+] OperateRange ||<br />
|}<br />
<br />
= IFileSystem =<br />
This is "nn::fssrv::sf::IFileSystem".<br />
<br />
There are two main implementations of this interface:<br />
<br />
* '''RomFS''': Filesystem implementation statically linked in the binary. Uses an [[#IStorage]] interface as underlying raw device.<br />
* '''IPC proxy''': Used for all non-RomFS filesystems. In this case, actual filesystem implementation is in the FS process.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || CreateFile<br />
|-<br />
| 1 || DeleteFile<br />
|-<br />
| 2 || CreateDirectory<br />
|-<br />
| 3 || DeleteDirectory<br />
|-<br />
| 4 || DeleteDirectoryRecursively<br />
|-<br />
| 5 || RenameFile<br />
|-<br />
| 6 || RenameDirectory<br />
|-<br />
| 7 || [[#GetEntryType]]<br />
|-<br />
| 8 || [[#OpenFile]]<br />
|-<br />
| 9 || [[#OpenDirectory]]<br />
|-<br />
| 10 || [[#Commit]]<br />
|-<br />
| 11 || [[#GetFreeSpaceSize]]<br />
|-<br />
| 12 || [[#GetTotalSpaceSize]]<br />
|-<br />
| 13 || [3.0.0+] [[#CleanDirectoryRecursively]]<br />
|-<br />
| 14 || [3.0.0+] GetFileTimeStampRaw<br />
|-<br />
| 15 || [4.0.0+] QueryEntry<br />
|}<br />
<br />
== GetEntryType ==<br />
Takes a type-0x9 input buffer for the path and returns [[#DirectoryEntryType]] as an output u32.<br />
<br />
== OpenFile ==<br />
Takes a type-0x19 input buffer for the path, and an u32 '''mode'''. '''mode''' controls how the file is opened, based on which bits are set:<br />
<br />
* When bit 0 is set, the file is Readable: you can use the Read operation.<br />
* When bit 1 is set, the file is Writable: you can use the Write operation.<br />
* When bit 2 is set, the file is Appendable: unless this bit is set, you will not be able to write beyond the end of a file (such writes will result in an error 0x307202)<br />
<br />
== OpenDirectory ==<br />
Takes a type-0x9 input buffer for the path and an u64 '''filter_flags'''. '''filter_flags''' controls what type of entries are read by the [[#IDirectory]]: bitmask 0x1 = directories, bitmask 0x2 = files.<br />
<br />
== Commit ==<br />
Like [https://3dbrew.org/wiki/FS:ControlArchive 3DS], this has to be used after writing to savedata for the changes to take affect.<br />
<br />
== GetFreeSpaceSize ==<br />
Takes a type-0x9 input buffer for the path and returns an output byte-size u64 for the total free space with this FS.<br />
<br />
== GetTotalSpaceSize ==<br />
Takes a type-0x9 input buffer for the path and returns an output byte-size u64 for the total space available with this FS(free+used).<br />
<br />
== CleanDirectoryRecursively ==<br />
Takes a type-0x9 input buffer for the path and clears the contents of the directory specified in the path.<br />
<br />
= IDirectory =<br />
This is "nn::fssrv::sf::IDirectory".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [[#Read]]<br />
|-<br />
| 1 || [[#GetEntryCount]]<br />
|}<br />
<br />
== Read ==<br />
Takes a type-0x6 output buffer. Returns an output u64(?) for the total number of read entries, this is 0 when no more entries are available.<br />
<br />
The output buffer contains the read array of [[#DirectoryEntry]]. This doesn't include entries for "." and "..".<br />
<br />
== GetEntryCount ==<br />
Returns an u64 for the total number of readable entries.<br />
<br />
= DirectoryEntry =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset || Size || Description<br />
|-<br />
| 0x0 || 0x300 || Path<br />
|-<br />
| 0x300 || 0x4 || ?<br />
|-<br />
| 0x304 || 0x1 || [[#DirectoryEntryType]]<br />
|-<br />
| 0x305 || 0x3 || Padding?<br />
|-<br />
| 0x308 || 0x8? || Filesize, 0 for directories.<br />
|}<br />
<br />
= DirectoryEntryType =<br />
s8 type: 0 = directory, 1 = file.<br />
<br />
= IFile =<br />
This is "nn::fssrv::sf::IFile".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || Read<br />
|-<br />
| 1 || Write<br />
|-<br />
| 2 || Flush<br />
|-<br />
| 3 || SetSize<br />
|-<br />
| 4 || GetSize<br />
|-<br />
| 5 || [4.0.0+] OperateRange<br />
|}<br />
<br />
= ISaveDataInfoReader =<br />
This is "nn::fssrv::sf::ISaveDataInfoReader".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [[#ReadSaveDataInfo]]<br />
|}<br />
<br />
== ReadSaveDataInfo ==<br />
Takes a type-0x6 output buffer. Returns an output u64 for total output entries. This buffer contains an array of [[#SaveDataInfo]].<br />
<br />
This is used to get [[#SaveDataInfo]] for all savedata on the system (or all savedata for the current [[#SaveDataSpaceId]]). When used multiple times, it will resume reading where it left off, until no more entries are available (in that case the out u64 is value 0).<br />
<br />
= IDeviceOperator =<br />
This is "nn::fssrv::sf::IDeviceOperator".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || IsSdCardInserted<br />
|-<br />
| 1 || GetSdCardSpeedMode<br />
|-<br />
| 2 || [2.0.0+] GetSdCardCid<br />
|-<br />
| 3 || [2.0.0+] GetSdCardUserAreaSize<br />
|-<br />
| 4 || [2.0.0+] GetSdCardProtectedAreaSize<br />
|-<br />
| 5 || [2.0.0+] GetAndClearSdCardErrorInfo<br />
|-<br />
| 100 || GetMmcCid<br />
|-<br />
| 101 || GetMmcSpeedMode<br />
|-<br />
| 110 || EraseMmc<br />
|-<br />
| 111 || GetMmcPartitionSize<br />
|-<br />
| 112 || [2.0.0+] GetMmcPatrolCount<br />
|-<br />
| 113 || [2.0.0+] GetAndClearMmcErrorInfo<br />
|-<br />
| 114 || [2.0.0+] GetMmcExtendedCsd<br />
|-<br />
| 115 || [4.0.0+] SuspendMmcPatrol<br />
|-<br />
| 116 || [4.0.0+] ResumeMmcPatrol<br />
|-<br />
| 200 || IsGameCardInserted<br />
|-<br />
| 201 || EraseGameCard<br />
|-<br />
| 202 || GetGameCardHandle<br />
|-<br />
| 203 || [[#GetGameCardUpdatePartitionInfo]]<br />
|-<br />
| 204 || FinalizeGameCardDriver<br />
|-<br />
| 205 || GetGameCardAttribute<br />
|-<br />
| 206 || GetGameCardDeviceCertificate<br />
|-<br />
| 207 || GetGameCardAsicInfo<br />
|-<br />
| 208 || GetGameCardIdSet<br />
|-<br />
| 209 || WriteToGameCard<br />
|-<br />
| 210 || SetVerifyWriteEnalbleFlag<br />
|-<br />
| 211 || GetGameCardImageHash<br />
|-<br />
| 212 || [2.0.0+] GetGameCardErrorInfo<br />
|-<br />
| 213 || [2.0.0+] EraseAndWriteParamDirectly<br />
|-<br />
| 214 || [2.0.0+] ReadParamDirectly<br />
|-<br />
| 215 || [2.0.0+] ForceEraseGameCard<br />
|-<br />
| 216 || [2.0.0+] GetGameCardErrorInfo2<br />
|-<br />
| 217 || [2.1.0+] GetGameCardErrorReportInfo<br />
|-<br />
| 218 || [3.0.0+] GetGameCardDeviceId<br />
|-<br />
| 300 || SetSpeedEmulationMode<br />
|-<br />
| 301 || GetSpeedEmulationMode<br />
|-<br />
| 400 || [5.0.0+] SuspendSdmmcControl<br />
|-<br />
| 401 || [5.0.0+] ResumeSdmmcControl<br />
|}<br />
<br />
== GetGameCardUpdatePartitionInfo ==<br />
Returns a titleID and the title-version for it.<br />
<br />
* Output u32 with ARMS-gamecard: title-version v131162. This is the title-version for [[2.1.0]], which is the sysupdate included with this gamecard. Launch-day gamecards return title-version v450.<br />
* Output u64 with ARMS-gamecard: titleID 0100000000000816.<br />
<br />
[[NS_Services|NS]] appears to only use this with [[Content_Manager_services#GetTitleIdInfo]] and [[Content_Manager_services#GetUpdateTitleList]] with storageid=nandsys, for checking whether a sysupdate is required.<br />
<br />
= IEventNotifier =<br />
This is "nn::fssrv::sf::IEventNotifier".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || GetEventHandle<br />
|}<br />
<br />
= FileSystemType =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value || Name<br />
|-<br />
| 0 || Invalid<br />
|-<br />
| 1 || Invalid<br />
|-<br />
| 2 || Logo<br />
|-<br />
| 3 || ContentControl<br />
|-<br />
| 4 || ContentManual<br />
|-<br />
| 5 || ContentMeta<br />
|-<br />
| 6 || ContentData<br />
|-<br />
| 7 || ApplicationPackage<br />
|}<br />
<br />
= StorageId =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value || Name<br />
|-<br />
| 0 || None<br />
|-<br />
| 1 || Host<br />
|-<br />
| 2 || GameCard<br />
|-<br />
| 3 || NandSystem<br />
|-<br />
| 4 || NandUser<br />
|-<br />
| 5 || SdCard<br />
|}<br />
<br />
= ContentStorageId =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value || Name<br />
|-<br />
| 0 || NandSystem<br />
|-<br />
| 1 || NandUser<br />
|-<br />
| 2 || SdCard<br />
|}<br />
<br />
= SaveDataSpaceId =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value || Name<br />
|-<br />
| 0 || NandSystem<br />
|-<br />
| 1 || NandUser<br />
|-<br />
| 2 || SdCard<br />
|-<br />
| 3 || [3.0.0+] TemporaryStorage<br />
|}<br />
<br />
Determines the storage where the savedata is stored.<br />
<br />
= SaveDataType =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value || Name<br />
|-<br />
| 0 || SystemSaveData<br />
|-<br />
| 1 || SaveData<br />
|-<br />
| 2 || BcatDeliveryCacheStorage<br />
|-<br />
| 3 || DeviceSaveData<br />
|-<br />
| 4 || [3.0.0+] TemporaryStorage<br />
|-<br />
| 5 || [3.0.0+] CacheStorage<br />
|}<br />
<br />
= ContentPath =<br />
These are the 0x300 paths to NCA files for the various filesystems FS can access, beginning with @. They're passed via X descriptors, and returned via various [[Location Resolver services|ncm/lr]] commands.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Path || Notes<br />
|-<br />
| @SystemContent ||<br />
|- <br />
| @UserContent ||<br />
|-<br />
| @SdCardContent ||<br />
|-<br />
| @CalibFile ||<br />
|-<br />
| @Safe ||<br />
|-<br />
| @User ||<br />
|-<br />
| @System ||<br />
|-<br />
| @Sdcard ||<br />
|-<br />
| @Host ||<br />
|-<br />
| @GcApp || Gamecard App partition (Partition 2)<br />
|-<br />
| @GcS00000001 || Gamecard Contents.<br />
|-<br />
| @upp || Gamecard update partition (Partition 0)<br />
|-<br />
| [4.0.0+] @RegUpdate || Registered update partition<br />
|}<br />
<br />
= Save Struct =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 0x8<br />
| 0 for SystemSaveData. SaveData: 0 can be used for accessing the savedata associated with the current FS session titleID, otherwise when set this is the titleID associated with the savedata to access.<br />
|-<br />
| 0x8<br />
| 0x10<br />
| userID for user-specific savedata(saveuser) when set, otherwise when zero this indicates the common savedata(savecommon). This is loaded from [[Account_services]].<br />
|-<br />
| 0x18<br />
| 0x8<br />
| u64 [[Flash_Filesystem|saveID]]. 0 for SaveData.<br />
|-<br />
| 0x20<br />
| 0x1<br />
| [[#SaveDataType]]<br />
|-<br />
| 0x21<br />
| 0x7<br />
| Padding<br />
|-<br />
| 0x28<br />
| 0x8<br />
| 0 for SystemSaveData/SaveData.<br />
|-<br />
| 0x30<br />
| 0x8<br />
| 0 for SystemSaveData/SaveData.<br />
|-<br />
| 0x38<br />
| 0x8<br />
| 0 for SystemSaveData/SaveData.<br />
|}<br />
<br />
Total size is 0x40-bytes.<br />
<br />
For DeviceSaveData, this struct is all-zero except for the [[#SaveDataType]] field.<br />
<br />
= SaveCreate Struct =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 0x8<br />
| [[Savegames|IVFC]] level4 size?<br />
|-<br />
| 0x8<br />
| 0x8<br />
| Same as offset 0x0 normally? Hard-coded to 0x80000 for BcatSaveData.<br />
|-<br />
| 0x10<br />
| 0x8<br />
| 0x4000 for SystemSaveData/SaveData/DeviceSaveData/BcatSaveData. [[Savegames|IVFC]] level4 block-size in bytes?<br />
|-<br />
| 0x18<br />
| 0x8<br />
| Official user-processes only uses 0 here for SystemSaveData/SaveData. For the dedicated save-creation code with SaveData/DeviceSaveData, this value comes from an input param with official user-processes. For BcatSaveData, this is the hard-coded [[Title_list|titleID]] of the bcat-sysmodule.<br />
|-<br />
| 0x20<br />
| 0x4<br />
| Written using an input param for official user-processes. Hard-coded 0 for BcatSaveData.<br />
|-<br />
| 0x24<br />
| 0x1<br />
| Official user-processes only uses 0 here for SystemSaveData, 1 for SaveData/DeviceSaveData/BcatSaveData.<br />
|-<br />
| 0x25<br />
| 0x1<br />
| 0 for SystemSaveData/SaveData.<br />
|-<br />
| 0x26<br />
| 0x1A<br />
| Not initialized for SystemSaveData/SaveData.<br />
|}<br />
<br />
Total size is 0x40-bytes.<br />
<br />
= DeviceSaveData =<br />
This is accessed using the same commands for SaveData with the same input u8, the only difference compared to SaveData is the Save-struct.<br />
<br />
= BcatSaveData =<br />
This is accessed using the same commands for SaveData with the same input u8. The Save-struct is the same as DeviceSaveData, except that the titleID field is set to <input titleID>. See above regarding SaveCreate-struct.<br />
<br />
The 0x10-byte struct passed to [[#CreateSaveDataFileSystem]] has the first 0x5-bytes set to all-zero.<br />
<br />
= SaveDataInfo =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 0x8<br />
| Unknown saveID<br />
|-<br />
| 0x8<br />
| 0x1<br />
| [[#SaveDataSpaceId]]<br />
|-<br />
| 0x9<br />
| 0x1<br />
| [[#SaveDataType]]<br />
|-<br />
| 0xA<br />
| 0x6<br />
| Padding?<br />
|-<br />
| 0x10<br />
| 0x10<br />
| userID<br />
|-<br />
| 0x20<br />
| 0x8<br />
| saveID, 0 for regular SaveData.<br />
|-<br />
| 0x28<br />
| 0x8<br />
| Application titleID, for regular SaveData.<br />
|-<br />
| 0x30<br />
| 0x8<br />
| Raw saveimage size<br />
|-<br />
| 0x38<br />
| 0x28<br />
| Unknown. Usually zeros?<br />
|}<br />
<br />
This is a 0x60-byte struct.<br />
<br />
[[Category:Services]]</div>
Rajkosto
https://switchbrew.org/w/index.php?title=NCM_services&diff=4839
NCM services
2018-07-18T23:16:56Z
<p>Rajkosto: Even better clarification of IContentMetaDatabase::Get</p>
<hr />
<div>NCM contains services for internal file path and content management.<br />
<br />
= Location Resolver services =<br />
== lr ==<br />
This is "nn::lr::ILocationResolverManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || OpenLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 1 || OpenRegisteredLocationResolver || None || <br />
|-<br />
| 2 || RefreshLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 3 || [2.0.0+] OpenAddOnContentLocationResolver || None ||<br />
|}<br />
<br />
The only sysmodules which use this service are [[Filesystem_services|FS]], [[Loader_services|Loader]], and [[NS_Services|NS]]. [[boot2]] has access but doesn't use it.<br />
<br />
=== ILocationResolver ===<br />
This is "nn::lr::ILocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [[#ResolveProgramPath]]<br />
|-<br />
| 1 || [[#RedirectProgramPath]]<br />
|-<br />
| 2 || [[#ResolveApplicationControlPath]]<br />
|-<br />
| 3 || [[#ResolveApplicationHtmlDocumentPath]]<br />
|-<br />
| 4 || [[#ResolveDataPath]]<br />
|-<br />
| 5 || [[#RedirectApplicationControlPath]]<br />
|-<br />
| 6 || [[#RedirectApplicationHtmlDocumentPath]]<br />
|-<br />
| 7 || [[#ResolveApplicationLegalInformationPath]]<br />
|-<br />
| 8 || [[#RedirectApplicationLegalInformationPath]]<br />
|-<br />
| 9 || [[#Refresh]]<br />
|-<br />
| 10 || [5.0.0+] [[#SetProgramNcaPath2]]<br />
|-<br />
| 11 || [5.0.0+] [[#ClearLocationResolver2]]<br />
|-<br />
| 12 || [5.0.0+] [[#DeleteProgramNcaPath]]<br />
|-<br />
| 13 || [5.0.0+] [[#DeleteControlNcaPath]]<br />
|-<br />
| 14 || [5.0.0+] [[#DeleteDocHtmlNcaPath]]<br />
|-<br />
| 15 || [5.0.0+] [[#DeleteInfoHtmlNcaPath]]<br />
|}<br />
<br />
If the supplied [[Filesystem_services#StorageId|StorageID]] is 1 (Host), a different set of internal functions is used to handle these commands. In this more restricted set of functions, GetControlNcaPath is stubbed and only returns error 0x608.<br />
<br />
The Get* commands load the [[Filesystem_services|ContentPath]] from linked-lists' [[#Location_List_Entry|entries]] in memory using the input TitleID. When the command fails to find an entry for the specified TitleID, 0x408 is returned for GetProgramNcaPath and 0xA08 is returned for the rest.<br />
<br />
The Set* commands always return 0 and add a new entry to the list. If a matching entry is found, it's removed first.<br />
<br />
==== ResolveProgramPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
==== RedirectProgramPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 0.<br />
<br />
==== ResolveApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== ResolveApplicationHtmlDocumentPath====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
==== ResolveDataPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== RedirectApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== RedirectApplicationHtmlDocumentPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ResolveApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
==== RedirectApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== Refresh ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 0.<br />
<br />
==== SetProgramNcaPath2 ====<br />
Same as [[#SetProgramNcaPath|SetProgramNcaPath]], but inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ClearLocationResolver2 ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 1.<br />
<br />
==== DeleteProgramNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteControlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteDocHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteInfoHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
=== IRegisteredLocationResolver ===<br />
This is "nn::lr::IRegisteredLocationResolver".<br />
<br />
This works like [[#ILocationResolver]], but only two types of NCA paths can be gotten/set. In addition, each type has a fallback path that can be set for a single title ID at a time.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveProgramPath || u64 TitleID + C descriptor || Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
|-<br />
| 1 || RegisterProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 0 fallback TID and path to the provided arguments.<br />
|-<br />
| 2 || UnregisterProgramPath || u64 TitleID || If the Type 0 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 3 || RedirectProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|-<br />
| 4 || [2.0.0+] ResolveHtmlDocumentPath || u64 TitleID + C descriptor ||<br />
|-<br />
| 5 || [2.0.0+] RegisterHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 1 fallback TID and path to the provided arguments.<br />
|-<br />
| 6 || [2.0.0+] UnregisterHtmlDocumentPath || u64 TitleID || If the Type 1 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 7 || [2.0.0+] RedirectHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|}<br />
<br />
=== IAddOnContentLocationResolver ===<br />
This is "nn::lr::IAddOnContentLocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveAddOnContentPath || u64 TitleID + C descriptor || <br />
|-<br />
| 1 || RegisterAddOnContentStorage || [[Filesystem_services#StorageId|StorageID]] + u64 TitleID || <br />
|-<br />
| 2 || UnregisterAllAddOnContentPath || None || Clears all registered titles here.<br />
|}<br />
<br />
=== Location List Entry ===<br />
Total size is 0x320 bytes. <br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset || Size || Description<br />
|-<br />
| 0x0 || 0x8|| Pointer to previous entry<br />
|-<br />
| 0x8 || 0x8|| Pointer to next entry<br />
|-<br />
| 0x10 || 0x8|| TitleID<br />
|-<br />
| 0x18 || 0x300 || [[Filesystem_services|ContentPath]]<br />
|-<br />
| 0x318 || 0x4 || Flag<br />
|-<br />
| 0x31C || 0x4 || Padding<br />
|}<br />
<br />
= Content Manager services =<br />
== ncm ==<br />
This is "nn::ncm::IContentManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || CreateContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 1 || CreateContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 2 || VerifyContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 3 || VerifyContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 4 || OpenContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 5 || OpenContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 6 || [1.0.0] CloseContentStorageForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentStorage->CloseAndFlushStorage().<br />
|-<br />
| 7 || [1.0.0] CloseContentMetaDatabaseForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentMetaDatabase->CloseMetaDatabase().<br />
|-<br />
| 8 || CleanupContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and deletes the associated savedata.<br />
|-<br />
| 9 || [2.0.0+] OpenContentStorage2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentStorage for the StorageID to be gotten with GetIContentStorage. Note: Name is not official.<br />
|-<br />
| 10 || [2.0.0+] CloseContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentStorage. Note: Name is not official.<br />
|-<br />
| 11 || [2.0.0+] OpenContentMetaDatabase2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentMetaDatabase for the StorageID to be gotten with GetIContentMetaDatabase. Note: Name is not official.<br />
|-<br />
| 12 || [2.0.0+] CloseContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentMetaDatabase. Note: Name is not official.<br />
|}<br />
<br />
=== IContentStorage ===<br />
This is "nn::ncm::IContentStorage".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage.<br />
|-<br />
| 1 || CreatePlaceHolder || Takes two [[#NcaID]]s, and a u64 filesize.<br />
|-<br />
| 2 || DeletePlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 3 || HasPlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 4 || WritePlaceHolder || Takes a [[#NcaID]], a u64-offset, and type 5 buffer. Writes the buffer to the file for the NcaID's placeholder path at the specified offset.<br />
|-<br />
| 5 || Register || Takes two [[#NcaID]]s, moves the Placeholder NCA content to the registered NCA path.<br />
|-<br />
| 6 || Delete || Takes a [[#NcaID]].<br />
|-<br />
| 7 || Has || Takes a [[#NcaID]].<br />
|-<br />
| 8 || GetPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 9 || GetPlaceHolderPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory.<br />
|-<br />
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory.<br />
|-<br />
| 12 || [[#GetContentCount]] ||<br />
|-<br />
| 13 || [[#ListContentId]] ||<br />
|-<br />
| 14 || [[#GetSize]] || <br />
|-<br />
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805.<br />
|-<br />
| 16 || [2.0.0+] RevertToPlaceHolder || Takes three 0x10-sized [[#NcaID]]s. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path.<br />
|-<br />
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#NcaID]], and a u64 size<br />
|-<br />
| 18 || [2.0.0+] [[#ReadContentIdFile]] ||<br />
|-<br />
| 19 || [2.0.0+] GetRightsIdFromPlaceHolderId || Gets the Rights ID for the [[#NcaID]]'s placeholder path.<br />
|-<br />
| 20 || [2.0.0+] GetRightsIdFromContentId || Gets the Rights ID for the [[#NcaID]]'s registered path<br />
|-<br />
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[#NcaID]], a u64 offset, and a type 5 buffer. On debug units, writes the buffer to the NCA's registered path. On retail units, this just aborts.<br />
|-<br />
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage.<br />
|-<br />
| 23 || [2.0.0+] GetTotalSpaceSize || Gets total space for the storage.<br />
|-<br />
| 24 || [3.0.0+] FlushStorage || Flushes resources for the storage without closing it.<br />
|-<br />
| 25 || [4.0.0+] || <br />
|-<br />
| 26 || [4.0.0+] || <br />
|}<br />
<br />
==== GeneratePlaceHolderId ====<br />
Generates a random [[#NcaID]] for use as a placeholder.<br />
<br />
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16);<br />
<br />
==== GetContentCount ====<br />
Writes the total number of entries which can be read by GetEntries, to cmdreply <SFCO_offset>+0x10.<br />
<br />
==== ListContentId====<br />
Takes an output buffer, u32 offset and gets all entries starting at that offset.<br />
Returns number of entries read.<br />
<br />
Each entry is a [[#NcaID]].<br />
<br />
The total read entries is exactly the same as the number of "<hex>.nca" directories in the storage FS(or at least under the "registered" directory?).<br />
<br />
==== GetSize ====<br />
Takes a [[#NcaID]] as input.<br />
<br />
Returns the total size readable by ReadEntryRaw. This is the same as the size-field in the [[NAX0]] "<NcaID>.nca/00" file.<br />
<br />
==== ReadContentIdFile ====<br />
Takes an output buffer, a [[#NcaID]] as input, and a u64 file offset.<br />
<br />
Reads plaintext NCA file contents from the Registered path for the NcaID.<br />
<br />
=== IContentMetaDatabase ===<br />
This is "nn::ncm::IContentMetaDatabase".<br />
<br />
Note the official name for Meta Record is "ContentMetaKey".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || Set || Takes a [[NCA#Meta_records|Meta Record]], a type-5 [[NCA#Content_records|Content Records]] buffer and a u64 size.<br />
|-<br />
| 1 || Get || Takes a [[NCA#Meta_records|Meta Record]], a type-6 buffer to write [[NCA#Content_records|Content Records]] to and a u64 size. Returns the actual number of bytes read into the buffer. First 8 bytes of the data is header (u16 numExtraDataBytes, numContentRecords, numMetaRecords, padding). After the header is numExtraDataBytes of additional data, after which follow content records and meta records. Set takes this same data as input.<br />
|-<br />
| 2 || Remove || Takes a [[NCA#Meta_records|Meta Record]], and removes the associated record.<br />
|-<br />
| 3 || GetContentIdByType || Takes a [[NCA#Meta_records|Meta Record]] and a u8 [[#Title_Types|Title Type]]. Returns a [[#NcaID]].<br />
|-<br />
| 4 || ListContentInfo || Takes a type-6 buffer to write [[NCA#Content_records|Content Record]] entries to, a [[NCA#Meta_records|Meta Record]], and a u32 index into the Content Record entries to start copying from. Returns a u32 entries_read.<br />
|-<br />
| 5 || List || Takes a type-6 buffer to write [[NCA#Meta_records|Meta Record]]s to, a u32 [[#Title_Types|Title Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Meta Records with low <= record->title_id <= high, and record->type == type. Returns u32 numEntriesTotal, numEntriesWritten. Additionally requires record->title_id == TID, if record->type is Application, Patch, Add-On, or Delta, otherwise, you can pass 0 for type to ignore the type and list them all in the range.<br />
|-<br />
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[NCA#Meta_records|Meta Record]] with the highest version field for that title id.<br />
|-<br />
| 7 || [[#ListApplication]] ||<br />
|-<br />
| 8 || Has || Takes a [[NCA#Meta_records|Meta Record]] and returns whether that record is present in the database.<br />
|-<br />
| 9 || HasAll || Takes a type-5 buffer containing [[NCA#Meta_records|Meta Records]] (code assumes there are size/sizeof(meta_record) records in the buffer), and returns whether all of those records are present in the database.<br />
|-<br />
| 10 || GetSize || Takes a [[NCA#Meta_records|Meta Record]], and returns the size of the associated [[NCA#Content_records|Content Records]].<br />
|-<br />
| 11 || GetRequiredSystemVersion || Takes a [[NCA#Meta_records|Meta Record]], and returns u32 from ContentRecords + 16 (only if the Meta record has type Application or Patch).<br />
|-<br />
| 12 || GetPatchId || Takes a [[NCA#Meta_records|Meta Record]], and returns the update title id for that record.<br />
|-<br />
| 13 || DisableForcibly || Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05.<br />
|-<br />
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#NcaID]]s.<br />
|-<br />
| 15 || Commit || Flushes the in-memory database to savedata.<br />
|-<br />
| 16 || HasContent || Takes a [[NCA#Meta_records|Meta Record]] and an [[#NcaID]]. Returns whether the content records for that meta record contain the NcaID.<br />
|-<br />
| 17 || ListContentMetaInfo || Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]].<br />
|-<br />
| 18 || GetAttributes || Takes a [[NCA#Meta_records|Meta Record]], and returns u8 from ContentRecords + 6.<br />
|-<br />
| 19 || [2.0.0+] GetRequiredApplicationVersion || Does the same thing as GetEntryUnknownRecordSize, but for AddOnContents.<br />
|-<br />
| 20 || [5.0.0+] ||<br />
|}<br />
<br />
==== ListApplication ====<br />
Each 24-byte entry (officially "ApplicationContentMetaKey") is as follows:<br />
[[NCA#Meta_records|meta_record]] meta_record;<br />
u64 base_title_id;<br />
<br />
This function takes in a type 6 buffer to write entries to, and a u8 "filter" [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer.<br />
<br />
This func returns a u32 num_entries_total, and a u32 num_entries_written.<br />
<br />
==== ReadEntryMetaRecords ====<br />
Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]] entry. Returns a u32 for total_read_entries.<br />
<br />
Reads the meta records stored in the entry's content records into the output buffer.<br />
<br />
This is used, for example, with System Update title 0100000000000816, which contains Meta Records for all other systitles in its Content Records.<br />
<br />
==== LookupOrphanContent ====<br />
Takes a type-6 byte buffer, and a type-5 buffer containing [[#NcaID]]s.<br />
<br />
This function was stubbed to return 0xDC05 in [[2.0.0]].<br />
<br />
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#NcaID]] in the input buffer, it checks if that NcaID is present anywhere in the database, and if so writes 0 to the corresponding output byte.<br />
<br />
In pseudocode, the function basically does the following:<br />
<br />
for i in range(len(out_buf)):<br />
out_buf[i] = 1<br />
<br />
for i, NcaID in NcaIDs:<br />
if is_present_in_database(NcaID):<br />
out_buf[i] = 0<br />
<br />
=== NcaID ===<br />
This is a 0x10-byte entry. This is originally from the hex portion of "<hex>.nca" directory-names from this storage FS(like [[SD_Filesystem|SD]]). This is also referred to as "ContentId" in the official SDK.<br />
<br />
The NcaID is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from ReadEntryRaw.<br />
<br />
=== Enums ===<br />
==== Title Types ====<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value<br />
! Description<br />
|-<br />
| 0x01<br />
| System Programs ([[Title_list#System_Modules|System Modules]] or [[Title_list#System_Applets|System Applets]])<br />
|-<br />
| 0x02<br />
| [[Title_list#System_Data_Archives|System Data Archives]]<br />
|-<br />
| 0x03<br />
| System Update<br />
|-<br />
| 0x04<br />
| [[Title_list|Firmware package A]]<br />
|-<br />
| 0x05<br />
| [[Title_list|Firmware package B]]<br />
|-<br />
| 0x80<br />
| Regular application<br />
|-<br />
| 0x81<br />
| Update title<br />
|-<br />
| 0x82<br />
| Add-on content<br />
|-<br />
| 0x83<br />
| Delta title<br />
|}<br />
<br />
== ncm:v ==<br />
This service doesn't normally exist on retail.<br />
<br />
[[Category:Services]]</div>
Rajkosto
https://switchbrew.org/w/index.php?title=NCM_services&diff=4838
NCM services
2018-07-18T19:23:22Z
<p>Rajkosto: Clarification of IContentMetaDatabase::Get output buffer contents</p>
<hr />
<div>NCM contains services for internal file path and content management.<br />
<br />
= Location Resolver services =<br />
== lr ==<br />
This is "nn::lr::ILocationResolverManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || OpenLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 1 || OpenRegisteredLocationResolver || None || <br />
|-<br />
| 2 || RefreshLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 3 || [2.0.0+] OpenAddOnContentLocationResolver || None ||<br />
|}<br />
<br />
The only sysmodules which use this service are [[Filesystem_services|FS]], [[Loader_services|Loader]], and [[NS_Services|NS]]. [[boot2]] has access but doesn't use it.<br />
<br />
=== ILocationResolver ===<br />
This is "nn::lr::ILocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [[#ResolveProgramPath]]<br />
|-<br />
| 1 || [[#RedirectProgramPath]]<br />
|-<br />
| 2 || [[#ResolveApplicationControlPath]]<br />
|-<br />
| 3 || [[#ResolveApplicationHtmlDocumentPath]]<br />
|-<br />
| 4 || [[#ResolveDataPath]]<br />
|-<br />
| 5 || [[#RedirectApplicationControlPath]]<br />
|-<br />
| 6 || [[#RedirectApplicationHtmlDocumentPath]]<br />
|-<br />
| 7 || [[#ResolveApplicationLegalInformationPath]]<br />
|-<br />
| 8 || [[#RedirectApplicationLegalInformationPath]]<br />
|-<br />
| 9 || [[#Refresh]]<br />
|-<br />
| 10 || [5.0.0+] [[#SetProgramNcaPath2]]<br />
|-<br />
| 11 || [5.0.0+] [[#ClearLocationResolver2]]<br />
|-<br />
| 12 || [5.0.0+] [[#DeleteProgramNcaPath]]<br />
|-<br />
| 13 || [5.0.0+] [[#DeleteControlNcaPath]]<br />
|-<br />
| 14 || [5.0.0+] [[#DeleteDocHtmlNcaPath]]<br />
|-<br />
| 15 || [5.0.0+] [[#DeleteInfoHtmlNcaPath]]<br />
|}<br />
<br />
If the supplied [[Filesystem_services#StorageId|StorageID]] is 1 (Host), a different set of internal functions is used to handle these commands. In this more restricted set of functions, GetControlNcaPath is stubbed and only returns error 0x608.<br />
<br />
The Get* commands load the [[Filesystem_services|ContentPath]] from linked-lists' [[#Location_List_Entry|entries]] in memory using the input TitleID. When the command fails to find an entry for the specified TitleID, 0x408 is returned for GetProgramNcaPath and 0xA08 is returned for the rest.<br />
<br />
The Set* commands always return 0 and add a new entry to the list. If a matching entry is found, it's removed first.<br />
<br />
==== ResolveProgramPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
==== RedirectProgramPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 0.<br />
<br />
==== ResolveApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== ResolveApplicationHtmlDocumentPath====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
==== ResolveDataPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== RedirectApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== RedirectApplicationHtmlDocumentPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ResolveApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
==== RedirectApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== Refresh ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 0.<br />
<br />
==== SetProgramNcaPath2 ====<br />
Same as [[#SetProgramNcaPath|SetProgramNcaPath]], but inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ClearLocationResolver2 ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 1.<br />
<br />
==== DeleteProgramNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteControlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteDocHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteInfoHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
=== IRegisteredLocationResolver ===<br />
This is "nn::lr::IRegisteredLocationResolver".<br />
<br />
This works like [[#ILocationResolver]], but only two types of NCA paths can be gotten/set. In addition, each type has a fallback path that can be set for a single title ID at a time.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveProgramPath || u64 TitleID + C descriptor || Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
|-<br />
| 1 || RegisterProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 0 fallback TID and path to the provided arguments.<br />
|-<br />
| 2 || UnregisterProgramPath || u64 TitleID || If the Type 0 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 3 || RedirectProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|-<br />
| 4 || [2.0.0+] ResolveHtmlDocumentPath || u64 TitleID + C descriptor ||<br />
|-<br />
| 5 || [2.0.0+] RegisterHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 1 fallback TID and path to the provided arguments.<br />
|-<br />
| 6 || [2.0.0+] UnregisterHtmlDocumentPath || u64 TitleID || If the Type 1 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 7 || [2.0.0+] RedirectHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|}<br />
<br />
=== IAddOnContentLocationResolver ===<br />
This is "nn::lr::IAddOnContentLocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveAddOnContentPath || u64 TitleID + C descriptor || <br />
|-<br />
| 1 || RegisterAddOnContentStorage || [[Filesystem_services#StorageId|StorageID]] + u64 TitleID || <br />
|-<br />
| 2 || UnregisterAllAddOnContentPath || None || Clears all registered titles here.<br />
|}<br />
<br />
=== Location List Entry ===<br />
Total size is 0x320 bytes. <br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset || Size || Description<br />
|-<br />
| 0x0 || 0x8|| Pointer to previous entry<br />
|-<br />
| 0x8 || 0x8|| Pointer to next entry<br />
|-<br />
| 0x10 || 0x8|| TitleID<br />
|-<br />
| 0x18 || 0x300 || [[Filesystem_services|ContentPath]]<br />
|-<br />
| 0x318 || 0x4 || Flag<br />
|-<br />
| 0x31C || 0x4 || Padding<br />
|}<br />
<br />
= Content Manager services =<br />
== ncm ==<br />
This is "nn::ncm::IContentManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || CreateContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 1 || CreateContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 2 || VerifyContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 3 || VerifyContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 4 || OpenContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 5 || OpenContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 6 || [1.0.0] CloseContentStorageForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentStorage->CloseAndFlushStorage().<br />
|-<br />
| 7 || [1.0.0] CloseContentMetaDatabaseForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentMetaDatabase->CloseMetaDatabase().<br />
|-<br />
| 8 || CleanupContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and deletes the associated savedata.<br />
|-<br />
| 9 || [2.0.0+] OpenContentStorage2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentStorage for the StorageID to be gotten with GetIContentStorage. Note: Name is not official.<br />
|-<br />
| 10 || [2.0.0+] CloseContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentStorage. Note: Name is not official.<br />
|-<br />
| 11 || [2.0.0+] OpenContentMetaDatabase2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentMetaDatabase for the StorageID to be gotten with GetIContentMetaDatabase. Note: Name is not official.<br />
|-<br />
| 12 || [2.0.0+] CloseContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentMetaDatabase. Note: Name is not official.<br />
|}<br />
<br />
=== IContentStorage ===<br />
This is "nn::ncm::IContentStorage".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage.<br />
|-<br />
| 1 || CreatePlaceHolder || Takes two [[#NcaID]]s, and a u64 filesize.<br />
|-<br />
| 2 || DeletePlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 3 || HasPlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 4 || WritePlaceHolder || Takes a [[#NcaID]], a u64-offset, and type 5 buffer. Writes the buffer to the file for the NcaID's placeholder path at the specified offset.<br />
|-<br />
| 5 || Register || Takes two [[#NcaID]]s, moves the Placeholder NCA content to the registered NCA path.<br />
|-<br />
| 6 || Delete || Takes a [[#NcaID]].<br />
|-<br />
| 7 || Has || Takes a [[#NcaID]].<br />
|-<br />
| 8 || GetPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 9 || GetPlaceHolderPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory.<br />
|-<br />
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory.<br />
|-<br />
| 12 || [[#GetContentCount]] ||<br />
|-<br />
| 13 || [[#ListContentId]] ||<br />
|-<br />
| 14 || [[#GetSize]] || <br />
|-<br />
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805.<br />
|-<br />
| 16 || [2.0.0+] RevertToPlaceHolder || Takes three 0x10-sized [[#NcaID]]s. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path.<br />
|-<br />
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#NcaID]], and a u64 size<br />
|-<br />
| 18 || [2.0.0+] [[#ReadContentIdFile]] ||<br />
|-<br />
| 19 || [2.0.0+] GetRightsIdFromPlaceHolderId || Gets the Rights ID for the [[#NcaID]]'s placeholder path.<br />
|-<br />
| 20 || [2.0.0+] GetRightsIdFromContentId || Gets the Rights ID for the [[#NcaID]]'s registered path<br />
|-<br />
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[#NcaID]], a u64 offset, and a type 5 buffer. On debug units, writes the buffer to the NCA's registered path. On retail units, this just aborts.<br />
|-<br />
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage.<br />
|-<br />
| 23 || [2.0.0+] GetTotalSpaceSize || Gets total space for the storage.<br />
|-<br />
| 24 || [3.0.0+] FlushStorage || Flushes resources for the storage without closing it.<br />
|-<br />
| 25 || [4.0.0+] || <br />
|-<br />
| 26 || [4.0.0+] || <br />
|}<br />
<br />
==== GeneratePlaceHolderId ====<br />
Generates a random [[#NcaID]] for use as a placeholder.<br />
<br />
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16);<br />
<br />
==== GetContentCount ====<br />
Writes the total number of entries which can be read by GetEntries, to cmdreply <SFCO_offset>+0x10.<br />
<br />
==== ListContentId====<br />
Takes an output buffer, u32 offset and gets all entries starting at that offset.<br />
Returns number of entries read.<br />
<br />
Each entry is a [[#NcaID]].<br />
<br />
The total read entries is exactly the same as the number of "<hex>.nca" directories in the storage FS(or at least under the "registered" directory?).<br />
<br />
==== GetSize ====<br />
Takes a [[#NcaID]] as input.<br />
<br />
Returns the total size readable by ReadEntryRaw. This is the same as the size-field in the [[NAX0]] "<NcaID>.nca/00" file.<br />
<br />
==== ReadContentIdFile ====<br />
Takes an output buffer, a [[#NcaID]] as input, and a u64 file offset.<br />
<br />
Reads plaintext NCA file contents from the Registered path for the NcaID.<br />
<br />
=== IContentMetaDatabase ===<br />
This is "nn::ncm::IContentMetaDatabase".<br />
<br />
Note the official name for Meta Record is "ContentMetaKey".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || Set || Takes a [[NCA#Meta_records|Meta Record]], a type-5 [[NCA#Content_records|Content Records]] buffer and a u64 size.<br />
|-<br />
| 1 || Get || Takes a [[NCA#Meta_records|Meta Record]], a type-6 buffer to write [[NCA#Content_records|Content Records]] to and a u64 size. Returns the actual number of bytes read into the buffer. Content Records start at offset 0x8 of the buffer, at 0x2 is how many there are.<br />
|-<br />
| 2 || Remove || Takes a [[NCA#Meta_records|Meta Record]], and removes the associated record.<br />
|-<br />
| 3 || GetContentIdByType || Takes a [[NCA#Meta_records|Meta Record]] and a u8 [[#Title_Types|Title Type]]. Returns a [[#NcaID]].<br />
|-<br />
| 4 || ListContentInfo || Takes a type-6 buffer to write [[NCA#Content_records|Content Record]] entries to, a [[NCA#Meta_records|Meta Record]], and a u32 index into the Content Record entries to start copying from. Returns a u32 entries_read.<br />
|-<br />
| 5 || List || Takes a type-6 buffer to write [[NCA#Meta_records|Meta Record]]s to, a u32 [[#Title_Types|Title Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Meta Records with low <= record->title_id <= high, and record->type == type. Returns u32 numEntriesTotal, numEntriesWritten. Additionally requires record->title_id == TID, if record->type is Application, Patch, Add-On, or Delta, otherwise, you can pass 0 for type to ignore the type and list them all in the range.<br />
|-<br />
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[NCA#Meta_records|Meta Record]] with the highest version field for that title id.<br />
|-<br />
| 7 || [[#ListApplication]] ||<br />
|-<br />
| 8 || Has || Takes a [[NCA#Meta_records|Meta Record]] and returns whether that record is present in the database.<br />
|-<br />
| 9 || HasAll || Takes a type-5 buffer containing [[NCA#Meta_records|Meta Records]] (code assumes there are size/sizeof(meta_record) records in the buffer), and returns whether all of those records are present in the database.<br />
|-<br />
| 10 || GetSize || Takes a [[NCA#Meta_records|Meta Record]], and returns the size of the associated [[NCA#Content_records|Content Records]].<br />
|-<br />
| 11 || GetRequiredSystemVersion || Takes a [[NCA#Meta_records|Meta Record]], and returns u32 from ContentRecords + 16 (only if the Meta record has type Application or Patch).<br />
|-<br />
| 12 || GetPatchId || Takes a [[NCA#Meta_records|Meta Record]], and returns the update title id for that record.<br />
|-<br />
| 13 || DisableForcibly || Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05.<br />
|-<br />
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#NcaID]]s.<br />
|-<br />
| 15 || Commit || Flushes the in-memory database to savedata.<br />
|-<br />
| 16 || HasContent || Takes a [[NCA#Meta_records|Meta Record]] and an [[#NcaID]]. Returns whether the content records for that meta record contain the NcaID.<br />
|-<br />
| 17 || ListContentMetaInfo || Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]].<br />
|-<br />
| 18 || GetAttributes || Takes a [[NCA#Meta_records|Meta Record]], and returns u8 from ContentRecords + 6.<br />
|-<br />
| 19 || [2.0.0+] GetRequiredApplicationVersion || Does the same thing as GetEntryUnknownRecordSize, but for AddOnContents.<br />
|-<br />
| 20 || [5.0.0+] ||<br />
|}<br />
<br />
==== ListApplication ====<br />
Each 24-byte entry (officially "ApplicationContentMetaKey") is as follows:<br />
[[NCA#Meta_records|meta_record]] meta_record;<br />
u64 base_title_id;<br />
<br />
This function takes in a type 6 buffer to write entries to, and a u8 "filter" [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer.<br />
<br />
This func returns a u32 num_entries_total, and a u32 num_entries_written.<br />
<br />
==== ReadEntryMetaRecords ====<br />
Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]] entry. Returns a u32 for total_read_entries.<br />
<br />
Reads the meta records stored in the entry's content records into the output buffer.<br />
<br />
This is used, for example, with System Update title 0100000000000816, which contains Meta Records for all other systitles in its Content Records.<br />
<br />
==== LookupOrphanContent ====<br />
Takes a type-6 byte buffer, and a type-5 buffer containing [[#NcaID]]s.<br />
<br />
This function was stubbed to return 0xDC05 in [[2.0.0]].<br />
<br />
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#NcaID]] in the input buffer, it checks if that NcaID is present anywhere in the database, and if so writes 0 to the corresponding output byte.<br />
<br />
In pseudocode, the function basically does the following:<br />
<br />
for i in range(len(out_buf)):<br />
out_buf[i] = 1<br />
<br />
for i, NcaID in NcaIDs:<br />
if is_present_in_database(NcaID):<br />
out_buf[i] = 0<br />
<br />
=== NcaID ===<br />
This is a 0x10-byte entry. This is originally from the hex portion of "<hex>.nca" directory-names from this storage FS(like [[SD_Filesystem|SD]]). This is also referred to as "ContentId" in the official SDK.<br />
<br />
The NcaID is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from ReadEntryRaw.<br />
<br />
=== Enums ===<br />
==== Title Types ====<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value<br />
! Description<br />
|-<br />
| 0x01<br />
| System Programs ([[Title_list#System_Modules|System Modules]] or [[Title_list#System_Applets|System Applets]])<br />
|-<br />
| 0x02<br />
| [[Title_list#System_Data_Archives|System Data Archives]]<br />
|-<br />
| 0x03<br />
| System Update<br />
|-<br />
| 0x04<br />
| [[Title_list|Firmware package A]]<br />
|-<br />
| 0x05<br />
| [[Title_list|Firmware package B]]<br />
|-<br />
| 0x80<br />
| Regular application<br />
|-<br />
| 0x81<br />
| Update title<br />
|-<br />
| 0x82<br />
| Add-on content<br />
|-<br />
| 0x83<br />
| Delta title<br />
|}<br />
<br />
== ncm:v ==<br />
This service doesn't normally exist on retail.<br />
<br />
[[Category:Services]]</div>
Rajkosto
https://switchbrew.org/w/index.php?title=NCM_services&diff=4837
NCM services
2018-07-18T16:24:01Z
<p>Rajkosto: Some more details about IContentMetaDatabase::List</p>
<hr />
<div>NCM contains services for internal file path and content management.<br />
<br />
= Location Resolver services =<br />
== lr ==<br />
This is "nn::lr::ILocationResolverManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || OpenLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 1 || OpenRegisteredLocationResolver || None || <br />
|-<br />
| 2 || RefreshLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||<br />
|-<br />
| 3 || [2.0.0+] OpenAddOnContentLocationResolver || None ||<br />
|}<br />
<br />
The only sysmodules which use this service are [[Filesystem_services|FS]], [[Loader_services|Loader]], and [[NS_Services|NS]]. [[boot2]] has access but doesn't use it.<br />
<br />
=== ILocationResolver ===<br />
This is "nn::lr::ILocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name<br />
|-<br />
| 0 || [[#ResolveProgramPath]]<br />
|-<br />
| 1 || [[#RedirectProgramPath]]<br />
|-<br />
| 2 || [[#ResolveApplicationControlPath]]<br />
|-<br />
| 3 || [[#ResolveApplicationHtmlDocumentPath]]<br />
|-<br />
| 4 || [[#ResolveDataPath]]<br />
|-<br />
| 5 || [[#RedirectApplicationControlPath]]<br />
|-<br />
| 6 || [[#RedirectApplicationHtmlDocumentPath]]<br />
|-<br />
| 7 || [[#ResolveApplicationLegalInformationPath]]<br />
|-<br />
| 8 || [[#RedirectApplicationLegalInformationPath]]<br />
|-<br />
| 9 || [[#Refresh]]<br />
|-<br />
| 10 || [5.0.0+] [[#SetProgramNcaPath2]]<br />
|-<br />
| 11 || [5.0.0+] [[#ClearLocationResolver2]]<br />
|-<br />
| 12 || [5.0.0+] [[#DeleteProgramNcaPath]]<br />
|-<br />
| 13 || [5.0.0+] [[#DeleteControlNcaPath]]<br />
|-<br />
| 14 || [5.0.0+] [[#DeleteDocHtmlNcaPath]]<br />
|-<br />
| 15 || [5.0.0+] [[#DeleteInfoHtmlNcaPath]]<br />
|}<br />
<br />
If the supplied [[Filesystem_services#StorageId|StorageID]] is 1 (Host), a different set of internal functions is used to handle these commands. In this more restricted set of functions, GetControlNcaPath is stubbed and only returns error 0x608.<br />
<br />
The Get* commands load the [[Filesystem_services|ContentPath]] from linked-lists' [[#Location_List_Entry|entries]] in memory using the input TitleID. When the command fails to find an entry for the specified TitleID, 0x408 is returned for GetProgramNcaPath and 0xA08 is returned for the rest.<br />
<br />
The Set* commands always return 0 and add a new entry to the list. If a matching entry is found, it's removed first.<br />
<br />
==== ResolveProgramPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
==== RedirectProgramPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 0.<br />
<br />
==== ResolveApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== ResolveApplicationHtmlDocumentPath====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
==== ResolveDataPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
==== RedirectApplicationControlPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== RedirectApplicationHtmlDocumentPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ResolveApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a C descriptor. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
==== RedirectApplicationLegalInformationPath ====<br />
Takes an u64 '''TitleID''' and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== Refresh ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 0.<br />
<br />
==== SetProgramNcaPath2 ====<br />
Same as [[#SetProgramNcaPath|SetProgramNcaPath]], but inserts a new [[#Location_List_Entry|entry]] with '''flag''' set to 1.<br />
<br />
==== ClearLocationResolver2 ====<br />
Takes no input. Frees all linked-lists' entries that have '''flag''' set to 1.<br />
<br />
==== DeleteProgramNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteControlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteDocHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
==== DeleteInfoHtmlNcaPath ====<br />
Takes an u64 '''TitleID'''. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].<br />
<br />
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.<br />
<br />
=== IRegisteredLocationResolver ===<br />
This is "nn::lr::IRegisteredLocationResolver".<br />
<br />
This works like [[#ILocationResolver]], but only two types of NCA paths can be gotten/set. In addition, each type has a fallback path that can be set for a single title ID at a time.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveProgramPath || u64 TitleID + C descriptor || Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].<br />
|-<br />
| 1 || RegisterProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 0 fallback TID and path to the provided arguments.<br />
|-<br />
| 2 || UnregisterProgramPath || u64 TitleID || If the Type 0 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 3 || RedirectProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|-<br />
| 4 || [2.0.0+] ResolveHtmlDocumentPath || u64 TitleID + C descriptor ||<br />
|-<br />
| 5 || [2.0.0+] RegisterHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 1 fallback TID and path to the provided arguments.<br />
|-<br />
| 6 || [2.0.0+] UnregisterHtmlDocumentPath || u64 TitleID || If the Type 1 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.<br />
|-<br />
| 7 || [2.0.0+] RedirectHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||<br />
|}<br />
<br />
=== IAddOnContentLocationResolver ===<br />
This is "nn::lr::IAddOnContentLocationResolver".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Arguments || Notes<br />
|-<br />
| 0 || ResolveAddOnContentPath || u64 TitleID + C descriptor || <br />
|-<br />
| 1 || RegisterAddOnContentStorage || [[Filesystem_services#StorageId|StorageID]] + u64 TitleID || <br />
|-<br />
| 2 || UnregisterAllAddOnContentPath || None || Clears all registered titles here.<br />
|}<br />
<br />
=== Location List Entry ===<br />
Total size is 0x320 bytes. <br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset || Size || Description<br />
|-<br />
| 0x0 || 0x8|| Pointer to previous entry<br />
|-<br />
| 0x8 || 0x8|| Pointer to next entry<br />
|-<br />
| 0x10 || 0x8|| TitleID<br />
|-<br />
| 0x18 || 0x300 || [[Filesystem_services|ContentPath]]<br />
|-<br />
| 0x318 || 0x4 || Flag<br />
|-<br />
| 0x31C || 0x4 || Padding<br />
|}<br />
<br />
= Content Manager services =<br />
== ncm ==<br />
This is "nn::ncm::IContentManager".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || CreateContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 1 || CreateContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 2 || VerifyContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 3 || VerifyContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].<br />
|-<br />
| 4 || OpenContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 5 || OpenContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.<br />
|-<br />
| 6 || [1.0.0] CloseContentStorageForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentStorage->CloseAndFlushStorage().<br />
|-<br />
| 7 || [1.0.0] CloseContentMetaDatabaseForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentMetaDatabase->CloseMetaDatabase().<br />
|-<br />
| 8 || CleanupContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and deletes the associated savedata.<br />
|-<br />
| 9 || [2.0.0+] OpenContentStorage2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentStorage for the StorageID to be gotten with GetIContentStorage. Note: Name is not official.<br />
|-<br />
| 10 || [2.0.0+] CloseContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentStorage. Note: Name is not official.<br />
|-<br />
| 11 || [2.0.0+] OpenContentMetaDatabase2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentMetaDatabase for the StorageID to be gotten with GetIContentMetaDatabase. Note: Name is not official.<br />
|-<br />
| 12 || [2.0.0+] CloseContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentMetaDatabase. Note: Name is not official.<br />
|}<br />
<br />
=== IContentStorage ===<br />
This is "nn::ncm::IContentStorage".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage.<br />
|-<br />
| 1 || CreatePlaceHolder || Takes two [[#NcaID]]s, and a u64 filesize.<br />
|-<br />
| 2 || DeletePlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 3 || HasPlaceHolder || Takes a [[#NcaID]].<br />
|-<br />
| 4 || WritePlaceHolder || Takes a [[#NcaID]], a u64-offset, and type 5 buffer. Writes the buffer to the file for the NcaID's placeholder path at the specified offset.<br />
|-<br />
| 5 || Register || Takes two [[#NcaID]]s, moves the Placeholder NCA content to the registered NCA path.<br />
|-<br />
| 6 || Delete || Takes a [[#NcaID]].<br />
|-<br />
| 7 || Has || Takes a [[#NcaID]].<br />
|-<br />
| 8 || GetPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 9 || GetPlaceHolderPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].<br />
|-<br />
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory.<br />
|-<br />
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory.<br />
|-<br />
| 12 || [[#GetContentCount]] ||<br />
|-<br />
| 13 || [[#ListContentId]] ||<br />
|-<br />
| 14 || [[#GetSize]] || <br />
|-<br />
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805.<br />
|-<br />
| 16 || [2.0.0+] RevertToPlaceHolder || Takes three 0x10-sized [[#NcaID]]s. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path.<br />
|-<br />
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#NcaID]], and a u64 size<br />
|-<br />
| 18 || [2.0.0+] [[#ReadContentIdFile]] ||<br />
|-<br />
| 19 || [2.0.0+] GetRightsIdFromPlaceHolderId || Gets the Rights ID for the [[#NcaID]]'s placeholder path.<br />
|-<br />
| 20 || [2.0.0+] GetRightsIdFromContentId || Gets the Rights ID for the [[#NcaID]]'s registered path<br />
|-<br />
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[#NcaID]], a u64 offset, and a type 5 buffer. On debug units, writes the buffer to the NCA's registered path. On retail units, this just aborts.<br />
|-<br />
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage.<br />
|-<br />
| 23 || [2.0.0+] GetTotalSpaceSize || Gets total space for the storage.<br />
|-<br />
| 24 || [3.0.0+] FlushStorage || Flushes resources for the storage without closing it.<br />
|-<br />
| 25 || [4.0.0+] || <br />
|-<br />
| 26 || [4.0.0+] || <br />
|}<br />
<br />
==== GeneratePlaceHolderId ====<br />
Generates a random [[#NcaID]] for use as a placeholder.<br />
<br />
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16);<br />
<br />
==== GetContentCount ====<br />
Writes the total number of entries which can be read by GetEntries, to cmdreply <SFCO_offset>+0x10.<br />
<br />
==== ListContentId====<br />
Takes an output buffer, u32 offset and gets all entries starting at that offset.<br />
Returns number of entries read.<br />
<br />
Each entry is a [[#NcaID]].<br />
<br />
The total read entries is exactly the same as the number of "<hex>.nca" directories in the storage FS(or at least under the "registered" directory?).<br />
<br />
==== GetSize ====<br />
Takes a [[#NcaID]] as input.<br />
<br />
Returns the total size readable by ReadEntryRaw. This is the same as the size-field in the [[NAX0]] "<NcaID>.nca/00" file.<br />
<br />
==== ReadContentIdFile ====<br />
Takes an output buffer, a [[#NcaID]] as input, and a u64 file offset.<br />
<br />
Reads plaintext NCA file contents from the Registered path for the NcaID.<br />
<br />
=== IContentMetaDatabase ===<br />
This is "nn::ncm::IContentMetaDatabase".<br />
<br />
Note the official name for Meta Record is "ContentMetaKey".<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Cmd || Name || Notes<br />
|-<br />
| 0 || Set || Takes a [[NCA#Meta_records|Meta Record]], a type-5 [[NCA#Content_records|Content Records]] buffer and a u64 size.<br />
|-<br />
| 1 || Get || Takes a [[NCA#Meta_records|Meta Record]], a type-6 buffer to write [[NCA#Content_records|Content Records]] to and a u64 size. Returns the actual Content Records size read.<br />
|-<br />
| 2 || Remove || Takes a [[NCA#Meta_records|Meta Record]], and removes the associated record.<br />
|-<br />
| 3 || GetContentIdByType || Takes a [[NCA#Meta_records|Meta Record]] and a u8 [[#Title_Types|Title Type]]. Returns a [[#NcaID]].<br />
|-<br />
| 4 || ListContentInfo || Takes a type-6 buffer to write [[NCA#Content_records|Content Record]] entries to, a [[NCA#Meta_records|Meta Record]], and a u32 index into the Content Record entries to start copying from. Returns a u32 entries_read.<br />
|-<br />
| 5 || List || Takes a type-6 buffer to write [[NCA#Meta_records|Meta Record]]s to, a u32 [[#Title_Types|Title Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Meta Records with low <= record->title_id <= high, and record->type == type. Returns u32 numEntriesTotal, numEntriesWritten. Additionally requires record->title_id == TID, if record->type is Application, Patch, Add-On, or Delta, otherwise, you can pass 0 for type to ignore the type and list them all in the range.<br />
|-<br />
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[NCA#Meta_records|Meta Record]] with the highest version field for that title id.<br />
|-<br />
| 7 || [[#ListApplication]] ||<br />
|-<br />
| 8 || Has || Takes a [[NCA#Meta_records|Meta Record]] and returns whether that record is present in the database.<br />
|-<br />
| 9 || HasAll || Takes a type-5 buffer containing [[NCA#Meta_records|Meta Records]] (code assumes there are size/sizeof(meta_record) records in the buffer), and returns whether all of those records are present in the database.<br />
|-<br />
| 10 || GetSize || Takes a [[NCA#Meta_records|Meta Record]], and returns the size of the associated [[NCA#Content_records|Content Records]].<br />
|-<br />
| 11 || GetRequiredSystemVersion || Takes a [[NCA#Meta_records|Meta Record]], and returns u32 from ContentRecords + 16 (only if the Meta record has type Application or Patch).<br />
|-<br />
| 12 || GetPatchId || Takes a [[NCA#Meta_records|Meta Record]], and returns the update title id for that record.<br />
|-<br />
| 13 || DisableForcibly || Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05.<br />
|-<br />
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#NcaID]]s.<br />
|-<br />
| 15 || Commit || Flushes the in-memory database to savedata.<br />
|-<br />
| 16 || HasContent || Takes a [[NCA#Meta_records|Meta Record]] and an [[#NcaID]]. Returns whether the content records for that meta record contain the NcaID.<br />
|-<br />
| 17 || ListContentMetaInfo || Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]].<br />
|-<br />
| 18 || GetAttributes || Takes a [[NCA#Meta_records|Meta Record]], and returns u8 from ContentRecords + 6.<br />
|-<br />
| 19 || [2.0.0+] GetRequiredApplicationVersion || Does the same thing as GetEntryUnknownRecordSize, but for AddOnContents.<br />
|-<br />
| 20 || [5.0.0+] ||<br />
|}<br />
<br />
==== ListApplication ====<br />
Each 24-byte entry (officially "ApplicationContentMetaKey") is as follows:<br />
[[NCA#Meta_records|meta_record]] meta_record;<br />
u64 base_title_id;<br />
<br />
This function takes in a type 6 buffer to write entries to, and a u8 "filter" [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer.<br />
<br />
This func returns a u32 num_entries_total, and a u32 num_entries_written.<br />
<br />
==== ReadEntryMetaRecords ====<br />
Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]] entry. Returns a u32 for total_read_entries.<br />
<br />
Reads the meta records stored in the entry's content records into the output buffer.<br />
<br />
This is used, for example, with System Update title 0100000000000816, which contains Meta Records for all other systitles in its Content Records.<br />
<br />
==== LookupOrphanContent ====<br />
Takes a type-6 byte buffer, and a type-5 buffer containing [[#NcaID]]s.<br />
<br />
This function was stubbed to return 0xDC05 in [[2.0.0]].<br />
<br />
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#NcaID]] in the input buffer, it checks if that NcaID is present anywhere in the database, and if so writes 0 to the corresponding output byte.<br />
<br />
In pseudocode, the function basically does the following:<br />
<br />
for i in range(len(out_buf)):<br />
out_buf[i] = 1<br />
<br />
for i, NcaID in NcaIDs:<br />
if is_present_in_database(NcaID):<br />
out_buf[i] = 0<br />
<br />
=== NcaID ===<br />
This is a 0x10-byte entry. This is originally from the hex portion of "<hex>.nca" directory-names from this storage FS(like [[SD_Filesystem|SD]]). This is also referred to as "ContentId" in the official SDK.<br />
<br />
The NcaID is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from ReadEntryRaw.<br />
<br />
=== Enums ===<br />
==== Title Types ====<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Value<br />
! Description<br />
|-<br />
| 0x01<br />
| System Programs ([[Title_list#System_Modules|System Modules]] or [[Title_list#System_Applets|System Applets]])<br />
|-<br />
| 0x02<br />
| [[Title_list#System_Data_Archives|System Data Archives]]<br />
|-<br />
| 0x03<br />
| System Update<br />
|-<br />
| 0x04<br />
| [[Title_list|Firmware package A]]<br />
|-<br />
| 0x05<br />
| [[Title_list|Firmware package B]]<br />
|-<br />
| 0x80<br />
| Regular application<br />
|-<br />
| 0x81<br />
| Update title<br />
|-<br />
| 0x82<br />
| Add-on content<br />
|-<br />
| 0x83<br />
| Delta title<br />
|}<br />
<br />
== ncm:v ==<br />
This service doesn't normally exist on retail.<br />
<br />
[[Category:Services]]</div>
Rajkosto
https://switchbrew.org/w/index.php?title=Fuses&diff=4508
Fuses
2018-04-23T10:07:51Z
<p>Rajkosto: add idc version of ipatch assembly</p>
<hr />
<div>The Nintendo Switch makes use of Tegra's fuse driver for a number of operations. This driver is mapped to physical address 0x7000F800 with a total size of 0x400 bytes and exposes several registers for fuse programming.<br />
<br />
Registers from 0x7000F800 to 0x7000F800 + 0xFF can be used to directly program the hardware fuse array, while registers from 0x7000F800 + 0x100 (FUSE_CHIP_REG_START_OFFSET) to 0x7000F800 + 0x3FC (FUSE_CHIP_REG_END_OFFSET) represent cached values read from certain fuses.<br />
<br />
== Registers ==<br />
Below is a list of fuse driver registers used by the Switch's bootloaders.<br />
<br />
=== Driver registers ===<br />
{| class="wikitable" border="1"<br />
! Name<br />
! Address<br />
|-<br />
| [[#FUSE_CTRL|FUSE_CTRL]]<br />
| 0x7000F800<br />
|-<br />
| [[#FUSE_REG_ADDR|FUSE_REG_ADDR]]<br />
| 0x7000F804<br />
|-<br />
| [[#FUSE_REG_READ|FUSE_REG_READ]]<br />
| 0x7000F808<br />
|-<br />
| [[#FUSE_REG_WRITE|FUSE_REG_WRITE]]<br />
| 0x7000F80C<br />
|-<br />
| FUSE_TIME_RD1<br />
| 0x7000F810<br />
|-<br />
| FUSE_TIME_RD2<br />
| 0x7000F814<br />
|-<br />
| FUSE_TIME_PGM1<br />
| 0x7000F818<br />
|-<br />
| [[#FUSE_TIME_PGM2|FUSE_TIME_PGM2]]<br />
| 0x7000F81C<br />
|-<br />
| FUSE_PRIV2INTFC<br />
| 0x7000F820<br />
|-<br />
| FUSE_FUSEBYPASS<br />
| 0x7000F824<br />
|-<br />
| FUSE_PRIVATEKEYDISABLE<br />
| 0x7000F828<br />
|-<br />
| [[#FUSE_DIS_PGM|FUSE_DIS_PGM]]<br />
| 0x7000F82C<br />
|-<br />
| [[#FUSE_WRITE_ACCESS|FUSE_WRITE_ACCESS]]<br />
| 0x7000F830<br />
|-<br />
| FUSE_PWR_GOOD_SW<br />
| 0x7000F834<br />
|-<br />
|}<br />
<br />
==== FUSE_CTRL ====<br />
{| class="wikitable" border="1"<br />
! Bits<br />
! Description<br />
|-<br />
| 0-1<br />
| Fuse command (1 = FUSE_READ; 2 = FUSE_WRITE; 3 = FUSE_SENSE)<br />
|-<br />
| 26<br />
| Fuse power down mode flag (FUSE_CTRL_PD)<br />
|-<br />
|}<br />
<br />
Before fuse reading/writing the power down mode must be disabled.<br />
FUSE_SENSE mode flushes programmed values into the [[Fuses#Cache_registers|cache registers]].<br />
<br />
==== FUSE_REG_ADDR ====<br />
This register takes the address of the fuse to be read/written/sensed.<br />
<br />
==== FUSE_REG_READ ====<br />
This register receives the value read from the fuse.<br />
<br />
==== FUSE_REG_WRITE ====<br />
This register takes the value to be written to the fuse.<br />
<br />
==== FUSE_TIME_PGM2 ====<br />
This register takes the fuse programming pulse (0xC0 == 19200 kHz).<br />
<br />
==== FUSE_DIS_PGM ====<br />
If set to 0x01, this register disables fuse programming.<br />
<br />
==== FUSE_WRITE_ACCESS ====<br />
If set to 0x01, this register disables software writes to the fuse driver registers.<br />
<br />
<br />
=== Cache registers ===<br />
{| class="wikitable" border="1"<br />
! Name<br />
! Address<br />
|-<br />
| FUSE_PRODUCTION_MODE<br />
| 0x7000F900<br />
|-<br />
| [[#FUSE_SKU_INFO|FUSE_SKU_INFO]]<br />
| 0x7000F910<br />
|-<br />
| FUSE_CPU_SPEEDO_0<br />
| 0x7000F914<br />
|-<br />
| FUSE_CPU_IDDQ<br />
| 0x7000F918<br />
|-<br />
| FUSE_FT_REV<br />
| 0x7000F928<br />
|-<br />
| FUSE_CPU_SPEEDO_1<br />
| 0x7000F92C<br />
|-<br />
| FUSE_CPU_SPEEDO_2<br />
| 0x7000F930<br />
|-<br />
| FUSE_SOC_SPEEDO_0<br />
| 0x7000F934<br />
|-<br />
| [[#FUSE_SOC_SPEEDO_1|FUSE_SOC_SPEEDO_1]]<br />
| 0x7000F938<br />
|-<br />
| FUSE_SOC_SPEEDO_2<br />
| 0x7000F93C<br />
|-<br />
| FUSE_SOC_IDDQ<br />
| 0x7000F940<br />
|-<br />
| [[#FUSE_FA|FUSE_FA]]<br />
| 0x7000F948<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY0]]<br />
| 0x7000F964<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY1]]<br />
| 0x7000F968<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY2]]<br />
| 0x7000F96C<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY3]]<br />
| 0x7000F970<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY4]]<br />
| 0x7000F974<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY5]]<br />
| 0x7000F978<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY6]]<br />
| 0x7000F97C<br />
|-<br />
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY7]]<br />
| 0x7000F980<br />
|-<br />
| FUSE_TSENSOR_1<br />
| 0x7000F984<br />
|-<br />
| FUSE_TSENSOR_2<br />
| 0x7000F988<br />
|-<br />
| FUSE_CP_REV<br />
| 0x7000F990<br />
|-<br />
| FUSE_TSENSOR_0<br />
| 0x7000F998<br />
|-<br />
| FUSE_FIRST_BOOTROM_PATCH_SIZE_REG<br />
| 0x7000F99C<br />
|-<br />
| FUSE_SECURITY_MODE<br />
| 0x7000F9A0<br />
|-<br />
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY0]]<br />
| 0x7000F9A4<br />
|-<br />
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY1]]<br />
| 0x7000F9A8<br />
|-<br />
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY2]]<br />
| 0x7000F9AC<br />
|-<br />
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY3]]<br />
| 0x7000F9B0<br />
|-<br />
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY4]]<br />
| 0x7000F9B4<br />
|-<br />
| FUSE_BOOT_DEVICE_INFO<br />
| 0x7000F9BC<br />
|-<br />
| [[#FUSE_RESERVED_SW|FUSE_RESERVED_SW]]<br />
| 0x7000F9C0<br />
|-<br />
| FUSE_VP8_ENABLE<br />
| 0x7000F9C4<br />
|-<br />
| [[#FUSE_RESERVED_ODM0|FUSE_RESERVED_ODM0]]<br />
| 0x7000F9C8<br />
|-<br />
| [[#FUSE_RESERVED_ODM1|FUSE_RESERVED_ODM1]]<br />
| 0x7000F9CC<br />
|-<br />
| [[#FUSE_RESERVED_ODM2|FUSE_RESERVED_ODM2]]<br />
| 0x7000F9D0<br />
|-<br />
| [[#FUSE_RESERVED_ODM3|FUSE_RESERVED_ODM3]]<br />
| 0x7000F9D4<br />
|-<br />
| [[#FUSE_RESERVED_ODM4|FUSE_RESERVED_ODM4]]<br />
| 0x7000F9D8<br />
|-<br />
| FUSE_RESERVED_ODM5<br />
| 0x7000F9DC<br />
|-<br />
| [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]]<br />
| 0x7000F9E0<br />
|-<br />
| [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]]<br />
| 0x7000F9E4<br />
|-<br />
| FUSE_SKU_USB_CALIB<br />
| 0x7000F9F0<br />
|-<br />
| FUSE_SKU_DIRECT_CONFIG<br />
| 0x7000F9F4<br />
|-<br />
| FUSE_VENDOR_CODE<br />
| 0x7000FA00<br />
|-<br />
| FUSE_FAB_CODE<br />
| 0x7000FA04<br />
|-<br />
| FUSE_LOT_CODE_0<br />
| 0x7000FA08<br />
|-<br />
| FUSE_LOT_CODE_1<br />
| 0x7000FA0C<br />
|-<br />
| FUSE_WAFER_ID<br />
| 0x7000FA10<br />
|-<br />
| FUSE_X_COORDINATE<br />
| 0x7000FA14<br />
|-<br />
| FUSE_Y_COORDINATE<br />
| 0x7000FA18<br />
|-<br />
| FUSE_SATA_CALIB<br />
| 0x7000FA24<br />
|-<br />
| FUSE_GPU_IDDQ<br />
| 0x7000FA28<br />
|-<br />
| FUSE_TSENSOR_3<br />
| 0x7000FA2C<br />
|-<br />
| FUSE_OPT_SUBREVISION<br />
| 0x7000FA48<br />
|-<br />
| FUSE_TSENSOR_4<br />
| 0x7000FA54<br />
|-<br />
| FUSE_TSENSOR_5<br />
| 0x7000FA58<br />
|-<br />
| FUSE_TSENSOR_6<br />
| 0x7000FA5C<br />
|-<br />
| FUSE_TSENSOR_7<br />
| 0x7000FA60<br />
|-<br />
| FUSE_OPT_PRIV_SEC_DIS<br />
| 0x7000FA64<br />
|-<br />
| [[#FUSE_PKC_DISABLE|FUSE_PKC_DISABLE]]<br />
| 0x7000FA68<br />
|-<br />
| FUSE_TSENSOR_COMMON<br />
| 0x7000FA80<br />
|-<br />
| FUSE_DEBUG_AUTH_OVERRIDE<br />
| 0x7000FA9C<br />
|-<br />
| FUSE_TSENSOR_8<br />
| 0x7000FAD4<br />
|-<br />
| FUSE_SECURE_PROVISION_INDEX<br />
| 0x7000FAE8<br />
|-<br />
| FUSE_RESERVED_CALIB<br />
| 0x7000FB04<br />
|-<br />
| FUSE_TSENSOR_9<br />
| 0x7000FB1C<br />
|-<br />
| FUSE_USB_CALIB_EXT<br />
| 0x7000FB50<br />
|-<br />
| FUSE_SPARE_BIT_0<br />
| 0x7000FB80<br />
|-<br />
| FUSE_SPARE_BIT_1<br />
| 0x7000FB84<br />
|-<br />
| FUSE_SPARE_BIT_2<br />
| 0x7000FB88<br />
|-<br />
| FUSE_SPARE_BIT_3<br />
| 0x7000FB8C<br />
|-<br />
| FUSE_SPARE_BIT_4<br />
| 0x7000FB90<br />
|-<br />
| [[#FUSE_SPARE_BIT_5|FUSE_SPARE_BIT_5]]<br />
| 0x7000FB94<br />
|-<br />
| FUSE_SPARE_BIT_6<br />
| 0x7000FB98<br />
|-<br />
| FUSE_SPARE_BIT_7<br />
| 0x7000FB9C<br />
|-<br />
| FUSE_SPARE_BIT_8<br />
| 0x7000FBA0<br />
|-<br />
| FUSE_SPARE_BIT_9<br />
| 0x7000FBA4<br />
|-<br />
| FUSE_SPARE_BIT_10<br />
| 0x7000FBA8<br />
|-<br />
| FUSE_SPARE_BIT_11<br />
| 0x7000FBAC<br />
|-<br />
| FUSE_SPARE_BIT_12<br />
| 0x7000FBB0<br />
|-<br />
| FUSE_SPARE_BIT_13<br />
| 0x7000FBB4<br />
|-<br />
| FUSE_SPARE_BIT_14<br />
| 0x7000FBB8<br />
|-<br />
| FUSE_SPARE_BIT_15<br />
| 0x7000FBBC<br />
|-<br />
| FUSE_SPARE_BIT_16<br />
| 0x7000FBC0<br />
|-<br />
| FUSE_SPARE_BIT_17<br />
| 0x7000FBC4<br />
|-<br />
| FUSE_SPARE_BIT_18<br />
| 0x7000FBC8<br />
|-<br />
| FUSE_SPARE_BIT_19<br />
| 0x7000FBCC<br />
|-<br />
| FUSE_SPARE_BIT_20<br />
| 0x7000FBD0<br />
|-<br />
| FUSE_SPARE_BIT_21<br />
| 0x7000FBD4<br />
|-<br />
| FUSE_SPARE_BIT_22<br />
| 0x7000FBD8<br />
|-<br />
| FUSE_SPARE_BIT_23<br />
| 0x7000FBDC<br />
|-<br />
| FUSE_SPARE_BIT_24<br />
| 0x7000FBE0<br />
|-<br />
| FUSE_SPARE_BIT_25<br />
| 0x7000FBE4<br />
|-<br />
| FUSE_SPARE_BIT_26<br />
| 0x7000FBE8<br />
|-<br />
| FUSE_SPARE_BIT_27<br />
| 0x7000FBEC<br />
|-<br />
| FUSE_SPARE_BIT_28<br />
| 0x7000FBF0<br />
|-<br />
| FUSE_SPARE_BIT_29<br />
| 0x7000FBF4<br />
|-<br />
| FUSE_SPARE_BIT_30<br />
| 0x7000FBF8<br />
|-<br />
| FUSE_SPARE_BIT_31<br />
| 0x7000FBFC<br />
|-<br />
|}<br />
<br />
==== FUSE_SKU_INFO ====<br />
Stores the SKU ID (must be 0x83).<br />
<br />
==== FUSE_FA ====<br />
Stores failure analysis mode.<br />
<br />
==== FUSE_SOC_SPEEDO_1 ====<br />
Stores the bootrom patch version.<br />
<br />
==== FUSE_RESERVED_ODM0 ====<br />
This appears to store an hardware ID.<br />
<br />
==== FUSE_RESERVED_ODM1 ====<br />
This appears to store an hardware ID.<br />
<br />
==== FUSE_RESERVED_ODM2 ====<br />
{| class="wikitable" border="1"<br />
! Bits<br />
! Description<br />
|-<br />
| 0-4<br />
| [5.0.0+] Used as key generation<br />
|}<br />
<br />
This appears to store an hardware ID.<br />
<br />
==== FUSE_RESERVED_ODM3 ====<br />
This appears to store an hardware ID.<br />
<br />
==== FUSE_RESERVED_ODM4 ====<br />
{| class="wikitable" border="1"<br />
! Bits<br />
! Description<br />
|-<br />
| 0-1<br />
| Unit type (3 = debug; 0 = retail)<br />
|-<br />
| 2<br />
| Unknown config (must be 1 on retail)<br />
|-<br />
| [1.0.0-3.0.2] 3-5<br />
[4.0.0+] 3-7<br />
| DRAM id<br />
|-<br />
| 8<br />
| Unknown config mask (must be 0 on retail)<br />
|-<br />
| 9<br />
| Unit type mask (0 = debug; 1 = retail)<br />
|-<br />
| 10<br />
| [4.0.0+] Kiosk mode (0 = retail; 1 = kiosk)<br />
|-<br />
| 11<br />
| [5.0.0+] SoC variant (0 = T210; 1 = T214)<br />
|-<br />
| 16-19<br />
| [4.0.0+] New unit type<br />
|}<br />
<br />
This stores some device configuration parameters.<br />
<br />
==== FUSE_RESERVED_ODM6 ====<br />
This register returns the value programmed into index 0x3A of the fuse array. <br />
<br />
==== FUSE_RESERVED_ODM7 ====<br />
This register returns the value programmed into index 0x3C of the fuse array.<br />
<br />
==== FUSE_SPARE_BIT_5 ====<br />
Must be non-zero on retail units, otherwise the first bootloader panics.<br />
On debug units it can be zero, which tells the bootloader to choose from two debug master key seeds. If set to non-zero on a debug unit, it tells the bootloader to choose from two retail master key seeds (only the last one matches the retail master key seed).<br />
<br />
==== FUSE_PRIVATE_KEY ====<br />
This stores the 160-bit private key (128 bit SBK + 32-bit device key).<br />
Reads to these registers after the SBK is locked out produce all-FF output.<br />
<br />
==== FUSE_PUBLIC_KEY ====<br />
This stores the SHA256 hash of the 2048-bit RSA key expected at BCT+0x210.<br />
<br />
==== FUSE_RESERVED_SW ====<br />
{| class="wikitable" border="1"<br />
! Bits<br />
! Description<br />
|-<br />
| 0-2<br />
| Boot device<br />
|-<br />
| 3<br />
| Skip device selection straps (0 = don't skip; 1 = skip)<br />
|-<br />
| 4<br />
| ENABLE_CHARGER_DETECT<br />
|-<br />
| 5<br />
| ENABLE_WATCHDOG<br />
|-<br />
| 6<br />
| Forced RCM two button mode (0 = Only VOLUME_UP; 1 = VOLUME_UP + HOME)<br />
|-<br />
| 7<br />
| RCM USB controller mode (0 = USB 2.0; 1 = XUSB)<br />
|}<br />
<br />
This caches the value of the sw_reserved fuse from the hardware array.<br />
<br />
==== FUSE_PKC_DISABLE ====<br />
This caches the value of the pkc_disable fuse from the hardware array.<br />
<br />
== eFuses ==<br />
The actual hardware fuses can be programmed through the fuse driver after enabling fuse programming.<br />
<br />
Below is a list of common fuse indexes used by Tegra devices (and applicable to the Switch).<br />
Note that the indexes are relative to the start of the fuse array and each element is a 4 byte word. A single fuse write operation always writes the same word at both fuse_array + 0 (PRIMARY_ALIAS) and fuse_array + 1 (REDUNDANT_ALIAS).<br />
<br />
{| class="wikitable" border="1"<br />
! Name<br />
! Index<br />
! Bits<br />
|-<br />
| jtag_disable<br />
| 0x00<br />
| 1<br />
|-<br />
| odm_production_mode<br />
| 0x00<br />
| 1<br />
|-<br />
| odm_lock<br />
| 0x00<br />
| 4<br />
|-<br />
| public_key<br />
| 0x0C<br />
| 256<br />
|-<br />
| secure_boot_key<br />
| 0x22<br />
| 128<br />
|-<br />
| device_key<br />
| 0x2A<br />
| 32<br />
|-<br />
| sec_boot_dev_cfg<br />
| 0x2C<br />
| 16<br />
|-<br />
| sec_boot_dev_sel<br />
| 0x2C<br />
| 3<br />
|-<br />
| sw_reserved<br />
| 0x2E<br />
| 12<br />
|-<br />
| ignore_dev_sel_straps<br />
| 0x2E<br />
| 1<br />
|-<br />
| [[#odm_reserved|odm_reserved]]<br />
| 0x2E<br />
| 256<br />
|-<br />
| pkc_disable<br />
| 0x52<br />
| 1<br />
|-<br />
| [[#bootrom_ipatch|bootrom_ipatch]]<br />
| 0x72<br />
| 624<br />
|-<br />
|}<br />
<br />
=== odm_reserved ===<br />
The first bootloader only burns fuses in this region.<br />
Both fuse indexes 0x3A (odm_reserved + 0x0C) and 0x3C (odm_reserved + 0x0E) are used for anti-downgrade control. These fuses will have their values cached into [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]] and [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]].<br />
<br />
=== bootrom_ipatch ===<br />
Tegra210 based hardware such as the Switch provides support for bootrom patches. The patch data is burned to the hardware fuse array using a specific format (see [https://gist.github.com/shuffle2/f8728159da100e9df2606d43925de0af shuffle2's ipatch decoder]). The bootrom reads these fuses in order to initialize the IPATCH hardware, which allows overriding data returned for code and data fetches done by BPMP.<br />
<br />
The revision stored in FUSE_CP_REV indicates the unique set of values stored in ipatch fuses.<br />
<br />
The following represents the patch data dumped from a Switch console ([https://pastebin.com/yzVyA2vX IDC script with the same content]):<br />
<syntaxhighlight><br />
RAM:00000000 ; =============== S U B R O U T I N E =======================================<br />
RAM:00000000<br />
RAM:00000000<br />
RAM:00000000 irom_svc_dispatch<br />
RAM:00000000 STMFD SP!, {R0-R2} ; ipatches:<br />
RAM:00000000 ; 0 b57df00 16ae df00 : svc #0x00 (offset 0x48)<br />
RAM:00000000 ; 1 1820df22 3040 df22 : svc #0x22 (offset 0x8c)<br />
RAM:00000000 ; 2 3797df26 6f2e df26 : svc #0x26 (offset 0x94)<br />
RAM:00000000 ; 3 7d9e2000 fb3c 2000 : movs r0, #0x00<br />
RAM:00000000 ; 4 42bdf2c 856 df2c : svc #0x2c (offset 0xa0)<br />
RAM:00000000 ; 5 37aadf42 6f54 df42 : svc #0x42 (offset 0xcc)<br />
RAM:00000000 ; 6 972df4b 12e4 df4b : svc #0x4b (offset 0xde)<br />
RAM:00000000 ; 7 2293df54 4526 df54 : svc #0x54 (offset 0xf0)<br />
RAM:00000000 ; 8 21fadf5d 43f4 df5d : svc #0x5d (offset 0x102)<br />
RAM:00000000 ; 9 bba2ac57 17744 ac57 : data<br />
RAM:00000000 ; 10 bbac3d19 17758 3d19 : data<br />
RAM:00000000 ; 11 1e952001 3d2a 2001 : movs r0, #0x01<br />
RAM:00000004 MOV R2, LR<br />
RAM:00000008 SUB R2, R2, #2<br />
RAM:0000000C LDR R2, [R2]<br />
RAM:00000010 AND R2, R2, #0xFF<br />
RAM:00000014 MOV R2, R2,LSL#1<br />
RAM:00000018 LDR R0, =0x1007B0<br />
RAM:0000001C LDR R1, =0x1007F8<br />
RAM:00000020 SUB R1, R1, R0<br />
RAM:00000024 LDR R0, =0x40004C30<br />
RAM:00000028 ADD R0, R0, R1<br />
RAM:0000002C ADD R2, R2, R0<br />
RAM:00000030 ORR R2, R2, #1<br />
RAM:00000034 LDMFD SP!, {R0,R1}<br />
RAM:00000038 BX R2<br />
RAM:00000038 ; End of function irom_svc_dispatch<br />
RAM:00000038<br />
RAM:00000038 ; ---------------------------------------------------------------------------<br />
RAM:0000003C dword_3C DCD 0x1007B0 ; DATA XREF: irom_svc_dispatch+18↑r<br />
RAM:00000040 dword_40 DCD 0x1007F8 ; DATA XREF: irom_svc_dispatch+1C↑r<br />
RAM:00000044 dword_44 DCD 0x40004C30 ; DATA XREF: irom_svc_dispatch+24↑r<br />
RAM:00000048 CODE16<br />
RAM:00000048<br />
RAM:00000048 ; =============== S U B R O U T I N E =======================================<br />
RAM:00000048<br />
RAM:00000048<br />
RAM:00000048 sub_48<br />
RAM:00000048 MOVS R2, #0 ; 0 b57df00 16ae df00 : svc #0x00 (offset 0x48)<br />
RAM:0000004A MVNS R2, R2<br />
RAM:0000004C LDR R1, =0x60006410<br />
RAM:0000004E STR R2, [R1,#0x30]<br />
RAM:00000050 STR R2, [R1,#0x38]<br />
RAM:00000052 LDR R1, =0x600060F8<br />
RAM:00000054 STR R2, [R1]<br />
RAM:00000056 STR R2, [R1,#4]<br />
RAM:00000058 LDR R1, =0x60006284<br />
RAM:0000005A STR R2, [R1]<br />
RAM:0000005C STR R2, [R1,#0x18]<br />
RAM:0000005E ADDS R1, #0x80<br />
RAM:00000060 ADDS R1, #0x1C<br />
RAM:00000062 STR R2, [R1]<br />
RAM:00000064 STR R2, [R1,#8]<br />
RAM:00000066 STR R2, [R1,#0x10]<br />
RAM:00000068 ADDS R1, #0x80<br />
RAM:0000006A STR R2, [R1]<br />
RAM:0000006C STR R2, [R1,#4]<br />
RAM:0000006E LDR R1, =0x60006554<br />
RAM:00000070 STR R2, [R1]<br />
RAM:00000072 MOVS R2, #0xA0000000<br />
RAM:00000076 LDR R1, =0x60006148<br />
RAM:00000078 STR R2, [R1]<br />
RAM:0000007A ADDS R1, #0x38 ; '8'<br />
RAM:0000007C STR R2, [R1]<br />
RAM:0000007E MOVS R2, #0xE0000000<br />
RAM:00000082 LDR R1, =0x600066A0<br />
RAM:00000084 STR R2, [R1]<br />
RAM:00000086 MOVS R1, #0<br />
RAM:00000088 MOVS R0, #0xE<br />
RAM:0000008A B pop_r2_mov_pc_lr<br />
RAM:0000008A ; End of function sub_48<br />
RAM:0000008A<br />
RAM:0000008C<br />
RAM:0000008C ; =============== S U B R O U T I N E =======================================<br />
RAM:0000008C<br />
RAM:0000008C<br />
RAM:0000008C sub_8C<br />
RAM:0000008C LDR R0, [R1,#0x18] ; 1 1820df22 3040 df22 : svc #0x22 (offset 0x8c)<br />
RAM:0000008E MOVS R2, #1<br />
RAM:00000090 ORRS R0, R2<br />
RAM:00000092 B pop_r2_mov_pc_lr<br />
RAM:00000092 ; End of function sub_8C<br />
RAM:00000092<br />
RAM:00000094<br />
RAM:00000094 ; =============== S U B R O U T I N E =======================================<br />
RAM:00000094<br />
RAM:00000094<br />
RAM:00000094 sub_94<br />
RAM:00000094 LDR R2, [R4,#0x50] ; 2 3797df26 6f2e df26 : svc #0x26 (offset 0x94)<br />
RAM:00000096 ADDS R2, R2, #2<br />
RAM:00000098 STR R2, [R4,#0x50]<br />
RAM:0000009A SUBS R1, #0x80<br />
RAM:0000009C STR R1, [R4,#0x34]<br />
RAM:0000009E B pop_r2_mov_pc_lr<br />
RAM:0000009E ; End of function sub_94<br />
RAM:0000009E<br />
RAM:000000A0<br />
RAM:000000A0 ; =============== S U B R O U T I N E =======================================<br />
RAM:000000A0<br />
RAM:000000A0<br />
RAM:000000A0 sub_A0<br />
RAM:000000A0<br />
RAM:000000A0 ; FUNCTION CHUNK AT RAM:00000148 SIZE 00000004 BYTES<br />
RAM:000000A0<br />
RAM:000000A0 MOVS R0, #0x70000000 ; 4 42bdf2c 856 df2c : svc #0x2c (offset 0xa0)<br />
RAM:000000A4 LDR R6, =dword_7000EF14<br />
RAM:000000A6 LDR R2, =dword_7000E5B4<br />
RAM:000000A8 LDR R2, [R2]<br />
RAM:000000AA CMP R2, #0<br />
RAM:000000AC BEQ loc_B4<br />
RAM:000000AE LDR R2, [R6]<br />
RAM:000000B0 STR R2, [R0,#8]<br />
RAM:000000B2 B loc_BC<br />
RAM:000000B4 ; ---------------------------------------------------------------------------<br />
RAM:000000B4<br />
RAM:000000B4 loc_B4 ; CODE XREF: sub_A0+C↑j<br />
RAM:000000B4 LDR R2, [R0,#8]<br />
RAM:000000B6 LSRS R0, R0, #0x12<br />
RAM:000000B8 ORRS R2, R0<br />
RAM:000000BA STR R2, [R6]<br />
RAM:000000BC<br />
RAM:000000BC loc_BC ; CODE XREF: sub_A0+12↑j<br />
RAM:000000BC LDR R6, =dword_7000E9C0<br />
RAM:000000BE LDR R0, [R6]<br />
RAM:000000C0 MOVS R2, #0x4000<br />
RAM:000000C4 ORRS R2, R0<br />
RAM:000000C6 STR R2, [R6]<br />
RAM:000000C8 LDR R0, [R5,#0x10]<br />
RAM:000000CA B pop_r2_mov_pc_lr<br />
RAM:000000CA ; End of function sub_A0<br />
RAM:000000CA<br />
RAM:000000CC<br />
RAM:000000CC ; =============== S U B R O U T I N E =======================================<br />
RAM:000000CC<br />
RAM:000000CC<br />
RAM:000000CC sub_CC<br />
RAM:000000CC MOVS R2, #0xF000000 ; 5 37aadf42 6f54 df42 : svc #0x42 (offset 0xcc)<br />
RAM:000000D0 BICS R1, R2<br />
RAM:000000D2 STR R1, [R4,#0x10]<br />
RAM:000000D4 LDR R1, [R4,#0x50]<br />
RAM:000000D6 MOVS R2, #7<br />
RAM:000000D8 BICS R1, R2<br />
RAM:000000DA STR R1, [R4,#0x50]<br />
RAM:000000DC B pop_r2_mov_pc_lr<br />
RAM:000000DC ; End of function sub_CC<br />
RAM:000000DC<br />
RAM:000000DE<br />
RAM:000000DE ; =============== S U B R O U T I N E =======================================<br />
RAM:000000DE<br />
RAM:000000DE<br />
RAM:000000DE sub_DE<br />
RAM:000000DE LDR R2, =dword_7000FA9C ; 6 972df4b 12e4 df4b : svc #0x4b (offset 0xde)<br />
RAM:000000E0 LDR R2, [R2]<br />
RAM:000000E2 LSRS R2, R2, #8<br />
RAM:000000E4 LSLS R2, R2, #1<br />
RAM:000000E6 LDR R1, [R4]<br />
RAM:000000E8 BICS R1, R2<br />
RAM:000000EA STR R1, [R4]<br />
RAM:000000EC CMP R0, #0<br />
RAM:000000EE B pop_r2_mov_pc_lr<br />
RAM:000000EE ; End of function sub_DE<br />
RAM:000000EE<br />
RAM:000000F0<br />
RAM:000000F0 ; =============== S U B R O U T I N E =======================================<br />
RAM:000000F0<br />
RAM:000000F0<br />
RAM:000000F0 sub_F0<br />
RAM:000000F0<br />
RAM:000000F0 arg_0= 0<br />
RAM:000000F0<br />
RAM:000000F0 LDR R0, =0x400049F0 ; 7 2293df54 4526 df54 : svc #0x54 (offset 0xf0)<br />
RAM:000000F2 LDR R2, [R0]<br />
RAM:000000F4 STR R2, [SP,#arg_0]<br />
RAM:000000F6 LDR R0, =0x40010000<br />
RAM:000000F8 LSRS R2, R2, #17<br />
RAM:000000FA BEQ pop_r2_mov_pc_lr ; if ([0x400049F0] >> 17) == 0) {<br />
RAM:000000FA ; r2 = [0x400049F0];<br />
RAM:000000FA ; } else {<br />
RAM:000000FC LDR R0, =APBDEV_PMC_CNTRL_0<br />
RAM:000000FE STR R4, [R0] ; write APBDEV_PMC_CNTRL<br />
RAM:00000100<br />
RAM:00000100 loc_100 ; CODE XREF: sub_F0:loc_100↓j<br />
RAM:00000100 B loc_100 ; hang<br />
RAM:00000100 ; End of function sub_F0 ; }<br />
RAM:00000100<br />
RAM:00000102<br />
RAM:00000102 ; =============== S U B R O U T I N E =======================================<br />
RAM:00000102<br />
RAM:00000102<br />
RAM:00000102 sub_102<br />
RAM:00000102<br />
RAM:00000102 arg_0= 0<br />
RAM:00000102<br />
RAM:00000102 LDR R2, =0x40010220 ; 8 21fadf5d 43f4 df5d : svc #0x5d (offset 0x102)<br />
RAM:00000104 STR R2, [SP,#arg_0] ; set r2 retval = [0x40010220]<br />
RAM:00000106 LDR R2, [R2,#0x18]<br />
RAM:00000108 ADDS R0, #0xFC<br />
RAM:0000010A STR R2, [R0,#0x1C] ; [r0+0x118] = [0x40010220 + 0x18]<br />
RAM:0000010C B pop_r2_mov_pc_lr<br />
RAM:0000010C ; End of function sub_102<br />
RAM:0000010C<br />
RAM:0000010C ; ---------------------------------------------------------------------------<br />
RAM:0000010E DCB 0<br />
RAM:0000010F DCB 0<br />
RAM:00000110 off_110 DCD 0x60006410 ; DATA XREF: sub_48+4↑r<br />
RAM:00000114 off_114 DCD 0x600060F8 ; DATA XREF: sub_48+A↑r<br />
RAM:00000118 off_118 DCD 0x60006284 ; DATA XREF: sub_48+10↑r<br />
RAM:0000011C off_11C DCD 0x60006554 ; DATA XREF: sub_48+26↑r<br />
RAM:00000120 off_120 DCD 0x60006148 ; DATA XREF: sub_48+2E↑r<br />
RAM:00000124 off_124 DCD 0x600066A0 ; DATA XREF: sub_48+3A↑r<br />
RAM:00000128 off_128 DCD dword_7000EF14 ; DATA XREF: sub_A0+4↑r<br />
RAM:0000012C off_12C DCD dword_7000E5B4 ; DATA XREF: sub_A0+6↑r<br />
RAM:00000130 off_130 DCD dword_7000E9C0 ; DATA XREF: sub_A0:loc_BC↑r<br />
RAM:00000134 off_134 DCD dword_7000FA9C ; DATA XREF: sub_DE↑r<br />
RAM:00000138 off_138 DCD 0x400049F0 ; DATA XREF: sub_F0↑r<br />
RAM:0000013C dword_13C DCD 0x40010000 ; DATA XREF: sub_F0+6↑r<br />
RAM:00000140 off_140 DCD APBDEV_PMC_CNTRL_0 ; DATA XREF: sub_F0+C↑r<br />
RAM:00000144 off_144 DCD 0x40010220 ; DATA XREF: sub_102↑r<br />
RAM:00000148 ; ---------------------------------------------------------------------------<br />
RAM:00000148 ; START OF FUNCTION CHUNK FOR sub_A0<br />
RAM:00000148<br />
RAM:00000148 pop_r2_mov_pc_lr ; CODE XREF: sub_48+42↑j<br />
RAM:00000148 ; sub_8C+6↑j ...<br />
RAM:00000148 POP {R2}<br />
RAM:0000014A MOV PC, LR<br />
RAM:0000014A ; END OF FUNCTION CHUNK FOR sub_A0<br />
</syntaxhighlight><br />
<br />
The last 4 patches are exclusive to the Switch, while the remaining ones are often included in most Tegra210 based devices.<br />
<br />
== Anti-downgrade ==<br />
The first bootloader verifies [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]] to prevent downgrading.<br />
How many fuses are expected to be burnt depends the device's unit type as below.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! System version<br />
! Expected number of burnt fuses (retail)<br />
! Expected number of burnt fuses (non-retail)<br />
|-<br />
| 1.0.0<br />
| 1<br />
| 0<br />
|-<br />
| 2.0.0-2.3.0<br />
| 2<br />
| 0<br />
|-<br />
| 3.0.0<br />
| 3<br />
| 1<br />
|-<br />
| 3.0.1-3.0.2<br />
| 4<br />
| 1<br />
|-<br />
| 4.0.0-4.1.0<br />
| 5<br />
| 1<br />
|-<br />
| 5.0.0<br />
| 6<br />
| 1<br />
|}<br />
<br />
If too many fuses are burnt the bootloader will panic immediately.<br />
<br />
If too few are burnt, the bootloader will enable fuse programming and write the expected value to fuse indexes 0x3A and 0x3C. Afterwards, fuse programming is disabled and the panic value 0x21 is written to PMC_SCRATCH200 register (0x7000EC40). Finally, the watchdog timer is initialized and programmed to force a reset.<br />
<br />
On a subsequent boot, after the anti-downgrade fuses are checked again, the PMC_RST_STATUS register (0x7000E5B4) is checked and if set to 0x01 (watchdog reset) the PMC_SCRATCH200 register (0x7000EC40) will be checked for the panic value 0x21.<br />
PMC_RST_STATUS will only be set back to 0 (power on reset) if the fuse count matches the new expected value, otherwise the system will panic.</div>
Rajkosto
https://switchbrew.org/w/index.php?title=Flash_Filesystem&diff=4469
Flash Filesystem
2018-04-15T01:13:38Z
<p>Rajkosto: Specify which bis keys are used for which partitions</p>
<hr />
<div>= NAND structure =<br />
The Switch's eMMC storage features a large user area, two smaller boot partitions and a replay-protected memory block which is unused (no authentication key is programmed).<br />
<br />
All official partition names come from [[SystemInitializer]].<br />
<br />
== Boot Partitions ==<br />
<br />
'''Boot Partition 0 (0 of 1)'''<br />
<br />
The official name for this partition is "BootPartition1Root" and it has [[Filesystem_services|Bis]] Partition ID == 0.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x000000<br />
| 0x4000<br />
| Normal Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 0100000000000819]]<br />
|-<br />
| 0x004000<br />
| 0x4000<br />
| SafeMode Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 010000000000081A]]<br />
|-<br />
| 0x008000<br />
| 0x4000<br />
| Normal Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 0100000000000819]] (backup)<br />
|-<br />
| 0x00C000<br />
| 0x4000<br />
| SafeMode Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 010000000000081A]] (backup)<br />
|-<br />
| 0x010000<br />
| 0xF0000<br />
| 60 additional BCTs, normally unused/empty on retail systems.<br />
|-<br />
| 0x100000<br />
| 0x40000<br />
| Normal Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 0100000000000819]]<br />
|-<br />
| 0x140000<br />
| 0x40000<br />
| Normal Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 0100000000000819]] (backup)<br />
|-<br />
| 0x180000<br />
| 0x4000<br />
| [[#Keyblob|Keyblob area]]<br />
|-<br />
| 0x184000<br />
| 0x20<br />
| Unknown pseudorandom data, often changes on reboot. All zero on 1.0.<br />
|-<br />
| 0x184020<br />
| 0x8?<br />
| Increments on every boot until hitting a certain number? Bottom 10 bits (0x3FF) are always zero. All zero on 1.0.<br />
|}<br />
<br />
'''Boot Partition 1 (1 of 1)'''<br />
<br />
The official name for this partition is "BootPartition2Root" and it has [[Filesystem_services|Bis]] Partition ID == 10.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x000000<br />
| 0x40000<br />
| SafeMode Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 010000000000081A]]<br />
|-<br />
| 0x040000<br />
| 0x40000<br />
| SafeMode Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 010000000000081A]] (backup)<br />
|}<br />
<br />
=== Keyblob ===<br />
Starting at offset 0x180000 is an array of 0x200-byte entries, for a total of 32 keyblobs. Each one is unique compared to the others and they are all console unique. This is officially known as the "EKS" (encryption key source) area.<br />
<br />
From each 0x200-byte entry only the first 0xB0 bytes effectively form the keyblob as below.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 0x10<br />
| Keyblob AES-CMAC over the next 0xA0 bytes (safe against timing attacks)<br />
|-<br />
| 0x10<br />
| 0x10<br />
| Keyblob AES CTR<br />
|-<br />
| 0x20<br />
| 0x90<br />
| Keyblob encrypted payload<br />
|-<br />
| 0xB0<br />
| 0x150<br />
| Unused, all-zero.<br />
|}<br />
<br />
The active bootloader's version (offset 0x2330 in the BCT) acts as an index to control which keyblob should be installed into the system.<br />
[[NS_Services|NS]] uses this during system updates to install the keyblob into the [[BCT#customer_data|customer data]] section in BCTs (offset 0x450).<br />
<br />
[[Boot]] also uses this index for repairing corrupt sectors.<br />
<br />
The currently active keyblob is officially known as "SecureInfo".<br />
<br />
== User Partitions ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Partition name<br />
! Offset<br />
! Size<br />
! [[Filesystem_services|Bis]] Partition ID<br />
! Encrypted<br />
! Description<br />
|-<br />
| N/A<br />
| 0x0<br />
| <br />
| 20<br />
| No<br />
| GPT header, Bis-storage also allows raw access to the entire NAND eMMC sectors starting at sector0. The official name for this partition is "UserDataRoot".<br />
|-<br />
| PRODINFO<br />
| 0x00004400<br />
| 0x003FBC00<br />
| 27<br />
| Yes (Bis key 0)<br />
| "CAL0" raw partition containing set:cal data. The official name for this partition is "CalibrationBinary".<br />
|-<br />
| PRODINFOF<br />
| 0x00400000<br />
| 0x00400000<br />
| 28<br />
| Yes (Bis key 0)<br />
| FAT12 filesystem, additional calibration. The official name for this partition is "CalibrationFile".<br />
|-<br />
| BCPKG2-1-Normal-Main<br />
| 0x00800000<br />
| 0x00800000<br />
| 21<br />
| No<br />
| Raw partition where the first 0x4000 bytes (usually empty) contain the [[BootConfig]] and the remaining space contains the [[Package2|package2]] image from [[Title_list#System_Data_Archives|Title 0100000000000819]] by default. With the exFAT update installed, the [[Package2|package2]] image is switched to the one from [[Title_list#System_Data_Archives|Title 010000000000081B]]. The official name for this partition is "BootConfigAndPackage2Part1".<br />
|-<br />
| BCPKG2-2-Normal-Sub<br />
| 0x01000000<br />
| 0x00800000<br />
| 22<br />
| No<br />
| Backup partition for BCPKG2-1-Normal-Main. The official name for this partition is "BootConfigAndPackage2Part2".<br />
|-<br />
| BCPKG2-3-SafeMode-Main<br />
| 0x01800000<br />
| 0x00800000<br />
| 23<br />
| No<br />
| Raw partition where the first 0x4000 bytes (usually empty) contain the [[BootConfig]] and the remaining space contains the [[Package2|package2]] image from [[Title_list#System_Data_Archives|Title 010000000000081A]] by default. On [4.0.0+] and with the exFAT update installed, the [[Package2|package2]] image is switched to the one from [[Title_list#System_Data_Archives|Title 010000000000081C]]. The official name for this partition is "BootConfigAndPackage2Part3".<br />
|-<br />
| BCPKG2-4-SafeMode-Sub<br />
| 0x02000000<br />
| 0x00800000<br />
| 24<br />
| No<br />
| Backup partition for BCPKG2-3-SafeMode-Main. The official name for this partition is "BootConfigAndPackage2Part4".<br />
|-<br />
| BCPKG2-5-Repair-Main<br />
| 0x02800000<br />
| 0x00800000<br />
| 25<br />
| No<br />
| Installed at the factory, never written afterwards on retail. In one case this is identical to normal [[1.0.0]] [[Package2|package2]], except this has encrypted data at the end padded for 0x1000-byte alignment. The official name for this partition is "BootConfigAndPackage2Part5".<br />
|-<br />
| BCPKG2-6-Repair-Sub<br />
| 0x03000000<br />
| 0x00800000<br />
| 26<br />
| No<br />
| Backup partition for BCPKG2-5-Repair-Main. The official name for this partition is "BootConfigAndPackage2Part6".<br />
|-<br />
| SAFE<br />
| 0x03800000<br />
| 0x04000000<br />
| 29<br />
| Yes (Bis key 1)<br />
| FAT32 filesystem. The official name for this partition is "SafeMode".<br />
|-<br />
| SYSTEM<br />
| 0x07800000 <br />
| 0xA0000000<br />
| 31 and 32<br />
| Yes (Bis key 2)<br />
| FAT32 filesystem. The official name for this partition is "SystemProperEncryption".<br />
|-<br />
| USER<br />
| 0xA7800000<br />
| 0x680000000<br />
| 30<br />
| Yes (Bis key 3)<br />
| FAT32 filesystem.<br />
|-<br />
| <br />
| 0x747BFFE00<br />
| 0x200<br />
| <br />
| No<br />
| This is the backup GPT header specified by the main GPT header. This is also the last sector readable with Bis-storage paritionID 20.<br />
|}<br />
<br />
If the client process lacks the relevant permission for any of the above partition IDs, error 0x2EE202 is returned.<br />
<br />
[[NCA]]s stored in NAND are raw, identical to the data readable with [[Content_Manager_services#ReadEntryRaw]].<br />
<br />
The filenames for saveimages is just "<lower-case hex u64 saveID>". SYSTEM-partition saveIDs are specified by [[Filesystem_services|FS]] commands, while USER-partition saveIDs are determined by FS-module internally. The high u32 of the saveID is normally either 0x00000000 or 0x80000000.<br />
<br />
Encrypted partitions use AES-XTS using the same non-standard tweak (tweak[0] = sectorIdx[MSB] .. tweak[15] = sectorIdx[LSB], if using 32bit sectorIdx that means tweak[0]..tweak[11] are 0, with tweak[12]..tweak[15] containing big-endian sectorIdx) as other Nintendo AES-XTS code, initial_sector = 0, and sector size 0x4000. All encrypted partitions use console unique keydata.<br />
<br />
=== PRODINFOF ===<br />
PRODINFOF<br />
├── Certifications<br />
│ └── WirelessCertification.png<br />
└── ptd<br />
├── DeviceIdWithEmsBit.dat<br />
├── Ecid.dat<br />
├── prodCode.dat<br />
└── log<br />
├── Process_asm1.log<br />
├── Process_board1.log<br />
├── TestFlagLine.log<br />
├── TestFlagQc.log<br />
├── AGING<br />
│ └── Sequence.log<br />
├── BOARD_TEST<br />
│ └── Sequence.log<br />
├── BOARD_WIRELESS<br />
│ └── Sequence.log<br />
├── FINAL_CHECK<br />
│ └── Sequence.log<br />
├── LCD_AND_KEY<br />
│ └── Sequence.log<br />
└── USB_AND_HP<br />
└── Sequence.log<br />
<br />
==== DeviceIdWithEmsBit.dat ====<br />
Contains a 0x10-byte uppercase hex string, identical to the DeviceId in the [[Settings_services|DeviceCert]].<br />
<br />
=== SYSTEM ===<br />
SYSTEM<br />
├── PRF2SAFE.RCV<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]]<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
├── [[Savegames|save]]<br />
│ └── ...<br />
└── saveMeta<br />
└── ... (empty?)<br />
<br />
The saves stored under this partition are only for system-titles / etc.<br />
<br />
=== USER ===<br />
USER<br />
├── PRF2SAFE.RCV<br />
├── Album (Same layout as [[SD_Filesystem|SD]])<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]]<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
├── [[Savegames|save]]<br />
│ └── ...<br />
├── saveMeta<br />
│ └── ... <br />
└── temp <br />
<br />
The saves for all non-system applications, regardless of where the application is located(storageID), is stored here. Each user account which has savedata has a separate saveimage. Save-common for an application is presumably a separate saveimage too. Every saveimage here is ''only'' for applications.<br />
<br />
=== SAFE ===<br />
SAFE<br />
├── PRF2SAFE.RCV<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]] (nothing installed?)<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
└── [[Savegames|save]]<br />
├── 8000000000000000<br />
└── 8000000000000120<br />
<br />
On a v2.1 system with MountBis, the only thing under here is "PRF2SAFE.RCV".<br />
<br />
= System Savegames =<br />
<br />
This is a listing of known System Savedata and what titles they correspond to.<br />
<br />
{| class="wikitable" border="1"<br />
! SaveID || Owner || Mount || Notes<br />
|-<br />
| 0x8000000000000000 || || || <br />
|-<br />
| 0x8000000000000010 || account || <nowiki>account:/</nowiki> || Account database.<br />
|-<br />
| 0x8000000000000011 || account || <nowiki>idgen:/</nowiki> ||<br />
|-<br />
| 0x8000000000000020 || nfc || <nowiki>data:/</nowiki> || NFC data and backups.<br />
|-<br />
| 0x8000000000000030 || ns || <nowiki>mii:/</nowiki> || Mii database.<br />
|-<br />
| 0x8000000000000031 || ns || <nowiki>mii:/</nowiki> || Mii test mode database.<br />
|-<br />
| 0x8000000000000040 || ns || <nowiki>apprecdb:/</nowiki> ||<br />
|-<br />
| 0x8000000000000041 || ns || <nowiki>nsaccache:/</nowiki> || Home menu icondata/lru list for recently played games.<br />
|-<br />
| 0x8000000000000043 || ns || <nowiki>ns_appman:/</nowiki> ||<br />
|-<br />
| 0x8000000000000044 || ns || <nowiki>ns_sysup:/</nowiki> || Content update context.<br />
|-<br />
| 0x8000000000000045 || ns || <nowiki>vmdb:/</nowiki> || Version List/Required Version List storage.<br />
|-<br />
| 0x8000000000000046 || ns || <nowiki>dtlman:/</nowiki> ||<br />
|-<br />
| 0x8000000000000047 || ns || <nowiki>ns_exfat:/</nowiki> ||<br />
|-<br />
| 0x8000000000000048 || ns || <nowiki>ns_systemseed:/</nowiki> ||<br />
|-<br />
| 0x8000000000000050 || settings || <nowiki>SystemSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000051 || settings || <nowiki>FwdbgSettingsS:/</nowiki> ||<br />
|-<br />
| 0x8000000000000052 || settings || <nowiki>PrivateSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000053 || settings || <nowiki>DeviceSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000054 || settings || <nowiki>ApplnSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000060 || ssl || <nowiki>SslSave:/</nowiki> ||<br />
|-<br />
| 0x8000000000000070 || nim || <nowiki>nim_sys:/</nowiki> ||<br />
|-<br />
| 0x8000000000000071 || nim || <nowiki>nim_net:/</nowiki> ||<br />
|-<br />
| 0x8000000000000072 || nim || <nowiki>nim_tmp:/</nowiki> ||<br />
|-<br />
| 0x8000000000000073 || nim || <nowiki>nim_dac:/</nowiki> ||<br />
|-<br />
| 0x8000000000000074 || nim || <nowiki>nim_delta:/</nowiki> ||<br />
|-<br />
| 0x8000000000000075 || nim || <nowiki>nim_vac:/</nowiki> ||<br />
|-<br />
| 0x8000000000000080 || friends || <nowiki>friends:/</nowiki> ||<br />
|-<br />
| 0x8000000000000081 || friends || <nowiki>friends-sys:/</nowiki> ||<br />
|-<br />
| 0x8000000000000082 || friends || <nowiki>friends-image:/</nowiki> ||<br />
|-<br />
| 0x8000000000000090 || bcat || <nowiki>news:/</nowiki> || Actual news msgpack archives.<br />
|-<br />
| 0x8000000000000091 || bcat || <nowiki>news-sys:/</nowiki> || News metadata, tasklist, history, database, required system version, etc.<br />
|-<br />
| 0x8000000000000092 || bcat || <nowiki>news-dl:/</nowiki> || Storage for newly(?) downloaded news list/data.<br />
|-<br />
| 0x80000000000000A0 || bcat || <nowiki>prepo-sys:/</nowiki> || Play Report system information.<br />
|-<br />
| 0x80000000000000A1 || bcat || <nowiki>prepo:/</nowiki> || Play Report msgpack archives.<br />
|-<br />
| 0x80000000000000B0 || bsdsockets || <nowiki>nsdsave:/</nowiki> || Socket configuration saved data.<br />
|-<br />
| 0x80000000000000C1 || bcat || <nowiki>bcat-sys:/</nowiki> ||<br />
|-<br />
| 0x80000000000000C2 || bcat || <nowiki>bcat-dl:/</nowiki> ||<br />
|-<br />
| 0x80000000000000D1 || erpt || <nowiki>save:/</nowiki> || Contains "/journal" report listing + actual crash reports ("/%08x-%04x-%04x-%02x%02x-%04x%08x"), which are serialized via [http://msgpack.org/ MsgPack].<br />
|-<br />
| 0x80000000000000E0 || es || <nowiki>escertificate:/</nowiki> ||<br />
|-<br />
| 0x80000000000000E1 || es || <nowiki>escommon:/</nowiki> ||<br />
|-<br />
| 0x80000000000000E2 || es || <nowiki>espersonalized:/</nowiki> ||<br />
|-<br />
| 0x80000000000000F0 || ns || <nowiki>pdm:/</nowiki> || Play Data log.<br />
|-<br />
| 0x8000000000000100 || pctl || <nowiki>pctlss:/</nowiki> || Parental Control settings.<br />
|-<br />
| 0x8000000000000110 || npns || <nowiki>npns_save:/</nowiki> || Push notifications persistent storage.<br />
|-<br />
| 0x8000000000000120 || ncm || ? || meta/[[IMKV|imkvdb.arc]] for system partition. Cache of data extracted from the [[NCA|.cnmt]] for installed titles?(Including 816)<br />
|-<br />
| 0x8000000000000121 || ncm || ? || meta/[[IMKV|imkvdb.arc]] for sd partition. In some cases this save only contains a "meta/" directory without any file.<br />
|-<br />
| 0x8000000000000122 || || || <br />
|-<br />
| 0x8000000000001010 || || || <br />
|-<br />
| 0x8000000000001040 || || || <br />
|-<br />
| 0x8000000000001050 || || || <br />
|-<br />
| 0x8000000000001070 || || || <br />
|-<br />
| 0x80000000000010B0 || || || <br />
|-<br />
| 0x0000000000000001 || || || <br />
|-<br />
| 0x0000000000000003 || || || <br />
|-<br />
| 0x0000000000000004 || || || <br />
|-<br />
| 0x0000000000000005 || || || <br />
|-<br />
| 0x0000000000000006 || || || <br />
|-<br />
| 0x0000000000000007 || || || <br />
|-<br />
| 0x0000000000000008 || || || <br />
|-<br />
| 0x0000000000000009 || || || <br />
|-<br />
| 0x000000000000000A || || || <br />
|-<br />
| 0x8000000000001060 || || || <br />
|-<br />
| 0x000000000000000C || || || <br />
|-<br />
| 0x000000000000000D || || || <br />
|-<br />
|}</div>
Rajkosto
https://switchbrew.org/w/index.php?title=Flash_Filesystem&diff=4468
Flash Filesystem
2018-04-15T00:48:11Z
<p>Rajkosto: better explain the aes-xts tweak</p>
<hr />
<div>= NAND structure =<br />
The Switch's eMMC storage features a large user area, two smaller boot partitions and a replay-protected memory block which is unused (no authentication key is programmed).<br />
<br />
All official partition names come from [[SystemInitializer]].<br />
<br />
== Boot Partitions ==<br />
<br />
'''Boot Partition 0 (0 of 1)'''<br />
<br />
The official name for this partition is "BootPartition1Root" and it has [[Filesystem_services|Bis]] Partition ID == 0.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x000000<br />
| 0x4000<br />
| Normal Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 0100000000000819]]<br />
|-<br />
| 0x004000<br />
| 0x4000<br />
| SafeMode Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 010000000000081A]]<br />
|-<br />
| 0x008000<br />
| 0x4000<br />
| Normal Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 0100000000000819]] (backup)<br />
|-<br />
| 0x00C000<br />
| 0x4000<br />
| SafeMode Firmware [[BCT|BCT]] from [[Title_list#System_Data_Archives|Title 010000000000081A]] (backup)<br />
|-<br />
| 0x010000<br />
| 0xF0000<br />
| 60 additional BCTs, normally unused/empty on retail systems.<br />
|-<br />
| 0x100000<br />
| 0x40000<br />
| Normal Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 0100000000000819]]<br />
|-<br />
| 0x140000<br />
| 0x40000<br />
| Normal Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 0100000000000819]] (backup)<br />
|-<br />
| 0x180000<br />
| 0x4000<br />
| [[#Keyblob|Keyblob area]]<br />
|-<br />
| 0x184000<br />
| 0x20<br />
| Unknown pseudorandom data, often changes on reboot. All zero on 1.0.<br />
|-<br />
| 0x184020<br />
| 0x8?<br />
| Increments on every boot until hitting a certain number? Bottom 10 bits (0x3FF) are always zero. All zero on 1.0.<br />
|}<br />
<br />
'''Boot Partition 1 (1 of 1)'''<br />
<br />
The official name for this partition is "BootPartition2Root" and it has [[Filesystem_services|Bis]] Partition ID == 10.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x000000<br />
| 0x40000<br />
| SafeMode Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 010000000000081A]]<br />
|-<br />
| 0x040000<br />
| 0x40000<br />
| SafeMode Firmware [[Package1|package1]] from [[Title_list#System_Data_Archives|Title 010000000000081A]] (backup)<br />
|}<br />
<br />
=== Keyblob ===<br />
Starting at offset 0x180000 is an array of 0x200-byte entries, for a total of 32 keyblobs. Each one is unique compared to the others and they are all console unique. This is officially known as the "EKS" (encryption key source) area.<br />
<br />
From each 0x200-byte entry only the first 0xB0 bytes effectively form the keyblob as below.<br />
<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 0x10<br />
| Keyblob AES-CMAC over the next 0xA0 bytes (safe against timing attacks)<br />
|-<br />
| 0x10<br />
| 0x10<br />
| Keyblob AES CTR<br />
|-<br />
| 0x20<br />
| 0x90<br />
| Keyblob encrypted payload<br />
|-<br />
| 0xB0<br />
| 0x150<br />
| Unused, all-zero.<br />
|}<br />
<br />
The active bootloader's version (offset 0x2330 in the BCT) acts as an index to control which keyblob should be installed into the system.<br />
[[NS_Services|NS]] uses this during system updates to install the keyblob into the [[BCT#customer_data|customer data]] section in BCTs (offset 0x450).<br />
<br />
[[Boot]] also uses this index for repairing corrupt sectors.<br />
<br />
The currently active keyblob is officially known as "SecureInfo".<br />
<br />
== User Partitions ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Partition name<br />
! Offset<br />
! Size<br />
! [[Filesystem_services|Bis]] Partition ID<br />
! Encrypted<br />
! Description<br />
|-<br />
| N/A<br />
| 0x0<br />
| <br />
| 20<br />
| No<br />
| GPT header, Bis-storage also allows raw access to the entire NAND eMMC sectors starting at sector0. The official name for this partition is "UserDataRoot".<br />
|-<br />
| PRODINFO<br />
| 0x00004400<br />
| 0x003FBC00<br />
| 27<br />
| Yes<br />
| "CAL0" raw partition containing set:cal data. The official name for this partition is "CalibrationBinary".<br />
|-<br />
| PRODINFOF<br />
| 0x00400000<br />
| 0x00400000<br />
| 28<br />
| Yes<br />
| FAT12 filesystem, additional calibration. The official name for this partition is "CalibrationFile".<br />
|-<br />
| BCPKG2-1-Normal-Main<br />
| 0x00800000<br />
| 0x00800000<br />
| 21<br />
| No<br />
| Raw partition where the first 0x4000 bytes (usually empty) contain the [[BootConfig]] and the remaining space contains the [[Package2|package2]] image from [[Title_list#System_Data_Archives|Title 0100000000000819]] by default. With the exFAT update installed, the [[Package2|package2]] image is switched to the one from [[Title_list#System_Data_Archives|Title 010000000000081B]]. The official name for this partition is "BootConfigAndPackage2Part1".<br />
|-<br />
| BCPKG2-2-Normal-Sub<br />
| 0x01000000<br />
| 0x00800000<br />
| 22<br />
| No<br />
| Backup partition for BCPKG2-1-Normal-Main. The official name for this partition is "BootConfigAndPackage2Part2".<br />
|-<br />
| BCPKG2-3-SafeMode-Main<br />
| 0x01800000<br />
| 0x00800000<br />
| 23<br />
| No<br />
| Raw partition where the first 0x4000 bytes (usually empty) contain the [[BootConfig]] and the remaining space contains the [[Package2|package2]] image from [[Title_list#System_Data_Archives|Title 010000000000081A]] by default. On [4.0.0+] and with the exFAT update installed, the [[Package2|package2]] image is switched to the one from [[Title_list#System_Data_Archives|Title 010000000000081C]]. The official name for this partition is "BootConfigAndPackage2Part3".<br />
|-<br />
| BCPKG2-4-SafeMode-Sub<br />
| 0x02000000<br />
| 0x00800000<br />
| 24<br />
| No<br />
| Backup partition for BCPKG2-3-SafeMode-Main. The official name for this partition is "BootConfigAndPackage2Part4".<br />
|-<br />
| BCPKG2-5-Repair-Main<br />
| 0x02800000<br />
| 0x00800000<br />
| 25<br />
| No<br />
| Installed at the factory, never written afterwards on retail. In one case this is identical to normal [[1.0.0]] [[Package2|package2]], except this has encrypted data at the end padded for 0x1000-byte alignment. The official name for this partition is "BootConfigAndPackage2Part5".<br />
|-<br />
| BCPKG2-6-Repair-Sub<br />
| 0x03000000<br />
| 0x00800000<br />
| 26<br />
| No<br />
| Backup partition for BCPKG2-5-Repair-Main. The official name for this partition is "BootConfigAndPackage2Part6".<br />
|-<br />
| SAFE<br />
| 0x03800000<br />
| 0x04000000<br />
| 29<br />
| Yes<br />
| FAT32 filesystem. The official name for this partition is "SafeMode".<br />
|-<br />
| SYSTEM<br />
| 0x07800000 <br />
| 0xA0000000<br />
| 31 and 32<br />
| Yes<br />
| FAT32 filesystem. The official name for this partition is "SystemProperEncryption".<br />
|-<br />
| USER<br />
| 0xA7800000<br />
| 0x680000000<br />
| 30<br />
| Yes<br />
| FAT32 filesystem.<br />
|-<br />
| <br />
| 0x747BFFE00<br />
| 0x200<br />
| <br />
| No<br />
| This is the backup GPT header specified by the main GPT header. This is also the last sector readable with Bis-storage paritionID 20.<br />
|}<br />
<br />
If the client process lacks the relevant permission for any of the above partition IDs, error 0x2EE202 is returned.<br />
<br />
[[NCA]]s stored in NAND are raw, identical to the data readable with [[Content_Manager_services#ReadEntryRaw]].<br />
<br />
The filenames for saveimages is just "<lower-case hex u64 saveID>". SYSTEM-partition saveIDs are specified by [[Filesystem_services|FS]] commands, while USER-partition saveIDs are determined by FS-module internally. The high u32 of the saveID is normally either 0x00000000 or 0x80000000.<br />
<br />
Encrypted partitions use AES-XTS using the same non-standard tweak (tweak[0] = sectorIdx[MSB] .. tweak[15] = sectorIdx[LSB], if using 32bit sectorIdx that means tweak[0]..tweak[11] are 0, with tweak[12]..tweak[15] containing big-endian sectorIdx) as other Nintendo AES-XTS code, initial_sector = 0, and sector size 0x4000. All encrypted partitions use console unique keydata.<br />
<br />
=== PRODINFOF ===<br />
PRODINFOF<br />
├── Certifications<br />
│ └── WirelessCertification.png<br />
└── ptd<br />
├── DeviceIdWithEmsBit.dat<br />
├── Ecid.dat<br />
├── prodCode.dat<br />
└── log<br />
├── Process_asm1.log<br />
├── Process_board1.log<br />
├── TestFlagLine.log<br />
├── TestFlagQc.log<br />
├── AGING<br />
│ └── Sequence.log<br />
├── BOARD_TEST<br />
│ └── Sequence.log<br />
├── BOARD_WIRELESS<br />
│ └── Sequence.log<br />
├── FINAL_CHECK<br />
│ └── Sequence.log<br />
├── LCD_AND_KEY<br />
│ └── Sequence.log<br />
└── USB_AND_HP<br />
└── Sequence.log<br />
<br />
==== DeviceIdWithEmsBit.dat ====<br />
Contains a 0x10-byte uppercase hex string, identical to the DeviceId in the [[Settings_services|DeviceCert]].<br />
<br />
=== SYSTEM ===<br />
SYSTEM<br />
├── PRF2SAFE.RCV<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]]<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
├── [[Savegames|save]]<br />
│ └── ...<br />
└── saveMeta<br />
└── ... (empty?)<br />
<br />
The saves stored under this partition are only for system-titles / etc.<br />
<br />
=== USER ===<br />
USER<br />
├── PRF2SAFE.RCV<br />
├── Album (Same layout as [[SD_Filesystem|SD]])<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]]<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
├── [[Savegames|save]]<br />
│ └── ...<br />
├── saveMeta<br />
│ └── ... <br />
└── temp <br />
<br />
The saves for all non-system applications, regardless of where the application is located(storageID), is stored here. Each user account which has savedata has a separate saveimage. Save-common for an application is presumably a separate saveimage too. Every saveimage here is ''only'' for applications.<br />
<br />
=== SAFE ===<br />
SAFE<br />
├── PRF2SAFE.RCV<br />
├── Contents<br />
│ ├── registered<br />
│ │ └── ... [[NCA]] (nothing installed?)<br />
│ └── placehld<br />
│ └── ... [[NCA]]<br />
└── [[Savegames|save]]<br />
├── 8000000000000000<br />
└── 8000000000000120<br />
<br />
On a v2.1 system with MountBis, the only thing under here is "PRF2SAFE.RCV".<br />
<br />
= System Savegames =<br />
<br />
This is a listing of known System Savedata and what titles they correspond to.<br />
<br />
{| class="wikitable" border="1"<br />
! SaveID || Owner || Mount || Notes<br />
|-<br />
| 0x8000000000000000 || || || <br />
|-<br />
| 0x8000000000000010 || account || <nowiki>account:/</nowiki> || Account database.<br />
|-<br />
| 0x8000000000000011 || account || <nowiki>idgen:/</nowiki> ||<br />
|-<br />
| 0x8000000000000020 || nfc || <nowiki>data:/</nowiki> || NFC data and backups.<br />
|-<br />
| 0x8000000000000030 || ns || <nowiki>mii:/</nowiki> || Mii database.<br />
|-<br />
| 0x8000000000000031 || ns || <nowiki>mii:/</nowiki> || Mii test mode database.<br />
|-<br />
| 0x8000000000000040 || ns || <nowiki>apprecdb:/</nowiki> ||<br />
|-<br />
| 0x8000000000000041 || ns || <nowiki>nsaccache:/</nowiki> || Home menu icondata/lru list for recently played games.<br />
|-<br />
| 0x8000000000000043 || ns || <nowiki>ns_appman:/</nowiki> ||<br />
|-<br />
| 0x8000000000000044 || ns || <nowiki>ns_sysup:/</nowiki> || Content update context.<br />
|-<br />
| 0x8000000000000045 || ns || <nowiki>vmdb:/</nowiki> || Version List/Required Version List storage.<br />
|-<br />
| 0x8000000000000046 || ns || <nowiki>dtlman:/</nowiki> ||<br />
|-<br />
| 0x8000000000000047 || ns || <nowiki>ns_exfat:/</nowiki> ||<br />
|-<br />
| 0x8000000000000048 || ns || <nowiki>ns_systemseed:/</nowiki> ||<br />
|-<br />
| 0x8000000000000050 || settings || <nowiki>SystemSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000051 || settings || <nowiki>FwdbgSettingsS:/</nowiki> ||<br />
|-<br />
| 0x8000000000000052 || settings || <nowiki>PrivateSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000053 || settings || <nowiki>DeviceSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000054 || settings || <nowiki>ApplnSettings:/</nowiki> ||<br />
|-<br />
| 0x8000000000000060 || ssl || <nowiki>SslSave:/</nowiki> ||<br />
|-<br />
| 0x8000000000000070 || nim || <nowiki>nim_sys:/</nowiki> ||<br />
|-<br />
| 0x8000000000000071 || nim || <nowiki>nim_net:/</nowiki> ||<br />
|-<br />
| 0x8000000000000072 || nim || <nowiki>nim_tmp:/</nowiki> ||<br />
|-<br />
| 0x8000000000000073 || nim || <nowiki>nim_dac:/</nowiki> ||<br />
|-<br />
| 0x8000000000000074 || nim || <nowiki>nim_delta:/</nowiki> ||<br />
|-<br />
| 0x8000000000000075 || nim || <nowiki>nim_vac:/</nowiki> ||<br />
|-<br />
| 0x8000000000000080 || friends || <nowiki>friends:/</nowiki> ||<br />
|-<br />
| 0x8000000000000081 || friends || <nowiki>friends-sys:/</nowiki> ||<br />
|-<br />
| 0x8000000000000082 || friends || <nowiki>friends-image:/</nowiki> ||<br />
|-<br />
| 0x8000000000000090 || bcat || <nowiki>news:/</nowiki> || Actual news msgpack archives.<br />
|-<br />
| 0x8000000000000091 || bcat || <nowiki>news-sys:/</nowiki> || News metadata, tasklist, history, database, required system version, etc.<br />
|-<br />
| 0x8000000000000092 || bcat || <nowiki>news-dl:/</nowiki> || Storage for newly(?) downloaded news list/data.<br />
|-<br />
| 0x80000000000000A0 || bcat || <nowiki>prepo-sys:/</nowiki> || Play Report system information.<br />
|-<br />
| 0x80000000000000A1 || bcat || <nowiki>prepo:/</nowiki> || Play Report msgpack archives.<br />
|-<br />
| 0x80000000000000B0 || bsdsockets || <nowiki>nsdsave:/</nowiki> || Socket configuration saved data.<br />
|-<br />
| 0x80000000000000C1 || bcat || <nowiki>bcat-sys:/</nowiki> ||<br />
|-<br />
| 0x80000000000000C2 || bcat || <nowiki>bcat-dl:/</nowiki> ||<br />
|-<br />
| 0x80000000000000D1 || erpt || <nowiki>save:/</nowiki> || Contains "/journal" report listing + actual crash reports ("/%08x-%04x-%04x-%02x%02x-%04x%08x"), which are serialized via [http://msgpack.org/ MsgPack].<br />
|-<br />
| 0x80000000000000E0 || es || <nowiki>escertificate:/</nowiki> ||<br />
|-<br />
| 0x80000000000000E1 || es || <nowiki>escommon:/</nowiki> ||<br />
|-<br />
| 0x80000000000000E2 || es || <nowiki>espersonalized:/</nowiki> ||<br />
|-<br />
| 0x80000000000000F0 || ns || <nowiki>pdm:/</nowiki> || Play Data log.<br />
|-<br />
| 0x8000000000000100 || pctl || <nowiki>pctlss:/</nowiki> || Parental Control settings.<br />
|-<br />
| 0x8000000000000110 || npns || <nowiki>npns_save:/</nowiki> || Push notifications persistent storage.<br />
|-<br />
| 0x8000000000000120 || ncm || ? || meta/[[IMKV|imkvdb.arc]] for system partition. Cache of data extracted from the [[NCA|.cnmt]] for installed titles?(Including 816)<br />
|-<br />
| 0x8000000000000121 || ncm || ? || meta/[[IMKV|imkvdb.arc]] for sd partition. In some cases this save only contains a "meta/" directory without any file.<br />
|-<br />
| 0x8000000000000122 || || || <br />
|-<br />
| 0x8000000000001010 || || || <br />
|-<br />
| 0x8000000000001040 || || || <br />
|-<br />
| 0x8000000000001050 || || || <br />
|-<br />
| 0x8000000000001070 || || || <br />
|-<br />
| 0x80000000000010B0 || || || <br />
|-<br />
| 0x0000000000000001 || || || <br />
|-<br />
| 0x0000000000000003 || || || <br />
|-<br />
| 0x0000000000000004 || || || <br />
|-<br />
| 0x0000000000000005 || || || <br />
|-<br />
| 0x0000000000000006 || || || <br />
|-<br />
| 0x0000000000000007 || || || <br />
|-<br />
| 0x0000000000000008 || || || <br />
|-<br />
| 0x0000000000000009 || || || <br />
|-<br />
| 0x000000000000000A || || || <br />
|-<br />
| 0x8000000000001060 || || || <br />
|-<br />
| 0x000000000000000C || || || <br />
|-<br />
| 0x000000000000000D || || || <br />
|-<br />
|}</div>
Rajkosto
https://switchbrew.org/w/index.php?title=NSO&diff=3058
NSO
2017-11-26T11:39:53Z
<p>Rajkosto: Undo revision 3057 by Rajkosto (talk)</p>
<hr />
<div>NSO is the main executable format.<br />
<br />
It starts with the "NSO" header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers):<br />
<br />
= NSO Header =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| Magic "NSO0"<br />
|-<br />
| 0x4<br />
| 4<br />
| <br />
|-<br />
| 0x8<br />
| 4<br />
| <br />
|-<br />
| 0xC<br />
| 4<br />
| Always 0x3f?<br />
|-<br />
| 0x10<br />
| 0x10 * 3<br />
| SegmentHeader[3]<br />
|-<br />
| 0x40<br />
| 0x20<br />
| Value of "build id" from ELF's GNU .note section. Contains variable sized digest, up to 32bytes.<br />
|-<br />
| 0x60<br />
| 0x4 * 3<br />
| CompressedSize[3]<br />
|-<br />
| 0x6c<br />
| 0x24<br />
| Padding<br />
|-<br />
| 0x90<br />
| 8<br />
| .rodata-relative extents of .dynstr<br />
|-<br />
| 0x98<br />
| 8<br />
| .rodata-relative extents of .dynsym<br />
|-<br />
| 0xA0<br />
| 0x20 * 3<br />
| SHA256 hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data.<br />
|-<br />
| 0x100<br />
|<br />
| Compressed sections<br />
|}<br />
<br />
Most data in Switch binaries are standard ELF structures, however some are custom.<br />
For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header.<br />
<br />
== SegmentHeader ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| FileOffset<br />
|-<br />
| 0x4<br />
| 4<br />
| MemoryOffset<br />
|-<br />
| 0x8<br />
| 4<br />
| DecompressedSize<br />
|-<br />
| 0xC<br />
| 4<br />
| UnkOffset/UnkSize/BssSize<br />
|}<br />
<br />
== .rodata-relative extent ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| RegionRoDataOffset<br />
|-<br />
| 0x4<br />
| 4<br />
| RegionSize<br />
|}<br />
<br />
== MOD ==<br />
All offsets are signed 32bit values relative to the magic field.<br />
The 32bits at image base + 4 must point to the magic field.<br />
The MOD structure is designed such that it can be placed at image base and point to itself.<br />
The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base. If MOD is not located at image base, the value at offset 4 must still point to the MOD magic. In the case of .text being at image base, this implies that the first instruction can only be an unconditional branch over the offset literal.<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x00<br />
| 4<br />
| ZeroPadding<br />
|-<br />
| 0x04<br />
| 4<br />
| MagicOffset. Always 8 (so it works when MOD is at image_base + 0).<br />
|-<br />
| 0x08<br />
| 4<br />
| Magic "MOD0"<br />
|-<br />
| 0x0C<br />
| 4<br />
| .dynamic offset<br />
|-<br />
| 0x10<br />
| 4<br />
| .bss start offset<br />
|-<br />
| 0x14<br />
| 4<br />
| .bss end offset<br />
|-<br />
| 0x18<br />
| 4<br />
| .eh_frame_hdr start offset<br />
|-<br />
| 0x1C<br />
| 4<br />
| .eh_frame_hdr end offset<br />
|-<br />
| 0x20<br />
| 4<br />
| offset to runtime-generated module object. typically equal to .bss base.<br />
|}</div>
Rajkosto
https://switchbrew.org/w/index.php?title=NSO&diff=3057
NSO
2017-11-26T11:23:14Z
<p>Rajkosto: obtained by looking at rtld</p>
<hr />
<div>NSO is the main executable format.<br />
<br />
It starts with the "NSO" header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers):<br />
<br />
= NSO Header =<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| Magic "NSO0"<br />
|-<br />
| 0x4<br />
| 4<br />
| <br />
|-<br />
| 0x8<br />
| 4<br />
| <br />
|-<br />
| 0xC<br />
| 4<br />
| Always 0x3f?<br />
|-<br />
| 0x10<br />
| 0x10 * 3<br />
| SegmentHeader[3]<br />
|-<br />
| 0x40<br />
| 0x20<br />
| Value of "build id" from ELF's GNU .note section. Contains variable sized digest, up to 32bytes.<br />
|-<br />
| 0x60<br />
| 0x4 * 3<br />
| CompressedSize[3]<br />
|-<br />
| 0x6c<br />
| 0x24<br />
| Padding<br />
|-<br />
| 0x90<br />
| 8<br />
| .rodata-relative extents of .dynstr<br />
|-<br />
| 0x98<br />
| 8<br />
| .rodata-relative extents of .dynsym<br />
|-<br />
| 0xA0<br />
| 0x20 * 3<br />
| SHA256 hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data.<br />
|-<br />
| 0x100<br />
|<br />
| Compressed sections<br />
|}<br />
<br />
Most data in Switch binaries are standard ELF structures, however some are custom.<br />
For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header.<br />
<br />
== SegmentHeader ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| FileOffset<br />
|-<br />
| 0x4<br />
| 4<br />
| MemoryOffset<br />
|-<br />
| 0x8<br />
| 4<br />
| DecompressedSize<br />
|-<br />
| 0xC<br />
| 4<br />
| UnkOffset/UnkSize/BssSize<br />
|}<br />
<br />
== .rodata-relative extent ==<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x0<br />
| 4<br />
| RegionRoDataOffset<br />
|-<br />
| 0x4<br />
| 4<br />
| RegionSize<br />
|}<br />
<br />
== MOD ==<br />
All offsets are signed 32bit values relative to the magic field.<br />
The 32bits at image base + 4 must point to the magic field.<br />
The MOD structure is designed such that it can be placed at image base and point to itself.<br />
The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base. If MOD is not located at image base, the value at offset 4 must still point to the MOD magic. In the case of .text being at image base, this implies that the first instruction can only be an unconditional branch over the offset literal.<br />
{| class="wikitable" border="1"<br />
|-<br />
! Offset<br />
! Size<br />
! Description<br />
|-<br />
| 0x00<br />
| 4<br />
| ZeroPadding<br />
|-<br />
| 0x04<br />
| 4<br />
| MagicOffset. Always 8 (so it works when MOD is at image_base + 0).<br />
|-<br />
| 0x08<br />
| 4<br />
| Magic "MOD0"<br />
|-<br />
| 0x0C<br />
| 4<br />
| .dynamic offset<br />
|-<br />
| 0x10<br />
| 4<br />
| .tdata offset<br />
|-<br />
| 0x14<br />
| 4<br />
| .tbss offset<br />
|-<br />
| 0x18<br />
| 4<br />
| .eh_frame_hdr start offset<br />
|-<br />
| 0x1C<br />
| 4<br />
| .eh_frame_hdr end offset<br />
|-<br />
| 0x20<br />
| 4<br />
| offset to runtime-generated module object. typically equal to .bss base.<br />
|}</div>
Rajkosto