Commit 80a4800ee1526a4a46cd02b3ea2fd37eebb77504

Authored by Alexander Graf
1 parent 511d0b97ef

efi_loader: Allow boards to implement get_time and reset_system

EFI allows an OS to leverage firmware drivers while the OS is running. In the
generic code we so far had to stub those implementations out, because we would
need board specific knowledge about MMIO setups for it.

However, boards can easily implement those themselves. This patch provides the
framework so that a board can implement its own versions of get_time and
reset_system which would actually do something useful.

While at it we also introduce a simple way for code to reserve MMIO pointers
as runtime available.

Signed-off-by: Alexander Graf <agraf@suse.de>

Showing 3 changed files with 113 additions and 11 deletions Side-by-side Diff

... ... @@ -206,6 +206,10 @@
206 206 loaded_image_info.device_handle = nethandle;
207 207 #endif
208 208  
  209 + /* Initialize EFI runtime services */
  210 + efi_reset_system_init();
  211 + efi_get_time_init();
  212 +
209 213 /* Call our payload! */
210 214 debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
211 215  
include/efi_loader.h
... ... @@ -155,11 +155,29 @@
155 155 #define EFI_RUNTIME_DATA __attribute__ ((section ("efi_runtime_data")))
156 156 #define EFI_RUNTIME_TEXT __attribute__ ((section ("efi_runtime_text")))
157 157  
  158 +/* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region
  159 + * to make it available at runtime */
  160 +void efi_add_runtime_mmio(void *mmio_ptr, u64 len);
  161 +
  162 +/* Boards may provide the functions below to implement RTS functionality */
  163 +
  164 +void EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
  165 + enum efi_reset_type reset_type,
  166 + efi_status_t reset_status,
  167 + unsigned long data_size, void *reset_data);
  168 +void efi_reset_system_init(void);
  169 +
  170 +efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_get_time(
  171 + struct efi_time *time,
  172 + struct efi_time_cap *capabilities);
  173 +void efi_get_time_init(void);
  174 +
158 175 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
159 176  
160 177 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
161 178 #define EFI_RUNTIME_DATA
162 179 #define EFI_RUNTIME_TEXT
  180 +static inline void efi_add_runtime_mmio(void **mmio_ptr, u64 len) { }
163 181  
164 182 /* No loader configured, stub out EFI_ENTRY */
165 183 static inline void efi_restore_gd(void) { }
lib/efi_loader/efi_runtime.c
... ... @@ -16,6 +16,16 @@
16 16 /* For manual relocation support */
17 17 DECLARE_GLOBAL_DATA_PTR;
18 18  
  19 +struct efi_runtime_mmio_list {
  20 + struct list_head link;
  21 + void **ptr;
  22 + u64 paddr;
  23 + u64 len;
  24 +};
  25 +
  26 +/* This list contains all runtime available mmio regions */
  27 +LIST_HEAD(efi_runtime_mmio);
  28 +
19 29 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void);
20 30 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void);
21 31 static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void);
... ... @@ -55,9 +65,10 @@
55 65 * handle a good number of runtime callbacks
56 66 */
57 67  
58   -static void EFIAPI efi_reset_system(enum efi_reset_type reset_type,
59   - efi_status_t reset_status,
60   - unsigned long data_size, void *reset_data)
  68 +static void EFIAPI efi_reset_system_boottime(
  69 + enum efi_reset_type reset_type,
  70 + efi_status_t reset_status,
  71 + unsigned long data_size, void *reset_data)
61 72 {
62 73 EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
63 74 reset_data);
64 75  
... ... @@ -72,11 +83,12 @@
72 83 break;
73 84 }
74 85  
75   - EFI_EXIT(EFI_SUCCESS);
  86 + while (1) { }
76 87 }
77 88  
78   -static efi_status_t EFIAPI efi_get_time(struct efi_time *time,
79   - struct efi_time_cap *capabilities)
  89 +static efi_status_t EFIAPI efi_get_time_boottime(
  90 + struct efi_time *time,
  91 + struct efi_time_cap *capabilities)
80 92 {
81 93 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
82 94 struct rtc_time tm;
... ... @@ -107,6 +119,33 @@
107 119 #endif
108 120 }
109 121  
  122 +/* Boards may override the helpers below to implement RTS functionality */
  123 +
  124 +void __weak EFI_RUNTIME_TEXT EFIAPI efi_reset_system(
  125 + enum efi_reset_type reset_type,
  126 + efi_status_t reset_status,
  127 + unsigned long data_size, void *reset_data)
  128 +{
  129 + /* Nothing we can do */
  130 + while (1) { }
  131 +}
  132 +
  133 +void __weak efi_reset_system_init(void)
  134 +{
  135 +}
  136 +
  137 +efi_status_t __weak EFI_RUNTIME_TEXT EFIAPI efi_get_time(
  138 + struct efi_time *time,
  139 + struct efi_time_cap *capabilities)
  140 +{
  141 + /* Nothing we can do */
  142 + return EFI_DEVICE_ERROR;
  143 +}
  144 +
  145 +void __weak efi_get_time_init(void)
  146 +{
  147 +}
  148 +
