diff options
| -rw-r--r-- | arch/x86/include/asm/hypervisor.h | 25 | ||||
| -rw-r--r-- | arch/x86/include/asm/x86_init.h | 24 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 54 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/vmware.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/kvm.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/x86_init.c | 9 | ||||
| -rw-r--r-- | arch/x86/mm/init.c | 2 | ||||
| -rw-r--r-- | arch/x86/xen/enlighten_hvm.c | 8 | ||||
| -rw-r--r-- | arch/x86/xen/enlighten_pv.c | 2 | ||||
| -rw-r--r-- | include/linux/hypervisor.h | 8 |
12 files changed, 81 insertions, 61 deletions
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index 0ead9dbb9130..0eca7239a7aa 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #ifdef CONFIG_HYPERVISOR_GUEST | 23 | #ifdef CONFIG_HYPERVISOR_GUEST |
| 24 | 24 | ||
| 25 | #include <asm/kvm_para.h> | 25 | #include <asm/kvm_para.h> |
| 26 | #include <asm/x86_init.h> | ||
| 26 | #include <asm/xen/hypervisor.h> | 27 | #include <asm/xen/hypervisor.h> |
| 27 | 28 | ||
| 28 | /* | 29 | /* |
| @@ -35,17 +36,11 @@ struct hypervisor_x86 { | |||
| 35 | /* Detection routine */ | 36 | /* Detection routine */ |
| 36 | uint32_t (*detect)(void); | 37 | uint32_t (*detect)(void); |
| 37 | 38 | ||
| 38 | /* Platform setup (run once per boot) */ | 39 | /* init time callbacks */ |
| 39 | void (*init_platform)(void); | 40 | struct x86_hyper_init init; |
| 40 | 41 | ||
| 41 | /* X2APIC detection (run once per boot) */ | 42 | /* runtime callbacks */ |
| 42 | bool (*x2apic_available)(void); | 43 | struct x86_hyper_runtime runtime; |
| 43 | |||
| 44 | /* pin current vcpu to specified physical cpu (run rarely) */ | ||
| 45 | void (*pin_vcpu)(int); | ||
| 46 | |||
| 47 | /* called during init_mem_mapping() to setup early mappings. */ | ||
| 48 | void (*init_mem_mapping)(void); | ||
| 49 | }; | 44 | }; |
| 50 | 45 | ||
| 51 | extern const struct hypervisor_x86 *x86_hyper; | 46 | extern const struct hypervisor_x86 *x86_hyper; |
| @@ -58,17 +53,7 @@ extern const struct hypervisor_x86 x86_hyper_xen_hvm; | |||
| 58 | extern const struct hypervisor_x86 x86_hyper_kvm; | 53 | extern const struct hypervisor_x86 x86_hyper_kvm; |
| 59 | 54 | ||
| 60 | extern void init_hypervisor_platform(void); | 55 | extern void init_hypervisor_platform(void); |
| 61 | extern bool hypervisor_x2apic_available(void); | ||
| 62 | extern void hypervisor_pin_vcpu(int cpu); | ||
| 63 | |||
| 64 | static inline void hypervisor_init_mem_mapping(void) | ||
| 65 | { | ||
| 66 | if (x86_hyper && x86_hyper->init_mem_mapping) | ||
| 67 | x86_hyper->init_mem_mapping(); | ||
| 68 | } | ||
| 69 | #else | 56 | #else |
| 70 | static inline void init_hypervisor_platform(void) { } | 57 | static inline void init_hypervisor_platform(void) { } |
| 71 | static inline bool hypervisor_x2apic_available(void) { return false; } | ||
| 72 | static inline void hypervisor_init_mem_mapping(void) { } | ||
| 73 | #endif /* CONFIG_HYPERVISOR_GUEST */ | 58 | #endif /* CONFIG_HYPERVISOR_GUEST */ |
| 74 | #endif /* _ASM_X86_HYPERVISOR_H */ | 59 | #endif /* _ASM_X86_HYPERVISOR_H */ |
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 8a1ebf9540dd..ad15a0fda917 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h | |||
| @@ -115,6 +115,18 @@ struct x86_init_pci { | |||
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | /** | 117 | /** |
| 118 | * struct x86_hyper_init - x86 hypervisor init functions | ||
| 119 | * @init_platform: platform setup | ||
| 120 | * @x2apic_available: X2APIC detection | ||
| 121 | * @init_mem_mapping: setup early mappings during init_mem_mapping() | ||
| 122 | */ | ||
| 123 | struct x86_hyper_init { | ||
| 124 | void (*init_platform)(void); | ||
| 125 | bool (*x2apic_available)(void); | ||
| 126 | void (*init_mem_mapping)(void); | ||
| 127 | }; | ||
| 128 | |||
| 129 | /** | ||
| 118 | * struct x86_init_ops - functions for platform specific setup | 130 | * struct x86_init_ops - functions for platform specific setup |
| 119 | * | 131 | * |
| 120 | */ | 132 | */ |
| @@ -127,6 +139,7 @@ struct x86_init_ops { | |||
| 127 | struct x86_init_timers timers; | 139 | struct x86_init_timers timers; |
| 128 | struct x86_init_iommu iommu; | 140 | struct x86_init_iommu iommu; |
| 129 | struct x86_init_pci pci; | 141 | struct x86_init_pci pci; |
| 142 | struct x86_hyper_init hyper; | ||
| 130 | }; | 143 | }; |
| 131 | 144 | ||
| 132 | /** | 145 | /** |
| @@ -200,6 +213,15 @@ struct x86_legacy_features { | |||
| 200 | }; | 213 | }; |
| 201 | 214 | ||
| 202 | /** | 215 | /** |
| 216 | * struct x86_hyper_runtime - x86 hypervisor specific runtime callbacks | ||
| 217 | * | ||
| 218 | * @pin_vcpu: pin current vcpu to specified physical cpu (run rarely) | ||
| 219 | */ | ||
| 220 | struct x86_hyper_runtime { | ||
| 221 | void (*pin_vcpu)(int cpu); | ||
| 222 | }; | ||
| 223 | |||
| 224 | /** | ||
| 203 | * struct x86_platform_ops - platform specific runtime functions | 225 | * struct x86_platform_ops - platform specific runtime functions |
| 204 | * @calibrate_cpu: calibrate CPU | 226 | * @calibrate_cpu: calibrate CPU |
| 205 | * @calibrate_tsc: calibrate TSC, if different from CPU | 227 | * @calibrate_tsc: calibrate TSC, if different from CPU |
| @@ -218,6 +240,7 @@ struct x86_legacy_features { | |||
| 218 | * possible in x86_early_init_platform_quirks() by | 240 | * possible in x86_early_init_platform_quirks() by |
| 219 | * only using the current x86_hardware_subarch | 241 | * only using the current x86_hardware_subarch |
| 220 | * semantics. | 242 | * semantics. |
| 243 | * @hyper: x86 hypervisor specific runtime callbacks | ||
| 221 | */ | 244 | */ |
| 222 | struct x86_platform_ops { | 245 | struct x86_platform_ops { |
| 223 | unsigned long (*calibrate_cpu)(void); | 246 | unsigned long (*calibrate_cpu)(void); |
| @@ -233,6 +256,7 @@ struct x86_platform_ops { | |||
| 233 | void (*apic_post_init)(void); | 256 | void (*apic_post_init)(void); |
| 234 | struct x86_legacy_features legacy; | 257 | struct x86_legacy_features legacy; |
| 235 | void (*set_legacy_features)(void); | 258 | void (*set_legacy_features)(void); |
| 259 | struct x86_hyper_runtime hyper; | ||
| 236 | }; | 260 | }; |
| 237 | 261 | ||
| 238 | struct pci_dev; | 262 | struct pci_dev; |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ff891772c9f8..89c7c8569e5e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
| @@ -1645,7 +1645,7 @@ static __init void try_to_enable_x2apic(int remap_mode) | |||
| 1645 | * under KVM | 1645 | * under KVM |
| 1646 | */ | 1646 | */ |
| 1647 | if (max_physical_apicid > 255 || | 1647 | if (max_physical_apicid > 255 || |
| 1648 | !hypervisor_x2apic_available()) { | 1648 | !x86_init.hyper.x2apic_available()) { |
| 1649 | pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); | 1649 | pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); |
| 1650 | x2apic_disable(); | 1650 | x2apic_disable(); |
| 1651 | return; | 1651 | return; |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index 4fa90006ac68..22226c1bf092 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
| @@ -44,51 +44,49 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = | |||
| 44 | const struct hypervisor_x86 *x86_hyper; | 44 | const struct hypervisor_x86 *x86_hyper; |
| 45 | EXPORT_SYMBOL(x86_hyper); | 45 | EXPORT_SYMBOL(x86_hyper); |
| 46 | 46 | ||
| 47 | static inline void __init | 47 | static inline const struct hypervisor_x86 * __init |
| 48 | detect_hypervisor_vendor(void) | 48 | detect_hypervisor_vendor(void) |
| 49 | { | 49 | { |
| 50 | const struct hypervisor_x86 *h, * const *p; | 50 | const struct hypervisor_x86 *h = NULL, * const *p; |
| 51 | uint32_t pri, max_pri = 0; | 51 | uint32_t pri, max_pri = 0; |
| 52 | 52 | ||
| 53 | for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { | 53 | for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { |
| 54 | h = *p; | 54 | pri = (*p)->detect(); |
| 55 | pri = h->detect(); | 55 | if (pri > max_pri) { |
| 56 | if (pri != 0 && pri > max_pri) { | ||
| 57 | max_pri = pri; | 56 | max_pri = pri; |
| 58 | x86_hyper = h; | 57 | h = *p; |
| 59 | } | 58 | } |
| 60 | } | 59 | } |
| 61 | 60 | ||
| 62 | if (max_pri) | 61 | if (h) |
| 63 | pr_info("Hypervisor detected: %s\n", x86_hyper->name); | 62 | pr_info("Hypervisor detected: %s\n", h->name); |
| 63 | |||
| 64 | return h; | ||
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | void __init init_hypervisor_platform(void) | 67 | static void __init copy_array(const void *src, void *target, unsigned int size) |
| 67 | { | 68 | { |
| 69 | unsigned int i, n = size / sizeof(void *); | ||
| 70 | const void * const *from = (const void * const *)src; | ||
| 71 | const void **to = (const void **)target; | ||
| 68 | 72 | ||
| 69 | detect_hypervisor_vendor(); | 73 | for (i = 0; i < n; i++) |
| 70 | 74 | if (from[i]) | |
| 71 | if (!x86_hyper) | 75 | to[i] = from[i]; |
| 72 | return; | ||
| 73 | |||
| 74 | if (x86_hyper->init_platform) | ||
| 75 | x86_hyper->init_platform(); | ||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | bool __init hypervisor_x2apic_available(void) | 78 | void __init init_hypervisor_platform(void) |
| 79 | { | 79 | { |
| 80 | return x86_hyper && | 80 | const struct hypervisor_x86 *h; |
| 81 | x86_hyper->x2apic_available && | ||
| 82 | x86_hyper->x2apic_available(); | ||
| 83 | } | ||
| 84 | 81 | ||
| 85 | void hypervisor_pin_vcpu(int cpu) | 82 | h = detect_hypervisor_vendor(); |
| 86 | { | 83 | |
| 87 | if (!x86_hyper) | 84 | if (!h) |
| 88 | return; | 85 | return; |
| 89 | 86 | ||
| 90 | if (x86_hyper->pin_vcpu) | 87 | copy_array(&h->init, &x86_init.hyper, sizeof(h->init)); |
| 91 | x86_hyper->pin_vcpu(cpu); | 88 | copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime)); |
| 92 | else | 89 | |
| 93 | WARN_ONCE(1, "vcpu pinning requested but not supported!\n"); | 90 | x86_hyper = h; |
| 91 | x86_init.hyper.init_platform(); | ||
| 94 | } | 92 | } |
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 236324e83a3a..6bb84d655e4b 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c | |||
| @@ -257,6 +257,6 @@ static void __init ms_hyperv_init_platform(void) | |||
| 257 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | 257 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { |
| 258 | .name = "Microsoft Hyper-V", | 258 | .name = "Microsoft Hyper-V", |
| 259 | .detect = ms_hyperv_platform, | 259 | .detect = ms_hyperv_platform, |
| 260 | .init_platform = ms_hyperv_init_platform, | 260 | .init.init_platform = ms_hyperv_init_platform, |
| 261 | }; | 261 | }; |
| 262 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); | 262 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); |
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 40ed26852ebd..4804c1d063c8 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c | |||
| @@ -208,7 +208,7 @@ static bool __init vmware_legacy_x2apic_available(void) | |||
| 208 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { | 208 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { |
| 209 | .name = "VMware", | 209 | .name = "VMware", |
| 210 | .detect = vmware_platform, | 210 | .detect = vmware_platform, |
| 211 | .init_platform = vmware_platform_setup, | 211 | .init.init_platform = vmware_platform_setup, |
| 212 | .x2apic_available = vmware_legacy_x2apic_available, | 212 | .init.x2apic_available = vmware_legacy_x2apic_available, |
| 213 | }; | 213 | }; |
| 214 | EXPORT_SYMBOL(x86_hyper_vmware); | 214 | EXPORT_SYMBOL(x86_hyper_vmware); |
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 8bb9594d0761..9dca8437c795 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c | |||
| @@ -547,7 +547,7 @@ static uint32_t __init kvm_detect(void) | |||
| 547 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { | 547 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { |
| 548 | .name = "KVM", | 548 | .name = "KVM", |
| 549 | .detect = kvm_detect, | 549 | .detect = kvm_detect, |
| 550 | .x2apic_available = kvm_para_available, | 550 | .init.x2apic_available = kvm_para_available, |
| 551 | }; | 551 | }; |
| 552 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); | 552 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); |
| 553 | 553 | ||
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index a088b2c47f73..5b2d10c1973a 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
| @@ -28,6 +28,8 @@ void x86_init_noop(void) { } | |||
| 28 | void __init x86_init_uint_noop(unsigned int unused) { } | 28 | void __init x86_init_uint_noop(unsigned int unused) { } |
| 29 | int __init iommu_init_noop(void) { return 0; } | 29 | int __init iommu_init_noop(void) { return 0; } |
| 30 | void iommu_shutdown_noop(void) { } | 30 | void iommu_shutdown_noop(void) { } |
| 31 | bool __init bool_x86_init_noop(void) { return false; } | ||
| 32 | void x86_op_int_noop(int cpu) { } | ||
| 31 | 33 | ||
| 32 | /* | 34 | /* |
| 33 | * The platform setup functions are preset with the default functions | 35 | * The platform setup functions are preset with the default functions |
| @@ -81,6 +83,12 @@ struct x86_init_ops x86_init __initdata = { | |||
| 81 | .init_irq = x86_default_pci_init_irq, | 83 | .init_irq = x86_default_pci_init_irq, |
| 82 | .fixup_irqs = x86_default_pci_fixup_irqs, | 84 | .fixup_irqs = x86_default_pci_fixup_irqs, |
| 83 | }, | 85 | }, |
| 86 | |||
| 87 | .hyper = { | ||
| 88 | .init_platform = x86_init_noop, | ||
| 89 | .x2apic_available = bool_x86_init_noop, | ||
| 90 | .init_mem_mapping = x86_init_noop, | ||
| 91 | }, | ||
| 84 | }; | 92 | }; |
| 85 | 93 | ||
| 86 | struct x86_cpuinit_ops x86_cpuinit = { | 94 | struct x86_cpuinit_ops x86_cpuinit = { |
| @@ -101,6 +109,7 @@ struct x86_platform_ops x86_platform __ro_after_init = { | |||
| 101 | .get_nmi_reason = default_get_nmi_reason, | 109 | .get_nmi_reason = default_get_nmi_reason, |
| 102 | .save_sched_clock_state = tsc_save_sched_clock_state, | 110 | .save_sched_clock_state = tsc_save_sched_clock_state, |
| 103 | .restore_sched_clock_state = tsc_restore_sched_clock_state, | 111 | .restore_sched_clock_state = tsc_restore_sched_clock_state, |
| 112 | .hyper.pin_vcpu = x86_op_int_noop, | ||
| 104 | }; | 113 | }; |
| 105 | 114 | ||
| 106 | EXPORT_SYMBOL_GPL(x86_platform); | 115 | EXPORT_SYMBOL_GPL(x86_platform); |
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index af5c1ed21d43..a22c2b95e513 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
| @@ -671,7 +671,7 @@ void __init init_mem_mapping(void) | |||
| 671 | load_cr3(swapper_pg_dir); | 671 | load_cr3(swapper_pg_dir); |
| 672 | __flush_tlb_all(); | 672 | __flush_tlb_all(); |
| 673 | 673 | ||
| 674 | hypervisor_init_mem_mapping(); | 674 | x86_init.hyper.init_mem_mapping(); |
| 675 | 675 | ||
| 676 | early_memtest(0, max_pfn_mapped << PAGE_SHIFT); | 676 | early_memtest(0, max_pfn_mapped << PAGE_SHIFT); |
| 677 | } | 677 | } |
diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index de503c225ae1..7b1622089f96 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c | |||
| @@ -229,9 +229,9 @@ static uint32_t __init xen_platform_hvm(void) | |||
| 229 | const struct hypervisor_x86 x86_hyper_xen_hvm = { | 229 | const struct hypervisor_x86 x86_hyper_xen_hvm = { |
| 230 | .name = "Xen HVM", | 230 | .name = "Xen HVM", |
| 231 | .detect = xen_platform_hvm, | 231 | .detect = xen_platform_hvm, |
| 232 | .init_platform = xen_hvm_guest_init, | 232 | .init.init_platform = xen_hvm_guest_init, |
| 233 | .pin_vcpu = xen_pin_vcpu, | 233 | .init.x2apic_available = xen_x2apic_para_available, |
| 234 | .x2apic_available = xen_x2apic_para_available, | 234 | .init.init_mem_mapping = xen_hvm_init_mem_mapping, |
| 235 | .init_mem_mapping = xen_hvm_init_mem_mapping, | 235 | .runtime.pin_vcpu = xen_pin_vcpu, |
| 236 | }; | 236 | }; |
| 237 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | 237 | EXPORT_SYMBOL(x86_hyper_xen_hvm); |
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index d4396e27b1fb..69d1a7054ddb 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c | |||
| @@ -1463,6 +1463,6 @@ static uint32_t __init xen_platform_pv(void) | |||
| 1463 | const struct hypervisor_x86 x86_hyper_xen_pv = { | 1463 | const struct hypervisor_x86 x86_hyper_xen_pv = { |
| 1464 | .name = "Xen PV", | 1464 | .name = "Xen PV", |
| 1465 | .detect = xen_platform_pv, | 1465 | .detect = xen_platform_pv, |
| 1466 | .pin_vcpu = xen_pin_vcpu, | 1466 | .runtime.pin_vcpu = xen_pin_vcpu, |
| 1467 | }; | 1467 | }; |
| 1468 | EXPORT_SYMBOL(x86_hyper_xen_pv); | 1468 | EXPORT_SYMBOL(x86_hyper_xen_pv); |
diff --git a/include/linux/hypervisor.h b/include/linux/hypervisor.h index b4054fd5b6f6..b19563f9a8eb 100644 --- a/include/linux/hypervisor.h +++ b/include/linux/hypervisor.h | |||
| @@ -7,8 +7,12 @@ | |||
| 7 | * Juergen Gross <jgross@suse.com> | 7 | * Juergen Gross <jgross@suse.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #ifdef CONFIG_HYPERVISOR_GUEST | 10 | #ifdef CONFIG_X86 |
| 11 | #include <asm/hypervisor.h> | 11 | #include <asm/x86_init.h> |
| 12 | static inline void hypervisor_pin_vcpu(int cpu) | ||
| 13 | { | ||
| 14 | x86_platform.hyper.pin_vcpu(cpu); | ||
| 15 | } | ||
| 12 | #else | 16 | #else |
| 13 | static inline void hypervisor_pin_vcpu(int cpu) | 17 | static inline void hypervisor_pin_vcpu(int cpu) |
| 14 | { | 18 | { |
