Angel Pons | 32859fc | 2020-04-02 23:48:27 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Aaron Durbin | 04654a2 | 2015-03-17 11:43:44 -0500 | [diff] [blame] | 2 | #ifndef PROGRAM_LOADING_H |
| 3 | #define PROGRAM_LOADING_H |
Aaron Durbin | bdf913a | 2014-02-24 14:56:34 -0600 | [diff] [blame] | 4 | |
Ting Shen | 0553226 | 2019-01-28 17:22:22 +0800 | [diff] [blame] | 5 | #include <bootmem.h> |
Julius Werner | 965846f | 2021-01-11 16:07:02 -0800 | [diff] [blame] | 6 | #include <commonlib/bsd/cbfs_serialized.h> |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 7 | #include <commonlib/region.h> |
Julius Werner | 797a110 | 2022-03-07 18:54:47 -0800 | [diff] [blame] | 8 | #include <types.h> |
Aaron Durbin | bdf913a | 2014-02-24 14:56:34 -0600 | [diff] [blame] | 9 | |
Aaron Durbin | 6e76fff | 2015-03-20 09:42:05 -0500 | [diff] [blame] | 10 | enum { |
| 11 | /* Last segment of program. Can be used to take different actions for |
| 12 | * cache maintenance of a program load. */ |
| 13 | SEG_FINAL = 1 << 0, |
| 14 | }; |
Ionela Voinescu | 00903e5 | 2015-01-09 13:14:20 +0000 | [diff] [blame] | 15 | |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 16 | enum prog_type { |
Julius Werner | 55b3081 | 2018-05-21 18:30:17 +0000 | [diff] [blame] | 17 | PROG_UNKNOWN, |
Julius Werner | 99f4683 | 2018-05-16 14:14:04 -0700 | [diff] [blame] | 18 | PROG_BOOTBLOCK, |
Julius Werner | 55b3081 | 2018-05-21 18:30:17 +0000 | [diff] [blame] | 19 | PROG_VERSTAGE, |
| 20 | PROG_ROMSTAGE, |
| 21 | PROG_RAMSTAGE, |
| 22 | PROG_REFCODE, |
| 23 | PROG_PAYLOAD, |
| 24 | PROG_BL31, |
| 25 | PROG_BL32, |
Philipp Deppenwiese | 01797b1 | 2018-11-08 10:39:39 +0100 | [diff] [blame] | 26 | PROG_POSTCAR, |
Patrick Rudolph | 4c3da70 | 2019-07-07 13:10:56 +0200 | [diff] [blame] | 27 | PROG_OPENSBI, |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 28 | }; |
| 29 | |
Aaron Durbin | 096f457 | 2016-03-31 13:49:00 -0500 | [diff] [blame] | 30 | /* |
| 31 | * prog_segment_loaded() is called for each segment of a program loaded. The |
| 32 | * SEG_FINAL flag will be set on the last segment loaded. The following two |
| 33 | * functions, platform_segment_loaded() and arch_segment_loaded(), are called |
| 34 | * in that order within prog_segment_loaded(). In short, rely on |
| 35 | * prog_segment_loaded() to perform the proper dispatch sequence. |
| 36 | */ |
| 37 | void prog_segment_loaded(uintptr_t start, size_t size, int flags); |
| 38 | void platform_segment_loaded(uintptr_t start, size_t size, int flags); |
Aaron Durbin | 6e76fff | 2015-03-20 09:42:05 -0500 | [diff] [blame] | 39 | void arch_segment_loaded(uintptr_t start, size_t size, int flags); |
Ionela Voinescu | 00903e5 | 2015-01-09 13:14:20 +0000 | [diff] [blame] | 40 | |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 41 | /* Representation of a program. */ |
| 42 | struct prog { |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 43 | enum prog_type type; |
Julius Werner | 965846f | 2021-01-11 16:07:02 -0800 | [diff] [blame] | 44 | enum cbfs_type cbfs_type; |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 45 | const char *name; |
Julius Werner | 2e97394 | 2020-09-03 21:17:20 -0700 | [diff] [blame] | 46 | void *start; /* Program start in memory. */ |
| 47 | size_t size; /* Program size in memory (including BSS). */ |
| 48 | void (*entry)(void *); /* Function pointer to entry point. */ |
| 49 | void *arg; /* Optional argument (only valid for some archs). */ |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 50 | }; |
| 51 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 52 | #define PROG_INIT(type_, name_) \ |
| 53 | { \ |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 54 | .type = (type_), \ |
| 55 | .name = (name_), \ |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | static inline const char *prog_name(const struct prog *prog) |
| 59 | { |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 60 | return prog->name; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 61 | } |
| 62 | |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 63 | static inline enum prog_type prog_type(const struct prog *prog) |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 64 | { |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 65 | return prog->type; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 66 | } |
| 67 | |
Julius Werner | 965846f | 2021-01-11 16:07:02 -0800 | [diff] [blame] | 68 | static inline enum cbfs_type prog_cbfs_type(const struct prog *prog) |
Patrick Rudolph | 71327fb | 2018-05-03 10:35:26 +0200 | [diff] [blame] | 69 | { |
| 70 | return prog->cbfs_type; |
| 71 | } |
| 72 | |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 73 | static inline size_t prog_size(const struct prog *prog) |
| 74 | { |
Julius Werner | 2e97394 | 2020-09-03 21:17:20 -0700 | [diff] [blame] | 75 | return prog->size; |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | static inline void *prog_start(const struct prog *prog) |
| 79 | { |
Julius Werner | 2e97394 | 2020-09-03 21:17:20 -0700 | [diff] [blame] | 80 | return prog->start; |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | static inline void *prog_entry(const struct prog *prog) |
| 84 | { |
| 85 | return prog->entry; |
| 86 | } |
| 87 | |
| 88 | static inline void *prog_entry_arg(const struct prog *prog) |
| 89 | { |
| 90 | return prog->arg; |
| 91 | } |
| 92 | |
Julius Werner | 2e97394 | 2020-09-03 21:17:20 -0700 | [diff] [blame] | 93 | /* Can be used to get an rdev representation of program area in memory. */ |
| 94 | static inline void prog_chain_rdev(const struct prog *prog, |
| 95 | struct region_device *rdev_out) |
Aaron Durbin | 6a452ef | 2015-05-19 16:25:20 -0500 | [diff] [blame] | 96 | { |
Julius Werner | c893197 | 2021-04-16 16:48:32 -0700 | [diff] [blame] | 97 | rdev_chain_mem(rdev_out, prog->start, prog->size); |
Aaron Durbin | 6a452ef | 2015-05-19 16:25:20 -0500 | [diff] [blame] | 98 | } |
| 99 | |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 100 | static inline void prog_set_area(struct prog *prog, void *start, size_t size) |
| 101 | { |
Julius Werner | 2e97394 | 2020-09-03 21:17:20 -0700 | [diff] [blame] | 102 | prog->start = start; |
| 103 | prog->size = size; |
Aaron Durbin | 3948e53 | 2015-03-20 13:00:20 -0500 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | static inline void prog_set_entry(struct prog *prog, void *e, void *arg) |
| 107 | { |
| 108 | prog->entry = e; |
| 109 | prog->arg = arg; |
| 110 | } |
| 111 | |
Arthur Heymans | 5331a7c | 2019-10-23 17:07:15 +0200 | [diff] [blame] | 112 | static inline void prog_set_arg(struct prog *prog, void *arg) |
| 113 | { |
| 114 | prog->arg = arg; |
| 115 | } |
| 116 | |
Frans Hendriks | fc58034 | 2019-06-14 14:36:37 +0200 | [diff] [blame] | 117 | /* The prog_locate_hook() is called prior to CBFS traversal. The hook can be |
Julius Werner | 5358467 | 2021-01-11 16:44:06 -0800 | [diff] [blame] | 118 | * used to implement policy that allows or prohibits further program loading. |
| 119 | * The type and name field within struct prog are the only valid fields. A 0 |
| 120 | * return value allows loading while a non-zero return value prohibits it. */ |
Frans Hendriks | fc58034 | 2019-06-14 14:36:37 +0200 | [diff] [blame] | 121 | int prog_locate_hook(struct prog *prog); |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 122 | |
Aaron Durbin | b3847e6 | 2015-03-20 15:55:08 -0500 | [diff] [blame] | 123 | /* Run the program described by prog. */ |
| 124 | void prog_run(struct prog *prog); |
| 125 | /* Per architecture implementation running a program. */ |
| 126 | void arch_prog_run(struct prog *prog); |
| 127 | /* Platform (SoC/chipset) specific overrides for running a program. This is |
| 128 | * called prior to calling the arch_prog_run. Thus, if there is anything |
| 129 | * special that needs to be done by the platform similar to the architecture |
| 130 | * code it needs to that as well. */ |
| 131 | void platform_prog_run(struct prog *prog); |
| 132 | |
Aaron Durbin | d1b0e87 | 2015-03-17 13:17:06 -0500 | [diff] [blame] | 133 | /************************ |
| 134 | * ROMSTAGE LOADING * |
| 135 | ************************/ |
| 136 | |
| 137 | /* Run romstage from bootblock. */ |
| 138 | void run_romstage(void); |
Aaron Durbin | 04654a2 | 2015-03-17 11:43:44 -0500 | [diff] [blame] | 139 | |
Kyösti Mälkki | b8d575c | 2019-12-16 16:00:49 +0200 | [diff] [blame] | 140 | /* Runtime selector for CBFS_PREFIX of romstage. */ |
Julius Werner | 797a110 | 2022-03-07 18:54:47 -0800 | [diff] [blame] | 141 | enum cb_err legacy_romstage_select_and_load(struct prog *romstage); |
Kyösti Mälkki | b8d575c | 2019-12-16 16:00:49 +0200 | [diff] [blame] | 142 | |
Aaron Durbin | 04654a2 | 2015-03-17 11:43:44 -0500 | [diff] [blame] | 143 | /************************ |
| 144 | * RAMSTAGE LOADING * |
| 145 | ************************/ |
| 146 | |
Raul E Rangel | b25576f | 2021-11-05 10:29:24 -0600 | [diff] [blame] | 147 | /* |
| 148 | * Asynchronously preloads ramstage. |
| 149 | * |
| 150 | * This should be called early on to allow ramstage to load before |
| 151 | * `run_ramstage` is called. |
| 152 | */ |
| 153 | void preload_ramstage(void); |
Aaron Durbin | ce9efe0 | 2015-03-20 16:37:12 -0500 | [diff] [blame] | 154 | /* Run ramstage from romstage. */ |
Arthur Heymans | 84b2f9f | 2022-06-23 11:53:34 +0200 | [diff] [blame] | 155 | void __noreturn run_ramstage(void); |
Aaron Durbin | ce9efe0 | 2015-03-20 16:37:12 -0500 | [diff] [blame] | 156 | |
Aaron Durbin | 04654a2 | 2015-03-17 11:43:44 -0500 | [diff] [blame] | 157 | /*********************** |
| 158 | * PAYLOAD LOADING * |
| 159 | ***********************/ |
| 160 | |
Kyösti Mälkki | a48433d | 2018-06-07 06:31:43 +0300 | [diff] [blame] | 161 | int payload_arch_usable_ram_quirk(uint64_t start, uint64_t size); |
| 162 | |
Raul E Rangel | 67798cf | 2021-07-02 17:07:05 -0600 | [diff] [blame] | 163 | /* |
| 164 | * Asynchronously preloads the payload. |
| 165 | * |
| 166 | * This should be called early on to allow the payload to load before |
| 167 | * `payload_load` is called. |
| 168 | */ |
| 169 | void payload_preload(void); |
Aaron Durbin | ebf2ed4 | 2015-03-20 10:20:15 -0500 | [diff] [blame] | 170 | /* Load payload into memory in preparation to run. */ |
| 171 | void payload_load(void); |
Aaron Durbin | bdf913a | 2014-02-24 14:56:34 -0600 | [diff] [blame] | 172 | |
| 173 | /* Run the loaded payload. */ |
Aaron Durbin | ebf2ed4 | 2015-03-20 10:20:15 -0500 | [diff] [blame] | 174 | void payload_run(void); |
Aaron Durbin | bdf913a | 2014-02-24 14:56:34 -0600 | [diff] [blame] | 175 | |
Simon Glass | 7ae73fc | 2016-08-27 12:18:38 -0600 | [diff] [blame] | 176 | /* |
Ronald G. Minnich | c308554 | 2018-10-24 15:46:51 -0700 | [diff] [blame] | 177 | * selfload() and selfload_check() load payloads into memory. |
| 178 | * selfload() does not check the payload to see if it targets memory. |
| 179 | * Call selfload_check() to check that the payload targets usable memory. |
| 180 | * If it does not, the load will fail and this function |
| 181 | * will return false. On successful payload loading these functions return true. |
Simon Glass | 7ae73fc | 2016-08-27 12:18:38 -0600 | [diff] [blame] | 182 | * |
| 183 | * Defined in src/lib/selfboot.c |
| 184 | */ |
Ting Shen | 0553226 | 2019-01-28 17:22:22 +0800 | [diff] [blame] | 185 | bool selfload_check(struct prog *payload, enum bootmem_type dest_type); |
Ronald G. Minnich | c308554 | 2018-10-24 15:46:51 -0700 | [diff] [blame] | 186 | bool selfload(struct prog *payload); |
Julius Werner | 965846f | 2021-01-11 16:07:02 -0800 | [diff] [blame] | 187 | /* Like selfload_check() but with the payload data already mapped to memory. */ |
| 188 | bool selfload_mapped(struct prog *payload, void *mapping, |
| 189 | enum bootmem_type dest_type); |
| 190 | |
| 191 | /* Load a FIT payload. The payload data must already be mapped to memory. */ |
| 192 | void fit_payload(struct prog *payload, void *data); |
Aaron Durbin | 04654a2 | 2015-03-17 11:43:44 -0500 | [diff] [blame] | 193 | |
| 194 | #endif /* PROGRAM_LOADING_H */ |