IdStorage: Difference between revisions
(→Structure: Add detailed explanations on layout and limits) |
|||
Line 11: | Line 11: | ||
= Structure = | = Structure = | ||
The IdStorage partition is divided in two parts: the mapping table and the leaves. | |||
== Mapping table == | |||
The mapping table is located at the start of the partition. It's an array of 16-bit leaf IDs that serves as a leaf ID->index mapping table. The mapping table must be at least one-sector wide but may be bigger. | |||
There are two leaf IDs reserved for usage in the mapping table: all entries corresponding to the mapping table (i.e. the first <code>M</code> entries for an </code>M</code> sectors sized table) must hold the value <code>0xFFF5</code>, and all unallocated leaves hold the value <code>0xFFFF</code>. | |||
To lookup a leaf index based on its ID, use the following algorithm: | |||
<source lang="C"> | |||
#define M /* implementation defined */ | |||
#define NUM_TABLE_ITEMS ((M * SECTOR_SIZE) / sizeof(uint16_t)) | |||
uint16_t g_mappingTable[NUM_TABLE_ITEMS]; | |||
int leafIndexFromId(unsigned id) { | |||
if (id >= 0xFFF0) | |||
return /* ERROR: invalid leaf ID */; | |||
for (int i = 0; i < NUM_TABLE_ITEMS; i++) { | |||
if (g_mappingTable[i] == id) | |||
return i; | |||
} | |||
return /* ERROR: leaf ID is not in mapping table */; | |||
} | |||
</source> | |||
== Leaves == | |||
Leaves are used to store arbitrary data. On Vita, leaves are all 512-bytes sized (one sector). | |||
To read a leaf's data, obtain the leaf index (this can be known directly, or obtained from a leaf ID using the previously mentioned algorithm) then read 512 bytes starting at offset <code>512 * leafIndex</code> in the IdStorage partition. | |||
== Limits == | |||
The number of leaves that can be stored in an IdStorage partition is limited by three factors: the size of the partition, the size of the mapping table and the size of leaf IDs. | |||
* An <code>M</code> sectors wide mapping table can hold up to <code>255 * M</code> leaves | |||
** This is because a single-sector mapping table can hold <code>SECTOR_SIZE/sizeof(u16) - 1 = 255</code> leaves (<code>- 1</code> is needed because the table uses an entry for itself) | |||
* A <code>P</code> sectors wide partition can hold up to <code>P - M</code> leaves | |||
** This is because leaves are sector-sized, and the mapping table consumes <code>M</code> sectors | |||
* There are 65520 leaf IDs available | |||
** While an unsigned 16-bit variable can hold 65536 values, IDs superior or equal to 0xFFF0 are reserved and cannot be used | |||
From this, we can conclude that an IdStorage partition of <code>P</code> sectors with an <code>M</code> sectors mapping table can hold up to <code>min(255*M, P-M, 65520)</code> leaves. We can also deduce an IdStorage partition is optimally shaped (no space is non-allocatable) when <code>P = 256 * N</code>. | |||
On Vita, the IdStorage partition is 512KiB and 32 sectors are reserved for the indexing table (<code>P = 1024, M = 32</code>, a non-optimal choice), which means the console's partition can hold '''up to 992 IdStorage leaves'''. | |||
= Content = | = Content = |
Revision as of 15:22, 6 January 2023
See also [1].
Description
Region of the PSVita eMMC where perconsole info is stored.
Location
Idstorage data is stored at first raw partition (code 0x1). Use [2] to extract.
Structure
The IdStorage partition is divided in two parts: the mapping table and the leaves.
Mapping table
The mapping table is located at the start of the partition. It's an array of 16-bit leaf IDs that serves as a leaf ID->index mapping table. The mapping table must be at least one-sector wide but may be bigger.
There are two leaf IDs reserved for usage in the mapping table: all entries corresponding to the mapping table (i.e. the first M
entries for an M sectors sized table) must hold the value 0xFFF5
, and all unallocated leaves hold the value 0xFFFF
.
To lookup a leaf index based on its ID, use the following algorithm:
#define M /* implementation defined */ #define NUM_TABLE_ITEMS ((M * SECTOR_SIZE) / sizeof(uint16_t)) uint16_t g_mappingTable[NUM_TABLE_ITEMS]; int leafIndexFromId(unsigned id) { if (id >= 0xFFF0) return /* ERROR: invalid leaf ID */; for (int i = 0; i < NUM_TABLE_ITEMS; i++) { if (g_mappingTable[i] == id) return i; } return /* ERROR: leaf ID is not in mapping table */; }
Leaves
Leaves are used to store arbitrary data. On Vita, leaves are all 512-bytes sized (one sector).
To read a leaf's data, obtain the leaf index (this can be known directly, or obtained from a leaf ID using the previously mentioned algorithm) then read 512 bytes starting at offset 512 * leafIndex
in the IdStorage partition.
Limits
The number of leaves that can be stored in an IdStorage partition is limited by three factors: the size of the partition, the size of the mapping table and the size of leaf IDs.
- An
M
sectors wide mapping table can hold up to255 * M
leaves- This is because a single-sector mapping table can hold
SECTOR_SIZE/sizeof(u16) - 1 = 255
leaves (- 1
is needed because the table uses an entry for itself)
- This is because a single-sector mapping table can hold
- A
P
sectors wide partition can hold up toP - M
leaves- This is because leaves are sector-sized, and the mapping table consumes
M
sectors
- This is because leaves are sector-sized, and the mapping table consumes
- There are 65520 leaf IDs available
- While an unsigned 16-bit variable can hold 65536 values, IDs superior or equal to 0xFFF0 are reserved and cannot be used
From this, we can conclude that an IdStorage partition of P
sectors with an M
sectors mapping table can hold up to min(255*M, P-M, 65520)
leaves. We can also deduce an IdStorage partition is optimally shaped (no space is non-allocatable) when P = 256 * N
.
On Vita, the IdStorage partition is 512KiB and 32 sectors are reserved for the indexing table (P = 1024, M = 32
, a non-optimal choice), which means the console's partition can hold up to 992 IdStorage leaves.
Content
Table of leaves
Leaf Index | Empty? | Unique? | Notes |
---|---|---|---|
0x00->0x07 | No | No | SceIdStoragePspCertificates |
0x08->0x1F | Yes | No | |
0x20->0x27 | Yes | No | This is equal to SceIdStoragePspCertificates from leaf 0x00 to 0x07. |
0x28->0x3F | Yes | No | |
0x40->0x47 | No | Yes | SceIdStoragePsp2Certificates |
0x48->0x4F | No | Yes | It looks like a cert, but it may actually be useless data. |
0x50->0x7D | Yes | No | |
0x7E | No | Yes | |
0x7F | Yes | No | |
0x80 | No | Yes | Special leaf with "SMI" header. SMI data: factory firmware encrypted and signed. Contains minver at offset 0x08 (size 4 bytes). |
0x100 | No | Yes | Build data strings. |
0x102 | No | Yes | Like idstorage mgmt data, Some strings, Like some flags, And like mac address, Maybe more? |
0x103 | No | Yes | Hw info, Syscon version (include DL verstion), Production date, Mac address, Mac address (USB), some strings, and more. |
0x110 | No | Yes | Manufacturing flags (3 byte) + 0xFF padding. |
0x111 | No | Yes | Mac address (6 byte) + 0xFF padding. |
0x112 | No | Yes | Serial number wide strings. |
0x113 | No | Yes | 0xFFed. |
0x114 | No | Yes | some data (0x40 byte) + 0xFF padding. |
0x115 | No | Yes | Model strings + 0xFF padding. |