Ernie: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
 
(86 intermediate revisions by 6 users not shown)
Line 1: Line 1:
The Syscon is responsible for handling button input (including power button), and contains non-volatile memory for storing system flags (mostly encrypted and signed). For example Kiosk flag is stored here. Syscon is also responsible for maintaining the physical address to the resume buffer during [[Suspend]]. Communication between [[Kermit]] and Syscon is mainly through SPI (see [[SceSyscon]]) but there are also some GPIO pins connecting the two.
Ernie is the codename for the Syscon chip. The Syscon is for exemple responsible for handling button input (including power button), reading/writing to non-volatile storage (NVS) for storing system flags (mostly encrypted and signed). For example IDU flag is stored in NVS. Syscon is also responsible for maintaining the physical address to the resume buffer during [[Suspend]]. Communication between [[Kermit]] and Syscon is mainly through SPI (see [[SceSyscon]]) but there are also some GPIO pins connecting the two. The chip model is NEC/Renesas <code>uPD79F0109</code> and is likely custom designed for Sony.


== Boot Process ==
See also: [[Ernie Secure]]


The following is logged from boot. The timestamp is in seconds (the starting time is irrelevant). The arrow at the start indicates direction: '>' means Kermit to Syscon (MOSI) and '<' means Syscon to Kermit (MISO). Then there is a 2 byte command id or response code, followed by a flag byte (response only), the payload, a checksum byte, and an (response only) unknown byte. Please note that the packets are listed in transfer order but this may not represent the logical order of the packets. It is currently unknown what the logical order should be, but one can guess that a response is "close to" a request.
= Boot Process =


