root/arch/x86/xen/enlighten_hvm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xen_hvm_init_shared_info
  2. reserve_shared_info
  3. xen_hvm_init_mem_mapping
  4. init_hvm_pv_info
  5. xen_hvm_shutdown
  6. xen_hvm_crash_shutdown
  7. xen_cpu_up_prepare_hvm
  8. xen_cpu_dead_hvm
  9. xen_hvm_guest_init
  10. xen_parse_nopv
  11. xen_hvm_need_lapic
  12. xen_hvm_guest_late_init
  13. xen_platform_hvm

   1 // SPDX-License-Identifier: GPL-2.0
   2 
   3 #include <linux/acpi.h>
   4 #include <linux/cpu.h>
   5 #include <linux/kexec.h>
   6 #include <linux/memblock.h>
   7 
   8 #include <xen/features.h>
   9 #include <xen/events.h>
  10 #include <xen/interface/memory.h>
  11 
  12 #include <asm/cpu.h>
  13 #include <asm/smp.h>
  14 #include <asm/reboot.h>
  15 #include <asm/setup.h>
  16 #include <asm/hypervisor.h>
  17 #include <asm/e820/api.h>
  18 #include <asm/early_ioremap.h>
  19 
  20 #include <asm/xen/cpuid.h>
  21 #include <asm/xen/hypervisor.h>
  22 #include <asm/xen/page.h>
  23 
  24 #include "xen-ops.h"
  25 #include "mmu.h"
  26 #include "smp.h"
  27 
  28 static unsigned long shared_info_pfn;
  29 
  30 void xen_hvm_init_shared_info(void)
  31 {
  32         struct xen_add_to_physmap xatp;
  33 
  34         xatp.domid = DOMID_SELF;
  35         xatp.idx = 0;
  36         xatp.space = XENMAPSPACE_shared_info;
  37         xatp.gpfn = shared_info_pfn;
  38         if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
  39                 BUG();
  40 }
  41 
  42 static void __init reserve_shared_info(void)
  43 {
  44         u64 pa;
  45 
  46         /*
  47          * Search for a free page starting at 4kB physical address.
  48          * Low memory is preferred to avoid an EPT large page split up
  49          * by the mapping.
  50          * Starting below X86_RESERVE_LOW (usually 64kB) is fine as
  51          * the BIOS used for HVM guests is well behaved and won't
  52          * clobber memory other than the first 4kB.
  53          */
  54         for (pa = PAGE_SIZE;
  55              !e820__mapped_all(pa, pa + PAGE_SIZE, E820_TYPE_RAM) ||
  56              memblock_is_reserved(pa);
  57              pa += PAGE_SIZE)
  58                 ;
  59 
  60         shared_info_pfn = PHYS_PFN(pa);
  61 
  62         memblock_reserve(pa, PAGE_SIZE);
  63         HYPERVISOR_shared_info = early_memremap(pa, PAGE_SIZE);
  64 }
  65 
  66 static void __init xen_hvm_init_mem_mapping(void)
  67 {
  68         early_memunmap(HYPERVISOR_shared_info, PAGE_SIZE);
  69         HYPERVISOR_shared_info = __va(PFN_PHYS(shared_info_pfn));
  70 
  71         /*
  72          * The virtual address of the shared_info page has changed, so
  73          * the vcpu_info pointer for VCPU 0 is now stale.
  74          *
  75          * The prepare_boot_cpu callback will re-initialize it via
  76          * xen_vcpu_setup, but we can't rely on that to be called for
  77          * old Xen versions (xen_have_vector_callback == 0).
  78          *
  79          * It is, in any case, bad to have a stale vcpu_info pointer
  80          * so reset it now.
  81          */
  82         xen_vcpu_info_reset(0);
  83 }
  84 
  85 static void __init init_hvm_pv_info(void)
  86 {
  87         int major, minor;
  88         uint32_t eax, ebx, ecx, edx, base;
  89 
  90         base = xen_cpuid_base();
  91         eax = cpuid_eax(base + 1);
  92 
  93         major = eax >> 16;
  94         minor = eax & 0xffff;
  95         printk(KERN_INFO "Xen version %d.%d.\n", major, minor);
  96 
  97         xen_domain_type = XEN_HVM_DOMAIN;
  98 
  99         /* PVH set up hypercall page in xen_prepare_pvh(). */
 100         if (xen_pvh_domain())
 101                 pv_info.name = "Xen PVH";
 102         else {
 103                 u64 pfn;
 104                 uint32_t msr;
 105 
 106                 pv_info.name = "Xen HVM";
 107                 msr = cpuid_ebx(base + 2);
 108                 pfn = __pa(hypercall_page);
 109                 wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
 110         }
 111 
 112         xen_setup_features();
 113 
 114         cpuid(base + 4, &eax, &ebx, &ecx, &edx);
 115         if (eax & XEN_HVM_CPUID_VCPU_ID_PRESENT)
 116                 this_cpu_write(xen_vcpu_id, ebx);
 117         else
 118                 this_cpu_write(xen_vcpu_id, smp_processor_id());
 119 }
 120 
 121 #ifdef CONFIG_KEXEC_CORE
 122 static void xen_hvm_shutdown(void)
 123 {
 124         native_machine_shutdown();
 125         if (kexec_in_progress)
 126                 xen_reboot(SHUTDOWN_soft_reset);
 127 }
 128 
 129 static void xen_hvm_crash_shutdown(struct pt_regs *regs)
 130 {
 131         native_machine_crash_shutdown(regs);
 132         xen_reboot(SHUTDOWN_soft_reset);
 133 }
 134 #endif
 135 
 136 static int xen_cpu_up_prepare_hvm(unsigned int cpu)
 137 {
 138         int rc = 0;
 139 
 140         /*
 141          * This can happen if CPU was offlined earlier and
 142          * offlining timed out in common_cpu_die().
 143          */
 144         if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) {
 145                 xen_smp_intr_free(cpu);
 146                 xen_uninit_lock_cpu(cpu);
 147         }
 148 
 149         if (cpu_acpi_id(cpu) != U32_MAX)
 150                 per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
 151         else
 152                 per_cpu(xen_vcpu_id, cpu) = cpu;
 153         rc = xen_vcpu_setup(cpu);
 154         if (rc)
 155                 return rc;
 156 
 157         if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
 158                 xen_setup_timer(cpu);
 159 
 160         rc = xen_smp_intr_init(cpu);
 161         if (rc) {
 162                 WARN(1, "xen_smp_intr_init() for CPU %d failed: %d\n",
 163                      cpu, rc);
 164         }
 165         return rc;
 166 }
 167 
 168 static int xen_cpu_dead_hvm(unsigned int cpu)
 169 {
 170         xen_smp_intr_free(cpu);
 171 
 172         if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
 173                 xen_teardown_timer(cpu);
 174 
 175        return 0;
 176 }
 177 
 178 static void __init xen_hvm_guest_init(void)
 179 {
 180         if (xen_pv_domain())
 181                 return;
 182 
 183         init_hvm_pv_info();
 184 
 185         reserve_shared_info();
 186         xen_hvm_init_shared_info();
 187 
 188         /*
 189          * xen_vcpu is a pointer to the vcpu_info struct in the shared_info
 190          * page, we use it in the event channel upcall and in some pvclock
 191          * related functions.
 192          */
 193         xen_vcpu_info_reset(0);
 194 
 195         xen_panic_handler_init();
 196 
 197         if (xen_feature(XENFEAT_hvm_callback_vector))
 198                 xen_have_vector_callback = 1;
 199 
 200         xen_hvm_smp_init();
 201         WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_hvm, xen_cpu_dead_hvm));
 202         xen_unplug_emulated_devices();
 203         x86_init.irqs.intr_init = xen_init_IRQ;
 204         xen_hvm_init_time_ops();
 205         xen_hvm_init_mmu_ops();
 206 
 207 #ifdef CONFIG_KEXEC_CORE
 208         machine_ops.shutdown = xen_hvm_shutdown;
 209         machine_ops.crash_shutdown = xen_hvm_crash_shutdown;
 210 #endif
 211 }
 212 
 213 static __init int xen_parse_nopv(char *arg)
 214 {
 215         pr_notice("\"xen_nopv\" is deprecated, please use \"nopv\" instead\n");
 216 
 217         if (xen_cpuid_base())
 218                 nopv = true;
 219         return 0;
 220 }
 221 early_param("xen_nopv", xen_parse_nopv);
 222 
 223 bool __init xen_hvm_need_lapic(void)
 224 {
 225         if (xen_pv_domain())
 226                 return false;
 227         if (!xen_hvm_domain())
 228                 return false;
 229         if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
 230                 return false;
 231         return true;
 232 }
 233 
 234 static __init void xen_hvm_guest_late_init(void)
 235 {
 236 #ifdef CONFIG_XEN_PVH
 237         /* Test for PVH domain (PVH boot path taken overrides ACPI flags). */
 238         if (!xen_pvh &&
 239             (x86_platform.legacy.rtc || !x86_platform.legacy.no_vga))
 240                 return;
 241 
 242         /* PVH detected. */
 243         xen_pvh = true;
 244 
 245         if (nopv)
 246                 panic("\"nopv\" and \"xen_nopv\" parameters are unsupported in PVH guest.");
 247 
 248         /* Make sure we don't fall back to (default) ACPI_IRQ_MODEL_PIC. */
 249         if (!nr_ioapics && acpi_irq_model == ACPI_IRQ_MODEL_PIC)
 250                 acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
 251 
 252         machine_ops.emergency_restart = xen_emergency_restart;
 253         pv_info.name = "Xen PVH";
 254 #endif
 255 }
 256 
 257 static uint32_t __init xen_platform_hvm(void)
 258 {
 259         uint32_t xen_domain = xen_cpuid_base();
 260         struct x86_hyper_init *h = &x86_hyper_xen_hvm.init;
 261 
 262         if (xen_pv_domain())
 263                 return 0;
 264 
 265         if (xen_pvh_domain() && nopv) {
 266                 /* Guest booting via the Xen-PVH boot entry goes here */
 267                 pr_info("\"nopv\" parameter is ignored in PVH guest\n");
 268                 nopv = false;
 269         } else if (nopv && xen_domain) {
 270                 /*
 271                  * Guest booting via normal boot entry (like via grub2) goes
 272                  * here.
 273                  *
 274                  * Use interface functions for bare hardware if nopv,
 275                  * xen_hvm_guest_late_init is an exception as we need to
 276                  * detect PVH and panic there.
 277                  */
 278                 h->init_platform = x86_init_noop;
 279                 h->x2apic_available = bool_x86_init_noop;
 280                 h->init_mem_mapping = x86_init_noop;
 281                 h->init_after_bootmem = x86_init_noop;
 282                 h->guest_late_init = xen_hvm_guest_late_init;
 283                 x86_hyper_xen_hvm.runtime.pin_vcpu = x86_op_int_noop;
 284         }
 285         return xen_domain;
 286 }
 287 
 288 struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
 289         .name                   = "Xen HVM",
 290         .detect                 = xen_platform_hvm,
 291         .type                   = X86_HYPER_XEN_HVM,
 292         .init.init_platform     = xen_hvm_guest_init,
 293         .init.x2apic_available  = xen_x2apic_para_available,
 294         .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
 295         .init.guest_late_init   = xen_hvm_guest_late_init,
 296         .runtime.pin_vcpu       = xen_pin_vcpu,
 297         .ignore_nopv            = true,
 298 };

/* [<][>][^][v][top][bottom][index][help] */