Syscon UART RPC
The PlayStation Vita/TV's System Controller hosts a RPC server accessible from multiple interfaces, each of which has its own set of available commands.
One of the interfaces is UART, enabled by a special "jig" circuit that sets specific voltage levels on Syscon's voltage sense pins/probes.
This interface exposes around 100 RPC commands ranging from simple peripheral details retrieving to more complex procedures such as Syscon flash programming or alternative SoC boot modes.
Client
An example client implementation named Bert is provided by SKGleba.
Hardware
Model | Interface location |
---|---|
IRT-001 | Unknown |
IRT-002 | MultiConnector |
IRS-* | MultiConnector |
DOL-* | Service Connector (ffc) |
USS-* | microUSB |
MultiConnector circuit
The UART interface is enabled if the *"Jig Sense 1"* probe is at 0.47v-0.738v during *"Jig Sense 2"* probe state change (float <-> gnd).
Type | Location |
---|---|
Sense 1 | Pin 11 |
Sense 2 | Pin 12 |
Syscon RX | Pin 6 |
Syscon TX | Pin 7 |
Service Connector circuit
The UART interface is enabled if the *"Jig Sense 1"* probe is at 0.47v-0.738v during *"Jig Sense 2"* probe state change (float <-> gnd).
Type | Location |
---|---|
Sense 1 | Pin 4 |
Sense 2 | Pin 6 |
Syscon RX | Pin 20 |
Syscon TX | Pin 19 |
MicroUSB circuit
The UART interface is enabled if the *"Jig Sense"* probe is at 1.017v-1.14v for at least 32000 Syscon clock cycles. When enabled, a "UUU" hello packet is sent over UART.
Type | Location |
---|---|
Sense | Pin 4 / ID |
Syscon RX | Pin 3 / D+ |
Syscon TX | Pin 4 / D- |
Example circuit
Software
The UART RPC interface protocol is a simple message -> reply packet interaction, with each packet structured as below:
Offset | Size | Name |
---|---|---|
0x0 | 0x2 | Command ID |
0x2 | 0x1 | Return status |
0x3 | 0x2 | Data size |
0x5 | Up to 0x39 | Data |
After data | 0x2 | Checksum |
Each packet is converted to/from ASCII and ends in CRLF, max packet size is 0x40 bytes (ascii 0x80).
Message
Command list:
RPC Command ID | Lock | Description |
---|---|---|
0x100 | 0x0 | nop - response: 0x00 |
0x101 | 0x0 | get console info - response: 0x00 - output: 3850800011050301030175008040327F - last 4 bytes are variable |
0x102 | 0x0 | comm settings - response: 0x00 - input: 1byte protocol + 1byte baudrate + 2bytes unknown - protocol : 00 ascii, 01 ascii in/binary out - baudrate : 00 38400, 01 115200 |
0x103 | 0x0 | unlock T1 - response: 0x00 |
0x104 | 0x0 | lock T1 - response: 0x00 |
0x105 | 0x1 | kermit power control - response: 0x00 if completed, 0x50 if bad current power state - input: requested new power state, 1byte - 00 : resp 0x00 - power-off - 02 : resp 0x00 - power-on - 03 : resp 0x00 - powers on the SoC in SD boot mode, but does not reply to the challenge - this is used to talk with internal SoC subsystems via a SPI<->I2C interface |
0x106 | 0x0 | get power state - response: 0x00 - output: current power state - 0400 : off - 0800 : suspended - 2000 : on - 0002 : unk - 0004 : unk |
0x107 | 0x0 | get date string - response: 0x00 - output: 32303133313231333135353207000000000000000000000000000000 - output hex2ascii : 201312131552 |
0x108 | 0x0 | ? - response: 0x00 - output: - slim: 100001C20000000020008043000000003000A90016045300310020050208A90040FFFFFF00000000 - pstv: 100001920000000020FFFFFF0000000030FFFFFFFFFFFFFF31FFFFFFFFFFFFFF40001ACA00000000 - input: unknown, min size 2 bytes, only 0000 seems good |
0x109 | 0x0 | get task states - response: 0x00 - input: mem buf idx ( 00 / 01 ) - 00 : output: - slim: 0900040000000000320000000000000000000000000000000000000000000000 - pstv: 0900080000000000510000000000000000000000000000000000000000000000 - 01 : output: - slim: 0802020000000200610009020400000004003200000000000000000000000000 - pstv: 0802200000002000090009020800000008005100000000000000000000000000 - the buffers are updated by various tasks, from various states |
0x110 | 0x1 | unlock via handshake - response: 0x00 - input: 3-step handshake, ascii size 80 bytes - keyset 0: start/enter SD boot mode - keyset 1: unlock T2 - keyset 14: unlock T8 |
0x120 | 0x1 | get VisibleId - response: 0x00 - output: some serial (equivalent of PSP FuseID) read from fuses. Also stored in Cmep keyring 0x600 - uses the SPI<->i2c interface in a special boot mode (command 0x105 mode 03) - keyring: C477BC5336570D60009F5118052CD5624441E0DD4A3A2E610186E87801010000 - command: 53BC77C4600D573618519F0062D52C05DDE04144612E3A4A78E8860100000101 |
0x121 | 0x1 | SoC i2c device 0x40 read by offset - response: 0x00 - input: 16bit offset (BE) for SoC i2c device 0x40 - output: 32bit value read from offset - uses the SPI<->i2c interface in a special boot mode (command 0x105 mode 03) - example in=0004 -> out=94000115 (kermit rev) - example in=1060 -> out=00000029 - blacklisted offsets 0x8-0x1000 in release syscon firmware |
0x131 | 0x3 | NVS read - auth level: T2 - response: 0x00 - input: 2byte offset + 1byte size - output: data read from given offset |
0x132 | 0x3 | NVS write - auth level: T2 - response: 0x00 - input: 2byte offset + 1byte size + sizeBytes data, min size 6 ascii bytes - output: data read from given offset |
0x140 | 0x0 | ConfZZ param? - response: 0x00 - output: 32bit values from the 0x10 field before both main and backup ConfZZ - slim: 5800050058000400 - pstv: 5000040050000300 - whole buf 03B800: 43 6F 6E 66 5A 5A F0 03 50 00 03 00 E4 51 FF FF - whole buf 03BC00: 43 6F 6E 66 5A 5A F0 03 50 00 04 00 7E 52 FF FF |
0x141 | 0x9 | ConfZZ read - response: 0x00 - input: 2byte offset + 1byte size, max offset 0x3EF, max size 0x20 - output: ConfZZ data of size read from offset |
0x142 | 0x9 | ConfZZ write-backup - response: 0x00 - input: 2byte offset + 1byte size + sizeBytes data, max offset 0x3EF, max size 0x20 - data is written to backup ConfZZ |
0x143 | 0x9 | Unlock 0x142 - response: 0x00 |
0x144 | 0x9 | Lock 0x142 - response: 0x00 |
0x145 | 0x9 | Switch active ConfZZ? - response: 0x00 - active ConfZZ is changed / backup ConfZZ is written to main? |
0x146 | 0x9 | computes and checks some sha1, integrity checks? - response: 0x00 if all ok - input: unk, seems like 3 bytes followed by a sha1? |
0x147 | 0x9 | computes and checks some sha1, integrity checks? - response: 0x00 if all ok - input: unk, seems like 3 bytes followed by a sha1? |
0x148 | 0x9 | ?? |
0x150 | 0x1 | ? - response: 0x00 - output: some INVS flags preset? - slim: 0900001100000000 - pstv: 100001AA00000000 |
0x151 | 0x1 | Unlock INVS writes (0xAA) - response: 0x00 - unlocks 0x155 & 0x156, writes 0xAA to INVS+1 |
0x152 | 0x9 | Lock INVS writes - response: 0x00 - locks 0x155 & 0x156, writes 0x00 to INVS+1 |
0x153 | 0x9 | internal NVS read by id - response: 0x00 - input: unknown, min ascii size 4 bytes, read data id?, max id 0x1D - 00 : output: - slim: 01AA0900 - pstv: 01001000 - 01 : output 6A000000 - 02 : output 06000000 - 03,06,07,0C-10,12,14,16,1A,1D : output 00 - 04,19 : output 02 - 05 : output 1400 - 08,18 : output 01 - 09,0A,0B,17 : output 0000 - 11 : output 07 - 13 : output 08 - 15 : output 03 - 1B : output 2800 - 1C : output 29 |
0x154 | 0x9 | internal NVS read - response: 0x00 - input: 2byte offset + 1byte size, max offset 0x3F, max size 0x20 - output: unknown data of size read from offset, seems to contain data from 0x153 |
0x155 | 0x9 | ? - response: 0x00 - input: unknown, min ascii size 4 bytes, ?write data? |
0x156 | 0x9 | ? - response: 0x00 (?apply data?) |
0x157 | 0x1 | Unlock INVS writes (0x11) - response: 0x00 - unlocks 0x155 & 0x156, writes 0x11 to INVS+1 |
0x160 | 0x9 | Depersonalize - response: 0x00 - input: unknown, min size 2 ascii bytes - 01: long pause and no "UUU" message - 02: Formats NVS and SNVS |
0x161 | 0x9 | ?hard? reset syscon - response: 0x00 - causes ?soft reset?, "UUU" message sent again, console shutdown |
0x162 | 0x9 | ?soft? reset syscon - response: 0x00 - causes ?soft reset?, "UUU" message sent again, faster than 0x162 |
0x163 | 0x9 | ? - response: 0x00 - input: unknown, min size 2 ascii bytes - 5A: seems to shut down kermit and reset locks, no "UUU" message |
0x168 | 0x1 | ? - response: 0x00 - output: - slim: 70033737 - pstv: 70033535 |
0x170 | 0x9 | ? - response: 0x00 - output: - slim: 01420000250000001B0CFFFFF8000F00000000000018 - pstv: 0102000100 |
0x171 | 0x9 | ? - response: 0x00 - output: 8040327FFFFF61EDF4 - output is variable |
0x172 | 0x9 | ? - response: 0x00 - output: CC640500FFFFFFFF00 - output is variable |
0x180 | 0x1 | ? - response: 0x00 - output: - slim: 8607B70FF200F70056000000 - pstv: D007A00F2C012C0100000000 |
0x181 | 0x9 | ? - response: 0x00 - output: - slim: 110080016201000000000000 - pstv: 000000000000000000000000 |
0x182 | 0x9 | reset battery IC - response: 0x00 - causes ?hard reset?, "UUU" message sent again after a longer period (~6 seconds) - nothing on PS TV - |
0x183 | 0x9 | ? - response: 0x00 - unlocks 0x184,0x185,0x186,0x187,0x188,0x189 |
0x184 | 0x9 | ? - response: 0x00 |
0x185 | 0x9 | ? - response: 0x33 |
0x186 | 0x9 | ? - response: 0x00 |
0x187 | 0x9 | ? - response: 0x33 |
0x188 | 0x9 | ? - response: 0x00 |
0x189 | 0x9 | ? - response: 0x00 |
0x18A | 0x9 | ? - response: 0x00 - output: - slim: 40000000 - pstv: 00000000 |
0x18B | 0x9 | ? - response: 0x00 - output: 01 |
0x18C | 0x9 | ? - response: 0x00 - output: - slim: 0C - pstv: 09 |
0x18D | 0x9 | ? - response: 0x00 - output: - slim: 00 - pstv: 08 |
0x18E | 0x9 | ? - response: 0x00 - output: - slim: 01 - pstv: 0C |
0x18F | 0x9 | ?? |
0x190 | 0x9 | ? - response: 0x00 - output: 0100000000010000 |
0x191 | 0x9 | ?? |
0x192 | 0x9 | ?? |
0x1A0 | 0x1 | ? - response: 0x00 - output: 0000000000000000000000000000000000000000 |
0x1A1 | 0x1 | ? - response: 0x00 - output: 808080808080808080808080 |
0x1B0 | 0x1 | ? - response: 0x00 - output: 0000000000000000 |
0x1B2 | 0x9 | ?? |
0x1C0 | 0x1 | ? - response: 0x00 - output: 01550000 |
0x1C1 | 0x1 | ? - response: 0x00 |
0x1C2 | 0x1 | ? - response: 0x00 |
0x1C3 | 0x1 | ? - response: 0x00 - unlocks 0x1C1,0x1C4 |
0x1C4 | 0x1 | ? - response: 0x00 - output: 36300301FF000400 - input: unknown, min ascii size 4 bytes, ?id?, max id 0x29 - output: unknown, data read from id? for example id=01->data=A408020120000C0C |
0x1D0 | 0x9 | ? - response: 0x98 |
0x1D1 | 0x9 | ? - response: 0x98 |
0x1D2 | 0x1 | ? - response: 0x00 - output: 0000000000010000 |
0x1D3 | 0x9 | ?? |
0x1D4 | 0x1 | ?? |
0x1D5 | 0x9 | ?? |
0x1E0 | 0x1 | ?? |
0x1E1 | 0x1 | ?? |
0x1E2 | 0x1 | ?? |
0x1E3 | 0x1 | ?? |
0x300 | 0x0 | write to shared jig-kermit buffer - response: 0x00 - input: message to kermit, max ascii size 80 bytes - sets some key |
0x301 | 0x0 | read from jig-kermit shared buffer - response: 0x00 - output: message from kermit, ascii size 80 bytes |
0x900 | 0x0 | unlock T4 - response: 0x00 - input: password, ascii size 32 bytes |
0x901 | 0x0 | lock T4 - response: 0x00 |
0x910 | 0x4 | ? - response: 0x33 |
0x911 | 0x4 | ? - response: 0x33 |
0x912 | 0x4 | ? - response: 0x33 |
0x913 | 0x4 | ? - response: 0x33 |
0x914 | 0x4 | ? - response: 0x33 |
0x915 | 0x4 | ? - response: 0x33 |
0x916 | 0x4 | ? - response: 0x00 - output: 1B010600035402010100010000000000 |
0x917 | 0xC | ? - response: 0x00 - output: 2D3A0543 |
0x930 | 0x4 | ? - response: 0x00 - output: - slim: 01C2 - pstv: 0192 |
0x931 | 0x4 | ? - response: 0x00 - output: - slim: 8043 - pstv: FFFF |
0x932 | 0x4 | ? - response: 0x00 - output: - slim: 2005A900160453000208A900 - pstv: FFFFFFFFFFFFFFFFFFFFFFFF |
0x940 | 0xC | ? - response: 0x00 - output: 0300 - input: unknown - : output 05A9 resp 0x60 - 00-03,08-0D,24,25,33-35,37,41,44,48 : output 0300 - 04-07,0F-1F,36,38-3F : output 0400 - 0E : output 0600 - 20-22,40,43,46,47,49-4F : output 0200 - 23,26-32,90-9F : output 0100 - 42,71,72 : output 0004 - 45 : output 0404 - 50 : output 5541 - 51,54 : output 4105 - 52,55 : output 1000 - 53 : output AA81 - 56-5F,80,A0-A3,A5-A7,AA-B2,F0-FF : output 0000 - 60-70 : output FFF0 - 73 : output 0005 - 74-7F : output 0101 - 81 : output 1500 - 82-85 : output 1700 - 86-8F : output 0F00 - B3-BF : output F000 - A9,C0-CF : output 8000 - D0-EF : output 01C2 |
0x941 | 0xC | ? - response: 0x00 - input: unknown, min ascii size 2 bytes - writes somewhere or sets some flag for 0x942 |
0x942 | 0xC | ? - response: 0x00 - input: unknown, min ascii size 2 bytes - output: 0000 unless written with 0x941, mashed with input |
0x943 | 0xC | ? - response: 0x00 - input: unknown, min ascii size 2 bytes |
0x944 | 0xC | ? - response: 0x00 - output: 9801 |
0x945 | 0xC | ? - response: 0x00 - input: unknown, min ascii size 2 bytes |
0x952 | 0xC | ? - response: 0x00 - causes ?soft reset?, "UUU" message sent again after around 3s |
0x953 | 0x4 | ? - response: 0x00 - output: 1C000000A60BA30B |
0x954 | 0x4 | ?? |
0x955 | 0x4 | ?? |
0x961 | 0x4 | ? - response: 0x00 - output: 8080808080808080 |
0x962 | 0x4 | ? - response: 0x00 - output: 0080008000800080 |
0x963 | 0x4 | ? - response: 0x00 - output: 00000000000000000000000000000000 |
0x964 | 0x4 | ? - response: 0x00 - output: 0080008000800000008000800080000000800080008000000080008000800000 |
0x965 | 0x4 | ? - response: 0x00 - output: 0000C0FF0000C0FF0000C0FF0000C0FF |
Reply
The reply contains a command return status, currently the following common status IDs are known:
ID | Description |
---|---|
0x0 | "OK" |
0x1 | "UNK_CMD" |
0x2 | "BAD_LEN" |
0x3 | "BAD_CHKSUM" |
0x4 | "NO_CRLF" |
0x5 | "BAD_CMD_FORMAT" |
0x10 | "LOCKED_HANDSHAKE" |
0x20 | "LOCKED_T1" |
0x32 | "BAD_ARG_SIZE" |
0x33 | "BAD_ARG" |
0x40 | "WRONG_STATE" |
0x50 | "WRONG_POWER_STATE" |
Locks
Some commands are locked behind "locks", global bits that can be set using other commands.
For example the power control command (RPC command 0x105) requires the T1 "lock" to be removed by calling command 0x103.
Some commands, such as NVS-read (0x131), might be locked behind multiple "locks" - here besides T1, the T8 lock needs to be removed/unlocked first by performing a 3-step keyset 1 handshake with cmd 0x110.
Bitmask | Unlock RPC command ID | Lock RPC command ID | Usage |
---|---|---|---|
1 | 0x103 | 0x104 | RPC command 0x105 |
2 | 0x110 with keyset 1 | n/a | |
4 | 0x900 with password | 0x901 | |
8 | 0x110 with keyset 14 | n/a | Syscon command 0xD2 for SNVS read, RPC command 0x131 for NVS read |