diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod index 35064f8a3d173..a210b30be9a19 100644 --- a/WORKSPACE.bzlmod +++ b/WORKSPACE.bzlmod @@ -112,7 +112,7 @@ open_dice_repos() # Setup for linking in externally managed test and provisioning customizations # for both secure/non-secure manufacturer domains. -load("//rules:hooks_setup.bzl", "hooks_setup", "provisioning_exts_setup", "secure_hooks_setup") +load("//rules:hooks_setup.bzl", "hooks_setup", "provisioning_exts_setup", "secure_hooks_setup", "rom_hooks_setup") hooks_setup( name = "hooks_setup", dummy = "sw/device/tests/closed_source", @@ -125,16 +125,23 @@ provisioning_exts_setup( name = "provisioning_exts_setup", dummy = "sw/device/silicon_creator/manuf/extensions", ) +rom_hooks_setup( + name = "rom_hooks_setup", + dummy = "sw/device/silicon_creator/rom/hooks", +) # Declare the external repositories: # - One for both manufacturer secure and non-secure domains. # - One for provisioning source code extensions. +# - One for ROM vendor hooks. load("@hooks_setup//:repos.bzl", "hooks_repo") load("@secure_hooks_setup//:repos.bzl", "secure_hooks_repo") load("@provisioning_exts_setup//:repos.bzl", "provisioning_exts_repo") +load("@rom_hooks_setup//:repos.bzl", "rom_hooks_repo") hooks_repo(name = "manufacturer_test_hooks") secure_hooks_repo(name = "secure_manufacturer_test_hooks") provisioning_exts_repo(name = "provisioning_exts") +rom_hooks_repo(name = "rom_hooks") # The nonhermetic_repo imports environment variables needed to run vivado. load("//rules:nonhermetic.bzl", "nonhermetic_repo") diff --git a/rules/hooks_setup.bzl b/rules/hooks_setup.bzl index 03be439529368..22b7bcfcd6785 100644 --- a/rules/hooks_setup.bzl +++ b/rules/hooks_setup.bzl @@ -26,6 +26,14 @@ def provisioning_exts_repo(name): ) """ +_ROM_HOOKS_TEMPLATE = """ +def rom_hooks_repo(name): + native.local_repository( + name = name, + path = "{hooks_dir}", +) +""" + _BUILD = """ exports_files(glob(["**"])) """ @@ -77,3 +85,19 @@ provisioning_exts_setup = repository_rule( }, environ = ["PROV_EXTS_DIR"], ) + +def _rom_hooks_setup_impl(rctx): + rom_hooks_dir = rctx.os.environ.get("ROM_HOOKS_DIR", rctx.attr.dummy) + rctx.file("repos.bzl", _ROM_HOOKS_TEMPLATE.format(hooks_dir = rom_hooks_dir)) + rctx.file("BUILD.bazel", _BUILD) + +rom_hooks_setup = repository_rule( + implementation = _rom_hooks_setup_impl, + attrs = { + "dummy": attr.string( + mandatory = True, + doc = "Location of the dummy ROM extensions directory.", + ), + }, + environ = ["ROM_HOOKS_DIR"], +) diff --git a/sw/device/silicon_creator/rom/BUILD b/sw/device/silicon_creator/rom/BUILD index 0cef04a501261..67b7b103f2319 100644 --- a/sw/device/silicon_creator/rom/BUILD +++ b/sw/device/silicon_creator/rom/BUILD @@ -90,6 +90,7 @@ cc_library( "//sw/device/lib/base:csr", "//sw/device/lib/base:macros", "//sw/device/silicon_creator/lib:error", + "//sw/device/silicon_creator/lib:shutdown", ], ) @@ -135,6 +136,7 @@ cc_library( ":boot_policy_ptrs", ":bootstrap", ":rom_epmp", + ":rom_state", ":sigverify_keys_ecdsa_p256", ":sigverify_keys_spx", ":sigverify_otp_keys", @@ -177,6 +179,7 @@ cc_library( "//sw/device/silicon_creator/lib/drivers:uart", "//sw/device/silicon_creator/lib/drivers:watchdog", "//sw/device/silicon_creator/lib/sigverify", + "@rom_hooks", ], ) @@ -255,6 +258,20 @@ cc_library( ], ) +cc_library( + name = "rom_state", + srcs = ["rom_state.c"], + hdrs = ["rom_state.h"], + target_compatible_with = [OPENTITAN_CPU], + deps = [ + "//sw/device/lib/base:hardened", + "//sw/device/lib/base:macros", + "//sw/device/silicon_creator/lib:error", + "//sw/device/silicon_creator/lib:shutdown", + ], + alwayslink = True, +) + opentitan_test( name = "rom_epmp_test", srcs = [ diff --git a/sw/device/silicon_creator/rom/hooks/BUILD.bazel b/sw/device/silicon_creator/rom/hooks/BUILD.bazel new file mode 100644 index 0000000000000..f2a2575fab652 --- /dev/null +++ b/sw/device/silicon_creator/rom/hooks/BUILD.bazel @@ -0,0 +1,12 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "rom_hooks", + srcs = ["dummy_rom_hooks.c"], + deps = ["@//sw/device/silicon_creator/rom:rom_state"], + alwayslink = True, +) diff --git a/sw/device/silicon_creator/rom/hooks/README.md b/sw/device/silicon_creator/rom/hooks/README.md new file mode 100644 index 0000000000000..c9ce3022079de --- /dev/null +++ b/sw/device/silicon_creator/rom/hooks/README.md @@ -0,0 +1,85 @@ +#Silicon Creator ROM Hooks + +## Overview + +The OpenTitan ROM defines pre-run and post-run hooks for any defined ROM state. + +When transitioning to a ROM state, the ROM state machine first executes the pre-run hook. + +The state's run callback is called only if the pre-run hook does not return an error. +Finally, the post-run hook runs upon successful termination of the ROM state's run callback: + +``` +│ │ +│ ┌──────────────┐ │ +│ │Post-run Hook │ │ +│ └───────┬──────┘ │ +└───────────┼──────────┘ + │ + │ +┌───────────┼──────────┐ +│ ROM │ │ +│ State │ │ +│ ┌───────▼──────┐ │ +│ │ Pre-run Hook │ │ +│ └───────┬──────┘ │ +│ │ │ +│ │ │ +│ ┌───────▽──────┐ │ +│ │ Run Callback │ │ +│ └───────┬──────┘ │ +│ │ │ +│ │ │ +│ ┌───────▽──────┐ │ +│ │Post-run Hook │ │ +│ └───────┬──────┘ │ +└───────────┼──────────┘ + │ + │ +┌───────────┼──────────┐ +│ ┌───────▼──────┐ │ +│ │ Pre-run Hook │ │ +│ └──────────────┘ │ +│ │ + +``` + +The transition from one ROM state to the next one is defined by the current ROM state's run callback: + +``` c +rom_error_t rom_state_run_cb(void *arg, rom_state_t *next_state); +``` + +By default, the pre-run and post-run hooks do nothing. However, they provide a mechanism for silicon creators to override them with external implementations (e.g. with closed-source, vendor-specific initialization sequences). + +Each ROM state pre-run and post-run hooks are defined as weak symbols using a pre-defined naming scheme. + +For example the hooks prototypes for a ROM state named `kRomStateInit` would be: + +``` c +OT_WARN_UNUSED_RESULT rom_error_t rom_state_pre_kRomStateInit(void *arg); +OT_WARN_UNUSED_RESULT rom_error_t rom_state_post_kRomStateInit(void *arg); +``` + +## ROM State Hooks Implementation + +Downstream silicon creators can override the default pre-run and post-run hooks from an external, possibly closed-source repository. + +A downstream ROM hooks repository should follow the layout defined in this example. + +In particular, the repository must include: + +- A `WORKSPACE.bazel` file that defines a `rom_hooks` workspace. +- A `BUILD.bazel` file that defines a `rom_hooks` `cc_library` target. +- A C file implementing the desired ROM state hooks overrides. + Hooks implementations must follow the prototype defined in `rom_state.h`. + Binding a hook to a ROM state pre-run or post-run step is done through respectively the `ROM_STATE_PRE_HOOK` and `ROM_STATE_POST_HOOK` macros. + See `dummy_rom_hooks.c` in this folder for a simple example. + +In order to link an OpenTitan ROM image with externally defined hooks override, `bazel` must be invoked with the `ROM_HOOKS_DIR` environment variable set to the local path of the hooks override repository. + +For example: + +``` bash +ROM_HOOKS_DIR= ./bazelisk.sh test --test_output=streamed --cache_test_results=no //sw/device/silicon_creator/rom/e2e:rom_e2e_smoke_sim_verilator +``` diff --git a/sw/device/silicon_creator/rom/hooks/WORKSPACE.bazel b/sw/device/silicon_creator/rom/hooks/WORKSPACE.bazel new file mode 100644 index 0000000000000..9ccc96fc52fb5 --- /dev/null +++ b/sw/device/silicon_creator/rom/hooks/WORKSPACE.bazel @@ -0,0 +1,13 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +workspace(name = "rom_hooks") + +# This is a sample workspace to demonstrate how to write custom ROM hooks. +# This bazel repository is not stand-alone project: it must be connected into +# the main OpenTitan repository by way of the `rom_hooks_setup` call in +# OpenTitan's WORKSPACE file. + +# See this repository's README.md and BUILD.bazel files to understand how to +# write rules for custom ROM hooks. diff --git a/sw/device/silicon_creator/rom/hooks/dummy_rom_hooks.c b/sw/device/silicon_creator/rom/hooks/dummy_rom_hooks.c new file mode 100644 index 0000000000000..be271f05a7fee --- /dev/null +++ b/sw/device/silicon_creator/rom/hooks/dummy_rom_hooks.c @@ -0,0 +1,15 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/silicon_creator/rom/rom_state.h" + +/** + * A dummy pre-run hook for the `kRomStateInit` ROM state. + * + * This is an example on how Silicon Creators should define a ROM state hook. + */ +OT_WARN_UNUSED_RESULT rom_error_t dummy_rom_init_pre_hook(void *arg) { + return kErrorOk; +} +ROM_STATE_PRE_HOOK(kRomStateInit, dummy_rom_init_pre_hook); diff --git a/sw/device/silicon_creator/rom/rom.c b/sw/device/silicon_creator/rom/rom.c index 38bd13b1f4a9c..f5d0c9ddf62c7 100644 --- a/sw/device/silicon_creator/rom/rom.c +++ b/sw/device/silicon_creator/rom/rom.c @@ -47,6 +47,7 @@ #include "sw/device/silicon_creator/rom/boot_policy_ptrs.h" #include "sw/device/silicon_creator/rom/bootstrap.h" #include "sw/device/silicon_creator/rom/rom_epmp.h" +#include "sw/device/silicon_creator/rom/rom_state.h" #include "sw/device/silicon_creator/rom/sigverify_keys_ecdsa_p256.h" #include "sw/device/silicon_creator/rom/sigverify_keys_spx.h" #include "sw/device/silicon_creator/rom/sigverify_otp_keys.h" @@ -757,26 +758,95 @@ static rom_error_t rom_try_boot(void) { return kErrorRomBootFailed; } -void rom_main(void) { +/* + * The bootstrap request is the kRomStateBootstrapCheck and kRomStateBootstrap + * ROM states argument. It must be undefined before entering the + * kRomStateBootstrapCheck state as only the kRomStateBootstrapCheck run + * callback or hooks should set it to either kHardenedBoolFalse or + * kHardenedBoolTrue. + */ +static hardened_bool_t bootstrap_request = 0; + +enum { + kRomStateCnt_ = 4, +}; +static const size_t kRomStateCnt = kRomStateCnt_; + +/** + * Table of ROM states. + * + * Encoding generated with: + * $ ./util/design/sparse-fsm-encode.py -d 6 -m 4 -n 32 \ + * -s 519644925 --language=c + */ +// clang-format off +#define ROM_STATES(X) \ + X(kRomStateInit, 0x5616ae08, rom_state_init, NULL) \ + X(kRomStateBootstrapCheck, 0x0a9243ab, rom_state_bootstrap_check, &bootstrap_request) \ + X(kRomStateBootstrap, 0xd0a0ff08, rom_state_bootstrap, &bootstrap_request) \ + X(kRomStateBootRomExt, 0xed14f55f, rom_state_boot_rom_ext, NULL) +// clang-format on + +ROM_STATE_INIT_TABLE(rom_states, kRomStateCnt_, ROM_STATES); + +static OT_WARN_UNUSED_RESULT rom_error_t rom_state_init(void *arg, + uint32_t *next_state) { CFI_FUNC_COUNTER_INIT(rom_counters, kCfiRomMain); CFI_FUNC_COUNTER_PREPCALL(rom_counters, kCfiRomMain, 1, kCfiRomInit); - SHUTDOWN_IF_ERROR(rom_init()); + HARDENED_RETURN_IF_ERROR(rom_init()); CFI_FUNC_COUNTER_INCREMENT(rom_counters, kCfiRomMain, 3); - CFI_FUNC_COUNTER_CHECK(rom_counters, kCfiRomInit, 3); - if (launder32(waking_from_low_power) != kHardenedBoolTrue) { - HARDENED_CHECK_EQ(waking_from_low_power, kHardenedBoolFalse); - hardened_bool_t bootstrap_req = bootstrap_requested(); - if (launder32(bootstrap_req) == kHardenedBoolTrue) { - HARDENED_CHECK_EQ(bootstrap_req, kHardenedBoolTrue); - rom_bootstrap_message(); - watchdog_disable(); - shutdown_finalize(bootstrap()); - } + *next_state = kRomStateBootstrapCheck; + + return kErrorOk; +} + +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_bootstrap_check(void *arg, uint32_t *next_state) { + if (launder32(waking_from_low_power) == kHardenedBoolTrue) { + HARDENED_CHECK_EQ(waking_from_low_power, kHardenedBoolTrue); + *next_state = kRomStateBootRomExt; + + return kErrorOk; + } + + HARDENED_CHECK_EQ(waking_from_low_power, kHardenedBoolFalse); + + hardened_bool_t *bootstrap_req = (hardened_bool_t *)arg; + + // The pre_ hook may have set the bootstrap request flag. + if (launder32(*bootstrap_req) != kHardenedBoolTrue) { + *bootstrap_req = bootstrap_requested(); + } + + *next_state = kRomStateBootRomExt; + return kErrorOk; +} + +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_bootstrap(void *arg, uint32_t *next_state) { + hardened_bool_t *bootstrap_req = (hardened_bool_t *)arg; + + if (launder32(*bootstrap_req) == kHardenedBoolTrue) { + HARDENED_CHECK_EQ(bootstrap_req, kHardenedBoolTrue); + rom_bootstrap_message(); + watchdog_disable(); + // `bootstrap` will not return unless there is an error. + HARDENED_RETURN_IF_ERROR(bootstrap()); } + return kErrorRomBootFailed; +} + +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_boot_rom_ext(void *arg, uint32_t *next_state) { // `rom_try_boot` will not return unless there is an error. CFI_FUNC_COUNTER_PREPCALL(rom_counters, kCfiRomMain, 4, kCfiRomTryBoot); - shutdown_finalize(rom_try_boot()); + return rom_try_boot(); +} + +void rom_main(void) { + CFI_FUNC_COUNTER_INIT(rom_counters, kCfiRomMain); + shutdown_finalize(rom_state_fsm(rom_states, kRomStateCnt, kRomStateInit)); } diff --git a/sw/device/silicon_creator/rom/rom.h b/sw/device/silicon_creator/rom/rom.h index 6dd8e6bbaf2e2..64723c71ec1b9 100644 --- a/sw/device/silicon_creator/rom/rom.h +++ b/sw/device/silicon_creator/rom/rom.h @@ -7,10 +7,24 @@ #include +#include "sw/device/silicon_creator/lib/error.h" + #ifdef __cplusplus extern "C" { #endif // __cplusplus +/** + * ROM states run callbacks. + */ +static OT_WARN_UNUSED_RESULT rom_error_t rom_state_init(void *arg, + uint32_t *next_state); +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_bootstrap_check(void *arg, uint32_t *next_state); +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_bootstrap(void *arg, uint32_t *next_state); +static OT_WARN_UNUSED_RESULT rom_error_t +rom_state_boot_rom_ext(void *arg, uint32_t *next_state); + /** * The first C function executed by the ROM (defined in `rom.c`) */ diff --git a/sw/device/silicon_creator/rom/rom_state.c b/sw/device/silicon_creator/rom/rom_state.c new file mode 100644 index 0000000000000..27944370565dc --- /dev/null +++ b/sw/device/silicon_creator/rom/rom_state.c @@ -0,0 +1,51 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/silicon_creator/rom/rom_state.h" + +#include "sw/device/silicon_creator/lib/shutdown.h" + +static OT_WARN_UNUSED_RESULT rom_error_t rom_state_get_state_cb( + const rom_state_cb_t state_callbacks[], const size_t state_callbacks_cnt, + const rom_state_t state, const rom_state_cb_t **state_cb) { + // TODO Start from a random index + for (size_t idx = 0; idx < state_callbacks_cnt; idx++) { + if (launder32(state_callbacks[idx].state) != state) { + continue; + } + + HARDENED_CHECK_EQ(state_callbacks[idx].state, state); + + *state_cb = &state_callbacks[idx]; + return kErrorOk; + } + + return kErrorRomBootFailed; +} + +OT_WARN_UNUSED_RESULT rom_error_t +rom_state_fsm(const rom_state_cb_t state_callbacks[], + const size_t state_callbacks_cnt, const rom_state_t init_state) { + rom_state_t next_state = init_state; + + while (true) { + rom_state_t current_state = next_state; + const rom_state_cb_t *current_state_cb = NULL; + + HARDENED_RETURN_IF_ERROR( + rom_state_get_state_cb(state_callbacks, state_callbacks_cnt, + current_state, ¤t_state_cb)); + + // Pre run hook + HARDENED_RETURN_IF_ERROR(current_state_cb->pre_run(current_state_cb->arg)); + + // State run callback. + HARDENED_RETURN_IF_ERROR( + current_state_cb->run(current_state_cb->arg, &next_state)); + HARDENED_CHECK_NE(current_state, next_state); + + // Post run hooks + HARDENED_RETURN_IF_ERROR(current_state_cb->post_run(current_state_cb->arg)); + } +} diff --git a/sw/device/silicon_creator/rom/rom_state.h b/sw/device/silicon_creator/rom/rom_state.h new file mode 100644 index 0000000000000..ecd75604a097e --- /dev/null +++ b/sw/device/silicon_creator/rom/rom_state.h @@ -0,0 +1,178 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_ROM_STATE_H_ +#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_ROM_STATE_H_ + +#include +#include + +#include "sw/device/lib/base/hardened.h" +#include "sw/device/lib/base/macros.h" +#include "sw/device/silicon_creator/lib/error.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * The ROM state API allows for declaring ROM states and their associated + * callbacks. A ROM state callback defines which new state the ROM should + * transition to if the current state executes successfully. The + * `rom_state_fsm()` function walks through the ROM defines states, runs + * the current state callback and transitions to the next state. + * + * Silicon creators can customize a ROM state execution flow through pre-run + * post-run callback hooks. Pre-run hooks are unconditionally called before a + * state callback is executed and can modify the state argument. Post-run hooks + * run only after the state callback successfully completed, and can also modify + * the state associated argument. The ROM transitions to the next state defined + * by the current state callback, if and only if the post-run hook returns + * without errors. + * + * By default, the pre-run and posr-run hooks are weakly defined symbols that do + * nothing. They can be optionally be overriden by silicon creators, through an + * external repository. See the corresponding documentation and example in + * `sw/device/silicon_creator/rom/hooks/` + */ + +/** + * A ROM state. + */ +typedef uint32_t rom_state_t; + +/** + * A ROM state hook. + * ROM state hooks are called prior and after the state run callback. + * They can be overridden by silicon creator implementation, through an external + * repository. + * + * @param arg The ROM state argument. + */ +typedef OT_WARN_UNUSED_RESULT rom_error_t rom_state_hook_cb(void *arg); + +/** + * A ROM state run callback. + * This is the main callback for a ROM state. It can not be overridden by + * silicon creator hooks, unlike ROM state hooks. + * + * @param arg The ROM state callback and hooks argument. This pointer is shared + * between a state run callback and hooks, and will typically point + * to a static structure or variable. + * @param next_state The next state the ROM should transition to. + */ +typedef OT_WARN_UNUSED_RESULT rom_error_t +rom_state_run_cb(void *arg, rom_state_t *next_state); + +/** + * A ROM state callback + */ +typedef struct rom_state_cb { + rom_state_t state; + void *arg; + rom_state_hook_cb *pre_run; + rom_state_hook_cb *post_run; + rom_state_run_cb *run; +} rom_state_cb_t; + +// clang-format off +#define ROM_STATE_PRE_HOOK_WEAK_(state_) \ + OT_WEAK OT_WARN_UNUSED_RESULT \ + rom_error_t rom_state_pre_##state_(void *arg) { \ + return kErrorOk; \ + } + +#define ROM_STATE_POST_HOOK_WEAK_(state_) \ + OT_WEAK OT_WARN_UNUSED_RESULT \ + rom_error_t rom_state_post_##state_(void *arg) { \ + return kErrorOk; \ + } + +#define ROM_STATE_CALLBACKS_(state_, value_, run_, run_arg_) \ + ROM_STATE_PRE_HOOK_WEAK_(state_) \ + ROM_STATE_POST_HOOK_WEAK_(state_) + +#define ROM_STATE_VALUES_(state_, value_, run_, run_arg) state_ = value_, + +#define ROM_STATE_TABLE_ENTRIES_(state_, value_, run_, run_arg_) \ + { \ + .state = state_, \ + .pre_run = rom_state_pre_##state_, \ + .post_run = rom_state_post_##state_, \ + .run = run_, \ + .arg = run_arg_, \ + }, + +/** + * Binds a hook implementation to a ROM state, in order for it to be run + * before the state's run callback. + * + * This macro overrides the default, empty pre-run hook for a given state. + */ +#define ROM_STATE_PRE_HOOK(state_, hook_) \ + OT_WARN_UNUSED_RESULT \ + rom_error_t rom_state_pre_##state_(void *arg) { \ + return hook_(arg); \ + } + +/** + * Binds a hook implementation to a ROM state, in order for it to be run + * after the state's run callback. + * + * This macro overrides the default, empty post-run hook for a given state. + */ +#define ROM_STATE_POST_HOOK(state_, hook_) \ + OT_WARN_UNUSED_RESULT \ + rom_error_t rom_state_post_##state_(void *arg) { \ + return hook_(arg); \ + } + +/** + * The ROM states table. + * + * This macro declares and defines: + * - All ROM state values as an enum. + * - For each ROM state, its callback, its pre-run and post-run, + * weakly-defined and overridable hooks, and its argument. + * - The ROM states array. + * + * @param table_name_ The ROM states array name. This will be defined as a + * static, constant array of `rom_state_cb_t` entries. + * @param table_cnt_ The exact number of entries in the states array. + * @param TABLE_ The ROM state table definition. `TABLE_` is C macro that + * takes another macro as its argument. The macro passed to + * `TABLE_` takes 4 arguments in order to create a ROM state + * tuple: one identifier, one value, one run callback and one + * argument to pass to the callback. The created tuple is used to + * define and declare a ROM state related structure or variable. + */ +#define ROM_STATE_INIT_TABLE(table_name_, table_cnt_, TABLE_) \ + enum { TABLE_(ROM_STATE_VALUES_) }; \ + TABLE_(ROM_STATE_CALLBACKS_) \ + static const rom_state_cb_t table_name_[table_cnt_] = {TABLE_(ROM_STATE_TABLE_ENTRIES_) } +// clang-format on + +/** + * The ROM state machine walker. + * + * ROM implementations call this function with the initial ROM state, and it + * walk through the ROM states defined in @states_callback. + * When transitioning to a ROM state, this function will first call the pre-run + * hook for the state, then the state run callback and finally the post-run + * hook. If any one of these three call returns an error, `rom_state_fsm` + * returns and propagates the error. + * + * @param states_callbacks The array of all ROM states callbacks. + * @param states_callbacks_cnt The number of entries in states_callbacks. + * @param init_state The initial state of the ROM. + */ +OT_WARN_UNUSED_RESULT rom_error_t +rom_state_fsm(const rom_state_cb_t states_callbacks[], + const size_t state_callbacks_cnt, const rom_state_t init_state); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_ROM_STATE_H_