Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | // SPDX-License-Identifier: GPL-2.0 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG #include <linux/memblock.h> #endif #include <linux/cpu.h> #include <linux/kexec.h> #include <linux/slab.h> #include <xen/xen.h> #include <xen/features.h> #include <xen/page.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> #include <asm/cpu.h> #include <asm/e820/api.h> #include "xen-ops.h" #include "smp.h" #include "pmu.h" EXPORT_SYMBOL_GPL(hypercall_page); /* * Pointer to the xen_vcpu_info structure or * &HYPERVISOR_shared_info->vcpu_info[cpu]. See xen_hvm_init_shared_info * and xen_vcpu_setup for details. By default it points to share_info->vcpu_info * but if the hypervisor supports VCPUOP_register_vcpu_info then it can point * to xen_vcpu_info. The pointer is used in __xen_evtchn_do_upcall to * acknowledge pending events. * Also more subtly it is used by the patched version of irq enable/disable * e.g. xen_irq_enable_direct and xen_iret in PV mode. * * The desire to be able to do those mask/unmask operations as a single * instruction by using the per-cpu offset held in %gs is the real reason * vcpu info is in a per-cpu pointer and the original reason for this * hypercall. * */ DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); /* * Per CPU pages used if hypervisor supports VCPUOP_register_vcpu_info * hypercall. This can be used both in PV and PVHVM mode. The structure * overrides the default per_cpu(xen_vcpu, cpu) value. */ DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); /* Linux <-> Xen vCPU id mapping */ DEFINE_PER_CPU(uint32_t, xen_vcpu_id); EXPORT_PER_CPU_SYMBOL(xen_vcpu_id); enum xen_domain_type xen_domain_type = XEN_NATIVE; EXPORT_SYMBOL_GPL(xen_domain_type); unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; EXPORT_SYMBOL(machine_to_phys_mapping); unsigned long machine_to_phys_nr; EXPORT_SYMBOL(machine_to_phys_nr); struct start_info *xen_start_info; EXPORT_SYMBOL_GPL(xen_start_info); struct shared_info xen_dummy_shared_info; __read_mostly int xen_have_vector_callback; EXPORT_SYMBOL_GPL(xen_have_vector_callback); /* * NB: needs to live in .data because it's used by xen_prepare_pvh which runs * before clearing the bss. */ uint32_t xen_start_flags __attribute__((section(".data"))) = 0; EXPORT_SYMBOL(xen_start_flags); /* * Point at some empty memory to start with. We map the real shared_info * page as soon as fixmap is up and running. */ struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; /* * Flag to determine whether vcpu info placement is available on all * VCPUs. We assume it is to start with, and then set it to zero on * the first failure. This is because it can succeed on some VCPUs * and not others, since it can involve hypervisor memory allocation, * or because the guest failed to guarantee all the appropriate * constraints on all VCPUs (ie buffer can't cross a page boundary). * * Note that any particular CPU may be using a placed vcpu structure, * but we can only optimise if the all are. * * 0: not available, 1: available */ int xen_have_vcpu_info_placement = 1; static int xen_cpu_up_online(unsigned int cpu) { xen_init_lock_cpu(cpu); return 0; } int xen_cpuhp_setup(int (*cpu_up_prepare_cb)(unsigned int), int (*cpu_dead_cb)(unsigned int)) { int rc; rc = cpuhp_setup_state_nocalls(CPUHP_XEN_PREPARE, "x86/xen/guest:prepare", cpu_up_prepare_cb, cpu_dead_cb); if (rc >= 0) { rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/xen/guest:online", xen_cpu_up_online, NULL); if (rc < 0) cpuhp_remove_state_nocalls(CPUHP_XEN_PREPARE); } return rc >= 0 ? 0 : rc; } static int xen_vcpu_setup_restore(int cpu) { int rc = 0; /* Any per_cpu(xen_vcpu) is stale, so reset it */ xen_vcpu_info_reset(cpu); /* * For PVH and PVHVM, setup online VCPUs only. The rest will * be handled by hotplug. */ if (xen_pv_domain() || (xen_hvm_domain() && cpu_online(cpu))) { rc = xen_vcpu_setup(cpu); } return rc; } /* * On restore, set the vcpu placement up again. * If it fails, then we're in a bad state, since * we can't back out from using it... */ void xen_vcpu_restore(void) { int cpu, rc; for_each_possible_cpu(cpu) { bool other_cpu = (cpu != smp_processor_id()); bool is_up; if (xen_vcpu_nr(cpu) == XEN_VCPU_ID_INVALID) continue; /* Only Xen 4.5 and higher support this. */ is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, xen_vcpu_nr(cpu), NULL) > 0; if (other_cpu && is_up && HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(cpu), NULL)) BUG(); if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) xen_setup_runstate_info(cpu); rc = xen_vcpu_setup_restore(cpu); if (rc) pr_emerg_once("vcpu restore failed for cpu=%d err=%d. " "System will hang.\n", cpu, rc); /* * In case xen_vcpu_setup_restore() fails, do not bring up the * VCPU. This helps us avoid the resulting OOPS when the VCPU * accesses pvclock_vcpu_time via xen_vcpu (which is NULL.) * Note that this does not improve the situation much -- now the * VM hangs instead of OOPSing -- with the VCPUs that did not * fail, spinning in stop_machine(), waiting for the failed * VCPUs to come up. */ if (other_cpu && is_up && (rc == 0) && HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL)) BUG(); } } void xen_vcpu_info_reset(int cpu) { if (xen_vcpu_nr(cpu) < MAX_VIRT_CPUS) { per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[xen_vcpu_nr(cpu)]; } else { /* Set to NULL so that if somebody accesses it we get an OOPS */ per_cpu(xen_vcpu, cpu) = NULL; } } int xen_vcpu_setup(int cpu) { struct vcpu_register_vcpu_info info; int err; struct vcpu_info *vcpup; BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); /* * This path is called on PVHVM at bootup (xen_hvm_smp_prepare_boot_cpu) * and at restore (xen_vcpu_restore). Also called for hotplugged * VCPUs (cpu_init -> xen_hvm_cpu_prepare_hvm). * However, the hypercall can only be done once (see below) so if a VCPU * is offlined and comes back online then let's not redo the hypercall. * * For PV it is called during restore (xen_vcpu_restore) and bootup * (xen_setup_vcpu_info_placement). The hotplug mechanism does not * use this function. */ if (xen_hvm_domain()) { if (per_cpu(xen_vcpu, cpu) == &per_cpu(xen_vcpu_info, cpu)) return 0; } if (xen_have_vcpu_info_placement) { vcpup = &per_cpu(xen_vcpu_info, cpu); info.mfn = arbitrary_virt_to_mfn(vcpup); info.offset = offset_in_page(vcpup); /* * Check to see if the hypervisor will put the vcpu_info * structure where we want it, which allows direct access via * a percpu-variable. * N.B. This hypercall can _only_ be called once per CPU. * Subsequent calls will error out with -EINVAL. This is due to * the fact that hypervisor has no unregister variant and this * hypercall does not allow to over-write info.mfn and * info.offset. */ err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu), &info); if (err) { pr_warn_once("register_vcpu_info failed: cpu=%d err=%d\n", cpu, err); xen_have_vcpu_info_placement = 0; } else { /* * This cpu is using the registered vcpu info, even if * later ones fail to. */ per_cpu(xen_vcpu, cpu) = vcpup; } } if (!xen_have_vcpu_info_placement) xen_vcpu_info_reset(cpu); return ((per_cpu(xen_vcpu, cpu) == NULL) ? -ENODEV : 0); } void xen_reboot(int reason) { struct sched_shutdown r = { .reason = reason }; int cpu; for_each_online_cpu(cpu) xen_pmu_finish(cpu); if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r)) BUG(); } static int reboot_reason = SHUTDOWN_reboot; static bool xen_legacy_crash; void xen_emergency_restart(void) { xen_reboot(reboot_reason); } static int xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { if (!kexec_crash_loaded()) { if (xen_legacy_crash) xen_reboot(SHUTDOWN_crash); reboot_reason = SHUTDOWN_crash; /* * If panic_timeout==0 then we are supposed to wait forever. * However, to preserve original dom0 behavior we have to drop * into hypervisor. (domU behavior is controlled by its * config file) */ if (panic_timeout == 0) panic_timeout = -1; } return NOTIFY_DONE; } static int __init parse_xen_legacy_crash(char *arg) { xen_legacy_crash = true; return 0; } early_param("xen_legacy_crash", parse_xen_legacy_crash); static struct notifier_block xen_panic_block = { .notifier_call = xen_panic_event, .priority = INT_MIN }; int xen_panic_handler_init(void) { atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); return 0; } void xen_pin_vcpu(int cpu) { static bool disable_pinning; struct sched_pin_override pin_override; int ret; if (disable_pinning) return; pin_override.pcpu = cpu; ret = HYPERVISOR_sched_op(SCHEDOP_pin_override, &pin_override); /* Ignore errors when removing override. */ if (cpu < 0) return; switch (ret) { case -ENOSYS: pr_warn("Unable to pin on physical cpu %d. In case of problems consider vcpu pinning.\n", cpu); disable_pinning = true; break; case -EPERM: WARN(1, "Trying to pin vcpu without having privilege to do so\n"); disable_pinning = true; break; case -EINVAL: case -EBUSY: pr_warn("Physical cpu %d not available for pinning. Check Xen cpu configuration.\n", cpu); break; case 0: break; default: WARN(1, "rc %d while trying to pin vcpu\n", ret); disable_pinning = true; } } #ifdef CONFIG_HOTPLUG_CPU void xen_arch_register_cpu(int num) { arch_register_cpu(num); } EXPORT_SYMBOL(xen_arch_register_cpu); void xen_arch_unregister_cpu(int num) { arch_unregister_cpu(num); } EXPORT_SYMBOL(xen_arch_unregister_cpu); #endif |