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->Attribute & EFI_MEMORY_WB &&
153 (desc_ptr->Type == EfiConventionalMemory ||
154 desc_ptr->Type == EfiLoaderCode ||
155 desc_ptr->Type == EfiLoaderData ||
156 (!map_bs &&
157 (desc_ptr->Type == EfiBootServicesCode ||
158 desc_ptr->Type == EfiBootServicesData))) )
159 {
160 if ( !meminfo_add_bank(&bootinfo.mem, desc_ptr) )
161 {
162 PrintStr(L"Warning: All " __stringify(NR_MEM_BANKS)
163 " bootinfo mem banks exhausted.\r\n");
164 break;
165 }
166 }
167 #ifdef CONFIG_ACPI
168 else if ( desc_ptr->Type == EfiACPIReclaimMemory )
169 {
170 if ( !meminfo_add_bank(&bootinfo.acpi, desc_ptr) )
171 {
172 PrintStr(L"Error: All " __stringify(NR_MEM_BANKS)
173 " acpi meminfo mem banks exhausted.\r\n");
174 return EFI_LOAD_ERROR;
175 }
176 }
177 #endif
178 desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
179 }
180
181 return EFI_SUCCESS;
182 }
183
184 /*
185 * Add the FDT nodes for the standard EFI information, which consist
186 * of the System table address, the address of the final EFI memory map,
187 * and memory map information.
188 */
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)189 EFI_STATUS __init fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table,
190 void *fdt,
191 EFI_MEMORY_DESCRIPTOR *memory_map,
192 UINTN map_size,
193 UINTN desc_size,
194 UINT32 desc_ver)
195 {
196 int node;
197 int status;
198 u32 fdt_val32;
199 u64 fdt_val64;
200 int prev;
201 int num_rsv;
202
203 /*
204 * Delete any memory nodes present. The EFI memory map is the only
205 * memory description provided to Xen.
206 */
207 prev = 0;
208 for (;;)
209 {
210 const char *type;
211 int len;
212
213 node = fdt_next_node(fdt, prev, NULL);
214 if ( node < 0 )
215 break;
216
217 type = fdt_getprop(fdt, node, "device_type", &len);
218 if ( type && strncmp(type, "memory", len) == 0 )
219 {
220 fdt_del_node(fdt, node);
221 continue;
222 }
223
224 prev = node;
225 }
226
227 /*
228 * Delete all memory reserve map entries. When booting via UEFI,
229 * kernel will use the UEFI memory map to find reserved regions.
230 */
231 num_rsv = fdt_num_mem_rsv(fdt);
232 while ( num_rsv-- > 0 )
233 fdt_del_mem_rsv(fdt, num_rsv);
234
235 /* Add FDT entries for EFI runtime services in chosen node. */
236 node = fdt_subnode_offset(fdt, 0, "chosen");
237 if ( node < 0 )
238 {
239 node = fdt_add_subnode(fdt, 0, "chosen");
240 if ( node < 0 )
241 {
242 status = node; /* node is error code when negative */
243 goto fdt_set_fail;
244 }
245 }
246
247 fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)sys_table);
248 status = fdt_setprop(fdt, node, "linux,uefi-system-table",
249 &fdt_val64, sizeof(fdt_val64));
250 if ( status )
251 goto fdt_set_fail;
252
253 fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)memory_map);
254 status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
255 &fdt_val64, sizeof(fdt_val64));
256 if ( status )
257 goto fdt_set_fail;
258
259 fdt_val32 = cpu_to_fdt32(map_size);
260 status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
261 &fdt_val32, sizeof(fdt_val32));
262 if ( status )
263 goto fdt_set_fail;
264
265 fdt_val32 = cpu_to_fdt32(desc_size);
266 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
267 &fdt_val32, sizeof(fdt_val32));
268 if ( status )
269 goto fdt_set_fail;
270
271 fdt_val32 = cpu_to_fdt32(desc_ver);
272 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
273 &fdt_val32, sizeof(fdt_val32));
274 if ( status )
275 goto fdt_set_fail;
276
277 return EFI_SUCCESS;
278
279 fdt_set_fail:
280 if ( status == -FDT_ERR_NOSPACE )
281 return EFI_BUFFER_TOO_SMALL;
282
283 return EFI_LOAD_ERROR;
284 }
285
286 /*
287 * Allocates new memory for a larger FDT, and frees existing memory if
288 * struct file size is non-zero. Updates file struct with new memory
289 * address/size for later freeing. If fdtfile.ptr is NULL, an empty FDT
290 * is created.
291 */
fdt_increase_size(struct file * fdtfile,int add_size)292 static void __init *fdt_increase_size(struct file *fdtfile, int add_size)
293 {
294 EFI_STATUS status;
295 EFI_PHYSICAL_ADDRESS fdt_addr;
296 int fdt_size;
297 int pages;
298 void *new_fdt;
299
300 if ( fdtfile->ptr )
301 fdt_size = fdt_totalsize(fdtfile->ptr);
302 else
303 fdt_size = 0;
304
305 pages = PFN_UP(fdt_size + add_size);
306 status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData,
307 pages, &fdt_addr);
308
309 if ( status != EFI_SUCCESS )
310 return NULL;
311
312 new_fdt = (void *)fdt_addr;
313
314 if ( fdt_size )
315 {
316 if ( fdt_open_into(dtbfile.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
317 return NULL;
318 }
319 else
320 {
321 /*
322 * Create an empty FDT if not provided one, which is the expected case
323 * when booted from the UEFI shell on an ACPI only system. We will use
324 * the FDT to pass the EFI information to Xen, as well as nodes for
325 * any modules the stub loads. The ACPI tables are part of the UEFI
326 * system table that is passed in the FDT.
327 */
328 if ( fdt_create_empty_tree(new_fdt, pages * EFI_PAGE_SIZE) )
329 return NULL;
330 }
331
332 /*
333 * Now that we have the new FDT allocated and copied, free the
334 * original and update the struct file so that the error handling
335 * code will free it. If the original FDT came from a configuration
336 * table, we don't own that memory and can't free it.
337 */
338 if ( dtbfile.size )
339 efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
340
341 /* Update 'file' info for new memory so we clean it up on error exits */
342 dtbfile.addr = fdt_addr;
343 dtbfile.size = pages * EFI_PAGE_SIZE;
344 return new_fdt;
345 }
346
efi_arch_relocate_image(unsigned long delta)347 static void __init efi_arch_relocate_image(unsigned long delta)
348 {
349 }
350
efi_arch_process_memory_map(EFI_SYSTEM_TABLE * SystemTable,void * map,UINTN map_size,UINTN desc_size,UINT32 desc_ver)351 static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
352 void *map,
353 UINTN map_size,
354 UINTN desc_size,
355 UINT32 desc_ver)
356 {
357 EFI_STATUS status;
358
359 status = efi_process_memory_map_bootinfo(map, map_size, desc_size);
360 if ( EFI_ERROR(status) )
361 blexit(L"EFI memory map processing failed");
362
363 status = fdt_add_uefi_nodes(SystemTable, fdt, map, map_size, desc_size,
364 desc_ver);
365 if ( EFI_ERROR(status) )
366 PrintErrMesg(L"Updating FDT failed", status);
367 }
368
efi_arch_pre_exit_boot(void)369 static void __init efi_arch_pre_exit_boot(void)
370 {
371 }
372
efi_arch_post_exit_boot(void)373 static void __init noreturn efi_arch_post_exit_boot(void)
374 {
375 efi_xen_start(fdt, fdt_totalsize(fdt));
376 }
377
efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle,char * section)378 static void __init efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle, char *section)
379 {
380 union string name;
381
382 /*
383 * The DTB must be processed before any other entries in the configuration
384 * file, as the DTB is updated as modules are loaded.
385 */
386 name.s = get_value(&cfg, section, "dtb");
387 if ( name.s )
388 {
389 split_string(name.s);
390 read_file(dir_handle, s2w(&name), &dtbfile, NULL);
391 efi_bs->FreePool(name.w);
392 }
393 fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE);
394 if ( !fdt )
395 blexit(L"Unable to create new FDT");
396 }
397
efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle,char * section)398 static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section)
399 {
400 }
401
efi_arch_allocate_mmap_buffer(UINTN map_size)402 static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size)
403 {
404 void *ptr;
405 EFI_STATUS status;
406
407 status = efi_bs->AllocatePool(EfiLoaderData, map_size, &ptr);
408 if ( status != EFI_SUCCESS )
409 return NULL;
410 return ptr;
411 }
412
efi_arch_edd(void)413 static void __init efi_arch_edd(void)
414 {
415 }
416
efi_arch_memory_setup(void)417 static void __init efi_arch_memory_setup(void)
418 {
419 }
420
efi_arch_handle_cmdline(CHAR16 * image_name,CHAR16 * cmdline_options,char * cfgfile_options)421 static void __init efi_arch_handle_cmdline(CHAR16 *image_name,
422 CHAR16 *cmdline_options,
423 char *cfgfile_options)
424 {
425 union string name;
426 char *buf;
427 EFI_STATUS status;
428 int prop_len;
429 int chosen;
430
431 /* locate chosen node, which is where we add Xen module info. */
432 chosen = fdt_subnode_offset(fdt, 0, "chosen");
433 if ( chosen < 0 )
434 blexit(L"Unable to find chosen node");
435
436 status = efi_bs->AllocatePool(EfiBootServicesData, EFI_PAGE_SIZE, (void **)&buf);
437 if ( EFI_ERROR(status) )
438 PrintErrMesg(L"Unable to allocate string buffer", status);
439
440 if ( image_name )
441 {
442 name.w = image_name;
443 w2s(&name);
444 }
445 else
446 name.s = "xen";
447
448 prop_len = 0;
449 prop_len += snprintf(buf + prop_len,
450 EFI_PAGE_SIZE - prop_len, "%s", name.s);
451 if ( prop_len >= EFI_PAGE_SIZE )
452 blexit(L"FDT string overflow");
453
454 if ( cfgfile_options )
455 {
456 prop_len += snprintf(buf + prop_len,
457 EFI_PAGE_SIZE - prop_len, " %s", cfgfile_options);
458 if ( prop_len >= EFI_PAGE_SIZE )
459 blexit(L"FDT string overflow");
460 }
461
462 if ( cmdline_options )
463 {
464 name.w = cmdline_options;
465 w2s(&name);
466 }
467 else
468 name.s = NULL;
469
470 if ( name.s )
471 {
472 prop_len += snprintf(buf + prop_len,
473 EFI_PAGE_SIZE - prop_len, " %s", name.s);
474 if ( prop_len >= EFI_PAGE_SIZE )
475 blexit(L"FDT string overflow");
476 }
477
478 if ( fdt_setprop_string(fdt, chosen, "xen,xen-bootargs", buf) < 0 )
479 blexit(L"Unable to set xen,xen-bootargs property.");
480
481 efi_bs->FreePool(buf);
482 }
483
efi_arch_handle_module(struct file * file,const CHAR16 * name,char * options)484 static void __init efi_arch_handle_module(struct file *file, const CHAR16 *name,
485 char *options)
486 {
487 int node;
488 int chosen;
489 int addr_len, size_len;
490
491 if ( file == &dtbfile )
492 return;
493 chosen = setup_chosen_node(fdt, &addr_len, &size_len);
494 if ( chosen < 0 )
495 blexit(L"Unable to setup chosen node");
496
497 if ( file == &ramdisk )
498 {
499 char ramdisk_compat[] = "multiboot,ramdisk\0multiboot,module";
500 node = fdt_add_subnode(fdt, chosen, "ramdisk");
501 if ( node < 0 )
502 blexit(L"Unable to add ramdisk FDT node.");
503 if ( fdt_setprop(fdt, node, "compatible", ramdisk_compat,
504 sizeof(ramdisk_compat)) < 0 )
505 blexit(L"Unable to set compatible property.");
506 if ( fdt_set_reg(fdt, node, addr_len, size_len, ramdisk.addr,
507 ramdisk.size) < 0 )
508 blexit(L"Unable to set reg property.");
509 }
510 else if ( file == &xsm )
511 {
512 char xsm_compat[] = "xen,xsm-policy\0multiboot,module";
513 node = fdt_add_subnode(fdt, chosen, "xsm");
514 if ( node < 0 )
515 blexit(L"Unable to add xsm FDT node.");
516 if ( fdt_setprop(fdt, node, "compatible", xsm_compat,
517 sizeof(xsm_compat)) < 0 )
518 blexit(L"Unable to set compatible property.");
519 if ( fdt_set_reg(fdt, node, addr_len, size_len, xsm.addr,
520 xsm.size) < 0 )
521 blexit(L"Unable to set reg property.");
522 }
523 else if ( file == &kernel )
524 {
525 char kernel_compat[] = "multiboot,kernel\0multiboot,module";
526 node = fdt_add_subnode(fdt, chosen, "kernel");
527 if ( node < 0 )
528 blexit(L"Unable to add dom0 FDT node.");
529 if ( fdt_setprop(fdt, node, "compatible", kernel_compat,
530 sizeof(kernel_compat)) < 0 )
531 blexit(L"Unable to set compatible property.");
532 if ( options && fdt_setprop_string(fdt, node, "bootargs", options) < 0 )
533 blexit(L"Unable to set bootargs property.");
534 if ( fdt_set_reg(fdt, node, addr_len, size_len, kernel.addr,
535 kernel.size) < 0 )
536 blexit(L"Unable to set reg property.");
537 }
538 else
539 blexit(L"Unknown module type");
540 }
541
efi_arch_cpu(void)542 static void __init efi_arch_cpu(void)
543 {
544 }
545
efi_arch_blexit(void)546 static void __init efi_arch_blexit(void)
547 {
548 if ( dtbfile.addr && dtbfile.size )
549 efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
550 if ( memmap )
551 efi_bs->FreePool(memmap);
552 }
553
efi_arch_halt(void)554 static void __init efi_arch_halt(void)
555 {
556 stop_cpu();
557 }
558
efi_arch_load_addr_check(EFI_LOADED_IMAGE * loaded_image)559 static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image)
560 {
561 if ( (unsigned long)loaded_image->ImageBase & ((1 << 12) - 1) )
562 blexit(L"Xen must be loaded at a 4 KByte boundary.");
563 }
564
efi_arch_use_config_file(EFI_SYSTEM_TABLE * SystemTable)565 static bool __init efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable)
566 {
567 /*
568 * For arm, we may get a device tree from GRUB (or other bootloader)
569 * that contains modules that have already been loaded into memory. In
570 * this case, we do not use a configuration file, and rely on the
571 * bootloader to have loaded all required modules and appropriate
572 * options.
573 */
574
575 fdt = lookup_fdt_config_table(SystemTable);
576 dtbfile.ptr = fdt;
577 dtbfile.size = 0; /* Config table memory can't be freed, so set size to 0 */
578 if ( !fdt || fdt_node_offset_by_compatible(fdt, 0, "multiboot,module") < 0 )
579 {
580 /*
581 * We either have no FDT, or one without modules, so we must have a
582 * Xen EFI configuration file to specify modules. (dom0 required)
583 */
584 return true;
585 }
586 PrintStr(L"Using modules provided by bootloader in FDT\r\n");
587 /* We have modules already defined in fdt, just add space. */
588 fdt = fdt_increase_size(&dtbfile, EFI_PAGE_SIZE);
589
590 return false;
591 }
592
efi_arch_console_init(UINTN cols,UINTN rows)593 static void __init efi_arch_console_init(UINTN cols, UINTN rows)
594 {
595 }
596
efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL * gop,UINTN info_size,EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * mode_info)597 static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
598 UINTN info_size,
599 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info)
600 {
601 }
602
efi_arch_flush_dcache_area(const void * vaddr,UINTN size)603 static void __init efi_arch_flush_dcache_area(const void *vaddr, UINTN size)
604 {
605 __flush_dcache_area(vaddr, size);
606 }
607
608 /*
609 * Local variables:
610 * mode: C
611 * c-file-style: "BSD"
612 * c-basic-offset: 4
613 * indent-tabs-mode: nil
614 * End:
615 */
616