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 */