Software APIs
boot_log.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/silicon_creator/lib/boot_log.h"
6
8#include "sw/device/silicon_creator/lib/drivers/hmac.h"
9
10static void boot_log_digest_compute(const boot_log_t *boot_log,
11 hmac_digest_t *digest) {
12 enum {
13 kDigestRegionOffset = sizeof(boot_log->digest),
14 kDigestRegionSize = sizeof(boot_log_t) - kDigestRegionOffset,
15 };
16 static_assert(offsetof(boot_log_t, digest) == 0,
17 "`digest` must be the first field of `boot_log_t`.");
18 hmac_sha256((const char *)boot_log + kDigestRegionOffset, kDigestRegionSize,
19 digest);
20}
21
22void boot_log_digest_update(boot_log_t *boot_log) {
23 boot_log_digest_compute(boot_log, &boot_log->digest);
24}
25
26/*
27 * Shares for producing the `error` value in `boot_log_digest_check()`. First 8
28 * shares are generated using the `sparse-fsm-encode` script while the last
29 * share is `kErrorOk ^ kErrorBootLogInvalid^ kBootLogIdentifier ^
30 * kCheckShares[0] ^ ... ^ kCheckShares[7]` so that xor'ing all shares with the
31 * initial value of `error`, i.e. `kErrorBootLogInvalid`, and
32 * `kBootLogIdentifier` produces `kErrorOk`.
33 *
34 * Encoding generated with:
35 * $ ./util/design/sparse-fsm-encode.py -d 6 -m 8 -n 32 \
36 * -s 273200238 --language=c
37 *
38 * Minimum Hamming distance: 10
39 * Maximum Hamming distance: 21
40 * Minimum Hamming weight: 12
41 * Maximum Hamming weight: 22
42 */
43
44static const uint32_t kCheckShares[kHmacDigestNumWords + 1] = {
45 0x7b00d08e, 0xfdb69374, 0x336c86df, 0xff2ef417, 0xe1517012,
46 0x4bf5408c, 0x9c6a7b25, 0xf771f8fa, 0xcd468505,
47};
48
49rom_error_t boot_log_check(const boot_log_t *boot_log) {
50 static_assert(offsetof(boot_log_t, digest) == 0,
51 "`digest` must be the first field of `boot_log_t`.");
52
53 rom_error_t error = kErrorBootLogInvalid;
54 hmac_digest_t actual_digest;
55 boot_log_digest_compute(boot_log, &actual_digest);
56
57 size_t i = 0;
58 for (; launder32(i) < kHmacDigestNumWords; ++i) {
59 error ^=
60 boot_log->digest.digest[i] ^ actual_digest.digest[i] ^ kCheckShares[i];
61 }
62 HARDENED_CHECK_EQ(i, kHmacDigestNumWords);
63
64 error ^= boot_log->identifier ^ kCheckShares[kHmacDigestNumWords];
65
66 if (launder32(error) == kErrorOk) {
67 HARDENED_CHECK_EQ(error, kErrorOk);
68 return error;
69 }
70
71 return kErrorBootLogInvalid;
72}
73
74void boot_log_check_or_init(boot_log_t *boot_log, uint32_t rom_ext_slot,
75 const chip_info_t *info) {
76 rom_error_t error = boot_log_check(boot_log);
77 if (launder32(error) == kErrorOk) {
78 HARDENED_CHECK_EQ(error, kErrorOk);
79 return;
80 }
81 boot_log->identifier = kBootLogIdentifier;
85 boot_log->rom_ext_slot = rom_ext_slot;
86 boot_log->bl0_slot = 0; // Unknown: no BL0 slot selected yet.
87 for (size_t i = 0; i < ARRAYSIZE(boot_log->reserved); ++i) {
88 boot_log->reserved[i] = 0;
89 }
90 boot_log_digest_update(boot_log);
91 return;
92}