110 149 struct efi_runtime_detach_list_struct {
111 150 void *ptr;
112 151 void *patchto;
... ... @@ -116,7 +155,7 @@
116 155 {
117 156 /* do_reset is gone */
118 157 .ptr = &efi_runtime_services.reset_system,
119   - .patchto = NULL,
  158 + .patchto = efi_reset_system,
120 159 }, {
121 160 /* invalidate_*cache_all are gone */
122 161 .ptr = &efi_runtime_services.set_virtual_address_map,
... ... @@ -124,7 +163,7 @@
124 163 }, {
125 164 /* RTC accessors are gone */
126 165 .ptr = &efi_runtime_services.get_time,
127   - .patchto = &efi_device_error,
  166 + .patchto = &efi_get_time,
128 167 }, {
129 168 /* Clean up system table */
130 169 .ptr = &systab.con_in,
131 170  
132 171  
... ... @@ -233,12 +272,39 @@
233 272 EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
234 273 descriptor_version, virtmap);
235 274  
  275 + /* Rebind mmio pointers */
236 276 for (i = 0; i < n; i++) {
  277 + struct efi_mem_desc *map = (void*)virtmap +
  278 + (descriptor_size * i);
  279 + struct list_head *lhandle;
  280 + efi_physical_addr_t map_start = map->physical_start;
  281 + efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
  282 + efi_physical_addr_t map_end = map_start + map_len;
  283 +
  284 + /* Adjust all mmio pointers in this region */
  285 + list_for_each(lhandle, &efi_runtime_mmio) {
  286 + struct efi_runtime_mmio_list *lmmio;
  287 +
  288 + lmmio = list_entry(lhandle,
  289 + struct efi_runtime_mmio_list,
  290 + link);
  291 + if ((map_start <= lmmio->paddr) &&
  292 + (map_end >= lmmio->paddr)) {
  293 + u64 off = map->virtual_start - map_start;
  294 + uintptr_t new_addr = lmmio->paddr + off;
  295 + *lmmio->ptr = (void *)new_addr;
  296 + }
  297 + }
  298 + }
  299 +
  300 + /* Move the actual runtime code over */
  301 + for (i = 0; i < n; i++) {
237 302 struct efi_mem_desc *map;
238 303  
239 304 map = (void*)virtmap + (descriptor_size * i);
240 305 if (map->type == EFI_RUNTIME_SERVICES_CODE) {
241   - ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr);
  306 + ulong new_offset = map->virtual_start -
  307 + (runtime_start - gd->relocaddr);
242 308  
243 309 efi_runtime_relocate(new_offset, map);
244 310 /* Once we're virtual, we can no longer handle
... ... @@ -251,6 +317,20 @@
251 317 return EFI_EXIT(EFI_INVALID_PARAMETER);
252 318 }
253 319  
  320 +void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
  321 +{
  322 + struct efi_runtime_mmio_list *newmmio;
  323 +
  324 + u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
  325 + efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
  326 +
  327 + newmmio = calloc(1, sizeof(*newmmio));
  328 + newmmio->ptr = mmio_ptr;
  329 + newmmio->paddr = *(uintptr_t *)mmio_ptr;
  330 + newmmio->len = len;
  331 + list_add_tail(&newmmio->link, &efi_runtime_mmio);
  332 +}
  333 +
254 334 /*
255 335 * In the second stage, U-Boot has disappeared. To isolate our runtime code
256 336 * that at this point still exists from the rest, we put it into a special
... ... @@ -292,7 +372,7 @@
292 372 .revision = EFI_RUNTIME_SERVICES_REVISION,
293 373 .headersize = sizeof(struct efi_table_hdr),
294 374 },
295   - .get_time = &efi_get_time,
  375 + .get_time = &efi_get_time_boottime,
296 376 .set_time = (void *)&efi_device_error,
297 377 .get_wakeup_time = (void *)&efi_unimplemented,
298 378 .set_wakeup_time = (void *)&efi_unimplemented,
... ... @@ -302,6 +382,6 @@
302 382 .get_next_variable = (void *)&efi_device_error,
303 383 .set_variable = (void *)&efi_device_error,
304 384 .get_next_high_mono_count = (void *)&efi_device_error,
305   - .reset_system = &efi_reset_system,
  385 + .reset_system = &efi_reset_system_boottime,
306 386 };