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