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