Software APIs
bootstrap_fuzzer_util.cc
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/bootstrap_fuzzer_util.h"
6 
7 #include <iostream>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <type_traits>
11 #include <utility>
12 
13 #include "absl/types/optional.h"
14 #include "absl/types/span.h"
15 #include "gmock/gmock.h"
18 #include "sw/device/silicon_creator/lib/bootstrap_unittest_util.h"
19 #include "sw/device/silicon_creator/lib/drivers/mock_flash_ctrl.h"
20 #include "sw/device/silicon_creator/lib/drivers/mock_otp.h"
21 #include "sw/device/silicon_creator/lib/drivers/mock_rstmgr.h"
22 #include "sw/device/silicon_creator/lib/drivers/mock_spi_device.h"
23 
24 #include "flash_ctrl_regs.h"
26 #include "otp_ctrl_regs.h"
27 
28 namespace bootstrap_fuzzer {
29 
30 namespace {
31 void Crash() { __builtin_trap(); }
32 } // namespace
33 
34 StaticFuzzerEnvironment::StaticFuzzerEnvironment() {
35  testing::InitGoogleMock();
36 }
37 
38 AbstractBootstrapMockGroup::AbstractBootstrapMockGroup(StreamParser stream,
39  bool verbose)
40  : verbose_(verbose), stream_(std::move(stream)) {}
41 
43  using ::testing::_;
44  using ::testing::Return;
45 
46  ON_CALL(flash_ctrl_, DataErase(_, _)).WillByDefault(Return(kErrorOk));
47  ON_CALL(flash_ctrl_, DataWrite(_, _, _)).WillByDefault(Return(kErrorOk));
48  ON_CALL(flash_ctrl_, DataEraseVerify(_, _)).WillByDefault(Return(kErrorOk));
49 
50  ON_CALL(rstmgr_, ReasonGet()).WillByDefault([&] {
51  return stream_.ParseIntOr<uint32_t>(
52  "reset_reason",
53  1 << kRstmgrReasonPowerOn | 1 << kRstmgrReasonSoftwareRequest);
54  });
55 
56  // It's possible that the bootstrap code will get stuck in a loop asking for
57  // new SPI commands. The bootstrap loop will ignore RESET commands unless it
58  // has first seen an erase command. It will also ignore RESET commands unless
59  // the flash status's WEL bit is enabled.
60 
61  max_spi_cmd_count_ =
62  (stream_.ParseIntOr<size_t>("max_spi_cmd_count_", 1024) % 1024) + 16;
63  if (verbose_) {
64  std::cout << "Clamped max_spi_cmd_count_: " << max_spi_cmd_count_
65  << std::endl;
66  }
67 
68  ON_CALL(spi_device_, FlashStatusGet()).WillByDefault([&] {
69  return flash_status_override_
70  ? uint32_t{1 << kSpiDeviceWelBit}
71  : stream_.ParseIntOr<uint32_t>("flash_status", 0);
72  });
73 
74  ON_CALL(spi_device_, CmdGet(testing::NotNull()))
75  .WillByDefault([&](spi_device_cmd_t *cmd) -> rom_error_t {
76  spi_cmd_count_++;
77 
78  if (spi_cmd_count_ < max_spi_cmd_count_) {
79  *cmd = stream_.ParseCmdOr(bootstrap_unittest_util::ChipEraseCmd());
80  return kErrorOk;
81  }
82  if (spi_cmd_count_ == max_spi_cmd_count_) {
83  *cmd = bootstrap_unittest_util::ChipEraseCmd();
84  flash_status_override_ = true;
85  if (verbose_) {
86  std::cout << "Attempting to end session: CHIP_ERASE" << std::endl;
87  }
88  return kErrorOk;
89  }
90  if (spi_cmd_count_ == max_spi_cmd_count_ + 1) {
91  *cmd = bootstrap_unittest_util::ResetCmd();
92  if (verbose_) {
93  std::cout << "Attempting to end session: RESET" << std::endl;
94  }
95  return kErrorOk;
96  }
97 
98  // We've already synthesized CHIP_ERASE and RESET commands, so the
99  // bootstrap code should not have requested another SPI command.
100  Crash();
101  return kErrorUnknown;
102  });
103 }
104 
105 } // namespace bootstrap_fuzzer