blob: a1743a81aba4bcf427276fefdf68e065a1930b8f [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef BOOTSTATE_H
#define BOOTSTATE_H
#include <assert.h>
#include <string.h>
#include <stddef.h>
/* Only declare main() when in ramstage. */
#if ENV_RAMSTAGE
#include <main_decl.h>
#endif
/*
* The boot state machine provides a mechanism for calls to be made through-
* out the main boot process. The boot process is separated into discrete
* states. Upon a state's entry and exit and callbacks can be made. For
* example:
*
* Enter State
* +
* |
* V
* +-----------------+
* | Entry callbacks |
* +-----------------+
* | State Actions |
* +-----------------+
* | Exit callbacks |
* +-------+---------+
* |
* V
* Next State
*
* Below is the current flow from top to bottom:
*
* start
* |
* BS_PRE_DEVICE
* |
* BS_DEV_INIT_CHIPS
* |
* BS_DEV_ENUMERATE
* |
* BS_DEV_RESOURCES
* |
* BS_DEV_ENABLE
* |
* BS_DEV_INIT
* |
* BS_POST_DEVICE
* |
* BS_OS_RESUME_CHECK -------- BS_OS_RESUME
* | |
* BS_WRITE_TABLES os handoff
* |
* BS_PAYLOAD_LOAD
* |
* BS_PAYLOAD_BOOT
* |
* payload run
*
* Brief description of states:
* BS_PRE_DEVICE - before any device tree actions take place
* BS_DEV_INIT_CHIPS - init all chips in device tree
* BS_DEV_ENUMERATE - device tree probing
* BS_DEV_RESOURCES - device tree resource allocation and assignment
* BS_DEV_ENABLE - device tree enabling/disabling of devices
* BS_DEV_INIT - device tree device initialization
* BS_POST_DEVICE - all device tree actions performed
* BS_OS_RESUME_CHECK - check for OS resume
* BS_OS_RESUME - resume to OS
* BS_WRITE_TABLES - write coreboot tables
* BS_PAYLOAD_LOAD - Load payload into memory
* BS_PAYLOAD_BOOT - Boot to payload
*/
typedef enum {
BS_PRE_DEVICE,
BS_DEV_INIT_CHIPS,
BS_DEV_ENUMERATE,
BS_DEV_RESOURCES,
BS_DEV_ENABLE,
BS_DEV_INIT,
BS_POST_DEVICE,
BS_OS_RESUME_CHECK,
BS_OS_RESUME,
BS_WRITE_TABLES,
BS_PAYLOAD_LOAD,
BS_PAYLOAD_BOOT,
} boot_state_t;
/* The boot_state_sequence_t describes when a callback is to be made. It is
* called either before a state is entered or when a state is exited. */
typedef enum {
BS_ON_ENTRY,
BS_ON_EXIT
} boot_state_sequence_t;
struct boot_state_callback {
void *arg;
void (*callback)(void *arg);
/* For use internal to the boot state machine. */
struct boot_state_callback *next;
#if CONFIG(DEBUG_BOOT_STATE)
const char *location;
#endif
};
static inline const char *bscb_location(const struct boot_state_callback *bscb)
{
#if CONFIG(DEBUG_BOOT_STATE)
return bscb->location;
#else
return dead_code_t(const char *);
#endif
}
#if CONFIG(DEBUG_BOOT_STATE)
#define BOOT_STATE_CALLBACK_LOC __FILE__ ":" STRINGIFY(__LINE__)
#define BOOT_STATE_CALLBACK_INIT_DEBUG .location = BOOT_STATE_CALLBACK_LOC,
#define INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_) \
do { \
bscb_->location = BOOT_STATE_CALLBACK_LOC; \
} while (0)
#else
#define BOOT_STATE_CALLBACK_INIT_DEBUG
#define INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_)
#endif
#define BOOT_STATE_CALLBACK_INIT(func_, arg_) \
{ \
.arg = arg_, \
.callback = func_, \
.next = NULL, \
BOOT_STATE_CALLBACK_INIT_DEBUG \
}
#define BOOT_STATE_CALLBACK(name_, func_, arg_) \
struct boot_state_callback name_ = BOOT_STATE_CALLBACK_INIT(func_, arg_)
/* Initialize an allocated boot_state_callback. */
#define INIT_BOOT_STATE_CALLBACK(bscb_, func_, arg_) \
do { \
INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_) \
bscb_->callback = func_; \
bscb_->arg = arg_ \
} while (0)
/* The following 2 functions schedule a callback to be called on entry/exit
* to a given state. Note that there are no ordering guarantees between the
* individual callbacks on a given state. 0 is returned on success < 0 on
* error. */
int boot_state_sched_on_entry(struct boot_state_callback *bscb,
boot_state_t state);
int boot_state_sched_on_exit(struct boot_state_callback *bscb,
boot_state_t state);
/* Schedule an array of entries of size num. */
struct boot_state_init_entry;
void boot_state_sched_entries(struct boot_state_init_entry *entries,
size_t num);
/* Block/Unblock the (state, seq) pair from transitioning. Returns 0 on
* success < 0 when the phase of the (state,seq) has already ran. */
int boot_state_block(boot_state_t state, boot_state_sequence_t seq);
int boot_state_unblock(boot_state_t state, boot_state_sequence_t seq);
/* In order to schedule boot state callbacks at compile-time specify the
* entries in an array using the BOOT_STATE_INIT_ENTRIES and
* BOOT_STATE_INIT_ENTRY macros below. */
struct boot_state_init_entry {
boot_state_t state;
boot_state_sequence_t when;
struct boot_state_callback bscb;
};
#if ENV_RAMSTAGE
#define BOOT_STATE_INIT_ATTR __attribute__((used, section(".bs_init")))
#else
#define BOOT_STATE_INIT_ATTR __attribute__((unused))
#endif
#define BOOT_STATE_INIT_ENTRY(state_, when_, func_, arg_) \
static struct boot_state_init_entry func_ ##_## state_ ##_## when_ = \
{ \
.state = state_, \
.when = when_, \
.bscb = BOOT_STATE_CALLBACK_INIT(func_, arg_), \
}; \
static struct boot_state_init_entry * \
bsie_ ## func_ ##_## state_ ##_## when_ BOOT_STATE_INIT_ATTR = \
&func_ ##_## state_ ##_## when_; \
_Static_assert(!(state_ == BS_PAYLOAD_BOOT && when_ == BS_ON_EXIT), \
"Invalid bootstate hook"); \
_Static_assert(!(state_ == BS_OS_RESUME && when_ == BS_ON_EXIT), \
"Invalid bootstate hook");
/* Hook per arch when coreboot is exiting to payload or ACPI OS resume. It's
* the very last thing done before the transition. */
void arch_bootstate_coreboot_exit(void);
#endif /* BOOTSTATE_H */