Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/acpi.h>
0003 
0004 #include <xen/hvc-console.h>
0005 
0006 #include <asm/io_apic.h>
0007 #include <asm/hypervisor.h>
0008 #include <asm/e820/api.h>
0009 #include <asm/x86_init.h>
0010 
0011 #include <asm/xen/interface.h>
0012 
0013 #include <xen/xen.h>
0014 #include <xen/interface/hvm/start_info.h>
0015 
0016 /*
0017  * PVH variables.
0018  *
0019  * pvh_bootparams and pvh_start_info need to live in a data segment since
0020  * they are used after startup_{32|64}, which clear .bss, are invoked.
0021  */
0022 struct boot_params __initdata pvh_bootparams;
0023 struct hvm_start_info __initdata pvh_start_info;
0024 
0025 const unsigned int __initconst pvh_start_info_sz = sizeof(pvh_start_info);
0026 
0027 static u64 __init pvh_get_root_pointer(void)
0028 {
0029     return pvh_start_info.rsdp_paddr;
0030 }
0031 
0032 /*
0033  * Xen guests are able to obtain the memory map from the hypervisor via the
0034  * HYPERVISOR_memory_op hypercall.
0035  * If we are trying to boot a Xen PVH guest, it is expected that the kernel
0036  * will have been configured to provide an override for this routine to do
0037  * just that.
0038  */
0039 void __init __weak mem_map_via_hcall(struct boot_params *ptr __maybe_unused)
0040 {
0041     xen_raw_printk("Error: Could not find memory map\n");
0042     BUG();
0043 }
0044 
0045 static void __init init_pvh_bootparams(bool xen_guest)
0046 {
0047     if ((pvh_start_info.version > 0) && (pvh_start_info.memmap_entries)) {
0048         struct hvm_memmap_table_entry *ep;
0049         int i;
0050 
0051         ep = __va(pvh_start_info.memmap_paddr);
0052         pvh_bootparams.e820_entries = pvh_start_info.memmap_entries;
0053 
0054         for (i = 0; i < pvh_bootparams.e820_entries ; i++, ep++) {
0055             pvh_bootparams.e820_table[i].addr = ep->addr;
0056             pvh_bootparams.e820_table[i].size = ep->size;
0057             pvh_bootparams.e820_table[i].type = ep->type;
0058         }
0059     } else if (xen_guest) {
0060         mem_map_via_hcall(&pvh_bootparams);
0061     } else {
0062         /* Non-xen guests are not supported by version 0 */
0063         BUG();
0064     }
0065 
0066     if (pvh_bootparams.e820_entries < E820_MAX_ENTRIES_ZEROPAGE - 1) {
0067         pvh_bootparams.e820_table[pvh_bootparams.e820_entries].addr =
0068             ISA_START_ADDRESS;
0069         pvh_bootparams.e820_table[pvh_bootparams.e820_entries].size =
0070             ISA_END_ADDRESS - ISA_START_ADDRESS;
0071         pvh_bootparams.e820_table[pvh_bootparams.e820_entries].type =
0072             E820_TYPE_RESERVED;
0073         pvh_bootparams.e820_entries++;
0074     } else
0075         xen_raw_printk("Warning: Can fit ISA range into e820\n");
0076 
0077     pvh_bootparams.hdr.cmd_line_ptr =
0078         pvh_start_info.cmdline_paddr;
0079 
0080     /* The first module is always ramdisk. */
0081     if (pvh_start_info.nr_modules) {
0082         struct hvm_modlist_entry *modaddr =
0083             __va(pvh_start_info.modlist_paddr);
0084         pvh_bootparams.hdr.ramdisk_image = modaddr->paddr;
0085         pvh_bootparams.hdr.ramdisk_size = modaddr->size;
0086     }
0087 
0088     /*
0089      * See Documentation/x86/boot.rst.
0090      *
0091      * Version 2.12 supports Xen entry point but we will use default x86/PC
0092      * environment (i.e. hardware_subarch 0).
0093      */
0094     pvh_bootparams.hdr.version = (2 << 8) | 12;
0095     pvh_bootparams.hdr.type_of_loader = ((xen_guest ? 0x9 : 0xb) << 4) | 0;
0096 
0097     x86_init.acpi.get_root_pointer = pvh_get_root_pointer;
0098 }
0099 
0100 /*
0101  * If we are trying to boot a Xen PVH guest, it is expected that the kernel
0102  * will have been configured to provide the required override for this routine.
0103  */
0104 void __init __weak xen_pvh_init(struct boot_params *boot_params)
0105 {
0106     xen_raw_printk("Error: Missing xen PVH initialization\n");
0107     BUG();
0108 }
0109 
0110 static void __init hypervisor_specific_init(bool xen_guest)
0111 {
0112     if (xen_guest)
0113         xen_pvh_init(&pvh_bootparams);
0114 }
0115 
0116 /*
0117  * This routine (and those that it might call) should not use
0118  * anything that lives in .bss since that segment will be cleared later.
0119  */
0120 void __init xen_prepare_pvh(void)
0121 {
0122 
0123     u32 msr = xen_cpuid_base();
0124     bool xen_guest = !!msr;
0125 
0126     if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
0127         xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
0128                 pvh_start_info.magic);
0129         BUG();
0130     }
0131 
0132     memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
0133 
0134     hypervisor_specific_init(xen_guest);
0135 
0136     init_pvh_bootparams(xen_guest);
0137 }