Skip to content

Commit baf2128

Browse files
rivos-eblotloiclefort
authored andcommitted
[ot] scripts/opentitan: otptool.py: add a new option to read Present constants from QEMU config file
Signed-off-by: Emmanuel Blot <eblot@rivosinc.com>
1 parent b7bdb16 commit baf2128

File tree

4 files changed

+83
-15
lines changed

4 files changed

+83
-15
lines changed

docs/opentitan/otptool.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ controller virtual device.
77

88
````text
99
usage: otptool.py [-h] [-j HJSON] [-m VMEM] [-l SV] [-o C] [-r RAW]
10-
[-k {auto,otp,fuz}] [-e BITS] [-c INT] [-i INT] [-w] [-n]
11-
[-s] [-E] [-D] [-U] [--empty PARTITION]
10+
[-k {auto,otp,fuz}] [-e BITS] [-C CONFIG] [-c INT] [-i INT]
11+
[-w] [-n] [-s] [-E] [-D] [-U] [--empty PARTITION]
1212
[--clear-bit CLEAR_BIT] [--set-bit SET_BIT]
1313
[--toggle-bit TOGGLE_BIT] [-L | -P | -R] [-v] [-d]
1414
@@ -30,6 +30,8 @@ Parameters:
3030
-k {auto,otp,fuz}, --kind {auto,otp,fuz}
3131
kind of content in VMEM input file, default: auto
3232
-e BITS, --ecc BITS ECC bit count
33+
-C CONFIG, --config CONFIG
34+
read Present constants from QEMU config file
3335
-c INT, --constant INT
3436
finalization constant for Present scrambler
3537
-i INT, --iv INT initialization vector for Present scrambler
@@ -87,12 +89,18 @@ Fuse RAW images only use the v1 type.
8789
`-D` to verify partition digests, and stored in the optional QEMU OTP RAW image file for use by
8890
the virtual OTP controller when used along with the `-r` option.
8991

90-
* `-c` specify the register file, which is only useful to decode OTP content (see `-s` option).
91-
This option is required when `-D` Present digest checking is used.
92+
* `-C` specify a QEMU [configuration file](otcfg.md) from which to read the Present constants that
93+
are required for digest computation. It is a convenience switch to replace both `-i` and options.
94+
See [`cfggen.py`](cfggen.md) tool to generate such a file.
95+
96+
* `-c` specify the initialization constant for the Present scrambler used for partition digests.
97+
This option is required when `-D` Present digest checking is used. See also `-i` option switch.
98+
Override option `-C` if any.
9299

93100
* `-D` performs a partition digest checks for all partitions with a defined digest. The Present
94101
constant should be defined to perform digest verification. They can be specified with the `-c` and
95-
`-i` options switches, or when using a QEMU OTP RAW v2 file that stores these constants.
102+
`-i` options switches, or when using a QEMU OTP RAW v2 file that stores these constants, or when
103+
a QEMU configuration file is specified with the `-C` option.
96104

97105
* `-d` only useful to debug the script, reports any Python traceback to the standard error stream.
98106

@@ -101,6 +109,12 @@ Fuse RAW images only use the v1 type.
101109
* `-e` specify how many bits are used in the VMEM file to store ECC information. Note that ECC
102110
information is not stored in the QEMU RAW file for now.
103111

112+
* `-i` specify the initialization vector for the Present scrambler used for partition digests.
113+
This value is "usually" found within the `hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv` OT file,
114+
from the last entry of `RndCnstDigestIV` array, _i.e._ item 0. It is used along with option
115+
`-D` to verify partition digests, and stored in the optional output OTP image file for use by
116+
the virtual OTP controller when used along with the `-o` option. Override option `-C` if any.
117+
104118
* `-j` specify the path to the HJSON OTP controller map file, usually stored in OT
105119
`hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson`. This file is required with many options when the OTP
106120
image file needs to be interpreted, such as digest verification, content dump, C file generation,
@@ -117,12 +131,6 @@ Fuse RAW images only use the v1 type.
117131
states. This option is not required to generate a RAW image file, but required when the `-L`
118132
option switch is used.
119133

120-
* `-i` specify the initialization vector for the Present scrambler used for partition digests.
121-
This value is "usually" found within the `hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv` OT file,
122-
from the last entry of `RndCnstDigestIV` array, _i.e._ item 0. It is used along with option
123-
`-D` to verify partition digests, and stored in the optional output OTP image file for use by
124-
the virtual OTP controller when used along with the `-o` option.
125-
126134
* `-m` specify the input VMEM file that contains the OTP fuse content. See also the `-k` option.
127135

128136
* `-n` tell the script not to attempt to decode the content of encoded fields, such as the hardened
@@ -170,8 +178,8 @@ Fuse RAW images only use the v1 type.
170178

171179
#### Note
172180

173-
Earlgrey OTP virtual device has not been updated to support Present scrambler, so neither `-C` nor
174-
`-I` option should be used to generate an Earlgrey-compatible RAW image.
181+
Earlgrey OTP virtual device has not been updated to support Present scrambler, so neither `-c` nor
182+
`-i` option should be used to generate an Earlgrey-compatible RAW image.
175183

