|
2 | 2 |
|
3 | 3 | #include <linux/console.h> |
4 | 4 | #include <linux/cpu.h> |
| 5 | +#include <linux/instrumentation.h> |
5 | 6 | #include <linux/kexec.h> |
6 | 7 | #include <linux/memblock.h> |
7 | 8 | #include <linux/slab.h> |
|
23 | 24 |
|
24 | 25 | EXPORT_SYMBOL_GPL(hypercall_page); |
25 | 26 |
|
| 27 | +DEFINE_STATIC_CALL(xen_hypercall, xen_hypercall_hvm); |
| 28 | +EXPORT_STATIC_CALL_TRAMP(xen_hypercall); |
| 29 | + |
26 | 30 | /* |
27 | 31 | * Pointer to the xen_vcpu_info structure or |
28 | 32 | * &HYPERVISOR_shared_info->vcpu_info[cpu]. See xen_hvm_init_shared_info |
@@ -68,6 +72,67 @@ EXPORT_SYMBOL(xen_start_flags); |
68 | 72 | */ |
69 | 73 | struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; |
70 | 74 |
|
| 75 | +static __ref void xen_get_vendor(void) |
| 76 | +{ |
| 77 | + init_cpu_devs(); |
| 78 | + cpu_detect(&boot_cpu_data); |
| 79 | + get_cpu_vendor(&boot_cpu_data); |
| 80 | +} |
| 81 | + |
| 82 | +void xen_hypercall_setfunc(void) |
| 83 | +{ |
| 84 | + if (static_call_query(xen_hypercall) != xen_hypercall_hvm) |
| 85 | + return; |
| 86 | + |
| 87 | + if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || |
| 88 | + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) |
| 89 | + static_call_update(xen_hypercall, xen_hypercall_amd); |
| 90 | + else |
| 91 | + static_call_update(xen_hypercall, xen_hypercall_intel); |
| 92 | +} |
| 93 | + |
| 94 | +/* |
| 95 | + * Evaluate processor vendor in order to select the correct hypercall |
| 96 | + * function for HVM/PVH guests. |
| 97 | + * Might be called very early in boot before vendor has been set by |
| 98 | + * early_cpu_init(). |
| 99 | + */ |
| 100 | +noinstr void *__xen_hypercall_setfunc(void) |
| 101 | +{ |
| 102 | + void (*func)(void); |
| 103 | + |
| 104 | + /* |
| 105 | + * Xen is supported only on CPUs with CPUID, so testing for |
| 106 | + * X86_FEATURE_CPUID is a test for early_cpu_init() having been |
| 107 | + * run. |
| 108 | + * |
| 109 | + * Note that __xen_hypercall_setfunc() is noinstr only due to a nasty |
| 110 | + * dependency chain: it is being called via the xen_hypercall static |
| 111 | + * call when running as a PVH or HVM guest. Hypercalls need to be |
| 112 | + * noinstr due to PV guests using hypercalls in noinstr code. So we |
| 113 | + * can safely tag the function body as "instrumentation ok", since |
| 114 | + * the PV guest requirement is not of interest here (xen_get_vendor() |
| 115 | + * calls noinstr functions, and static_call_update_early() might do |
| 116 | + * so, too). |
| 117 | + */ |
| 118 | + instrumentation_begin(); |
| 119 | + |
| 120 | + if (!boot_cpu_has(X86_FEATURE_CPUID)) |
| 121 | + xen_get_vendor(); |
| 122 | + |
| 123 | + if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || |
| 124 | + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) |
| 125 | + func = xen_hypercall_amd; |
| 126 | + else |
| 127 | + func = xen_hypercall_intel; |
| 128 | + |
| 129 | + static_call_update_early(xen_hypercall, func); |
| 130 | + |
| 131 | + instrumentation_end(); |
| 132 | + |
| 133 | + return func; |
| 134 | +} |
| 135 | + |
71 | 136 | static int xen_cpu_up_online(unsigned int cpu) |
72 | 137 | { |
73 | 138 | xen_init_lock_cpu(cpu); |
|
0 commit comments