Open orangecms opened 10 months ago
From the forum post:
The recovery tool has (unsurprisingly) a header that is similar to that added by the spl_tool. However, it is not exact. For example the version field is
0x01010001
instead of0x01010101
. Is there any significance to that? There is also some further data at offset0x2d4
, that is not specified in thespl_tool
source. Does anybody have a more complete header description at hand?The recovery tool has a menu option to blow OTP fuses. Is there any documentation about these fuses?
The
spl_tool
source file says that the header is discussed on the page “Creating SPL File 1”. However, on this page there is no discussion of the header and its contents
dd if=jh7110-devkits-recovery-20230918.bin bs=1024 count=1 | hexdump -C
00000000 40 02 00 00 00 00 20 00 00 00 00 00 00 00 00 00 |@..... .........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000280 00 00 00 00 01 00 01 01 10 72 03 00 00 04 00 00 |.........r......|
00000290 a0 3a d2 53 00 00 00 00 00 00 00 00 00 00 00 00 |.:.S............|
000002a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 00 00 00 00 10 72 03 00 01 00 00 00 00 00 00 00 |.....r..........|
000002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
dd bs=1024 count=1 if=jh7110-recovery-20230322.bin | hexdump -C
00000000 40 02 00 00 00 00 20 00 00 00 00 00 00 00 00 00 |@..... .........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000280 00 00 00 00 01 00 01 01 a0 81 02 00 00 04 00 00 |................|
00000290 30 43 4d 78 00 00 00 00 00 00 00 00 00 00 00 00 |0CMx............|
000002a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 00 00 00 00 a0 81 02 00 01 00 00 00 00 00 00 00 |................|
000002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
dd bs=1024 count=1 if=jh7110-recovery-20221205.bin | hexdump -C
00000000 40 02 00 00 00 00 20 00 00 00 00 00 00 00 00 00 |@..... .........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000280 00 00 00 00 01 00 01 01 f0 81 02 00 00 04 00 00 |................|
00000290 f5 dc e1 a4 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000002a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 00 00 00 00 f0 81 02 00 01 00 00 00 00 00 00 00 |................|
000002e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
The manual says that something called OTPC
is here (table 2-4 System Memory Map):
Start Address | End Address | Size | Attribute | Device/Description |
---|---|---|---|---|
0x00_1705_0000 |
0x00_1705_FFFF |
64KB | RW A | OTPC |
I was able to get a bunch of data into the create_hdr
tool. It outputs a "common header" and the "sbl header".
A configuration file is needed to hold all the data.
A full header is 0x400
in site; I am not sure why the common and sbl header are split as 0x240
+ 0x160
0x180
bytes,
What is in the sbl header starts at 0x280
in a real image. Those
EDIT: Those 0x40
in between might be taken from the end of the sbl header, or those last 0x40
bytes there are meaningless... that's an open thing to figure out.0x40
in between come from something called sig(nature?) padding, and so 0x240
+ 0x040
+ 0x180
add up to 0x400
.
Here is my config; not everything shows up though, maybe the tool wasn't that complete?
create_hdr.cfg
# path of sbl firmware, can be overrided by "--bin file" argument
SBL_BIN = test/test1.bin
# version of sbl firmware, can be overrided by "--version val" argument
# Endian: Little
SBL_VER = 0x01010001
# Offset of backup SBL from Flash info start
# Endian: Little
SBL_BAK_OFFSET = 0x200000
OUTPUT_COMMON_HDR_FILENAME = test/common.hdr.out
OUTPUT_SBL_HDR_FILENAME = test/sbl.hdr
OUTPUT_SBL_HASH_FILENAME = test/sbl.hash
# unused ?
OUTPUT_SBL_BIN_CIPHER_FILENAME = test/sbl.bin.cipher
OUTPUT_SBL_SIG_FILENAME = test/sbl.sig
OUTPUT_SBL_VER_CIPHER_FILENAME = test/sbl_ver.cipher
OUTPUT_EC_KEY_REVOKE_CIPHER_FILENAME = test/ec_key_revoke.cipher
OUTPUT_AES_IV_FILENAME = test/aes_iv
# OTP secret?
OUTPUT_OTPSCR_FILENAME = test/otp_scr
# TODO
CHIP_UID = 0x01234567
# TODO
DBG_KEY = 0x1337
CHIP_MODE = 1
FL_SECBT = 2
# TODO
AES_KEY = "abcd"
AES_IV = 0x00001234,0x00001234,0x00001234,0x00001234
# Key select for multiple pri(vate) keys?
EC_KEY_SEL = 3
# TODO
EC_KEY_REVOKE = 2,1,4,3
EC_PARAM_P = 0x22002020,0x22002020,0x22002020,0x22002020,0x22002020,0x22002020,0x22002020,0x22002020
EC_PARAM_A = 0x33003030,0x33003030,0x33003030,0x33003030,0x33003030,0x33003030,0x33003030,0x33003030
EC_PARAM_B = 0x44004040,0x44004040,0x44004040,0x44004040,0x44004040,0x44004040,0x44004040,0x44004040
EC_PARAM_GX = 0x55005050,0x55005050,0x55005050,0x55005050,0x55005050,0x55005050,0x55005050,0x55005050
EC_PARAM_GY = 0x66006060,0x66006060,0x66006060,0x66006060,0x66006060,0x66006060,0x66006060,0x66006060
EC_PARAM_N = 0x77007070,0x77007070,0x77007070,0x77007070,0x77007070,0x77007070,0x77007070,0x77007070
EC_SIGN_KINV = 0x88008080,0x88008080,0x88008080,0x88008080,0x88008080,0x88008080,0x88008080,0x88008080
# ??
EC_SIGN_RP = 0x99009090,0x99009090,0x99009090,0x99009090,0x99009090,0x99009090,0x99009090,0x99009090
# How does this work?
# https://developers.yubico.com/PIV/Guides/Generating_keys_using_OpenSSL.html
# openssl ecparam -name prime256v1 -genkey -noout -out key.pem
EC_PRI_KEYS = "test/ec_key.pem","test/ec_key.pem","test/ec_key.pem","test/ec_key.pem"
invoked like this:
create_hdr create_hdr.cfg
the funny numbers are the EC parameters
the last 4x 0x40
are the EC keys, which the tool reads from PEM files; to create them:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
xxd common.hdr.out
00000000: 4002 0000 0000 2000 0000 0000 0000 0000 @..... .........
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 2020 0022 2020 0022 2020 0022 2020 0022 ." ." ." ."
00000050: 2020 0022 2020 0022 2020 0022 2020 0022 ." ." ." ."
00000060: 3030 0033 3030 0033 3030 0033 3030 0033 00.300.300.300.3
00000070: 3030 0033 3030 0033 3030 0033 3030 0033 00.300.300.300.3
00000080: 4040 0044 4040 0044 4040 0044 4040 0044 @@.D@@.D@@.D@@.D
00000090: 4040 0044 4040 0044 4040 0044 4040 0044 @@.D@@.D@@.D@@.D
000000a0: 5050 0055 5050 0055 5050 0055 5050 0055 PP.UPP.UPP.UPP.U
000000b0: 5050 0055 5050 0055 5050 0055 5050 0055 PP.UPP.UPP.UPP.U
000000c0: 6060 0066 6060 0066 6060 0066 6060 0066 ``.f``.f``.f``.f
000000d0: 6060 0066 6060 0066 6060 0066 6060 0066 ``.f``.f``.f``.f
000000e0: 7070 0077 7070 0077 7070 0077 7070 0077 pp.wpp.wpp.wpp.w
000000f0: 7070 0077 7070 0077 7070 0077 7070 0077 pp.wpp.wpp.wpp.w
00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000140: cae7 0af0 8dcf 9381 5549 2d2a 0f85 f57d ........UI-*...}
00000150: 6cd1 8252 76df f475 2319 9913 4f98 fdc9 l..Rv..u#...O...
00000160: 7677 fa40 5b21 777c 96c6 d85e 905d cf17 vw.@[!w|...^.]..
00000170: 0abc 68fe 6bc3 231e bd98 bb49 224c a2c4 ..h.k.#....I"L..
00000180: cae7 0af0 8dcf 9381 5549 2d2a 0f85 f57d ........UI-*...}
00000190: 6cd1 8252 76df f475 2319 9913 4f98 fdc9 l..Rv..u#...O...
000001a0: 7677 fa40 5b21 777c 96c6 d85e 905d cf17 vw.@[!w|...^.]..
000001b0: 0abc 68fe 6bc3 231e bd98 bb49 224c a2c4 ..h.k.#....I"L..
000001c0: cae7 0af0 8dcf 9381 5549 2d2a 0f85 f57d ........UI-*...}
000001d0: 6cd1 8252 76df f475 2319 9913 4f98 fdc9 l..Rv..u#...O...
000001e0: 7677 fa40 5b21 777c 96c6 d85e 905d cf17 vw.@[!w|...^.]..
000001f0: 0abc 68fe 6bc3 231e bd98 bb49 224c a2c4 ..h.k.#....I"L..
00000200: cae7 0af0 8dcf 9381 5549 2d2a 0f85 f57d ........UI-*...}
00000210: 6cd1 8252 76df f475 2319 9913 4f98 fdc9 l..Rv..u#...O...
00000220: 7677 fa40 5b21 777c 96c6 d85e 905d cf17 vw.@[!w|...^.]..
00000230: 0abc 68fe 6bc3 231e bd98 bb49 224c a2c4 ..h.k.#....I"L..
The first field here is the EC key to use; it can be 0
(none) or some value of 1
, 2
, 3
, 4
; otherwise, the mask ROM loader would reject, from what I can tell. This would be at 0x280
in a full image.
xxd sbl.hdr
00000000: 0300 0000 0100 0101 0000 4000 0004 0000 ..........@.....
00000010: fab3 4d89 0000 0000 0000 0000 0000 0000 ..M.............
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
addendum to the sbl part:
the next fields after the checksum are
On the EC keys
creating a key is also described in the config file I provided above; taken from
https://developers.yubico.com/PIV/Guides/Generating_keys_using_OpenSSL.html
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
Anyway, that gets us a PEM format file like this:
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFpLCSboXWMteMtlhSgFneRRdizkaIKOSfTXhE1VapDxoAoGCCqGSM49
AwEHoUQDQgAEyf2YTxOZGSN19N92UoLRbH31hQ8qLUlVgZPPjfAK58rEokwiSbuY
vR4jw2v+aLwKF89dkF7YxpZ8dyFbQPp3dg==
-----END EC PRIVATE KEY-----
let's quick-hack that to a hex representation
https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)To_Hex('Space',0)
I've marked the relevant parts
30 77 02 01 01 04 20 5a 4b 09 26 e8 5d 63 2d 78
cb 65 85 28 05 9d e4 51 76 2c e4 68 82 8e 49 f4
d7 84 4d 55 6a 90 f1 a0 0a 06 08 2a 86 48 ce 3d
03 01 07 a1 44 03 42 00 04 [c9 fd 98 4f 13 99 19
23 75 f4 df 76 52 82 d1 6c 7d f5 85 0f 2a 2d 49
55 81 93 cf 8d f0 0a e7 ca][c4 a2 4c 22 49 bb 98
bd 1e 23 c3 6b fe 68 bc 0a 17 cf 5d 90 5e d8 c6
96 7c 77 21 5b 40 fa 77 76]
looking at the resulting header file, it appears that the last two parts are just reversed, respectively, which becomes
cae7 0af0 8dcf 9381 5549 2d2a 0f85 f57d ........UI-*...}
6cd1 8252 76df f475 2319 9913 4f98 fdc9 l..Rv..u#...O...
7677 fa40 5b21 777c 96c6 d85e 905d cf17 vw.@[!w|...^.]..
0abc 68fe 6bc3 231e bd98 bb49 224c a2c4 ..h.k.#....I"L..
now I have no clue what exactly the pieces are; just look at then OpenSSL manual or whatever or recap your crypto intro 101 on elliptic curves to get an idea :-)
Addendum:
okay so OpenSSL 101... the pub key has a fixed 04
at the beginning
generate multiple keys to check:
openssl ecparam -name prime256v1 -genkey -text | tail -n 5 | openssl ec -text
Note that the format is not too excellent for human processing; it is 15 bytes per line. Now, here is our key, just as we got it with CyberChef:
openssl ec -in test/ec_key.pem -text
read EC key
Private-Key: (256 bit)
priv:
5a:4b:09:26:e8:5d:63:2d:78:cb:65:85:28:05:9d:
e4:51:76:2c:e4:68:82:8e:49:f4:d7:84:4d:55:6a:
90:f1
pub:
04:c9:fd:98:4f:13:99:19:23:75:f4:df:76:52:82:
d1:6c:7d:f5:85:0f:2a:2d:49:55:81:93:cf:8d:f0:
0a:e7:ca:c4:a2:4c:22:49:bb:98:bd:1e:23:c3:6b:
fe:68:bc:0a:17:cf:5d:90:5e:d8:c6:96:7c:77:21:
5b:40:fa:77:76
ASN1 OID: prime256v1
NIST CURVE: P-256
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFpLCSboXWMteMtlhSgFneRRdizkaIKOSfTXhE1VapDxoAoGCCqGSM49
AwEHoUQDQgAEyf2YTxOZGSN19N92UoLRbH31hQ8qLUlVgZPPjfAK58rEokwiSbuY
vR4jw2v+aLwKF89dkF7YxpZ8dyFbQPp3dg==
-----END EC PRIVATE KEY-----
On the OTPC block again
OTPC = One-Time Programmable Configuration
0x1705_0000
64k
I read this as blocks of 64x 32 bytes each, which has repeating entries for me on a Milk-V Mars.
This here is repeated 64 times, the first block
0b040200 03000000 00000000 00000000 00000000 21000000 00000000 ffffffff
Note: 0x21000000
is the QSPI XIP memory; this might be coincidental, here it'd be BE
then comes 64 times all ffffffff...
and then a block of this 64 times
0b040200 03000000 00000000 00000000 00000000 ff010000 00000000 ffffffff
then all ffffffff...
again, and then the above block again, all-ffffffff
again, and those repeat to the end.
Note:
From the mask ROM, I can tell that there is a fixed function just writing the value 0x0002040b
to the OTPC base address which you see repeated in the beginning as pointed out above. That function is called as part of the OTP init, right in the beginning after GPIO, UART and CLINT init, before evaluating the boot source.
If XIP flash is disabled in OTP configuration, system cannot boot from XIP flash.
The On-Chip boot ROM is 32 KB.
The boot mode and boot options could be loaded from the SYSCON status registers.
from the manual, Table 2-2 System Boot Process
Processor | Boot Mode (PAD_RGPIO2 ) |
Boot Vector | Boot Selection (PAD_RGPIO [1:0]) |
---|---|---|---|
U74MC | 0x1 |
0x2100_0000 |
XIP Flash |
0x0 |
0x2A00_0000 |
0x0 : Boot from 1-bit QSPI instead of flash |
|
0x1 : Boot from SDIO3.0 |
|||
0x2 : Boot from EMMC5.1 |
|||
0x3 : Boot from UART |
|||
Audio DSP | Defined by U74MC or E24 | ||
E24 | Defined by U74MC |
my OTP config in AON_SYSCON
(24 onwards):
00000000000000000000000000000111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
00000000000000000000000010110010
first line: u0_otpc_chip_mode , u0_otpc_crc_pass and u0_otpc_dbg_enable are all set
second: u0_otpc_fl_func_lock (all 0 by default)
third: u0_otpc_fl_pll0_lock (all 0 by default)
fourth: u0_otpc_fl_pll1_lock (all 0 by default)
last: |
bit | name | mode | default |
---|---|---|---|---|
[1] | u0_otpc_fl_xip | RO | 0x0 | |
[2] | u0_otpc_load_busy | RO | 0x0 | |
[3] | u0_reset_ctrl_clr_reset_status | WR | 0x0 | |
[4] | u0_reset_ctrl_pll_timecnt_finish | RO | 0x0 | |
[5] | u0_reset_ctrl_rstn_sw | WR | 0x1 | |
[9:6] | u0_reset_ctrl_sys_reset_status | RO | 0x0 |
@MichaelZhuxx any comment on this so far? This is very tedious... would be great to have some support here. :grimacing: Thank you!
In #1, we discussed the basics of creating a valid header for a simple boot.
Still open is
For reference:
I would like to provision my JH7110 SoCs with secure boot and need this documentation. I can write the tools for that myself and would integrate support in oreboot.