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