18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#include <xen/xen.h> 38c2ecf20Sopenharmony_ci#include <xen/events.h> 48c2ecf20Sopenharmony_ci#include <xen/grant_table.h> 58c2ecf20Sopenharmony_ci#include <xen/hvm.h> 68c2ecf20Sopenharmony_ci#include <xen/interface/vcpu.h> 78c2ecf20Sopenharmony_ci#include <xen/interface/xen.h> 88c2ecf20Sopenharmony_ci#include <xen/interface/memory.h> 98c2ecf20Sopenharmony_ci#include <xen/interface/hvm/params.h> 108c2ecf20Sopenharmony_ci#include <xen/features.h> 118c2ecf20Sopenharmony_ci#include <xen/platform_pci.h> 128c2ecf20Sopenharmony_ci#include <xen/xenbus.h> 138c2ecf20Sopenharmony_ci#include <xen/page.h> 148c2ecf20Sopenharmony_ci#include <xen/interface/sched.h> 158c2ecf20Sopenharmony_ci#include <xen/xen-ops.h> 168c2ecf20Sopenharmony_ci#include <asm/xen/hypervisor.h> 178c2ecf20Sopenharmony_ci#include <asm/xen/hypercall.h> 188c2ecf20Sopenharmony_ci#include <asm/system_misc.h> 198c2ecf20Sopenharmony_ci#include <asm/efi.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/irqreturn.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci#include <linux/of_fdt.h> 258c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 268c2ecf20Sopenharmony_ci#include <linux/of_address.h> 278c2ecf20Sopenharmony_ci#include <linux/cpuidle.h> 288c2ecf20Sopenharmony_ci#include <linux/cpufreq.h> 298c2ecf20Sopenharmony_ci#include <linux/cpu.h> 308c2ecf20Sopenharmony_ci#include <linux/console.h> 318c2ecf20Sopenharmony_ci#include <linux/pvclock_gtod.h> 328c2ecf20Sopenharmony_ci#include <linux/time64.h> 338c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 348c2ecf20Sopenharmony_ci#include <linux/timekeeper_internal.h> 358c2ecf20Sopenharmony_ci#include <linux/acpi.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/mm.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct start_info _xen_start_info; 408c2ecf20Sopenharmony_cistruct start_info *xen_start_info = &_xen_start_info; 418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xen_start_info); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cienum xen_domain_type xen_domain_type = XEN_NATIVE; 448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xen_domain_type); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct shared_info xen_dummy_shared_info; 478c2ecf20Sopenharmony_cistruct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); 508c2ecf20Sopenharmony_cistatic struct vcpu_info __percpu *xen_vcpu_info; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Linux <-> Xen vCPU id mapping */ 538c2ecf20Sopenharmony_ciDEFINE_PER_CPU(uint32_t, xen_vcpu_id); 548c2ecf20Sopenharmony_ciEXPORT_PER_CPU_SYMBOL(xen_vcpu_id); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* These are unused until we support booting "pre-ballooned" */ 578c2ecf20Sopenharmony_ciunsigned long xen_released_pages; 588c2ecf20Sopenharmony_cistruct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic __read_mostly unsigned int xen_events_irq; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciuint32_t xen_start_flags; 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xen_start_flags); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciint xen_unmap_domain_gfn_range(struct vm_area_struct *vma, 668c2ecf20Sopenharmony_ci int nr, struct page **pages) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return xen_xlate_unmap_gfn_range(vma, nr, pages); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void xen_read_wallclock(struct timespec64 *ts) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 version; 758c2ecf20Sopenharmony_ci struct timespec64 now, ts_monotonic; 768c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 778c2ecf20Sopenharmony_ci struct pvclock_wall_clock *wall_clock = &(s->wc); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* get wallclock at system boot */ 808c2ecf20Sopenharmony_ci do { 818c2ecf20Sopenharmony_ci version = wall_clock->version; 828c2ecf20Sopenharmony_ci rmb(); /* fetch version before time */ 838c2ecf20Sopenharmony_ci now.tv_sec = ((uint64_t)wall_clock->sec_hi << 32) | wall_clock->sec; 848c2ecf20Sopenharmony_ci now.tv_nsec = wall_clock->nsec; 858c2ecf20Sopenharmony_ci rmb(); /* fetch time before checking version */ 868c2ecf20Sopenharmony_ci } while ((wall_clock->version & 1) || (version != wall_clock->version)); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* time since system boot */ 898c2ecf20Sopenharmony_ci ktime_get_ts64(&ts_monotonic); 908c2ecf20Sopenharmony_ci *ts = timespec64_add(now, ts_monotonic); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int xen_pvclock_gtod_notify(struct notifier_block *nb, 948c2ecf20Sopenharmony_ci unsigned long was_set, void *priv) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci /* Protected by the calling core code serialization */ 978c2ecf20Sopenharmony_ci static struct timespec64 next_sync; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct xen_platform_op op; 1008c2ecf20Sopenharmony_ci struct timespec64 now, system_time; 1018c2ecf20Sopenharmony_ci struct timekeeper *tk = priv; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci now.tv_sec = tk->xtime_sec; 1048c2ecf20Sopenharmony_ci now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); 1058c2ecf20Sopenharmony_ci system_time = timespec64_add(now, tk->wall_to_monotonic); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* 1088c2ecf20Sopenharmony_ci * We only take the expensive HV call when the clock was set 1098c2ecf20Sopenharmony_ci * or when the 11 minutes RTC synchronization time elapsed. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci if (!was_set && timespec64_compare(&now, &next_sync) < 0) 1128c2ecf20Sopenharmony_ci return NOTIFY_OK; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci op.cmd = XENPF_settime64; 1158c2ecf20Sopenharmony_ci op.u.settime64.mbz = 0; 1168c2ecf20Sopenharmony_ci op.u.settime64.secs = now.tv_sec; 1178c2ecf20Sopenharmony_ci op.u.settime64.nsecs = now.tv_nsec; 1188c2ecf20Sopenharmony_ci op.u.settime64.system_time = timespec64_to_ns(&system_time); 1198c2ecf20Sopenharmony_ci (void)HYPERVISOR_platform_op(&op); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * Move the next drift compensation time 11 minutes 1238c2ecf20Sopenharmony_ci * ahead. That's emulating the sync_cmos_clock() update for 1248c2ecf20Sopenharmony_ci * the hardware RTC. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci next_sync = now; 1278c2ecf20Sopenharmony_ci next_sync.tv_sec += 11 * 60; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return NOTIFY_OK; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic struct notifier_block xen_pvclock_gtod_notifier = { 1338c2ecf20Sopenharmony_ci .notifier_call = xen_pvclock_gtod_notify, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int xen_starting_cpu(unsigned int cpu) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct vcpu_register_vcpu_info info; 1398c2ecf20Sopenharmony_ci struct vcpu_info *vcpup; 1408c2ecf20Sopenharmony_ci int err; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * VCPUOP_register_vcpu_info cannot be called twice for the same 1448c2ecf20Sopenharmony_ci * vcpu, so if vcpu_info is already registered, just get out. This 1458c2ecf20Sopenharmony_ci * can happen with cpu-hotplug. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (per_cpu(xen_vcpu, cpu) != NULL) 1488c2ecf20Sopenharmony_ci goto after_register_vcpu_info; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci pr_info("Xen: initializing cpu%d\n", cpu); 1518c2ecf20Sopenharmony_ci vcpup = per_cpu_ptr(xen_vcpu_info, cpu); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci info.mfn = percpu_to_gfn(vcpup); 1548c2ecf20Sopenharmony_ci info.offset = xen_offset_in_page(vcpup); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu), 1578c2ecf20Sopenharmony_ci &info); 1588c2ecf20Sopenharmony_ci BUG_ON(err); 1598c2ecf20Sopenharmony_ci per_cpu(xen_vcpu, cpu) = vcpup; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciafter_register_vcpu_info: 1628c2ecf20Sopenharmony_ci enable_percpu_irq(xen_events_irq, 0); 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int xen_dying_cpu(unsigned int cpu) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci disable_percpu_irq(xen_events_irq); 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_civoid xen_reboot(int reason) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct sched_shutdown r = { .reason = reason }; 1758c2ecf20Sopenharmony_ci int rc; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); 1788c2ecf20Sopenharmony_ci BUG_ON(rc); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void xen_restart(enum reboot_mode reboot_mode, const char *cmd) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci xen_reboot(SHUTDOWN_reboot); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void xen_power_off(void) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci xen_reboot(SHUTDOWN_poweroff); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic irqreturn_t xen_arm_callback(int irq, void *arg) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci xen_hvm_evtchn_do_upcall(); 1958c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic __initdata struct { 1998c2ecf20Sopenharmony_ci const char *compat; 2008c2ecf20Sopenharmony_ci const char *prefix; 2018c2ecf20Sopenharmony_ci const char *version; 2028c2ecf20Sopenharmony_ci bool found; 2038c2ecf20Sopenharmony_ci} hyper_node = {"xen,xen", "xen,xen-", NULL, false}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int __init fdt_find_hyper_node(unsigned long node, const char *uname, 2068c2ecf20Sopenharmony_ci int depth, void *data) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci const void *s = NULL; 2098c2ecf20Sopenharmony_ci int len; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (depth != 1 || strcmp(uname, "hypervisor") != 0) 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (of_flat_dt_is_compatible(node, hyper_node.compat)) 2158c2ecf20Sopenharmony_ci hyper_node.found = true; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci s = of_get_flat_dt_prop(node, "compatible", &len); 2188c2ecf20Sopenharmony_ci if (strlen(hyper_node.prefix) + 3 < len && 2198c2ecf20Sopenharmony_ci !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) 2208c2ecf20Sopenharmony_ci hyper_node.version = s + strlen(hyper_node.prefix); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * Check if Xen supports EFI by checking whether there is the 2248c2ecf20Sopenharmony_ci * "/hypervisor/uefi" node in DT. If so, runtime services are available 2258c2ecf20Sopenharmony_ci * through proxy functions (e.g. in case of Xen dom0 EFI implementation 2268c2ecf20Sopenharmony_ci * they call special hypercall which executes relevant EFI functions) 2278c2ecf20Sopenharmony_ci * and that is why they are always enabled. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_XEN_EFI)) { 2308c2ecf20Sopenharmony_ci if ((of_get_flat_dt_subnode_by_name(node, "uefi") > 0) && 2318c2ecf20Sopenharmony_ci !efi_runtime_disabled()) 2328c2ecf20Sopenharmony_ci set_bit(EFI_RUNTIME_SERVICES, &efi.flags); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * see Documentation/devicetree/bindings/arm/xen.txt for the 2408c2ecf20Sopenharmony_ci * documentation of the Xen Device Tree format. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_civoid __init xen_early_init(void) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci of_scan_flat_dt(fdt_find_hyper_node, NULL); 2458c2ecf20Sopenharmony_ci if (!hyper_node.found) { 2468c2ecf20Sopenharmony_ci pr_debug("No Xen support\n"); 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (hyper_node.version == NULL) { 2518c2ecf20Sopenharmony_ci pr_debug("Xen version not found\n"); 2528c2ecf20Sopenharmony_ci return; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci pr_info("Xen %s support found\n", hyper_node.version); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci xen_domain_type = XEN_HVM_DOMAIN; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci xen_setup_features(); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (xen_feature(XENFEAT_dom0)) 2628c2ecf20Sopenharmony_ci xen_start_flags |= SIF_INITDOMAIN|SIF_PRIVILEGED; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!console_set_on_cmdline && !xen_initial_domain()) 2658c2ecf20Sopenharmony_ci add_preferred_console("hvc", 0, NULL); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic void __init xen_acpi_guest_init(void) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 2718c2ecf20Sopenharmony_ci struct xen_hvm_param a; 2728c2ecf20Sopenharmony_ci int interrupt, trigger, polarity; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci a.domid = DOMID_SELF; 2758c2ecf20Sopenharmony_ci a.index = HVM_PARAM_CALLBACK_IRQ; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (HYPERVISOR_hvm_op(HVMOP_get_param, &a) 2788c2ecf20Sopenharmony_ci || (a.value >> 56) != HVM_PARAM_CALLBACK_TYPE_PPI) { 2798c2ecf20Sopenharmony_ci xen_events_irq = 0; 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci interrupt = a.value & 0xff; 2848c2ecf20Sopenharmony_ci trigger = ((a.value >> 8) & 0x1) ? ACPI_EDGE_SENSITIVE 2858c2ecf20Sopenharmony_ci : ACPI_LEVEL_SENSITIVE; 2868c2ecf20Sopenharmony_ci polarity = ((a.value >> 8) & 0x2) ? ACPI_ACTIVE_LOW 2878c2ecf20Sopenharmony_ci : ACPI_ACTIVE_HIGH; 2888c2ecf20Sopenharmony_ci xen_events_irq = acpi_register_gsi(NULL, interrupt, trigger, polarity); 2898c2ecf20Sopenharmony_ci#endif 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void __init xen_dt_guest_init(void) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct device_node *xen_node; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci xen_node = of_find_compatible_node(NULL, NULL, "xen,xen"); 2978c2ecf20Sopenharmony_ci if (!xen_node) { 2988c2ecf20Sopenharmony_ci pr_err("Xen support was detected before, but it has disappeared\n"); 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci xen_events_irq = irq_of_parse_and_map(xen_node, 0); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int __init xen_guest_init(void) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct xen_add_to_physmap xatp; 3088c2ecf20Sopenharmony_ci struct shared_info *shared_info_page = NULL; 3098c2ecf20Sopenharmony_ci int cpu; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!xen_domain()) 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!acpi_disabled) 3158c2ecf20Sopenharmony_ci xen_acpi_guest_init(); 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci xen_dt_guest_init(); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!xen_events_irq) { 3208c2ecf20Sopenharmony_ci pr_err("Xen event channel interrupt not found\n"); 3218c2ecf20Sopenharmony_ci return -ENODEV; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * The fdt parsing codes have set EFI_RUNTIME_SERVICES if Xen EFI 3268c2ecf20Sopenharmony_ci * parameters are found. Force enable runtime services. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci if (efi_enabled(EFI_RUNTIME_SERVICES)) 3298c2ecf20Sopenharmony_ci xen_efi_runtime_setup(); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci shared_info_page = (struct shared_info *)get_zeroed_page(GFP_KERNEL); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (!shared_info_page) { 3348c2ecf20Sopenharmony_ci pr_err("not enough memory\n"); 3358c2ecf20Sopenharmony_ci return -ENOMEM; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci xatp.domid = DOMID_SELF; 3388c2ecf20Sopenharmony_ci xatp.idx = 0; 3398c2ecf20Sopenharmony_ci xatp.space = XENMAPSPACE_shared_info; 3408c2ecf20Sopenharmony_ci xatp.gpfn = virt_to_gfn(shared_info_page); 3418c2ecf20Sopenharmony_ci if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 3428c2ecf20Sopenharmony_ci BUG(); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info 3478c2ecf20Sopenharmony_ci * page, we use it in the event channel upcall and in some pvclock 3488c2ecf20Sopenharmony_ci * related functions. 3498c2ecf20Sopenharmony_ci * The shared info contains exactly 1 CPU (the boot CPU). The guest 3508c2ecf20Sopenharmony_ci * is required to use VCPUOP_register_vcpu_info to place vcpu info 3518c2ecf20Sopenharmony_ci * for secondary CPUs as they are brought up. 3528c2ecf20Sopenharmony_ci * For uniformity we use VCPUOP_register_vcpu_info even on cpu0. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info), 3558c2ecf20Sopenharmony_ci 1 << fls(sizeof(struct vcpu_info) - 1)); 3568c2ecf20Sopenharmony_ci if (xen_vcpu_info == NULL) 3578c2ecf20Sopenharmony_ci return -ENOMEM; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* Direct vCPU id mapping for ARM guests. */ 3608c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 3618c2ecf20Sopenharmony_ci per_cpu(xen_vcpu_id, cpu) = cpu; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames(); 3648c2ecf20Sopenharmony_ci if (xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn, 3658c2ecf20Sopenharmony_ci &xen_auto_xlat_grant_frames.vaddr, 3668c2ecf20Sopenharmony_ci xen_auto_xlat_grant_frames.count)) { 3678c2ecf20Sopenharmony_ci free_percpu(xen_vcpu_info); 3688c2ecf20Sopenharmony_ci return -ENOMEM; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci gnttab_init(); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Making sure board specific code will not set up ops for 3748c2ecf20Sopenharmony_ci * cpu idle and cpu freq. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci disable_cpuidle(); 3778c2ecf20Sopenharmony_ci disable_cpufreq(); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci xen_init_IRQ(); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (request_percpu_irq(xen_events_irq, xen_arm_callback, 3828c2ecf20Sopenharmony_ci "events", &xen_vcpu)) { 3838c2ecf20Sopenharmony_ci pr_err("Error request IRQ %d\n", xen_events_irq); 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (xen_initial_domain()) 3888c2ecf20Sopenharmony_ci pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return cpuhp_setup_state(CPUHP_AP_ARM_XEN_STARTING, 3918c2ecf20Sopenharmony_ci "arm/xen:starting", xen_starting_cpu, 3928c2ecf20Sopenharmony_ci xen_dying_cpu); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ciearly_initcall(xen_guest_init); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int xen_starting_runstate_cpu(unsigned int cpu) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci xen_setup_runstate_info(cpu); 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int __init xen_late_init(void) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci if (!xen_domain()) 4058c2ecf20Sopenharmony_ci return -ENODEV; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci pm_power_off = xen_power_off; 4088c2ecf20Sopenharmony_ci arm_pm_restart = xen_restart; 4098c2ecf20Sopenharmony_ci if (!xen_initial_domain()) { 4108c2ecf20Sopenharmony_ci struct timespec64 ts; 4118c2ecf20Sopenharmony_ci xen_read_wallclock(&ts); 4128c2ecf20Sopenharmony_ci do_settimeofday64(&ts); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (xen_kernel_unmapped_at_usr()) 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci xen_time_setup_guest(); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return cpuhp_setup_state(CPUHP_AP_ARM_XEN_RUNSTATE_STARTING, 4218c2ecf20Sopenharmony_ci "arm/xen_runstate:starting", 4228c2ecf20Sopenharmony_ci xen_starting_runstate_cpu, NULL); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_cilate_initcall(xen_late_init); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* empty stubs */ 4288c2ecf20Sopenharmony_civoid xen_arch_pre_suspend(void) { } 4298c2ecf20Sopenharmony_civoid xen_arch_post_suspend(int suspend_cancelled) { } 4308c2ecf20Sopenharmony_civoid xen_timer_resume(void) { } 4318c2ecf20Sopenharmony_civoid xen_arch_resume(void) { } 4328c2ecf20Sopenharmony_civoid xen_arch_suspend(void) { } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* In the hypercall.S file. */ 4368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op); 4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op); 4388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_xen_version); 4398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_console_io); 4408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_sched_op); 4418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_hvm_op); 4428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_memory_op); 4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op); 4448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op); 4458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op); 4468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_platform_op_raw); 4478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_multicall); 4488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_vm_assist); 4498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(HYPERVISOR_dm_op); 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(privcmd_call); 451