176184
### Bit position specifier [#bit-syntax]
177185

@@ -206,6 +214,12 @@ scripts/opentitan/otptool.py -m img_rma.24.vmem -r otp.raw \
206214
-i 0x0123456789abcdef -c 0x00112233445566778899aabbccddeeff
207215
````
208216

217+
Generate a QEMU RAW v2 image for the virtual OTP controller, here with an RMA OTP configuration,
218+
load Present constants from a QEMU configuration file.
219+
````sh
220+
scripts/opentitan/otptool.py -m img_rma.24.vmem -r otp.raw -i ot.cfg
221+
````
222+
209223
Decode the content of an OTP VMEM file:
210224
````sh
211225
scripts/opentitan/otptool.py -m img_rma.24.vmem -j otp_ctrl_mmap.hjson -s

scripts/opentitan/ot/otp/image.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
from binascii import unhexlify
10+
from configparser import ConfigParser, NoOptionError
1011
from io import BytesIO
1112
from logging import getLogger
1213
from re import match as re_match, sub as re_sub
@@ -52,6 +53,9 @@ class OtpImage:
5253
0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x35)
5354
)
5455

56+
DEFAULT_OTP_DEVICE = 'ot-otp-dj'
57+
"""Default OTP device name in configuration file."""
58+
5559
def __init__(self, ecc_bits: Optional[int] = None):
5660
self._log = getLogger('otp.img')
5761
self._header: dict[str, Any] = {}
@@ -202,6 +206,50 @@ def load_lifecycle(self, lcext: OtpLifecycleExtension) -> None:
202206
if part.name == 'LIFE_CYCLE':
203207
part.set_decoder(lcext)
204208

209+
def load_config(self, cfp: TextIO, section: Optional[str] = None) -> None:
210+
"""Load Present constant from a QEMU configuration file.
211+
212+
:param cfp: the configuration stream
213+
:param section: the section name where to find the constants,
214+
default to DEFAULT_OTP_DEVICE.
215+
"""
216+
cfg = ConfigParser()
217+
cfg.read_file(cfp)
218+
if not section:
219+
section = self.DEFAULT_OTP_DEVICE
220+
sectnames = set()
221+
for sectname in cfg.sections():
222+
if not sectname.startswith('ot_device '):
223+
continue
224+
try:
225+
devname = sectname.strip().split('"')[1]
226+
except IndexError:
227+
continue
228+
if devname != section and not devname.startswith(f'{section}.'):
229+
continue
230+
sectnames.add(sectname)
231+
self._log.info('Found OTP candidate section %s', devname)
232+
if not sectnames:
233+
raise ValueError(f"Cannot find OTP device section '{section}'")
234+
# accept multiple sections with Present constants definitions as long
235+
# as they do match
236+
constants = set()
237+
ivs = set()
238+
for sectname in sectnames:
239+
try:
240+
constants.add(cfg.get(sectname, 'digest_const')
241+
.strip('"').lower())
242+
ivs.add(cfg.get(sectname, 'digest_iv')
243+
.strip('"').lower())
244+
except NoOptionError:
245+
pass
246+
if not constants or not ivs:
247+
raise ValueError('Incomplete configuration file')
248+
if len(constants) > 1 or len(ivs) > 1:
249+
raise ValueError(f"Too many OTP device sections '{section}'")
250+
self._digest_constant = HexInt.parse(constants.pop(), 16)
251+
self._digest_iv = HexInt.parse(ivs.pop(), 16)
252+
205253
# pylint: disable=invalid-name
206254
def set_digest_iv(self, iv: int) -> None:
207255
"""Set the Present digest initialization 64-bit vector."""

scripts/opentitan/ot/util/misc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ def __repr__(self) -> str:
3232
return f'0x{self:x}'
3333

3434
@staticmethod
35-
def parse(val: Optional[str]) -> Optional[int]:
35+
def parse(val: Optional[str], base: Optional[int] = None) -> Optional[int]:
3636
"""Simple helper to support hexadecimal integer in argument parser."""
3737
if val is None:
3838
return None
39-
return int(val, val.startswith('0x') and 16 or 10)
39+
if base is not None:
40+
return HexInt(int(val, base))
41+
return HexInt(int(val, val.startswith('0x') and 16 or 10))
4042

4143

4244
class EasyDict(dict):

scripts/opentitan/otptool.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def main():
5353
params.add_argument('-e', '--ecc', type=int,
5454
default=OtpImage.DEFAULT_ECC_BITS,
5555
metavar='BITS', help='ECC bit count')
56+
params.add_argument('-C', '--config', type=FileType('rt'),
57+
help='read Present constants from QEMU config file')
5658
params.add_argument('-c', '--constant', type=HexInt.parse,
5759
metavar='INT',
5860
help='finalization constant for Present scrambler')
@@ -196,6 +198,8 @@ def main():
196198
if args.empty:
197199
for part in args.empty:
198200
otp.empty_partition(part)
201+
if args.config:
202+
otp.load_config(args.config)
199203
if args.iv:
200204
otp.set_digest_iv(args.iv)
201205
if args.constant:

0 commit comments

Comments
 (0)