1 /*
2 * Architecture specific implementation for EFI boot code. This file
3 * is intended to be included by common/efi/boot.c _only_, and
4 * therefore can define arch specific global variables.
5 */
6 #include <xen/device_tree.h>
7 #include <xen/libfdt/libfdt.h>
8 #include <asm/setup.h>
9 #include <asm/smp.h>
10
11 void noreturn efi_xen_start(void *fdt_ptr, uint32_t fdt_size);
12 void __flush_dcache_area(const void *vaddr, unsigned long size);
13
14 #define DEVICE_TREE_GUID \
15 {0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}
16
17 static struct file __initdata dtbfile;
18 static void __initdata *fdt;
19 static void __initdata *memmap;
20
setup_chosen_node(void * fdt,int * addr_cells,int * size_cells)21 static int __init setup_chosen_node(void *fdt, int *addr_cells, int *size_cells)
22 {
23 int node;
24 const struct fdt_property *prop;
25 int len;
26 uint32_t val;
27
28 if ( !fdt || !addr_cells || !size_cells )
29 return -1;
30
31 /* locate chosen node, which is where we add Xen module info. */
32 node = fdt_subnode_offset(fdt, 0, "chosen");
33 if ( node < 0 )
34 {
35 node = fdt_add_subnode(fdt, 0, "chosen");
36 if ( node < 0 )
37 return node;
38 }
39
40 /* Get or set #address-cells and #size-cells */
41 prop = fdt_get_property(fdt, node, "#address-cells", &len);
42 if ( !prop )
43 {
44 val = cpu_to_fdt32(2);
45 if ( fdt_setprop(fdt, node, "#address-cells", &val, sizeof(val)) )
46 return -1;
47 *addr_cells = 2;
48 }
49 else
50 *addr_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
51
52 prop = fdt_get_property(fdt, node, "#size-cells", &len);
53 if ( !prop )
54 {
55 val = cpu_to_fdt32(2);
56 if ( fdt_setprop(fdt, node, "#size-cells", &val, sizeof(val)) )
57 return -1;
58 *size_cells = 2;
59 }
60 else
61 *size_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
62
63 /*
64 * Make sure ranges is empty if it exists, otherwise create empty ranges
65 * property.
66 */
67 prop = fdt_get_property(fdt, node, "ranges", &len);
68 if ( !prop )
69 {
70 val = cpu_to_fdt32(0);
71 if ( fdt_setprop(fdt, node, "ranges", &val, 0) )
72 return -1;
73 }
74 else if ( fdt32_to_cpu(prop->len) )
75 return -1; /* Non-empty ranges property */
76 return node;
77 }
78
79 /*
80 * Set a single 'reg' property taking into account the
81 * configured addr and size cell sizes.
82 */
fdt_set_reg(void * fdt,int node,int addr_cells,int size_cells,uint64_t addr,uint64_t len)83 static int __init fdt_set_reg(void *fdt, int node, int addr_cells,
84 int size_cells, uint64_t addr, uint64_t len)
85 {
86 __be32 val[4]; /* At most 2 64 bit values to be stored */
87 __be32 *cellp;
88
89 /*
90 * Make sure that the values provided can be represented in
91 * the reg property, and sizes are valid.
92 */
93 if ( addr_cells < 1 || addr_cells > 2 || size_cells < 1 || size_cells > 2 )
94 return -1;
95 if ( addr_cells == 1 && (addr >> 32) )
96 return -1;
97 if ( size_cells == 1 && (len >> 32) )
98 return -1;
99
100 cellp = (__be32 *)val;
101 dt_set_cell(&cellp, addr_cells, addr);
102 dt_set_cell(&cellp, size_cells, len);
103
104 return(fdt_setprop(fdt, node, "reg", val, sizeof(*cellp) * (cellp - val)));
105 }
106
lookup_fdt_config_table(EFI_SYSTEM_TABLE * sys_table)107 static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table)
108 {
109 static const EFI_GUID __initconst fdt_guid = DEVICE_TREE_GUID;
110 EFI_CONFIGURATION_TABLE *tables;
111 void *fdt = NULL;
112 int i;
113
114 tables = sys_table->ConfigurationTable;
115 for ( i = 0; i < sys_table->NumberOfTableEntries; i++ )
116 {
117 if ( match_guid(&tables[i].VendorGuid, &fdt_guid) )
118 {
119 fdt = tables[i].VendorTable;
120 break;
121 }
122 }
123 return fdt;
124 }
125
meminfo_add_bank(struct meminfo * mem,EFI_MEMORY_DESCRIPTOR * desc)126 static bool __init meminfo_add_bank(struct meminfo *mem,
127 EFI_MEMORY_DESCRIPTOR *desc)
128 {
129 struct membank *bank;
130
131 if ( mem->nr_banks >= NR_MEM_BANKS )
132 return false;
133
134 bank = &mem->bank[mem->nr_banks];
135 bank->start = desc->PhysicalStart;
136 bank->size = desc->NumberOfPages * EFI_PAGE_SIZE;
137
138 mem->nr_banks++;
139
140 return true;
141 }
142
efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR * map,UINTN mmap_size,UINTN desc_size)143 static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map,
144 UINTN mmap_size,
145 UINTN desc_size)
146 {
147 int Index;
148 EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
149
150 for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
151 {
152 if ( desc_ptr->Type == EfiConventionalMemory ||
153 (!map_bs &&
154 (desc_ptr->Type == EfiBootServicesCode ||
155 desc_ptr->Type == EfiBootServicesData)) )
156 {
157 if ( !meminfo_add_bank(&bootinfo.mem, desc_ptr) )
158 {
159 PrintStr(L"Warning: All " __stringify(NR_MEM_BANKS)
160 " bootinfo mem banks exhausted.\r\n");
161 break;
162 }
163 }
164 #ifdef CONFIG_ACPI
165 else if ( desc_ptr->Type == EfiACPIReclaimMemory )
166 {
167 if ( !meminfo_add_bank(&bootinfo.acpi, desc_ptr) )
168 {
169 PrintStr(L"Error: All " __stringify(NR_MEM_BANKS)
170 " acpi meminfo mem banks exhausted.\r\n");
171 return EFI_LOAD_ERROR;
172 }
173 }
174 #endif
175 desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
176 }
177
178 return EFI_SUCCESS;
179 }
180
181 /*
182 * Add the FDT nodes for the standard EFI information, which consist
183 * of the System table address, the address of the final EFI memory map,
184 * and memory map information.
185 */
fdt_add_uefi_nodes(EFI_SYSTEM_TABLE * sys_table,void * fdt,EFI_MEMORY_DESCRIPTOR * memory_map,UINTN map_size,UINTN desc_size,UINT32 desc_ver)186 EFI_STATUS __init fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table,
187 void *fdt,
188 EFI_MEMORY_DESCRIPTOR *memory_map,
189 UINTN map_size,
190 UINTN desc_size,
191 UINT32 desc_ver)
192 {
193 int node;
194 int status;
195 u32 fdt_val32;
196 u64 fdt_val64;
197 int prev;
198 int num_rsv;
199
200 /*
201 * Delete any memory nodes present. The EFI memory map is the only
202 * memory description provided to Xen.
203 */
204 prev = 0;
205 for (;;)
206 {
207 const char *type;
208 int len;
209
210 node = fdt_next_node(fdt, prev, NULL);
211 if ( node < 0 )
212 break;
213
214 type = fdt_getprop(fdt, node, "device_type", &len);
215 if ( type && strncmp(type, "memory", len) == 0 )
216 {
217 fdt_del_node(fdt, node);
218 continue;
219 }
220
221 prev = node;
222 }
223
224 /*
225 * Delete all memory reserve map entries. When booting via UEFI,
226 * kernel will use the UEFI memory map to find reserved regions.
227 */
228 num_rsv = fdt_num_mem_rsv(fdt);
229 while ( num_rsv-- > 0 )
230 fdt_del_mem_rsv(fdt, num_rsv);
231
232 /* Add FDT entries for EFI runtime services in chosen node. */
233 node = fdt_subnode_offset(fdt, 0, "chosen");
234 if ( node < 0 )
235 {
236 node = fdt_add_subnode(fdt, 0, "chosen");
237 if ( node < 0 )
238 {
239 status = node; /* node is error code when negative */
240 goto fdt_set_fail;
241 }
242 }
243
244 fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)sys_table);
245 status = fdt_setprop(fdt, node, "linux,uefi-system-table",
246 &fdt_val64, sizeof(fdt_val64));
247 if ( status )
248 goto fdt_set_fail;
249
250 fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)memory_map);
251 status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
252 &fdt_val64, sizeof(fdt_val64));
253 if ( status )
254 goto fdt_set_fail;
255
256 fdt_val32 = cpu_to_fdt32(map_size);
257 status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
258 &fdt_val32, sizeof(fdt_val32));
259 if ( status )
260 goto fdt_set_fail;
261
262 fdt_val32 = cpu_to_fdt32(desc_size);
263 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
264 &fdt_val32, sizeof(fdt_val32));
265 if ( status )
266 goto fdt_set_fail;
267
268 fdt_val32 = cpu_to_fdt32(desc_ver);
269 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
270 &fdt_val32, sizeof(fdt_val32));
271 if ( status )
272 goto fdt_set_fail;
273
274 return EFI_SUCCESS;
275
276 fdt_set_fail:
277 if ( status == -FDT_ERR_NOSPACE )
278 return EFI_BUFFER_TOO_SMALL;
279
280 return EFI_LOAD_ERROR;
281 }
282
283 /*
284 * Allocates new memory for a larger FDT, and frees existing memory if
285 * struct file size is non-zero. Updates file struct with new memory
286 * address/size for later freeing. If fdtfile.ptr is NULL, an empty FDT
287 * is created.
288 */
fdt_increase_size(struct file * fdtfile,int add_size)289 static void __init *fdt_increase_size(struct file *fdtfile, int add_size)
290 {
291 EFI_STATUS status;
292 EFI_PHYSICAL_ADDRESS fdt_addr;
293 int fdt_size;
294 int pages;
295 void *new_fdt;
296
297 if ( fdtfile->ptr )
298 fdt_size = fdt_totalsize(fdtfile->ptr);
299 else
300 fdt_size = 0;
301
302 pages = PFN_UP(fdt_size + add_size);
303 status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData,
304 pages, &fdt_addr);
305
306 if ( status != EFI_SUCCESS )
307 return NULL;
308
309 new_fdt = (void *)fdt_addr;
310
311 if ( fdt_size )
312 {
313 if ( fdt_open_into(dtbfile.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
314 return NULL;
315 }
316 else
317 {
318 /*
319 * Create an empty FDT if not provided one, which is the expected case
320 * when booted from the UEFI shell on an ACPI only system. We will use
321 * the FDT to pass the EFI information to Xen, as well as nodes for
322 * any modules the stub loads. The ACPI tables are part of the UEFI
323 * system table that is passed in the FDT.
324 */
325 if ( fdt_create_empty_tree(new_fdt, pages * EFI_PAGE_SIZE) )
326 return NULL;
327 }
328
329 /*
330 * Now that we have the new FDT allocated and copied, free the
331 * original and update the struct file so that the error handling
332 * code will free it. If the original FDT came from a configuration
333 * table, we don't own that memory and can't free it.
334 */
335 if ( dtbfile.size )
336 efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
337
338 /* Update 'file' info for new memory so we clean it up on error exits */
339 dtbfile.addr = fdt_addr;
340 dtbfile.size = pages * EFI_PAGE_SIZE;
341 return new_fdt;
342 }
343
efi_arch_relocate_image(unsigned long delta)344 static void __init efi_arch_relocate_image(unsigned long delta)
345 {
346 }
347
efi_arch_process_memory_map(EFI_SYSTEM_TABLE * SystemTable,void * map,UINTN map_size,UINTN desc_size,UINT32 desc_ver)348 static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
349 void *map,
350 UINTN map_size,
351 UINTN desc_size,
352 UINT32 desc_ver)
353 {
354 EFI_STATUS status;
355
356 status = efi_process_memory_map_bootinfo(map, map_size, desc_size);
357 if ( EFI_ERROR(status) )
358 blexit(L"EFI memory map processing failed");
359
360 status = fdt_add_uefi_nodes(SystemTable, fdt, map, map_size, desc_size,
361 desc_ver);
362 if ( EFI_ERROR(status) )
363 PrintErrMesg(L"Updating FDT failed", status);
364 }
365
efi_arch_pre_exit_boot(void)366 static void __init efi_arch_pre_exit_boot(void)
367 {
368 }
369
efi_arch_post_exit_boot(void)370 static void __init efi_arch_post_exit_boot(void)
371 {
372 efi_xen_start(fdt, fdt_totalsize(fdt));
373 }
374
efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle,char * section)375 static void __init efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle, char *section)
376 {
377 union string name;
378
379 /*
380 * The DTB must be processed before any other entries in the configuration
381 * file, as the DTB is updated as modules are loaded.
382 */
383 name.s = get_value(&cfg, section, "dtb");
384 if ( name.s )
385 {
386 split_string(name.s);
387 read_file(dir_handle, s2w(&name), &dtbfile, NULL);
388 efi_bs->FreePool(name.w);
389 }
390 fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE);
391 if ( !fdt )
392 blexit(L"Unable to create new FDT");
393 }
394
efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle,char * section)395 static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section)
396 {
397 }
398
efi_arch_allocate_mmap_buffer(UINTN map_size)399 static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size)
400 {
401 void *ptr;
402 EFI_STATUS status;
403
404 status = efi_bs->AllocatePool(EfiLoaderData, map_size, &ptr);
405 if ( status != EFI_SUCCESS )
406 return NULL;
407 return ptr;
408 }
409
efi_arch_edd(void)410 static void __init efi_arch_edd(void)
411 {
412 }
413
efi_arch_memory_setup(void)414 static void __init efi_arch_memory_setup(void)
415 {
416 }
417
efi_arch_handle_cmdline(CHAR16 * image_name,CHAR16 * cmdline_options,char * cfgfile_options)418 static void __init efi_arch_handle_cmdline(CHAR16 *image_name,
419 CHAR16 *cmdline_options,
420 char *cfgfile_options)
421 {
422 union string name;
423 char *buf;
424 EFI_STATUS status;
425 int prop_len;
426 int chosen;
427
428 /* locate chosen node, which is where we add Xen module info. */
429 chosen = fdt_subnode_offset(fdt, 0, "chosen");
430 if ( chosen < 0 )
431 blexit(L"Unable to find chosen node");
432
433 status = efi_bs->AllocatePool(EfiBootServicesData, EFI_PAGE_SIZE, (void **)&buf);
434 if ( EFI_ERROR(status) )
435 PrintErrMesg(L"Unable to allocate string buffer", status);
436
437 if ( image_name )
438 {
439 name.w = image_name;
440 w2s(&name);
441 }
442 else
443 name.s = "xen";
444
445 prop_len = 0;
446 prop_len += snprintf(buf + prop_len,
447 EFI_PAGE_SIZE - prop_len, "%s", name.s);
448 if ( prop_len >= EFI_PAGE_SIZE )
449 blexit(L"FDT string overflow");
450
451 if ( cfgfile_options )
452 {
453 prop_len += snprintf(buf + prop_len,
454 EFI_PAGE_SIZE - prop_len, " %s", cfgfile_options);
455 if ( prop_len >= EFI_PAGE_SIZE )
456 blexit(L"FDT string overflow");
457 }
458
459 if ( cmdline_options )
460 {
461 name.w = cmdline_options;
462 w2s(&name);
463 }
464 else
465 name.s = NULL;
466
467 if ( name.s )
468 {
469 prop_len += snprintf(buf + prop_len,
470 EFI_PAGE_SIZE - prop_len, " %s", name.s);
471 if ( prop_len >= EFI_PAGE_SIZE )
472 blexit(L"FDT string overflow");
473 }
474
475 if ( fdt_setprop_string(fdt, chosen, "xen,xen-bootargs", buf) < 0 )
476 blexit(L"Unable to set xen,xen-bootargs property.");
477
478 efi_bs->FreePool(buf);
479 }
480
efi_arch_handle_module(struct file * file,const CHAR16 * name,char * options)481 static void __init efi_arch_handle_module(struct file *file, const CHAR16 *name,
482 char *options)
483 {
484 int node;
485 int chosen;
486 int addr_len, size_len;
487
488 if ( file == &dtbfile )
489 return;
490 chosen = setup_chosen_node(fdt, &addr_len, &size_len);
491 if ( chosen < 0 )
492 blexit(L"Unable to setup chosen node");
493
494 if ( file == &ramdisk )
495 {
496 char ramdisk_compat[] = "multiboot,ramdisk\0multiboot,module";
497 node = fdt_add_subnode(fdt, chosen, "ramdisk");
498 if ( node < 0 )
499 blexit(L"Unable to add ramdisk FDT node.");
500 if ( fdt_setprop(fdt, node, "compatible", ramdisk_compat,
501 sizeof(ramdisk_compat)) < 0 )
502 blexit(L"Unable to set compatible property.");
503 if ( fdt_set_reg(fdt, node, addr_len, size_len, ramdisk.addr,
504 ramdisk.size) < 0 )
505 blexit(L"Unable to set reg property.");
506 }
507 else if ( file == &xsm )
508 {
509 char xsm_compat[] = "xen,xsm-policy\0multiboot,module";
510 node = fdt_add_subnode(fdt, chosen, "xsm");
511 if ( node < 0 )
512 blexit(L"Unable to add xsm FDT node.");
513 if ( fdt_setprop(fdt, node, "compatible", xsm_compat,
514 sizeof(xsm_compat)) < 0 )
515 blexit(L"Unable to set compatible property.");
516 if ( fdt_set_reg(fdt, node, addr_len, size_len, xsm.addr,
517 xsm.size) < 0 )
518 blexit(L"Unable to set reg property.");
519 }
520 else if ( file == &kernel )
521 {
522 char kernel_compat[] = "multiboot,kernel\0multiboot,module";
523 node = fdt_add_subnode(fdt, chosen, "kernel");
524 if ( node < 0 )
525 blexit(L"Unable to add dom0 FDT node.");
526 if ( fdt_setprop(fdt, node, "compatible", kernel_compat,
527 sizeof(kernel_compat)) < 0 )
528 blexit(L"Unable to set compatible property.");
529 if ( options && fdt_setprop_string(fdt, node, "bootargs", options) < 0 )
530 blexit(L"Unable to set bootargs property.");
531 if ( fdt_set_reg(fdt, node, addr_len, size_len, kernel.addr,
532 kernel.size) < 0 )
533 blexit(L"Unable to set reg property.");
534 }
535 else
536 blexit(L"Unknown module type");
537 }
538
efi_arch_cpu(void)539 static void __init efi_arch_cpu(void)
540 {
541 }
542
efi_arch_blexit(void)543 static void __init efi_arch_blexit(void)
544 {
545 if ( dtbfile.addr && dtbfile.size )
546 efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
547 if ( memmap )
548 efi_bs->FreePool(memmap);
549 }
550
efi_arch_halt(void)551 static void __init efi_arch_halt(void)
552 {
553 stop_cpu();
554 }
555
efi_arch_load_addr_check(EFI_LOADED_IMAGE * loaded_image)556 static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image)
557 {
558 if ( (unsigned long)loaded_image->ImageBase & ((1 << 12) - 1) )
559 blexit(L"Xen must be loaded at a 4 KByte boundary.");
560 }
561
efi_arch_use_config_file(EFI_SYSTEM_TABLE * SystemTable)562 static bool __init efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable)
563 {
564 /*
565 * For arm, we may get a device tree from GRUB (or other bootloader)
566 * that contains modules that have already been loaded into memory. In
567 * this case, we do not use a configuration file, and rely on the
568 * bootloader to have loaded all required modules and appropriate
569 * options.
570 */
571
572 fdt = lookup_fdt_config_table(SystemTable);
573 dtbfile.ptr = fdt;
574 dtbfile.size = 0; /* Config table memory can't be freed, so set size to 0 */
575 if ( !fdt || fdt_node_offset_by_compatible(fdt, 0, "multiboot,module") < 0 )
576 {
577 /*
578 * We either have no FDT, or one without modules, so we must have a
579 * Xen EFI configuration file to specify modules. (dom0 required)
580 */
581 return true;
582 }
583 PrintStr(L"Using modules provided by bootloader in FDT\r\n");
584 /* We have modules already defined in fdt, just add space. */
585 fdt = fdt_increase_size(&dtbfile, EFI_PAGE_SIZE);
586
587 return false;
588 }
589
efi_arch_console_init(UINTN cols,UINTN rows)590 static void __init efi_arch_console_init(UINTN cols, UINTN rows)
591 {
592 }
593
efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL * gop,UINTN info_size,EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * mode_info)594 static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
595 UINTN info_size,
596 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info)
597 {
598 }
599
efi_arch_flush_dcache_area(const void * vaddr,UINTN size)600 static void __init efi_arch_flush_dcache_area(const void *vaddr, UINTN size)
601 {
602 __flush_dcache_area(vaddr, size);
603 }
604
605 /*
606 * Local variables:
607 * mode: C
608 * c-file-style: "BSD"
609 * c-basic-offset: 4
610 * indent-tabs-mode: nil
611 * End:
612 */
613