First some version information seems to be sent from Syscon to Kermit. This is same for cold boot and resume boot.
The following is logged from boot. The timestamp is in seconds (the starting time is irrelevant). The arrow at the start indicates direction: '>' means Kermit to Syscon (MOSI) and '<' means Syscon to Kermit (MISO). Then there is a 2 byte command id or response code, followed by a flag byte (response only), the payload, a [[#Packet checksum|checksum byte]], and an (response only) unknown byte. Please note that the packets are listed in transfer order but this may not represent the logical order of the packets. It is currently unknown what the logical order should be, but one can guess that a response is "close to" a request.
 
First some version information seems to be sent from Syscon to Kermit. This is same for cold boot and resume boot. The last response indicates the type of boot where 0xFF80 is resume and 0xFF14 is regular boot.


<pre>
<pre>
Line 98: Line 100:
</pre>
</pre>


Then another set of shared sequence. Some differences in the warmboot responses though. On line 18, <pre>FF BF FF 74</pre> becomes <pre>FF FF FF 74</pre>. On line 12, the <pre>00 00 00 00</pre> becomes the address of the resume buffer (ex <pre>F0 1E 1F 41</pre>).
Then another set of shared sequence. Some differences in the warmboot responses though. On line 18, <pre>FF BF FF 74</pre> becomes <pre>FF FF FF 74</pre>. On line 12, the <pre>00 00 00 00</pre> becomes the physical address of the resume context buffer. Example:
<pre>F0 1E 1F 41</pre>


<pre>
<pre>
Line 157: Line 160:
...
...
</pre>
</pre>
= Packet checksum =
The checksum byte of the packet is calculated as the binary negation of the sum of all the bytes of the packet (including the 2 bytes of the command id and the byte for the length).
The checksum calculation can be implemented as follows:
<source lang="c">
void syscon_calc_checksum(unsigned char packet[32], int length)
{
int i;
unsigned char hash = 0;
for (i = 0; i < 3 + length; i++)
hash += packet[i];
packet[3 + length] = ~hash;
}
</source>
= Commands =
Commands are listed in the order seen in cold boot. The numbers in the captured packets indicate the assumed order with some unused packets filtered out (they appear to be resent). The ordering and grouping are assumed and may contain errors.
== CMD 0x0001 - sceSysconGetErnieVersion ==
Gets version of the current installed Ernie firmware. Can also be seen in the packet header in [[Syscon Update]]. Also sent at kernel boot.
<pre>
SEND 1    > [2.881037083333333] 0x0001, payload=[ | ], chk=0xFD
RESP 1    < [2.881037083333333] 0x0004, flags=00, payload=[0D 06 00 01 | ....], chk=0xE1, unk=0x71
</pre>
<pre>
SEND 23  > [4.167151583333333] 0x0001, payload=[ | ], chk=0xFD
RESP 23  < [4.167151583333333] 0x0000, flags=00, payload=[0D 06 00 01 | ....], chk=0xE5, unk=0x32
</pre>
== CMD 0x0005 - sceSysconGetHardwareInfo ==
See [[KBL Param#Hardware_Info]].
<pre>
SEND 2    > [2.881578833333333] 0x0005, payload=[ | ], chk=0xF9
RESP 2    < [2.881578833333333] 0x0004, flags=00, payload=[00 60 40 00 | .`@.], chk=0x55, unk=0x71
</pre>
== CMD 0x0002 - sceSysconGetTimeStamp ==
Gets Ernie firmware timestamp. Also sent at kernel boot.
<pre>
SEND 3    > [2.882249083333333] 0x0002, payload=[ | ], chk=0xFC
RESP 3    < [2.882249083333333] 0x0004, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x92, unk=0x00
</pre>
<pre>
SEND 24  > [4.171598000000000] 0x0002, payload=[ | ], chk=0xFC
RESP 24  < [4.171598000000000] 0x0000, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x96, unk=0xF7
</pre>
== CMD 0x0080 ==
Unknown. Sends data 0x0012 on FW 3.60. Does not get return data. Also sent at kernel boot.
<pre>
SEND 4    > [2.895635416666666] 0x0080, payload=[12 00 | ..], chk=0x6A
RESP 4    < [2.886923416666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x30
RESP 4    < [2.891092083333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
RESP 4    < [2.895635416666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
</pre>
<pre>
SEND 25  > [4.176620750000000] 0x0080, payload=[12 00 | ..], chk=0x6A
RESP 25  < [4.176123750000000] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x30
RESP 25  < [4.176620750000000] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x30
</pre>
== CMD 0x0010 - sceSysconGetWakeupFactor ==
See [[KBL Param#Wakeup Factor|Wakeup Factor]].
Boot type indicator. 0xFF14 on cold boot. 0xFF80 on resume boot.
<pre>
SEND 5    > [2.950546416666667] 0x0010, payload=[ | ], chk=0xEE
RESP 5    < [2.950546416666667] 0x0004, flags=00, payload=[14 FF | ..], chk=0xE4, unk=0x32
</pre>
== CMD 0x00A0 - Handshake ==
Runs twice. Appears to contain a 8 byte inner header. First packet sends all zeros and gets back a 8 byte random response. This is likely a nonce or challenge. This likely establishes an encrypted session. Encrypted data differs on each boot. There does not appear to be data transferred using the established session.
<pre>
SEND 6    > [2.994470666666667] 0x00A0, payload=[30 00 00 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xFB
RESP 6    < [2.972471333333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF
RESP 6    < [2.989889500000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
RESP 6    < [2.994470666666667] 0x0024, flags=00, payload=[30 01 00 0B 00 00 00 00 CA 71 11 BA 86 87 EF 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0........q..............................], chk=0x66, unk=0x00
SEND 7    > [3.033187750000000] 0x00A0, payload=[30 02 00 0B 01 00 00 00 92 45 B4 A5 49 15 CE F2 39 0E 9E 4C BF FA 19 E6 5D CF BA 5A 6E C3 7C ED 2A 6D 4E 79 84 28 1C 2A | 0........E..I...9..L....]..Zn.|.*mNy.(.*], chk=0x97
RESP 7    < [3.002893083333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 7    < [3.028592333333334] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 7    < [3.033187750000000] 0x0024, flags=00, payload=[30 03 00 0B 00 00 00 00 12 77 A5 98 67 F7 38 9B B4 54 48 FE 84 82 CF 84 41 42 87 A2 EA D1 CF 9C 5B D1 2A 3F 1E 50 B9 3D | 0........w..g.8..TH.....AB......[.*?.P.=], chk=0x0A, unk=0x00
</pre>
== CMD 0x088E - sceSysconCtrlVoltage ==
Controls voltage. Sends value 0x2201 on FW 3.60 and does not get any response.
<pre>
SEND 8    > [3.061354583333333] 0x088E, payload=[01 22 | ."], chk=0x43
RESP 8    < [3.041713500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 8    < [3.046148250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
RESP 8    < [3.056796250000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 8    < [3.061354583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
</pre>
== CMD 0x1082 - NVS Read ==
Get data from [[#NVS|NVS]]. 2-byte offset followed by 1 byte length. For example used to fetch boot-time flags, like Update Mode.
<pre>
Get Qaf Token area:
SEND 9    > [3.078212500000000] 0x1082, payload=[80 04 08 | ...], chk=0xDD
RESP 9    < [3.069790250000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 9    < [3.073736583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 9    < [3.078212500000000] 0x0024, flags=00, payload=[FF FF FF FF 01 FF FF FF | ........], chk=0xD7, unk=0x77
Get Update Mode:
SEND 10  > [3.094879833333333] 0x1082, payload=[A0 04 01 | ...], chk=0xC4
RESP 10  < [3.086322916666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF
RESP 10  < [3.090404000000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
RESP 10  < [3.094879833333333] 0x0024, flags=00, payload=[FF | .], chk=0xD9, unk=0x00
</pre>
== CMD 0x1100 - sceSysconGetErnieDLVersion ==
Gets Ernie DownLoader Version i.e. version of Ernie firmware.
<pre>
SEND 11  > [3.099025500000000] 0x1100, payload=[ | ], chk=0xED
RESP 11  < [3.099025500000000] 0x0004, flags=00, payload=[01 01 13 00 | ....], chk=0xE0, unk=0xFF
</pre>
== CMD 0x00D0 - Handshake before SNVS RW ==
Some encrypted transfer that looks close to [[Syscon#CMD 0x00A0]] in format. Different on each boot.
<pre>
SEND 12  > [3.122679833333333] 0x00D0, payload=[30 00 00 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xC7
RESP 12  < [3.103569583333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 12  < [3.107676166666667] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
RESP 12  < [3.118188666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 12  < [3.122679833333333] 0x0024, flags=00, payload=[30 01 00 0F 00 00 00 00 9F CC 4A 69 73 E9 C0 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.........Jis..Z........................], chk=0xDD, unk=0x00
SEND 13  > [3.150031916666667] 0x00D0, payload=[30 02 00 0F 01 00 00 00 98 6D 3A 1E C5 B1 E9 AF 54 65 55 91 3B DF 2B A8 0F AD B0 73 A0 A2 0F EE 5D 0A AF 41 A5 6D 32 20 | 0........m:.....TeU.;.+....s....]..A.m2.], chk=0xF4
RESP 13  < [3.130872500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 13  < [3.134978166666667] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
RESP 13  < [3.145539833333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 13  < [3.150031916666667] 0x0024, flags=00, payload=[30 03 00 0F 00 00 00 00 F5 19 C0 67 09 80 C6 DB 58 8D FB E1 86 22 D1 00 DA BB D2 AF AA 51 F9 57 7C 56 92 0A 94 D6 60 4D | 0..........g....X....".......Q.W|V....`M], chk=0xF0, unk=0x00
SEND 14  > [3.177452416666667] 0x00D0, payload=[30 04 00 0F 00 00 00 00 87 4E 59 41 22 98 F8 62 BD B4 C8 4F 4C 0A 81 90 47 1E 1E 70 D6 51 57 42 E5 EC 07 A2 D4 CF E5 02 | 0........NYA"..b...OL...G..p.QWB........], chk=0x9A
RESP 14  < [3.158257166666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 14  < [3.162363250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
RESP 14  < [3.172875666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 14  < [3.177452416666667] 0x0024, flags=00, payload=[30 05 00 0F 00 00 00 00 87 4E 59 41 22 98 F8 62 BD B4 C8 4F 4C 0A 81 90 47 1E 1E 70 D6 51 57 42 E5 EC 07 A2 D4 CF E5 02 | 0........NYA"..b...OL...G..p.QWB........], chk=0x44, unk=0x00
</pre>
== CMD 0x00D2 - SNVS RW ==
This command is used twice during boot and also quite often after boot. Data is different on each boot. Encrypted session using key from handshake above. Second transaction is the firmware version data written during the update process.
<pre>
SEND 15  > [3.204733083333333] 0x00D2, payload=[32 78 88 CF 3E 63 56 19 75 3A 0A 2D F3 49 63 E2 | 2x..>cV.u:.-.Ic.], chk=0xA4
RESP 15  < [3.185595250000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x05
RESP 15  < [3.189740333333333] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x05
RESP 15  < [3.200251666666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x05
RESP 15  < [3.204733083333333] 0x0024, flags=00, payload=[D3 57 9B F2 A2 45 E2 7A 2A FC 84 12 97 8E 23 5F C8 AB FB 58 97 EC DE 20 94 0A 78 28 C6 EE C5 45 18 29 00 F4 56 22 53 AF 24 47 8E FF B1 5C DA 2F | .W...E.z*.....#_...X......x(...E.)..V"S.$G...\./], chk=0x4C, unk=0xFF
</pre>
<pre>
SEND 21  > [3.359112250000000] 0x00D2, payload=[1C 0B 9E FF FB 68 90 4B FD C2 05 CD D8 67 4D D0 | .....h.K.....gM.], chk=0x2D
RESP 21  < [3.321934500000000] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x00
RESP 21  < [3.354626666666667] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x00
RESP 21  < [3.359112250000000] 0x0020, flags=00, payload=[6C B4 26 F3 CD 32 D3 3E 6F 80 F2 0F 68 F7 E2 96 58 DB 2F BB AB A6 98 DD 26 14 DD 61 12 E4 55 BA BB 32 1D 1F 75 D5 D1 4C 7E 4A 19 42 E5 B0 C6 AB | l.&..2.>o...h...X./.....&..a..U..2..u..L~J.B....], chk=0x84, unk=0xFF
</pre>
== CMD 0x0090 - sceSysconReadScratchPad ==
This command reads data from Ernie Scratch Pad. This is the inverse of command 0x91.
This is used for example to fetch the saved resume context buffer physical address. Kernel sets this before suspending and this value is passed to the resume function. See [[Suspend]]. The format is 2 byte offset and 1 byte length.
<pre>
SEND 16  > [3.221743166666667] 0x0090, payload=[0C 00 04 | ...], chk=0x5B
RESP 16  < [3.213273166666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x57
RESP 16  < [3.217267333333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x57
RESP 16  < [3.221743166666667] 0x0024, flags=00, payload=[F0 0E 1F 41 | ...A], chk=0x77, unk=0x45
</pre>
== CMD 0x0091 - sceSysconWriteScratchPad ==
This command writes data to Ernie Scratch Pad. This is the inverse of command 0x90.
== CMD 0x0800 - SceSysconForDriver_A2FE9BF9 ==
See [[KBL Param]].
<pre>
SEND 17  > [3.225828583333334] 0x0800, payload=[ | ], chk=0xF6
RESP 17  < [3.225828583333334] 0x0004, flags=00, payload=[40 00 | @.], chk=0xB7, unk=0x41
</pre>
== CMD 0x0100 - sceSysconGetControlsInfo ==
See [[KBL Param#Boot Controls Info|Boot Controls Info]].
<pre>
SEND 18  > [3.226331500000000] 0x0100, payload=[ | ], chk=0xFD
RESP 18  < [3.226331500000000] 0x0004, flags=00, payload=[FF BF FF 74 | ...t], chk=0xC4, unk=0x45
</pre>
== CMD 0x0003 - sceSysconGetSleepFactor ==
See [[KBL Param#Sleep Factor|Sleep Factor]].
<pre>
SEND 19  > [3.226820750000000] 0x0003, payload=[ | ], chk=0xFB
RESP 19  < [3.226820750000000] 0x0004, flags=00, payload=[10 00 00 00 | ....], chk=0xE5, unk=0x45
</pre>
== CMD 0x0006 - sceSysconGetHardwareInfo2 ==
See [[KBL Param#Hardware Info 2|Hardware Info 2]].
<pre>
SEND 20  > [3.227328833333333] 0x0006, payload=[ | ], chk=0xF8
RESP 20  < [3.227328833333333] 0x0000, flags=3F, payload=[ | ], chk=0xBE, unk=0x00
</pre>
== CMD 0x088E - sceSysconCtrlVoltage ==
Last command sent before a time-jump (likely indicating completion of early-boot).
<pre>
SEND 22  > [3.386554833333333] 0x088E, payload=[02 29 | .)], chk=0x3B
RESP 22  < [3.367488416666667] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0xB4
RESP 22  < [3.371567833333333] 0x0000, flags=00, payload=[ | ], chk=0xFD, unk=0xB4
RESP 22  < [3.382079833333334] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0xB4
RESP 22  < [3.386554833333333] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0xB4
</pre>
== CMD 0x0004 ==
Unknown. Likely happens after initial boot.
<pre>
SEND 26  > [4.177113250000000] 0x0004, payload=[ | ], chk=0xFA
RESP 26  < [4.177113250000000] 0x0000, flags=00, payload=[10 00 00 00 | ....], chk=0xE9, unk=0x31
</pre>
== CMD 0x0103 - sceSysconGetMultiCnInfo ==
Likely happens after initial boot.
<pre>
SEND 27  > [4.177586083333333] 0x0103, payload=[ | ], chk=0xFA
RESP 27  < [4.177586083333333] 0x0000, flags=00, payload=[00 FF 04 00 | ....], chk=0xF6, unk=0x31
</pre>
= Syscon Scratch Pad =
{| class="wikitable"
|-
! Offset !! Size !! Name !! Comment !! Used by
|-
| 0x0 || 8 || unknown ||  ||
|-
| 0x8 || 4 || Syscon power on time || ex on DevKit: 0xA, 0x16, 0x1F, 0x24. ex on retail: 0x01BC0CD0, 0x05AC1AF7, 0x80000269 || [[SceRtc#sceRtcSetCurrentTickForDriver]]
|-
| 0xC || 4 || Resume context physical address || Set on retail. Not set on DevKit. ex: 0x411F1EF0 || second_loader
|-
| 0x10 || 5 || Current Tick || Set on retail and DevKit. Stored in microseconds since 01/01/0001 divided by 2^19. || [[SceRtc#sceRtcSetCurrentTickForDriver]]
|-
| 0x15 || 3 || Padding of Current Tick ||  ||
|-
| 0x18 || 5 || Current Secure Tick || Set on retail. Not set on DevKit. || [[SceRtc#sceRtcSetCurrentSecureTickForDriver]]
|-
| 0x1D || 5 || Current Network Tick || Always a bit earlier than Current Tick and Current Secure Tick. || [[SceRtc#sceRtcSetCurrentNetworkTickForDriver]]
|-
| 0x22 || 5 || Current ?Debug Secure?/?Tool Secure? Tick || Set on DevKit. Not set on retail. || [[SceRtc#sceRtcGetCurrentToolSecureTickForDriver]]
|-
| 0x27 || 5 || Current Aux Tick ||  || [[SceRtc#sceRtcSetCurrentAuxTickForDriver]]
|-
| 0x2C || 5 || Current Debug Network Tick ||  || [[SceRtc#sceRtcSetCurrentDebugNetworkTickForDriver]]
|-
| 0x31 || 0x8F || unknown || Maybe reserved. Probably unused. ||
|-
| 0xE0 || 0x20 || [[KBL Param|CP DIP Switches]] || Set on DevKit having a CP. Hence not set on Retail nor TestKit. || ?secure_kernel? before system suspend, second_loader after system resume
|}
== Types ==
<source lang="C">
typedef struct SceSysconRtcTick { // size is 5 bytes
  uint8_t tick[5];
} SceSysconRtcTick;
typedef struct SceSysconScratchPad { // size is 0x100 bytes
  uint8_t unk_0[8];
  SceUInt32 powerOnTime;
  void *resumeContextPA;
  SceRtcSysconTick currentTick;
  uint8_t padding[3];
  SceSysconRtcTick currentSecureTick;
  SceSysconRtcTick currentNetworkTick;
  SceSysconRtcTick unk_0x22;
  SceSysconRtcTick currentAuxTick;
  SceSysconRtcTick currentDebugNetworkTick;
  uint8_t reserved[0x8F];
  SceDIPSW dipsw;
} SceSysconScratchPad;
</source>
= NVS =
Ernie Non-volatile storage (NVS) is a persistent storage allocated on Ernie Data Flash that is used by PS Vita OS for data required at boot time. Indeed, reading NVS requires no driver except the driver to communicate with Syscon, whilst reading PS Vita eMMC requires its AES-XTS decryption.
Not every NVS sector is directly readable from Kermit: the first sectors are part of [[Ernie Secure#SNVS|SNVS]] (Secure NVS) which means that they are XTS-encrypted and must be accessed through a Secure handshake.
NVS actual size is 0xBA0 bytes on new Syscon hardware revisions and 0xC20 on old. However, only 0xB60 bytes are accessible from Kermit on System Software 3.600.011 and more recent. The hidden area is probably used internally by Syscon as it is not blanked nor 0xFFed.
On FW 3.60, NVS size accessible from Kermit is 0xB60 bytes:
* Area from 0 to 0x3FF is named [[Ernie Secure#SNVS]]. It has an additional level of encryption. It cannot be read using [[SceSblSsMgr#sceSblNvsReadForKernel]] nor written using [[SceSblSsMgr#sceSblNvsWriteForKernel]]. This area is handled by [[Secure Modules]].
* Area from 0x400 to 0x75F is handled by Non-secure Kernel [[SceSblSsMgr]] module.
* Area from 0x760 to 0xB5F is reserved for Test and Tool consoles. However this area seems unused.
* Area from 0xB60 to the end of NVS is not accessible from Kermit.
{| class="wikitable"
|-
! Offset !! Size !! Name !! Comment !! Used by
|-
| 0 || 0x400 || SNVS || See [[Ernie Secure#SNVS]]. ||
|-
| 0x400 || 0x80 || Qaf Token || || second_loader
|-
| 0x480 || 0x1 || Qaf Token Flag || 1 when Qaf Token is not set (FFed), 0 when Qaf Token is set || second_loader
|-
| 0x481 || 0x1 || Extra UART Flag || 0xFF - extra UART disabled, 0x00 - extra UART enabled, 0x01 - extra UART enabled only when Jig dongle is connected || second_loader
|-
| 0x482 || 0x1 || Unknown || || [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]]
|-
| 0x483 || 0x1 || Safe Mode Flags || 0xFF - not safe mode, 1, 3, 5, 9, 0x11 - safemode type || [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]], second_loader, set by [[SceShellSvc#sceShellUtilRequestRebootWithError]], read by [[SceSafeMode]]
|-
| 0x484 || 0x1 || <code>KervResult</code>/<code>KervDiagResultFlag</code> || || Factory test <code>preCheckFactTest</code>
|-
| 0x485 || 0x1 || Unknown || ||
|-
| 0x486 || 0x1 || <code>MCEmu</code> Flag (use internal <code>ux0</code>) || 0xFF on FAT - no internal storage or on PS TV or Slim - internal storage enabled, 0xFE on PS TV or Slim - internal storage disabled <br>Not present on FWs 0.931-0.990. Present on FW 3.60. Maybe not used on FWs <= 0.995 || [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]], second_loader
|-
| 0x487 || 0x1 || Unknown || 0xFF - unknown, maybe not used on FWs <= 0.995 || second_loader
|-
| 0x4A0 || 0x1 || Update Mode || 0xFF - not update mode, other value - update step (to detail) || [[SceSblUpdateMgr#sceSblUsGetUpdateModeForUser]], [[SceSblUpdateMgr#sceSblUsSetUpdateModeForUser]]
|-
| 0x4A1 || 0x3 || Unknown. Unused. || ||
|-
| 0x4A4 || 0x4 || System Language || || [[SceRegistryMgr]], [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]]
|-
| 0x4A8 || 0x1C || Unknown. Unused. || ||
|-
| 0x4C4 || 0x1 || Unknown. Set to 0 by default. || ||
|-
| 0x4C5 || 0x1B || Unknown. Unused. || ||
|-
| 0x4E0 || 0x20 || KibanID || || Per-console ASCII string of length 22 characters. This is a serial number also present in PS3 and PS4 Serial Flash. [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]]
|-
| 0x500 || 0x1 || Wlan/Bt Flag || || [[SceSblSsMgr#sceSblSsGetNvsDataForDriver]], [[SceSblSsMgr#sceSblSsSetNvsDataForDriver]], [[SceWlanBt]] module_start
|-
| 0x501 || 0x1F || Unknown. Unused. || ||
|-
| 0x520 || 0x80 || Activation Area || first 0x20 bytes are SceNVSKitActivationData || [[SceSblSsMgr]], [[SceSblPostSsMgr]]
|-
| 0x5A0 || 0x100 || Qaf Token RSA signature || Not present on FW 0.990. Present on FW 3.60. Maybe added on FW 1.80. || second_loader
|-
| 0x6A0 || 0xC0 || Unknown. Unused. || ||
|-
| 0x760 || 0x400 || Reserved for Test and Tool consoles. || Seems unused. ||
|}
== Types ==
<source lang="C">
typedef struct SceNVSKitActivationData { // size is 0x20 bytes
  char magic[4]; // "act\n"
  uint32_t issue_no;
  uint32_t end_date;
  uint32_t start_date;
  char cmac_hash[0x10];
} SceNVSKitActivationData;
</source>
= Config Storage =
Config Storage is a similar storage than [[#NVS|NVS]] but is accessed in a different manner. Whilst [[#NVS|NVS]] is read and written by 32-byte sectors and is physically stored with a sort of history, Config Storage is written by sending scripts from [[Kermit]] to Syscon, and is not really readable but instead affects [[KBL Param#Hardware Info]].
== Sample scripts ==
Below are sample configstorage scripts hardcoded in [[SceSyscon]]:
<source lang="C">
const char syscon_idu_set_config[0x20] = {
    0x1F, 0x54, 0x35, 0x63, 0x38, 0x62, 0x31, 0x64,
    0x61, 0x63, 0x62, 0x38, 0x33, 0x36, 0x64, 0x64,
    0x36, 0x63, 0x39, 0x39, 0x36, 0x38, 0x65, 0x34,
    0x63, 0x30, 0x35, 0x30, 0x61, 0x36, 0x66, 0x35
};
const char syscon_idu_set_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x01, 0x00, 0x0D, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0x51, 0xBD, 0x52, 0x2C,
    0x4C, 0x83, 0x70, 0xDA, 0x4D, 0xF3, 0x8E, 0x82,
    0x6B, 0xD6, 0x34, 0x98, 0x3A, 0xFD, 0xA6, 0x94
};
const char syscon_show_set_config[0x20] = {
    0x1F, 0x54, 0x66, 0x63, 0x33, 0x39, 0x38, 0x39,
    0x30, 0x61, 0x33, 0x32, 0x64, 0x30, 0x66, 0x32,
    0x37, 0x36, 0x31, 0x35, 0x62, 0x65, 0x36, 0x65,
    0x63, 0x64, 0x63, 0x35, 0x65, 0x32, 0x63, 0x63
};
const char syscon_show_set_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x03, 0x00, 0x10, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0xB8, 0x1A, 0x54, 0xD1,
    0xF2, 0xA0, 0xD1, 0x05, 0x18, 0xEA, 0x22, 0x09,
    0x0A, 0x02, 0x2E, 0xAE, 0x00, 0x08, 0x25, 0xF1
};
const char syscon_clear_config[0x20] = {
    0x1F, 0x54, 0x65, 0x34, 0x61, 0x65, 0x38, 0x62,
    0x37, 0x61, 0x65, 0x38, 0x36, 0x33, 0x32, 0x65,
    0x64, 0x64, 0x39, 0x61, 0x61, 0x65, 0x38, 0x38,
    0x38, 0x39, 0x66, 0x30, 0x65, 0x65, 0x61, 0x38
};
const char syscon_clear_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0x88, 0xEA, 0xC7, 0xAD,
    0x65, 0xB1, 0x73, 0xC1, 0xCF, 0x48, 0xC7, 0x29,
    0x1B, 0x2B, 0x8A, 0x32, 0x89, 0xCF, 0xB3, 0xC1
};
</source>
The only actual differences between those scripts are:
* the ascii string: we do not know how it is generated and what it means
* the mode value:
** A8 01 00 00 00 00 = mode clear
** A8 01 01 00 0D 00 = idu mode set
** A8 01 03 00 10 00 = show mode set
== Types ==
<source lang="C">
// TODO
</source>
{| class="wikitable"
|-
! Offset !! Size !! Name !! Sample value !! Comment
|-
| 0 || 1 || ascii_data_size || 0x1F ||
|-
| 1 || 1 || ascii_data_flag || 0x54 ||
|-
| 2 || 0x1E || ascii_data || || ASCII hexadecimal string so maybe a hash
|-
| 0x20 || 1 || unk_7_data_size || 7 ||
|-
| 0x21 || 1 || unk_7_data_flag || ||
|-
| 0x22 || 6 || unk_7_data || ||
|-
| 0x28 || 1 || unk_1_data_size || 1 ||
|-
| 0x29 || 1 || unk_1_data_flag || 0x4E ||
|-
| 0x2A || 1 || sha1_hash_size || 0x15 ||
|-
| 0x2B || 1 || sha1_hash_flag || 0x48 ||
|-
| 0x2C || 0x14 || sha1_hash || || sha1 hash of the previous blocks (data from 0 of size 0x2A)
|}
Config storage scripts have in theory a variable size. It is the concatenation of some blocks where the first byte is the length of the body, followed by the body of variable size. Body structure is always the same: 1 byte representing the flag, followed by data of variable size.
== Usage ==
Theory by CelesteBlue (untested):
* 0) Begin Transaction
* 1) Load Script (part 1)
* A) configstorage data is read from SceSyscon memory
* B) configstorage data is sent by SceSyscon to Ernie
* C) Ernie FW checks hash of data and returns xx on success
if success:
* 2) Load Script (part 2)
* A) configstorage data is read from SceSyscon memory
* B) configstorage data is sent by SceSyscon to Ernie using Load
* C) Ernie FW loads data to memory and executes it
*6) Commit Transaction
*7) End Transaction
= Pinout =
[[File:ernie-package.png|600px|Ernie BGA package.]]
A candidate package for this chip is Renesas' [https://www.renesas.com/us/en/package-image/pdf/outdrawing/p121f1-50-bal.pdf P121F1-50-BAL-1]. It has the same size and number of pins.
=== UART ===
{| class='wikitable'
! Name || Pin || Description
|-
| CTS0 || J7 || UART0 clear to send
|-
| RTS0 || C6 || UART0 request to send
|-
| TX0 || B6 || UART0 transmit
|-
| RX0 || F11 || UART0 receive
|-
| SW0 || A8 || Switch, see [[UART Console#OLED PSVita UART0 location]]
|}
=== SPI ===
Main communication with [[Kermit]].
{| class='wikitable'
! Name || Pin || Description
|-
| SS || A7 || Slave Select (often active low, output from master)
|-
| MISO || A6 || Master In Slave Out (data output from slave)
|-
| MOSI || C7 || Master Out Slave In (data output from master)
|-
| SCLK || B7 || Serial Clock (output from master)
|}
=== Other ===
{| class='wikitable'
! Name || Pin || Description
|-
| ? || C11 || [[UDC]] pin 11
|-
| ? || F9 || [[UDC]] pin 12
|-
| ? || G4 || [[UDC]] pin 13
|-
| ? || G8 || [[SN99057]] pin 38
|-
| PWR_SW || G6 || Power switch through two transistor buffers
|}
= Versions =
== Hardware Versions ==
There are three hardware versions of Ernie:
* NEC 78K0R/Kx3-L: present on early PS Vita prototypes (never seen)
* NEC 78K0R/Kx3: present on Fat PS Vita and PS TV models, including some prototypes such as DEM-3000L
* Renesas RL78/G13: present on Slim PS Vita models
=== NEC 78K0R/Kx3-L ===
Never seen yet but exists according to Ernie update packages.
=== NEC 78K0R/Kx3 ===
NEC D79F0109 (78K0R/KH3, 121 pin)
Device Name : D79F0109
Other Device Name : SK0RT02N200GV120 (on DEM-3000L and PCH-1000)
Label:
<pre>
Model <- always D79F0109
Revision <- on DEM-3000H: ES1.0, blank on others
Build <- XXYYZZWWW <- XX: year, YY: week, ZZ: 2 letters (unknown usage), WWW: serial number
Manufacturing country <- always "MALAYSIA"
</pre>
=== Renesas RL78/G13 ===
Renesas R5F1ZCRK (RL78/G13, 121 pin)
<pre>
R5F1ZCRKABG#U0
R5    Renesas MCU
F      Flash
1      RL78
Z      Customer specific
C      Product group
R      121-pin
K      384KB
A      Consumer grade
BG    VFBGA 0.4mm
#U0  Tray*2
</pre>
<pre>
Device Name : R5F1ZCRK
Device Code : 10 00 06
Firmware Version : V3.03
Code Flash 1 (Address : 0x00000000,  Size : 384 K,  Erase Size : 1 K)
Data Flash 1 (Address : 0x000F1000,  Size : 8 K,  Erase Size : 1 K)
</pre>
Label:
<pre>
(C) XXXX <- Year
Revision <- A0xxx SCEI
Build <- XXYYZZWWW <- XX: year, YY: week, ZZ: 2 letters (unknown usage), WWW: serial number
Unknown data
</pre>
== Block sizes ==
Ernie flash memory is erasable in blocks. Size of one block in bytes depends on the hardware version:
* NEC 78K0R/Kx3-L: 0x800
* NEC 78K0R/Kx3: 0x400
* Renesas RL78/G13: 0x400
See also [https://playstationdev.wiki/psvitadevwiki/index.php?title=Ernie].
== Software Versions ==
See also [https://playstationdev.wiki/psvitadevwiki/index.php?title=System_Controller_Firmware].
Ernie firmware can be partly updated and downgraded with software updates embedded in PUP.
Ernie firmware is dependant of the hardware version and detects it based on [[KBL Param#Hardware_Info|Hardware Info]].
=== Examples ===
With DevKit connected, <code>psp2ctrl info</code> queries return the following results:
DEM-3000H running FW 0.990:
<source>SysConVersion: 591105</source> -> converted to hexadecimal: 0x00090501 -> 0.9.5.1
PDEL-1001 running FW 1.692:
<source>SCVersion: 0.9.2.4</source>
PDEL-1001 running FW 3.600-3.680:
<source>SCVersion: 1.0.3.6</source>
=== Downgrade ===
Syscon is downgradable on DEM/PDEL/PTEL/QAF units. It might also be downgraded on retail when using a downgrade enabler like modoru.
= Firmware =
See [[Ernie Firmware]]


[[Category:Devices]]
[[Category:Devices]]

Latest revision as of 18:08, 19 May 2024

Ernie is the codename for the Syscon chip. The Syscon is for exemple responsible for handling button input (including power button), reading/writing to non-volatile storage (NVS) for storing system flags (mostly encrypted and signed). For example IDU flag is stored in NVS. Syscon is also responsible for maintaining the physical address to the resume buffer during Suspend. Communication between Kermit and Syscon is mainly through SPI (see SceSyscon) but there are also some GPIO pins connecting the two. The chip model is NEC/Renesas uPD79F0109 and is likely custom designed for Sony.

See also: Ernie Secure

Boot Process

The following is logged from boot. The timestamp is in seconds (the starting time is irrelevant). The arrow at the start indicates direction: '>' means Kermit to Syscon (MOSI) and '<' means Syscon to Kermit (MISO). Then there is a 2 byte command id or response code, followed by a flag byte (response only), the payload, a checksum byte, and an (response only) unknown byte. Please note that the packets are listed in transfer order but this may not represent the logical order of the packets. It is currently unknown what the logical order should be, but one can guess that a response is "close to" a request.

First some version information seems to be sent from Syscon to Kermit. This is same for cold boot and resume boot. The last response indicates the type of boot where 0xFF80 is resume and 0xFF14 is regular boot.

< [2.048118000000000] 0x0004, flags=00, payload=[0D 06 00 01 | ....], chk=0xE1, unk=0x00
> [2.048118000000000] 0x0001, payload=[ | ], chk=0xFD
< [2.048659583333333] 0x0004, flags=00, payload=[00 60 40 00 | .`@.], chk=0x55, unk=0x00
> [2.048659583333333] 0x0005, payload=[ | ], chk=0xF9
< [2.049330083333333] 0x0004, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x92, unk=0x00
> [2.049330083333333] 0x0002, payload=[ | ], chk=0xFC
< [2.054004333333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x30
> [2.054004333333333] 0x0080, payload=[12 00 | ..], chk=0x6A
< [2.058172916666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
> [2.058172916666666] 0x0000, payload=[ | ], chk=0xFE
< [2.062716333333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
> [2.062716333333333] 0x0080, payload=[12 00 | ..], chk=0x6A
< [2.111457750000000] 0x0004, flags=00, payload=[14 FF | ..], chk=0xE4, unk=0x32

Next some encrypted session is established. A 8 byte nonce is sent from Syscon (it appears random for each boot, cold or warm). Encrypted data from this point on always differs each boot.

> [2.111457750000000] 0x0010, payload=[ | ], chk=0xEE
< [2.133389000000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF
> [2.133389000000000] 0x00A0, payload=[30 00 00 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xFB
< [2.150567250000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
> [2.150567250000000] 0x0000, payload=[ | ], chk=0xFE
< [2.155149500000000] 0x0024, flags=00, payload=[30 01 00 0B 00 00 00 00 A4 B0 EF 23 D6 9A 3A 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0..........#..:.........................], chk=0x5F, unk=0x00
> [2.155149500000000] 0x00A0, payload=[30 00 00 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xFB
< [2.163572000000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
> [2.163572000000000] 0x00A0, payload=[30 02 00 0B 01 00 00 00 6C 7F E0 79 AA 03 4B B0 96 B7 42 F0 BC F8 62 7A 35 27 53 68 3D 0D ED A7 13 F2 32 77 46 2D 54 F8 | 0.......l..y..K...B...bz5'Sh=.....2wF-T.], chk=0x9B
< [2.189271166666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
> [2.189271166666667] 0x0000, payload=[ | ], chk=0xFE
< [2.193866583333334] 0x0024, flags=00, payload=[30 03 00 0B 00 00 00 00 7A 44 6E C8 F5 FA 35 CB 9B E9 E6 A0 B6 5C 85 1D FB A8 89 5C 9C 04 0B 29 34 59 55 EB 1D 98 AB 83 | 0.......zDn...5......\.....\...)4YU.....], chk=0xC6, unk=0x00
> [2.193866583333334] 0x00A0, payload=[30 02 00 0B 01 00 00 00 6C 7F E0 79 AA 03 4B B0 96 B7 42 F0 BC F8 62 7A 35 27 53 68 3D 0D ED A7 13 F2 32 77 46 2D 54 F8 | 0.......l..y..K...B...bz5'Sh=.....2wF-T.], chk=0x9B

Some more data is exchanged. Up until this point all the plaintext payloads appear to be the same from coldboot and warmboot.

< [2.202246333333334] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
> [2.202246333333334] 0x088E, payload=[01 22 | ."], chk=0x43
< [2.206411750000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
> [2.206411750000000] 0x0000, payload=[ | ], chk=0xFE
< [2.217062666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
> [2.217062666666667] 0x0000, payload=[ | ], chk=0xFE
< [2.221620916666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
> [2.221620916666667] 0x088E, payload=[01 22 | ."], chk=0x43
< [2.229805500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
> [2.229805500000000] 0x1082, payload=[80 04 08 | ...], chk=0xDD
< [2.233887583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
> [2.233887583333333] 0x0000, payload=[ | ], chk=0xFE
< [2.238363416666667] 0x0024, flags=00, payload=[FF FF FF FF 01 FF FF FF | ........], chk=0xD7, unk=0x44
> [2.238363416666667] 0x1082, payload=[80 04 08 | ...], chk=0xDD
< [2.246473916666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF

Now, there appears to be a branch. The next sequence only shows up for cold boots.

> [2.246473916666667] 0x1082, payload=[A0 04 01 | ...], chk=0xC4
< [2.250555000000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
> [2.250555000000000] 0x0000, payload=[ | ], chk=0xFE
< [2.255030833333334] 0x0024, flags=00, payload=[FF | .], chk=0xD9, unk=0x00
> [2.255030833333334] 0x1082, payload=[A0 04 01 | ...], chk=0xC4
< [2.259176583333333] 0x0004, flags=00, payload=[01 01 13 00 | ....], chk=0xE0, unk=0xFF
> [2.259176583333333] 0x1100, payload=[ | ], chk=0xED
< [2.263720583333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
> [2.263720583333333] 0x00D0, payload=[30 00 00 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xC7
< [2.267827000000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
> [2.267827000000000] 0x0000, payload=[ | ], chk=0xFE
< [2.278339666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
> [2.278339666666667] 0x0000, payload=[ | ], chk=0xFE
< [2.282830833333333] 0x0024, flags=00, payload=[30 01 00 0F 00 00 00 00 E1 CA 65 96 BB 7E 81 7A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.........e..~.z........................], chk=0x97, unk=0x00
> [2.282830833333333] 0x00D0, payload=[30 00 00 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xC7
< [2.291023500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
> [2.291023500000000] 0x00D0, payload=[30 02 00 0F 01 00 00 00 4E D7 C0 7C D5 E8 BB D7 3E 9E 43 7B B2 E3 4D 81 23 C8 C4 BF B8 4D 9B 25 0A 3D C7 45 E6 0D 23 43 | 0.......N..|....>.C{..M.#....M.%.=.E..#C], chk=0x38
< [2.295129250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
> [2.295129250000000] 0x0000, payload=[ | ], chk=0xFE
< [2.305641750000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
> [2.305641750000000] 0x0000, payload=[ | ], chk=0xFE
< [2.310132916666667] 0x0024, flags=00, payload=[30 03 00 0F 00 00 00 00 5B 3E 5C 5F 11 F9 E4 6A 85 0D 1E 06 9E F9 33 25 9B 95 55 21 39 48 FC 55 C7 BF A7 E4 32 AD FC 65 | 0.......[>\_...j......3%..U!9H.U....2..e], chk=0x55, unk=0x00
> [2.310132916666667] 0x00D0, payload=[30 02 00 0F 01 00 00 00 4E D7 C0 7C D5 E8 BB D7 3E 9E 43 7B B2 E3 4D 81 23 C8 C4 BF B8 4D 9B 25 0A 3D C7 45 E6 0D 23 43 | 0.......N..|....>.C{..M.#....M.%.=.E..#C], chk=0x38
< [2.318358166666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
> [2.318358166666667] 0x00D0, payload=[30 04 00 0F 00 00 00 00 52 8D 6D BC 90 C9 00 EE FA CA 47 63 10 D1 4A E5 5A FD BB 91 3A 6C DA EF 64 CA 71 01 4A A9 D5 31 | 0.......R.m.......Gc..J.Z...:l..d.q.J..1], chk=0x4B
< [2.322464250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
> [2.322464250000000] 0x0000, payload=[ | ], chk=0xFE
< [2.332976833333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
> [2.332976833333333] 0x0000, payload=[ | ], chk=0xFE
< [2.337468000000000] 0x0024, flags=00, payload=[30 05 00 0F 00 00 00 00 52 8D 6D BC 90 C9 00 EE FA CA 47 63 10 D1 4A E5 5A FD BB 91 3A 6C DA EF 64 CA 71 01 4A A9 D5 31 | 0.......R.m.......Gc..J.Z...:l..d.q.J..1], chk=0xF5, unk=0x00
> [2.337468000000000] 0x00D0, payload=[30 04 00 0F 00 00 00 00 52 8D 6D BC 90 C9 00 EE FA CA 47 63 10 D1 4A E5 5A FD BB 91 3A 6C DA EF 64 CA 71 01 4A A9 D5 31 | 0.......R.m.......Gc..J.Z...:l..d.q.J..1], chk=0x4B
< [2.345696333333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x05

Then another set of shared sequence. Some differences in the warmboot responses though. On line 18,

FF BF FF 74

becomes

FF FF FF 74

. On line 12, the

00 00 00 00

becomes the physical address of the resume context buffer. Example:

F0 1E 1F 41
> [2.345696333333333] 0x00D2, payload=[20 7A 3E 7B 31 DE FC 3A 11 5F 64 E7 AB A4 EC 17 | .z>{1..:._d.....], chk=0x77
< [2.349790333333333] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x05
> [2.349790333333333] 0x0000, payload=[ | ], chk=0xFE
< [2.360448916666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x05
> [2.360448916666666] 0x0000, payload=[ | ], chk=0xFE
< [2.364930250000000] 0x0024, flags=00, payload=[9D 0B BC 4D BA 66 40 2C 63 BE F3 79 D0 31 26 1E 47 3A 64 DE 68 2F AE E2 8A B6 F0 27 37 46 89 16 0E 71 04 FA BF C9 4A A1 DF 4B EF D3 3D 0D 39 CD | ...M.f@,c..y.1&.G:d.h/.....'7F...q....J..K..=.9.], chk=0x11, unk=0x00
> [2.364930250000000] 0x00D2, payload=[20 7A 3E 7B 31 DE FC 3A 11 5F 64 E7 AB A4 EC 17 | .z>{1..:._d.....], chk=0x77
< [2.373236666666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x0B
> [2.373236666666667] 0x0090, payload=[0C 00 04 | ...], chk=0x5B
< [2.377318583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x0B
> [2.377318583333333] 0x0000, payload=[ | ], chk=0xFE
< [2.381794416666667] 0x0024, flags=00, payload=[00 00 00 00 | ....], chk=0xD5, unk=0x66
> [2.381794416666667] 0x0090, payload=[0C 00 04 | ...], chk=0x5B
< [2.385879750000000] 0x0004, flags=00, payload=[40 00 | @.], chk=0xB7, unk=0x00
> [2.385879750000000] 0x0800, payload=[ | ], chk=0xF6
< [2.386382583333333] 0x0004, flags=00, payload=[FF BF FF 74 | ...t], chk=0xC4, unk=0x66
> [2.386382583333333] 0x0100, payload=[ | ], chk=0xFD
< [2.386871833333333] 0x0004, flags=00, payload=[10 00 00 00 | ....], chk=0xE5, unk=0x66
> [2.386871833333333] 0x0003, payload=[ | ], chk=0xFB
< [2.387380083333333] 0x0000, flags=3F, payload=[ | ], chk=0xBE, unk=0x00
> [2.387380083333333] 0x0006, payload=[ | ], chk=0xF8
< [2.481997666666667] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x00
> [2.481986333333333] 0x00D2, payload=[30 14 F4 B8 84 89 81 AB 3D 07 66 DE AE B6 D3 24 | 0.......=.f....$], chk=0x10
< [2.514678500000000] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x00
> [2.514678500000000] 0x0000, payload=[ | ], chk=0xFE
< [2.519163916666667] 0x0020, flags=00, payload=[1A 1F BC 74 AA 16 59 D6 5C E7 FF 5B E0 85 B2 C8 39 2D D6 95 98 2F B7 4B 71 64 34 D7 8D 2C 94 A1 91 CB 73 D7 8D E1 D0 07 E6 1E 0F DA E7 51 BC 69 | ...t..Y.\..[....9-.../.Kqd4..,....s..........Q.i], chk=0x3C, unk=0x00
> [2.519163916666667] 0x00D2, payload=[30 14 F4 B8 84 89 81 AB 3D 07 66 DE AE B6 D3 24 | 0.......=.f....$], chk=0x10
< [2.527551416666667] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x1F
> [2.527540083333333] 0x088E, payload=[02 29 | .)], chk=0x3B
< [2.531619416666667] 0x0000, flags=00, payload=[ | ], chk=0xFD, unk=0x1F
> [2.531619416666667] 0x0000, payload=[ | ], chk=0xFE
< [2.542392416666666] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x1F
> [2.542392416666666] 0x0000, payload=[ | ], chk=0xFE
< [2.546867583333333] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x1F
> [2.546867583333333] 0x088E, payload=[02 29 | .)], chk=0x3B

Then, the two boot paths diverge completely (also note the time jump). It is suspected that at this point the kernel is started up on coldboot, and the kernel resumes for warmboot. For cold boot only, we see the beginning init sequence again, which is likely done in SceSyscon.

< [3.322105750000000] 0x0000, flags=00, payload=[0D 06 00 01 | ....], chk=0xE5, unk=0x16
> [3.322105750000000] 0x0001, payload=[ | ], chk=0xFD
< [3.326563916666667] 0x0000, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x96, unk=0x85
> [3.326552583333333] 0x0002, payload=[ | ], chk=0xFC
< [3.331090666666667] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x30
> [3.331079333333333] 0x0080, payload=[12 00 | ..], chk=0x6A
< [3.331576333333333] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x30
> [3.331576333333333] 0x0080, payload=[12 00 | ..], chk=0x6A
< [3.332068833333333] 0x0000, flags=00, payload=[10 00 00 00 | ....], chk=0xE9, unk=0x31
> [3.332068833333333] 0x0004, payload=[ | ], chk=0xFA
< [3.332541666666667] 0x0000, flags=00, payload=[00 FF 04 00 | ....], chk=0xF6, unk=0x31
> [3.332541666666667] 0x0103, payload=[ | ], chk=0xFA
< [3.336980333333333] 0x0000, flags=00, payload=[10 00 00 00 | ....], chk=0xE9, unk=0x31
> [3.336980333333333] 0x0003, payload=[ | ], chk=0xFB
...

Packet checksum

The checksum byte of the packet is calculated as the binary negation of the sum of all the bytes of the packet (including the 2 bytes of the command id and the byte for the length). The checksum calculation can be implemented as follows:

void syscon_calc_checksum(unsigned char packet[32], int length)
{
	int i;
	unsigned char hash = 0;
	
	for (i = 0; i < 3 + length; i++)
		hash += packet[i];

	packet[3 + length] = ~hash;
}

Commands

Commands are listed in the order seen in cold boot. The numbers in the captured packets indicate the assumed order with some unused packets filtered out (they appear to be resent). The ordering and grouping are assumed and may contain errors.

CMD 0x0001 - sceSysconGetErnieVersion

Gets version of the current installed Ernie firmware. Can also be seen in the packet header in Syscon Update. Also sent at kernel boot.

SEND 1    > [2.881037083333333] 0x0001, payload=[ | ], chk=0xFD
RESP 1    < [2.881037083333333] 0x0004, flags=00, payload=[0D 06 00 01 | ....], chk=0xE1, unk=0x71
SEND 23   > [4.167151583333333] 0x0001, payload=[ | ], chk=0xFD
RESP 23   < [4.167151583333333] 0x0000, flags=00, payload=[0D 06 00 01 | ....], chk=0xE5, unk=0x32

CMD 0x0005 - sceSysconGetHardwareInfo

See KBL Param#Hardware_Info.

SEND 2    > [2.881578833333333] 0x0005, payload=[ | ], chk=0xF9
RESP 2    < [2.881578833333333] 0x0004, flags=00, payload=[00 60 40 00 | .`@.], chk=0x55, unk=0x71

CMD 0x0002 - sceSysconGetTimeStamp

Gets Ernie firmware timestamp. Also sent at kernel boot.

SEND 3    > [2.882249083333333] 0x0002, payload=[ | ], chk=0xFC
RESP 3    < [2.882249083333333] 0x0004, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x92, unk=0x00
SEND 24   > [4.171598000000000] 0x0002, payload=[ | ], chk=0xFC
RESP 24   < [4.171598000000000] 0x0000, flags=00, payload=[32 30 31 32 31 31 30 38 31 37 30 34 | 201211081704], chk=0x96, unk=0xF7

CMD 0x0080

Unknown. Sends data 0x0012 on FW 3.60. Does not get return data. Also sent at kernel boot.

SEND 4    > [2.895635416666666] 0x0080, payload=[12 00 | ..], chk=0x6A
RESP 4    < [2.886923416666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x30
RESP 4    < [2.891092083333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
RESP 4    < [2.895635416666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x30
SEND 25   > [4.176620750000000] 0x0080, payload=[12 00 | ..], chk=0x6A
RESP 25   < [4.176123750000000] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x30
RESP 25   < [4.176620750000000] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x30

CMD 0x0010 - sceSysconGetWakeupFactor

See Wakeup Factor.

Boot type indicator. 0xFF14 on cold boot. 0xFF80 on resume boot.

SEND 5    > [2.950546416666667] 0x0010, payload=[ | ], chk=0xEE
RESP 5    < [2.950546416666667] 0x0004, flags=00, payload=[14 FF | ..], chk=0xE4, unk=0x32

CMD 0x00A0 - Handshake

Runs twice. Appears to contain a 8 byte inner header. First packet sends all zeros and gets back a 8 byte random response. This is likely a nonce or challenge. This likely establishes an encrypted session. Encrypted data differs on each boot. There does not appear to be data transferred using the established session.

SEND 6    > [2.994470666666667] 0x00A0, payload=[30 00 00 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xFB
RESP 6    < [2.972471333333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF
RESP 6    < [2.989889500000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
RESP 6    < [2.994470666666667] 0x0024, flags=00, payload=[30 01 00 0B 00 00 00 00 CA 71 11 BA 86 87 EF 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0........q..............................], chk=0x66, unk=0x00

SEND 7    > [3.033187750000000] 0x00A0, payload=[30 02 00 0B 01 00 00 00 92 45 B4 A5 49 15 CE F2 39 0E 9E 4C BF FA 19 E6 5D CF BA 5A 6E C3 7C ED 2A 6D 4E 79 84 28 1C 2A | 0........E..I...9..L....]..Zn.|.*mNy.(.*], chk=0x97
RESP 7    < [3.002893083333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 7    < [3.028592333333334] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 7    < [3.033187750000000] 0x0024, flags=00, payload=[30 03 00 0B 00 00 00 00 12 77 A5 98 67 F7 38 9B B4 54 48 FE 84 82 CF 84 41 42 87 A2 EA D1 CF 9C 5B D1 2A 3F 1E 50 B9 3D | 0........w..g.8..TH.....AB......[.*?.P.=], chk=0x0A, unk=0x00

CMD 0x088E - sceSysconCtrlVoltage

Controls voltage. Sends value 0x2201 on FW 3.60 and does not get any response.

SEND 8    > [3.061354583333333] 0x088E, payload=[01 22 | ."], chk=0x43
RESP 8    < [3.041713500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 8    < [3.046148250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
RESP 8    < [3.056796250000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 8    < [3.061354583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03

CMD 0x1082 - NVS Read

Get data from NVS. 2-byte offset followed by 1 byte length. For example used to fetch boot-time flags, like Update Mode.

Get Qaf Token area:
SEND 9    > [3.078212500000000] 0x1082, payload=[80 04 08 | ...], chk=0xDD
RESP 9    < [3.069790250000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 9    < [3.073736583333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 9    < [3.078212500000000] 0x0024, flags=00, payload=[FF FF FF FF 01 FF FF FF | ........], chk=0xD7, unk=0x77

Get Update Mode:
SEND 10   > [3.094879833333333] 0x1082, payload=[A0 04 01 | ...], chk=0xC4
RESP 10   < [3.086322916666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0xFF
RESP 10   < [3.090404000000000] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0xFF
RESP 10   < [3.094879833333333] 0x0024, flags=00, payload=[FF | .], chk=0xD9, unk=0x00

CMD 0x1100 - sceSysconGetErnieDLVersion

Gets Ernie DownLoader Version i.e. version of Ernie firmware.

SEND 11   > [3.099025500000000] 0x1100, payload=[ | ], chk=0xED
RESP 11   < [3.099025500000000] 0x0004, flags=00, payload=[01 01 13 00 | ....], chk=0xE0, unk=0xFF

CMD 0x00D0 - Handshake before SNVS RW

Some encrypted transfer that looks close to Syscon#CMD 0x00A0 in format. Different on each boot.

SEND 12   > [3.122679833333333] 0x00D0, payload=[30 00 00 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.......................................], chk=0xC7
RESP 12   < [3.103569583333333] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 12   < [3.107676166666667] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
RESP 12   < [3.118188666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 12   < [3.122679833333333] 0x0024, flags=00, payload=[30 01 00 0F 00 00 00 00 9F CC 4A 69 73 E9 C0 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0.........Jis..Z........................], chk=0xDD, unk=0x00

SEND 13   > [3.150031916666667] 0x00D0, payload=[30 02 00 0F 01 00 00 00 98 6D 3A 1E C5 B1 E9 AF 54 65 55 91 3B DF 2B A8 0F AD B0 73 A0 A2 0F EE 5D 0A AF 41 A5 6D 32 20 | 0........m:.....TeU.;.+....s....]..A.m2.], chk=0xF4
RESP 13   < [3.130872500000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x01
RESP 13   < [3.134978166666667] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x01
RESP 13   < [3.145539833333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x01
RESP 13   < [3.150031916666667] 0x0024, flags=00, payload=[30 03 00 0F 00 00 00 00 F5 19 C0 67 09 80 C6 DB 58 8D FB E1 86 22 D1 00 DA BB D2 AF AA 51 F9 57 7C 56 92 0A 94 D6 60 4D | 0..........g....X....".......Q.W|V....`M], chk=0xF0, unk=0x00

SEND 14   > [3.177452416666667] 0x00D0, payload=[30 04 00 0F 00 00 00 00 87 4E 59 41 22 98 F8 62 BD B4 C8 4F 4C 0A 81 90 47 1E 1E 70 D6 51 57 42 E5 EC 07 A2 D4 CF E5 02 | 0........NYA"..b...OL...G..p.QWB........], chk=0x9A
RESP 14   < [3.158257166666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x03
RESP 14   < [3.162363250000000] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x03
RESP 14   < [3.172875666666667] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x03
RESP 14   < [3.177452416666667] 0x0024, flags=00, payload=[30 05 00 0F 00 00 00 00 87 4E 59 41 22 98 F8 62 BD B4 C8 4F 4C 0A 81 90 47 1E 1E 70 D6 51 57 42 E5 EC 07 A2 D4 CF E5 02 | 0........NYA"..b...OL...G..p.QWB........], chk=0x44, unk=0x00

CMD 0x00D2 - SNVS RW

This command is used twice during boot and also quite often after boot. Data is different on each boot. Encrypted session using key from handshake above. Second transaction is the firmware version data written during the update process.

SEND 15   > [3.204733083333333] 0x00D2, payload=[32 78 88 CF 3E 63 56 19 75 3A 0A 2D F3 49 63 E2 | 2x..>cV.u:.-.Ic.], chk=0xA4
RESP 15   < [3.185595250000000] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x05
RESP 15   < [3.189740333333333] 0x0004, flags=00, payload=[ | ], chk=0xF9, unk=0x05
RESP 15   < [3.200251666666666] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x05
RESP 15   < [3.204733083333333] 0x0024, flags=00, payload=[D3 57 9B F2 A2 45 E2 7A 2A FC 84 12 97 8E 23 5F C8 AB FB 58 97 EC DE 20 94 0A 78 28 C6 EE C5 45 18 29 00 F4 56 22 53 AF 24 47 8E FF B1 5C DA 2F | .W...E.z*.....#_...X......x(...E.)..V"S.$G...\./], chk=0x4C, unk=0xFF
SEND 21   > [3.359112250000000] 0x00D2, payload=[1C 0B 9E FF FB 68 90 4B FD C2 05 CD D8 67 4D D0 | .....h.K.....gM.], chk=0x2D
RESP 21   < [3.321934500000000] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0x00
RESP 21   < [3.354626666666667] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0x00
RESP 21   < [3.359112250000000] 0x0020, flags=00, payload=[6C B4 26 F3 CD 32 D3 3E 6F 80 F2 0F 68 F7 E2 96 58 DB 2F BB AB A6 98 DD 26 14 DD 61 12 E4 55 BA BB 32 1D 1F 75 D5 D1 4C 7E 4A 19 42 E5 B0 C6 AB | l.&..2.>o...h...X./.....&..a..U..2..u..L~J.B....], chk=0x84, unk=0xFF

CMD 0x0090 - sceSysconReadScratchPad

This command reads data from Ernie Scratch Pad. This is the inverse of command 0x91.

This is used for example to fetch the saved resume context buffer physical address. Kernel sets this before suspending and this value is passed to the resume function. See Suspend. The format is 2 byte offset and 1 byte length.

SEND 16   > [3.221743166666667] 0x0090, payload=[0C 00 04 | ...], chk=0x5B
RESP 16   < [3.213273166666667] 0x0004, flags=80, payload=[ | ], chk=0x79, unk=0x57
RESP 16   < [3.217267333333333] 0x0024, flags=00, payload=[ | ], chk=0xD9, unk=0x57
RESP 16   < [3.221743166666667] 0x0024, flags=00, payload=[F0 0E 1F 41 | ...A], chk=0x77, unk=0x45

CMD 0x0091 - sceSysconWriteScratchPad

This command writes data to Ernie Scratch Pad. This is the inverse of command 0x90.

CMD 0x0800 - SceSysconForDriver_A2FE9BF9

See KBL Param.

SEND 17   > [3.225828583333334] 0x0800, payload=[ | ], chk=0xF6
RESP 17   < [3.225828583333334] 0x0004, flags=00, payload=[40 00 | @.], chk=0xB7, unk=0x41

CMD 0x0100 - sceSysconGetControlsInfo

See Boot Controls Info.

SEND 18   > [3.226331500000000] 0x0100, payload=[ | ], chk=0xFD
RESP 18   < [3.226331500000000] 0x0004, flags=00, payload=[FF BF FF 74 | ...t], chk=0xC4, unk=0x45

CMD 0x0003 - sceSysconGetSleepFactor

See Sleep Factor.

SEND 19   > [3.226820750000000] 0x0003, payload=[ | ], chk=0xFB
RESP 19   < [3.226820750000000] 0x0004, flags=00, payload=[10 00 00 00 | ....], chk=0xE5, unk=0x45

CMD 0x0006 - sceSysconGetHardwareInfo2

See Hardware Info 2.

SEND 20   > [3.227328833333333] 0x0006, payload=[ | ], chk=0xF8
RESP 20   < [3.227328833333333] 0x0000, flags=3F, payload=[ | ], chk=0xBE, unk=0x00

CMD 0x088E - sceSysconCtrlVoltage

Last command sent before a time-jump (likely indicating completion of early-boot).

SEND 22   > [3.386554833333333] 0x088E, payload=[02 29 | .)], chk=0x3B
RESP 22   < [3.367488416666667] 0x0000, flags=80, payload=[ | ], chk=0x7D, unk=0xB4
RESP 22   < [3.371567833333333] 0x0000, flags=00, payload=[ | ], chk=0xFD, unk=0xB4
RESP 22   < [3.382079833333334] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0xB4
RESP 22   < [3.386554833333333] 0x0020, flags=00, payload=[ | ], chk=0xDD, unk=0xB4

CMD 0x0004

Unknown. Likely happens after initial boot.

SEND 26   > [4.177113250000000] 0x0004, payload=[ | ], chk=0xFA
RESP 26   < [4.177113250000000] 0x0000, flags=00, payload=[10 00 00 00 | ....], chk=0xE9, unk=0x31

CMD 0x0103 - sceSysconGetMultiCnInfo

Likely happens after initial boot.

SEND 27   > [4.177586083333333] 0x0103, payload=[ | ], chk=0xFA
RESP 27   < [4.177586083333333] 0x0000, flags=00, payload=[00 FF 04 00 | ....], chk=0xF6, unk=0x31

Syscon Scratch Pad

Offset Size Name Comment Used by
0x0 8 unknown
0x8 4 Syscon power on time ex on DevKit: 0xA, 0x16, 0x1F, 0x24. ex on retail: 0x01BC0CD0, 0x05AC1AF7, 0x80000269 SceRtc#sceRtcSetCurrentTickForDriver
0xC 4 Resume context physical address Set on retail. Not set on DevKit. ex: 0x411F1EF0 second_loader
0x10 5 Current Tick Set on retail and DevKit. Stored in microseconds since 01/01/0001 divided by 2^19. SceRtc#sceRtcSetCurrentTickForDriver
0x15 3 Padding of Current Tick
0x18 5 Current Secure Tick Set on retail. Not set on DevKit. SceRtc#sceRtcSetCurrentSecureTickForDriver
0x1D 5 Current Network Tick Always a bit earlier than Current Tick and Current Secure Tick. SceRtc#sceRtcSetCurrentNetworkTickForDriver
0x22 5 Current ?Debug Secure?/?Tool Secure? Tick Set on DevKit. Not set on retail. SceRtc#sceRtcGetCurrentToolSecureTickForDriver
0x27 5 Current Aux Tick SceRtc#sceRtcSetCurrentAuxTickForDriver
0x2C 5 Current Debug Network Tick SceRtc#sceRtcSetCurrentDebugNetworkTickForDriver
0x31 0x8F unknown Maybe reserved. Probably unused.
0xE0 0x20 CP DIP Switches Set on DevKit having a CP. Hence not set on Retail nor TestKit. ?secure_kernel? before system suspend, second_loader after system resume

Types

typedef struct SceSysconRtcTick { // size is 5 bytes
  uint8_t tick[5];
} SceSysconRtcTick;

typedef struct SceSysconScratchPad { // size is 0x100 bytes
  uint8_t unk_0[8];
  SceUInt32 powerOnTime;
  void *resumeContextPA;
  SceRtcSysconTick currentTick;
  uint8_t padding[3];
  SceSysconRtcTick currentSecureTick;
  SceSysconRtcTick currentNetworkTick;
  SceSysconRtcTick unk_0x22;
  SceSysconRtcTick currentAuxTick;
  SceSysconRtcTick currentDebugNetworkTick;
  uint8_t reserved[0x8F];
  SceDIPSW dipsw;
} SceSysconScratchPad;

NVS

Ernie Non-volatile storage (NVS) is a persistent storage allocated on Ernie Data Flash that is used by PS Vita OS for data required at boot time. Indeed, reading NVS requires no driver except the driver to communicate with Syscon, whilst reading PS Vita eMMC requires its AES-XTS decryption.

Not every NVS sector is directly readable from Kermit: the first sectors are part of SNVS (Secure NVS) which means that they are XTS-encrypted and must be accessed through a Secure handshake.

NVS actual size is 0xBA0 bytes on new Syscon hardware revisions and 0xC20 on old. However, only 0xB60 bytes are accessible from Kermit on System Software 3.600.011 and more recent. The hidden area is probably used internally by Syscon as it is not blanked nor 0xFFed.

On FW 3.60, NVS size accessible from Kermit is 0xB60 bytes:

Offset Size Name Comment Used by
0 0x400 SNVS See Ernie Secure#SNVS.
0x400 0x80 Qaf Token second_loader
0x480 0x1 Qaf Token Flag 1 when Qaf Token is not set (FFed), 0 when Qaf Token is set second_loader
0x481 0x1 Extra UART Flag 0xFF - extra UART disabled, 0x00 - extra UART enabled, 0x01 - extra UART enabled only when Jig dongle is connected second_loader
0x482 0x1 Unknown SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver
0x483 0x1 Safe Mode Flags 0xFF - not safe mode, 1, 3, 5, 9, 0x11 - safemode type SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver, second_loader, set by SceShellSvc#sceShellUtilRequestRebootWithError, read by SceSafeMode
0x484 0x1 KervResult/KervDiagResultFlag Factory test preCheckFactTest
0x485 0x1 Unknown
0x486 0x1 MCEmu Flag (use internal ux0) 0xFF on FAT - no internal storage or on PS TV or Slim - internal storage enabled, 0xFE on PS TV or Slim - internal storage disabled
Not present on FWs 0.931-0.990. Present on FW 3.60. Maybe not used on FWs <= 0.995
SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver, second_loader
0x487 0x1 Unknown 0xFF - unknown, maybe not used on FWs <= 0.995 second_loader
0x4A0 0x1 Update Mode 0xFF - not update mode, other value - update step (to detail) SceSblUpdateMgr#sceSblUsGetUpdateModeForUser, SceSblUpdateMgr#sceSblUsSetUpdateModeForUser
0x4A1 0x3 Unknown. Unused.
0x4A4 0x4 System Language SceRegistryMgr, SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver
0x4A8 0x1C Unknown. Unused.
0x4C4 0x1 Unknown. Set to 0 by default.
0x4C5 0x1B Unknown. Unused.
0x4E0 0x20 KibanID Per-console ASCII string of length 22 characters. This is a serial number also present in PS3 and PS4 Serial Flash. SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver
0x500 0x1 Wlan/Bt Flag SceSblSsMgr#sceSblSsGetNvsDataForDriver, SceSblSsMgr#sceSblSsSetNvsDataForDriver, SceWlanBt module_start
0x501 0x1F Unknown. Unused.
0x520 0x80 Activation Area first 0x20 bytes are SceNVSKitActivationData SceSblSsMgr, SceSblPostSsMgr
0x5A0 0x100 Qaf Token RSA signature Not present on FW 0.990. Present on FW 3.60. Maybe added on FW 1.80. second_loader
0x6A0 0xC0 Unknown. Unused.
0x760 0x400 Reserved for Test and Tool consoles. Seems unused.

Types

typedef struct SceNVSKitActivationData { // size is 0x20 bytes
  char magic[4]; // "act\n"
  uint32_t issue_no;
  uint32_t end_date;
  uint32_t start_date;
  char cmac_hash[0x10];
} SceNVSKitActivationData;

Config Storage

Config Storage is a similar storage than NVS but is accessed in a different manner. Whilst NVS is read and written by 32-byte sectors and is physically stored with a sort of history, Config Storage is written by sending scripts from Kermit to Syscon, and is not really readable but instead affects KBL Param#Hardware Info.

Sample scripts

Below are sample configstorage scripts hardcoded in SceSyscon:

const char syscon_idu_set_config[0x20] = {
    0x1F, 0x54, 0x35, 0x63, 0x38, 0x62, 0x31, 0x64,
    0x61, 0x63, 0x62, 0x38, 0x33, 0x36, 0x64, 0x64,
    0x36, 0x63, 0x39, 0x39, 0x36, 0x38, 0x65, 0x34,
    0x63, 0x30, 0x35, 0x30, 0x61, 0x36, 0x66, 0x35
};

const char syscon_idu_set_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x01, 0x00, 0x0D, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0x51, 0xBD, 0x52, 0x2C,
    0x4C, 0x83, 0x70, 0xDA, 0x4D, 0xF3, 0x8E, 0x82,
    0x6B, 0xD6, 0x34, 0x98, 0x3A, 0xFD, 0xA6, 0x94
};

const char syscon_show_set_config[0x20] = {
    0x1F, 0x54, 0x66, 0x63, 0x33, 0x39, 0x38, 0x39,
    0x30, 0x61, 0x33, 0x32, 0x64, 0x30, 0x66, 0x32,
    0x37, 0x36, 0x31, 0x35, 0x62, 0x65, 0x36, 0x65,
    0x63, 0x64, 0x63, 0x35, 0x65, 0x32, 0x63, 0x63
};

const char syscon_show_set_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x03, 0x00, 0x10, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0xB8, 0x1A, 0x54, 0xD1,
    0xF2, 0xA0, 0xD1, 0x05, 0x18, 0xEA, 0x22, 0x09,
    0x0A, 0x02, 0x2E, 0xAE, 0x00, 0x08, 0x25, 0xF1
};

const char syscon_clear_config[0x20] = {
    0x1F, 0x54, 0x65, 0x34, 0x61, 0x65, 0x38, 0x62,
    0x37, 0x61, 0x65, 0x38, 0x36, 0x33, 0x32, 0x65,
    0x64, 0x64, 0x39, 0x61, 0x61, 0x65, 0x38, 0x38,
    0x38, 0x39, 0x66, 0x30, 0x65, 0x65, 0x61, 0x38
};

const char syscon_clear_config2[0x20] = {
    0x07, 0x57, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x4E, 0x15, 0x48, 0x88, 0xEA, 0xC7, 0xAD,
    0x65, 0xB1, 0x73, 0xC1, 0xCF, 0x48, 0xC7, 0x29,
    0x1B, 0x2B, 0x8A, 0x32, 0x89, 0xCF, 0xB3, 0xC1
};

The only actual differences between those scripts are:

  • the ascii string: we do not know how it is generated and what it means
  • the mode value:
    • A8 01 00 00 00 00 = mode clear
    • A8 01 01 00 0D 00 = idu mode set
    • A8 01 03 00 10 00 = show mode set

Types

// TODO
Offset Size Name Sample value Comment
0 1 ascii_data_size 0x1F
1 1 ascii_data_flag 0x54
2 0x1E ascii_data ASCII hexadecimal string so maybe a hash
0x20 1 unk_7_data_size 7
0x21 1 unk_7_data_flag
0x22 6 unk_7_data
0x28 1 unk_1_data_size 1
0x29 1 unk_1_data_flag 0x4E
0x2A 1 sha1_hash_size 0x15
0x2B 1 sha1_hash_flag 0x48
0x2C 0x14 sha1_hash sha1 hash of the previous blocks (data from 0 of size 0x2A)

Config storage scripts have in theory a variable size. It is the concatenation of some blocks where the first byte is the length of the body, followed by the body of variable size. Body structure is always the same: 1 byte representing the flag, followed by data of variable size.

Usage

Theory by CelesteBlue (untested):

  • 0) Begin Transaction
  • 1) Load Script (part 1)
  • A) configstorage data is read from SceSyscon memory
  • B) configstorage data is sent by SceSyscon to Ernie
  • C) Ernie FW checks hash of data and returns xx on success

if success:

  • 2) Load Script (part 2)
  • A) configstorage data is read from SceSyscon memory
  • B) configstorage data is sent by SceSyscon to Ernie using Load
  • C) Ernie FW loads data to memory and executes it
  • 6) Commit Transaction
  • 7) End Transaction

Pinout

Ernie BGA package.

A candidate package for this chip is Renesas' P121F1-50-BAL-1. It has the same size and number of pins.

UART

Name Pin Description
CTS0 J7 UART0 clear to send
RTS0 C6 UART0 request to send
TX0 B6 UART0 transmit
RX0 F11 UART0 receive
SW0 A8 Switch, see UART Console#OLED PSVita UART0 location

SPI

Main communication with Kermit.

Name Pin Description
SS A7 Slave Select (often active low, output from master)
MISO A6 Master In Slave Out (data output from slave)
MOSI C7 Master Out Slave In (data output from master)
SCLK B7 Serial Clock (output from master)

Other

Name Pin Description
? C11 UDC pin 11
? F9 UDC pin 12
? G4 UDC pin 13
? G8 SN99057 pin 38
PWR_SW G6 Power switch through two transistor buffers

Versions

Hardware Versions

There are three hardware versions of Ernie:

  • NEC 78K0R/Kx3-L: present on early PS Vita prototypes (never seen)
  • NEC 78K0R/Kx3: present on Fat PS Vita and PS TV models, including some prototypes such as DEM-3000L
  • Renesas RL78/G13: present on Slim PS Vita models

NEC 78K0R/Kx3-L

Never seen yet but exists according to Ernie update packages.

NEC 78K0R/Kx3

NEC D79F0109 (78K0R/KH3, 121 pin)

Device Name : D79F0109

Other Device Name : SK0RT02N200GV120 (on DEM-3000L and PCH-1000)

Label:

Model <- always D79F0109
Revision <- on DEM-3000H: ES1.0, blank on others
Build <- XXYYZZWWW <- XX: year, YY: week, ZZ: 2 letters (unknown usage), WWW: serial number
Manufacturing country <- always "MALAYSIA"

Renesas RL78/G13

Renesas R5F1ZCRK (RL78/G13, 121 pin)

R5F1ZCRKABG#U0
R5    Renesas MCU
F      Flash
1      RL78
Z      Customer specific
C      Product group
R      121-pin
K      384KB
A      Consumer grade
BG    VFBGA 0.4mm
#U0  Tray*2
Device Name : R5F1ZCRK
Device Code : 10 00 06
Firmware Version : V3.03
Code Flash 1 (Address : 0x00000000,  Size : 384 K,  Erase Size : 1 K)
Data Flash 1 (Address : 0x000F1000,  Size : 8 K,  Erase Size : 1 K)

Label:

(C) XXXX <- Year
Revision <- A0xxx SCEI
Build <- XXYYZZWWW <- XX: year, YY: week, ZZ: 2 letters (unknown usage), WWW: serial number
Unknown data

Block sizes

Ernie flash memory is erasable in blocks. Size of one block in bytes depends on the hardware version:

  • NEC 78K0R/Kx3-L: 0x800
  • NEC 78K0R/Kx3: 0x400
  • Renesas RL78/G13: 0x400

See also [1].

Software Versions

See also [2].

Ernie firmware can be partly updated and downgraded with software updates embedded in PUP.

Ernie firmware is dependant of the hardware version and detects it based on Hardware Info.

Examples

With DevKit connected, psp2ctrl info queries return the following results:

DEM-3000H running FW 0.990:

SysConVersion: 591105

-> converted to hexadecimal: 0x00090501 -> 0.9.5.1

PDEL-1001 running FW 1.692:

SCVersion: 0.9.2.4

PDEL-1001 running FW 3.600-3.680:

SCVersion: 1.0.3.6

Downgrade

Syscon is downgradable on DEM/PDEL/PTEL/QAF units. It might also be downgraded on retail when using a downgrade enabler like modoru.

Firmware

See Ernie Firmware