Skip to content

Commit

Permalink
[sw,silicon_creator,rom] Add a ROM state API
Browse files Browse the repository at this point in the history
The ROM state API allows for defining a set of ROM states and their
associated hooks and callback. Each state is defined by its run
callback, and two hooks: the pre-run hook is executed prior to the run
callback while the post-run one runs after.
The rom_state_fsm() function walks through the ROM states, as each state
run callback returns the next ROM state to transition to.

ROM state hooks can be overridden by silicon creator implementations,
through an external, potentially closed source, code repository.

Signed-off-by: Samuel Ortiz <[email protected]>
  • Loading branch information
sameo committed Dec 14, 2024
1 parent bfc10ee commit 60d4859
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 0 deletions.
14 changes: 14 additions & 0 deletions sw/device/silicon_creator/rom/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,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 = [
Expand Down
51 changes: 51 additions & 0 deletions sw/device/silicon_creator/rom/rom_state.c
Original file line number Diff line number Diff line change
@@ -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, &current_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));
}
}
178 changes: 178 additions & 0 deletions sw/device/silicon_creator/rom/rom_state.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <stdnoreturn.h>

#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_

0 comments on commit 60d4859

Please sign in to comment.