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