/ src / include / bootstate.h
bootstate.h
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  #ifndef BOOTSTATE_H
  3  #define BOOTSTATE_H
  4  
  5  #include <assert.h>
  6  #include <stddef.h>
  7  /* Only declare main() when in ramstage. */
  8  #if ENV_RAMSTAGE
  9  #include <main_decl.h>
 10  #endif
 11  
 12  /*
 13   * The boot state machine provides a mechanism for calls to be made through-
 14   * out the main boot process. The boot process is separated into discrete
 15   * states. Upon a state's entry and exit and callbacks can be made. For
 16   * example:
 17   *
 18   *      Enter State
 19   *           +
 20   *           |
 21   *           V
 22   *   +-----------------+
 23   *   | Entry callbacks |
 24   *   +-----------------+
 25   *   | State Actions   |
 26   *   +-----------------+
 27   *   | Exit callbacks  |
 28   *   +-------+---------+
 29   *           |
 30   *           V
 31   *       Next State
 32   *
 33   * Below is the current flow from top to bottom:
 34   *
 35   *        start
 36   *          |
 37   *    BS_PRE_DEVICE
 38   *          |
 39   *    BS_DEV_INIT_CHIPS
 40   *          |
 41   *    BS_DEV_ENUMERATE
 42   *          |
 43   *    BS_DEV_RESOURCES
 44   *          |
 45   *    BS_DEV_ENABLE
 46   *          |
 47   *    BS_DEV_INIT
 48   *          |
 49   *    BS_POST_DEVICE
 50   *          |
 51   *    BS_OS_RESUME_CHECK -------- BS_OS_RESUME
 52   *          |                          |
 53   *    BS_WRITE_TABLES              OS handoff
 54   *          |
 55   *    BS_PAYLOAD_LOAD
 56   *          |
 57   *    BS_PAYLOAD_BOOT
 58   *          |
 59   *      payload run
 60   *
 61   * Brief description of states:
 62   *   BS_PRE_DEVICE - before any device tree actions take place
 63   *   BS_DEV_INIT_CHIPS - init all chips in device tree
 64   *   BS_DEV_ENUMERATE - device tree probing
 65   *   BS_DEV_RESOURCES - device tree resource allocation and assignment
 66   *   BS_DEV_ENABLE - device tree enabling/disabling of devices
 67   *   BS_DEV_INIT - device tree device initialization
 68   *   BS_POST_DEVICE - all device tree actions performed
 69   *   BS_OS_RESUME_CHECK - check for OS resume
 70   *   BS_OS_RESUME - resume to OS
 71   *   BS_WRITE_TABLES - write coreboot tables
 72   *   BS_PAYLOAD_LOAD - Load payload into memory
 73   *   BS_PAYLOAD_BOOT - Boot to payload
 74   */
 75  
 76  typedef enum {
 77  	BS_PRE_DEVICE,
 78  	BS_DEV_INIT_CHIPS,
 79  	BS_DEV_ENUMERATE,
 80  	BS_DEV_RESOURCES,
 81  	BS_DEV_ENABLE,
 82  	BS_DEV_INIT,
 83  	BS_POST_DEVICE,
 84  	BS_OS_RESUME_CHECK,
 85  	BS_OS_RESUME,
 86  	BS_WRITE_TABLES,
 87  	BS_PAYLOAD_LOAD,
 88  	BS_PAYLOAD_BOOT,
 89  } boot_state_t;
 90  
 91  /* The boot_state_sequence_t describes when a callback is to be made. It is
 92   * called either before a state is entered or when a state is exited. */
 93  typedef enum {
 94  	BS_ON_ENTRY,
 95  	BS_ON_EXIT
 96  } boot_state_sequence_t;
 97  
 98  struct boot_state_callback {
 99  	void *arg;
100  	void (*callback)(void *arg);
101  	/* For use internal to the boot state machine. */
102  	struct boot_state_callback *next;
103  #if CONFIG(DEBUG_BOOT_STATE)
104  	const char *location;
105  #endif
106  };
107  
108  static inline const char *bscb_location(const struct boot_state_callback *bscb)
109  {
110  #if CONFIG(DEBUG_BOOT_STATE)
111  	return bscb->location;
112  #else
113  	return dead_code_t(const char *);
114  #endif
115  }
116  
117  #if CONFIG(DEBUG_BOOT_STATE)
118  #define BOOT_STATE_CALLBACK_LOC __FILE__ ":" STRINGIFY(__LINE__)
119  #define BOOT_STATE_CALLBACK_INIT_DEBUG .location = BOOT_STATE_CALLBACK_LOC,
120  #define INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_)			\
121  	do {							\
122  		bscb_->location = BOOT_STATE_CALLBACK_LOC;	\
123  	} while (0)
124  #else
125  #define BOOT_STATE_CALLBACK_INIT_DEBUG
126  #define INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_)
127  #endif
128  
129  #define BOOT_STATE_CALLBACK_INIT(func_, arg_)		\
130  	{						\
131  		.arg = arg_,				\
132  		.callback = func_,			\
133  		.next = NULL,				\
134  		BOOT_STATE_CALLBACK_INIT_DEBUG		\
135  	}
136  
137  #define BOOT_STATE_CALLBACK(name_, func_, arg_)	\
138  	struct boot_state_callback name_ = BOOT_STATE_CALLBACK_INIT(func_, arg_)
139  
140  /* Initialize an allocated boot_state_callback. */
141  #define INIT_BOOT_STATE_CALLBACK(bscb_, func_, arg_)	\
142  	do {						\
143  		INIT_BOOT_STATE_CALLBACK_DEBUG(bscb_)	\
144  		bscb_->callback = func_;		\
145  		bscb_->arg = arg_			\
146  	} while (0)
147  
148  /* The following 2 functions schedule a callback to be called on entry/exit
149   * to a given state. Note that there are no ordering guarantees between the
150   * individual callbacks on a given state. 0 is returned on success < 0 on
151   * error. */
152  int boot_state_sched_on_entry(struct boot_state_callback *bscb,
153  				boot_state_t state);
154  int boot_state_sched_on_exit(struct boot_state_callback *bscb,
155  				boot_state_t state);
156  /* Schedule an array of entries of size num. */
157  struct boot_state_init_entry;
158  void boot_state_sched_entries(struct boot_state_init_entry *entries,
159  				size_t num);
160  
161  /* Block/Unblock the (state, seq) pair from transitioning. Returns 0 on
162   * success < 0  when the phase of the (state,seq) has already ran. */
163  int boot_state_block(boot_state_t state, boot_state_sequence_t seq);
164  int boot_state_unblock(boot_state_t state, boot_state_sequence_t seq);
165  
166  /* In order to schedule boot state callbacks at compile-time specify the
167   * entries in an array using the BOOT_STATE_INIT_ENTRIES and
168   * BOOT_STATE_INIT_ENTRY macros below. */
169  struct boot_state_init_entry {
170  	boot_state_t state;
171  	boot_state_sequence_t when;
172  	struct boot_state_callback bscb;
173  };
174  
175  #if ENV_RAMSTAGE
176  #define BOOT_STATE_INIT_ATTR  __attribute__((used, section(".bs_init")))
177  #else
178  #define BOOT_STATE_INIT_ATTR  __attribute__((unused))
179  #endif
180  
181  #define BOOT_STATE_INIT_ENTRY(state_, when_, func_, arg_)		\
182  	static struct boot_state_init_entry func_ ##_## state_ ##_## when_ = \
183  	{								\
184  		.state = state_,					\
185  		.when = when_,						\
186  		.bscb = BOOT_STATE_CALLBACK_INIT(func_, arg_),		\
187  	};								\
188  	static struct boot_state_init_entry *				\
189  		bsie_ ## func_ ##_## state_ ##_## when_ BOOT_STATE_INIT_ATTR = \
190  		&func_ ##_## state_ ##_## when_;			\
191  	_Static_assert(!(state_ == BS_PAYLOAD_BOOT && when_ == BS_ON_EXIT), \
192  		       "Invalid bootstate hook");			\
193  	_Static_assert(!(state_ == BS_OS_RESUME && when_ == BS_ON_EXIT), \
194  		       "Invalid bootstate hook");
195  
196  /* Hook per arch when coreboot is exiting to payload or ACPI OS resume. It's
197   * the very last thing done before the transition. */
198  void arch_bootstate_coreboot_exit(void);
199  
200  #endif /* BOOTSTATE_H */