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 
10 static 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 
22 void 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 
44 static const uint32_t kCheckShares[kHmacDigestNumWords + 1] = {
45  0x7b00d08e, 0xfdb69374, 0x336c86df, 0xff2ef417, 0xe1517012,
46  0x4bf5408c, 0x9c6a7b25, 0xf771f8fa, 0xcd468505,
47 };
48 
49 rom_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 
74 void 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 }