xref: /openbmc/linux/arch/x86/xen/setup.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29702785aSThomas Gleixner /*
39702785aSThomas Gleixner  * Machine specific setup for xen
49702785aSThomas Gleixner  *
59702785aSThomas Gleixner  * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
69702785aSThomas Gleixner  */
79702785aSThomas Gleixner 
87a2463dcSPaul Gortmaker #include <linux/init.h>
99338c223SRoss Lagerwall #include <linux/iscsi_ibft.h>
109702785aSThomas Gleixner #include <linux/sched.h>
11639b2e2fSChristophe JAILLET #include <linux/kstrtox.h>
129702785aSThomas Gleixner #include <linux/mm.h>
139702785aSThomas Gleixner #include <linux/pm.h>
14a9ce6bc1SYinghai Lu #include <linux/memblock.h>
15d91ee586SLen Brown #include <linux/cpuidle.h>
1648cdd828SKonrad Rzeszutek Wilk #include <linux/cpufreq.h>
171d988ed4SJuergen Gross #include <linux/memory_hotplug.h>
18*adbb4453SJuergen Gross #include <linux/acpi.h>
199702785aSThomas Gleixner 
209702785aSThomas Gleixner #include <asm/elf.h>
216c3652efSRoland McGrath #include <asm/vdso.h>
2266441bd3SIngo Molnar #include <asm/e820/api.h>
239702785aSThomas Gleixner #include <asm/setup.h>
248d54db79SKonrad Rzeszutek Wilk #include <asm/numa.h>
252f6474e4SThomas Gleixner #include <asm/idtentry.h>
269702785aSThomas Gleixner #include <asm/xen/hypervisor.h>
279702785aSThomas Gleixner #include <asm/xen/hypercall.h>
289702785aSThomas Gleixner 
2945263cb0SIan Campbell #include <xen/xen.h>
308006ec3eSJeremy Fitzhardinge #include <xen/page.h>
31e2a81bafSJeremy Fitzhardinge #include <xen/interface/callback.h>
3235ae11fdSIan Campbell #include <xen/interface/memory.h>
339702785aSThomas Gleixner #include <xen/interface/physdev.h>
349702785aSThomas Gleixner #include <xen/features.h>
35808fdb71SJuergen Gross #include <xen/hvc-console.h>
369702785aSThomas Gleixner #include "xen-ops.h"
371f3ac86bSJuergen Gross #include "mmu.h"
389702785aSThomas Gleixner 
39c70727a5SJuergen Gross #define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024)
40c70727a5SJuergen Gross 
41aa24411bSDavid Vrabel /* Number of pages released from the initial allocation. */
42aa24411bSDavid Vrabel unsigned long xen_released_pages;
43aa24411bSDavid Vrabel 
44358cd9afSJuergen Gross /* Memory map would allow PCI passthrough. */
45358cd9afSJuergen Gross bool xen_pv_pci_possible;
46358cd9afSJuergen Gross 
4769632ecfSJuergen Gross /* E820 map used during setting up memory. */
48e7dbf7adSIngo Molnar static struct e820_table xen_e820_table __initdata;
4969632ecfSJuergen Gross 
50f12153eeSJuergen Gross /* Number of initially usable memory pages. */
51f12153eeSJuergen Gross static unsigned long ini_nr_pages __initdata;
52f12153eeSJuergen Gross 
531f3ac86bSJuergen Gross /*
541f3ac86bSJuergen Gross  * Buffer used to remap identity mapped pages. We only need the virtual space.
551f3ac86bSJuergen Gross  * The physical page behind this address is remapped as needed to different
561f3ac86bSJuergen Gross  * buffer pages.
571f3ac86bSJuergen Gross  */
581f3ac86bSJuergen Gross #define REMAP_SIZE	(P2M_PER_PAGE - 3)
591f3ac86bSJuergen Gross static struct {
601f3ac86bSJuergen Gross 	unsigned long	next_area_mfn;
611f3ac86bSJuergen Gross 	unsigned long	target_pfn;
621f3ac86bSJuergen Gross 	unsigned long	size;
631f3ac86bSJuergen Gross 	unsigned long	mfns[REMAP_SIZE];
641f3ac86bSJuergen Gross } xen_remap_buf __initdata __aligned(PAGE_SIZE);
651f3ac86bSJuergen Gross static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY;
664fbb67e3SMatt Rushton 
67c70727a5SJuergen Gross static bool xen_512gb_limit __initdata = IS_ENABLED(CONFIG_XEN_512GB);
68c70727a5SJuergen Gross 
xen_parse_512gb(void)69c70727a5SJuergen Gross static void __init xen_parse_512gb(void)
70c70727a5SJuergen Gross {
71c70727a5SJuergen Gross 	bool val = false;
72c70727a5SJuergen Gross 	char *arg;
73c70727a5SJuergen Gross 
74c70727a5SJuergen Gross 	arg = strstr(xen_start_info->cmd_line, "xen_512gb_limit");
75c70727a5SJuergen Gross 	if (!arg)
76c70727a5SJuergen Gross 		return;
77c70727a5SJuergen Gross 
78c70727a5SJuergen Gross 	arg = strstr(xen_start_info->cmd_line, "xen_512gb_limit=");
79c70727a5SJuergen Gross 	if (!arg)
80c70727a5SJuergen Gross 		val = true;
81639b2e2fSChristophe JAILLET 	else if (kstrtobool(arg + strlen("xen_512gb_limit="), &val))
82c70727a5SJuergen Gross 		return;
83c70727a5SJuergen Gross 
84c70727a5SJuergen Gross 	xen_512gb_limit = val;
85c70727a5SJuergen Gross }
86c70727a5SJuergen Gross 
xen_del_extra_mem(unsigned long start_pfn,unsigned long n_pfns)87626d7508SJuergen Gross static void __init xen_del_extra_mem(unsigned long start_pfn,
88626d7508SJuergen Gross 				     unsigned long n_pfns)
895b8e7d80SJuergen Gross {
905b8e7d80SJuergen Gross 	int i;
91626d7508SJuergen Gross 	unsigned long start_r, size_r;
9242ee1471SJeremy Fitzhardinge 
935b8e7d80SJuergen Gross 	for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
94626d7508SJuergen Gross 		start_r = xen_extra_mem[i].start_pfn;
95626d7508SJuergen Gross 		size_r = xen_extra_mem[i].n_pfns;
96c96aae1fSKonrad Rzeszutek Wilk 
975b8e7d80SJuergen Gross 		/* Start of region. */
98626d7508SJuergen Gross 		if (start_r == start_pfn) {
99626d7508SJuergen Gross 			BUG_ON(n_pfns > size_r);
100626d7508SJuergen Gross 			xen_extra_mem[i].start_pfn += n_pfns;
101626d7508SJuergen Gross 			xen_extra_mem[i].n_pfns -= n_pfns;
1025b8e7d80SJuergen Gross 			break;
1035b8e7d80SJuergen Gross 		}
1045b8e7d80SJuergen Gross 		/* End of region. */
105626d7508SJuergen Gross 		if (start_r + size_r == start_pfn + n_pfns) {
106626d7508SJuergen Gross 			BUG_ON(n_pfns > size_r);
107626d7508SJuergen Gross 			xen_extra_mem[i].n_pfns -= n_pfns;
1085b8e7d80SJuergen Gross 			break;
1095b8e7d80SJuergen Gross 		}
1105b8e7d80SJuergen Gross 		/* Mid of region. */
111626d7508SJuergen Gross 		if (start_pfn > start_r && start_pfn < start_r + size_r) {
112626d7508SJuergen Gross 			BUG_ON(start_pfn + n_pfns > start_r + size_r);
113626d7508SJuergen Gross 			xen_extra_mem[i].n_pfns = start_pfn - start_r;
1145b8e7d80SJuergen Gross 			/* Calling memblock_reserve() again is okay. */
115626d7508SJuergen Gross 			xen_add_extra_mem(start_pfn + n_pfns, start_r + size_r -
116626d7508SJuergen Gross 					  (start_pfn + n_pfns));
1175b8e7d80SJuergen Gross 			break;
1185b8e7d80SJuergen Gross 		}
1195b8e7d80SJuergen Gross 	}
1203ecc6834SMike Rapoport 	memblock_phys_free(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns));
1215b8e7d80SJuergen Gross }
1225b8e7d80SJuergen Gross 
1235b8e7d80SJuergen Gross /*
1245b8e7d80SJuergen Gross  * Called during boot before the p2m list can take entries beyond the
1255b8e7d80SJuergen Gross  * hypervisor supplied p2m list. Entries in extra mem are to be regarded as
1265b8e7d80SJuergen Gross  * invalid.
1275b8e7d80SJuergen Gross  */
xen_chk_extra_mem(unsigned long pfn)1285b8e7d80SJuergen Gross unsigned long __ref xen_chk_extra_mem(unsigned long pfn)
1295b8e7d80SJuergen Gross {
1305b8e7d80SJuergen Gross 	int i;
1315b8e7d80SJuergen Gross 
1325b8e7d80SJuergen Gross 	for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
133626d7508SJuergen Gross 		if (pfn >= xen_extra_mem[i].start_pfn &&
134626d7508SJuergen Gross 		    pfn < xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns)
1355b8e7d80SJuergen Gross 			return INVALID_P2M_ENTRY;
1365b8e7d80SJuergen Gross 	}
1375b8e7d80SJuergen Gross 
1385b8e7d80SJuergen Gross 	return IDENTITY_FRAME(pfn);
1395b8e7d80SJuergen Gross }
1405b8e7d80SJuergen Gross 
1415b8e7d80SJuergen Gross /*
1425b8e7d80SJuergen Gross  * Mark all pfns of extra mem as invalid in p2m list.
1435b8e7d80SJuergen Gross  */
xen_inv_extra_mem(void)1445b8e7d80SJuergen Gross void __init xen_inv_extra_mem(void)
1455b8e7d80SJuergen Gross {
1465b8e7d80SJuergen Gross 	unsigned long pfn, pfn_s, pfn_e;
1475b8e7d80SJuergen Gross 	int i;
1485b8e7d80SJuergen Gross 
1495b8e7d80SJuergen Gross 	for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
150626d7508SJuergen Gross 		if (!xen_extra_mem[i].n_pfns)
1519a17ad7fSJuergen Gross 			continue;
152626d7508SJuergen Gross 		pfn_s = xen_extra_mem[i].start_pfn;
153626d7508SJuergen Gross 		pfn_e = pfn_s + xen_extra_mem[i].n_pfns;
1545b8e7d80SJuergen Gross 		for (pfn = pfn_s; pfn < pfn_e; pfn++)
1555b8e7d80SJuergen Gross 			set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
15642ee1471SJeremy Fitzhardinge 	}
157c96aae1fSKonrad Rzeszutek Wilk }
15842ee1471SJeremy Fitzhardinge 
1594fbb67e3SMatt Rushton /*
1604fbb67e3SMatt Rushton  * Finds the next RAM pfn available in the E820 map after min_pfn.
1614fbb67e3SMatt Rushton  * This function updates min_pfn with the pfn found and returns
1624fbb67e3SMatt Rushton  * the size of that range or zero if not found.
1634fbb67e3SMatt Rushton  */
xen_find_pfn_range(unsigned long * min_pfn)16469632ecfSJuergen Gross static unsigned long __init xen_find_pfn_range(unsigned long *min_pfn)
1652e2fb754SKonrad Rzeszutek Wilk {
166e7dbf7adSIngo Molnar 	const struct e820_entry *entry = xen_e820_table.entries;
1672e2fb754SKonrad Rzeszutek Wilk 	unsigned int i;
1682e2fb754SKonrad Rzeszutek Wilk 	unsigned long done = 0;
1692e2fb754SKonrad Rzeszutek Wilk 
170e7dbf7adSIngo Molnar 	for (i = 0; i < xen_e820_table.nr_entries; i++, entry++) {
1712e2fb754SKonrad Rzeszutek Wilk 		unsigned long s_pfn;
1722e2fb754SKonrad Rzeszutek Wilk 		unsigned long e_pfn;
1732e2fb754SKonrad Rzeszutek Wilk 
17409821ff1SIngo Molnar 		if (entry->type != E820_TYPE_RAM)
1752e2fb754SKonrad Rzeszutek Wilk 			continue;
1762e2fb754SKonrad Rzeszutek Wilk 
177c3d93f88Szhenzhong.duan 		e_pfn = PFN_DOWN(entry->addr + entry->size);
1782e2fb754SKonrad Rzeszutek Wilk 
1794fbb67e3SMatt Rushton 		/* We only care about E820 after this */
180abed7d07SZhenzhong Duan 		if (e_pfn <= *min_pfn)
1812e2fb754SKonrad Rzeszutek Wilk 			continue;
1822e2fb754SKonrad Rzeszutek Wilk 
183c3d93f88Szhenzhong.duan 		s_pfn = PFN_UP(entry->addr);
1844fbb67e3SMatt Rushton 
1854fbb67e3SMatt Rushton 		/* If min_pfn falls within the E820 entry, we want to start
1864fbb67e3SMatt Rushton 		 * at the min_pfn PFN.
1872e2fb754SKonrad Rzeszutek Wilk 		 */
1884fbb67e3SMatt Rushton 		if (s_pfn <= *min_pfn) {
1894fbb67e3SMatt Rushton 			done = e_pfn - *min_pfn;
1902e2fb754SKonrad Rzeszutek Wilk 		} else {
1914fbb67e3SMatt Rushton 			done = e_pfn - s_pfn;
1924fbb67e3SMatt Rushton 			*min_pfn = s_pfn;
1932e2fb754SKonrad Rzeszutek Wilk 		}
194c3d93f88Szhenzhong.duan 		break;
1952e2fb754SKonrad Rzeszutek Wilk 	}
1964fbb67e3SMatt Rushton 
1972e2fb754SKonrad Rzeszutek Wilk 	return done;
1982e2fb754SKonrad Rzeszutek Wilk }
19983d51ab4SDavid Vrabel 
xen_free_mfn(unsigned long mfn)2001f3ac86bSJuergen Gross static int __init xen_free_mfn(unsigned long mfn)
2011f3ac86bSJuergen Gross {
2021f3ac86bSJuergen Gross 	struct xen_memory_reservation reservation = {
2031f3ac86bSJuergen Gross 		.address_bits = 0,
2041f3ac86bSJuergen Gross 		.extent_order = 0,
2051f3ac86bSJuergen Gross 		.domid        = DOMID_SELF
2061f3ac86bSJuergen Gross 	};
2071f3ac86bSJuergen Gross 
2081f3ac86bSJuergen Gross 	set_xen_guest_handle(reservation.extent_start, &mfn);
2091f3ac86bSJuergen Gross 	reservation.nr_extents = 1;
2101f3ac86bSJuergen Gross 
2111f3ac86bSJuergen Gross 	return HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
2121f3ac86bSJuergen Gross }
2131f3ac86bSJuergen Gross 
21483d51ab4SDavid Vrabel /*
2151f3ac86bSJuergen Gross  * This releases a chunk of memory and then does the identity map. It's used
2164fbb67e3SMatt Rushton  * as a fallback if the remapping fails.
21783d51ab4SDavid Vrabel  */
xen_set_identity_and_release_chunk(unsigned long start_pfn,unsigned long end_pfn)2184fbb67e3SMatt Rushton static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn,
219f12153eeSJuergen Gross 						      unsigned long end_pfn)
2204fbb67e3SMatt Rushton {
2211f3ac86bSJuergen Gross 	unsigned long pfn, end;
2221f3ac86bSJuergen Gross 	int ret;
2231f3ac86bSJuergen Gross 
2244fbb67e3SMatt Rushton 	WARN_ON(start_pfn > end_pfn);
225e201bfccSDavid Vrabel 
226bc7142cfSDavid Vrabel 	/* Release pages first. */
227f12153eeSJuergen Gross 	end = min(end_pfn, ini_nr_pages);
2281f3ac86bSJuergen Gross 	for (pfn = start_pfn; pfn < end; pfn++) {
2291f3ac86bSJuergen Gross 		unsigned long mfn = pfn_to_mfn(pfn);
2301f3ac86bSJuergen Gross 
2311f3ac86bSJuergen Gross 		/* Make sure pfn exists to start with */
2321f3ac86bSJuergen Gross 		if (mfn == INVALID_P2M_ENTRY || mfn_to_pfn(mfn) != pfn)
2331f3ac86bSJuergen Gross 			continue;
2341f3ac86bSJuergen Gross 
2351f3ac86bSJuergen Gross 		ret = xen_free_mfn(mfn);
2361f3ac86bSJuergen Gross 		WARN(ret != 1, "Failed to release pfn %lx err=%d\n", pfn, ret);
2371f3ac86bSJuergen Gross 
2381f3ac86bSJuergen Gross 		if (ret == 1) {
2395097cdf6SJuergen Gross 			xen_released_pages++;
2401f3ac86bSJuergen Gross 			if (!__set_phys_to_machine(pfn, INVALID_P2M_ENTRY))
2411f3ac86bSJuergen Gross 				break;
2421f3ac86bSJuergen Gross 		} else
2431f3ac86bSJuergen Gross 			break;
2441f3ac86bSJuergen Gross 	}
2451f3ac86bSJuergen Gross 
246bc7142cfSDavid Vrabel 	set_phys_range_identity(start_pfn, end_pfn);
24783d51ab4SDavid Vrabel }
24883d51ab4SDavid Vrabel 
2494fbb67e3SMatt Rushton /*
2501f3ac86bSJuergen Gross  * Helper function to update the p2m and m2p tables and kernel mapping.
2514fbb67e3SMatt Rushton  */
xen_update_mem_tables(unsigned long pfn,unsigned long mfn)2521f3ac86bSJuergen Gross static void __init xen_update_mem_tables(unsigned long pfn, unsigned long mfn)
2534fbb67e3SMatt Rushton {
2544fbb67e3SMatt Rushton 	struct mmu_update update = {
2553ba5c867SJuergen Gross 		.ptr = ((uint64_t)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE,
2564fbb67e3SMatt Rushton 		.val = pfn
2574fbb67e3SMatt Rushton 	};
2584fbb67e3SMatt Rushton 
2594fbb67e3SMatt Rushton 	/* Update p2m */
2601f3ac86bSJuergen Gross 	if (!set_phys_to_machine(pfn, mfn)) {
2614fbb67e3SMatt Rushton 		WARN(1, "Failed to set p2m mapping for pfn=%ld mfn=%ld\n",
2624fbb67e3SMatt Rushton 		     pfn, mfn);
2631f3ac86bSJuergen Gross 		BUG();
2644fbb67e3SMatt Rushton 	}
2654fbb67e3SMatt Rushton 
2664fbb67e3SMatt Rushton 	/* Update m2p */
2674fbb67e3SMatt Rushton 	if (HYPERVISOR_mmu_update(&update, 1, NULL, DOMID_SELF) < 0) {
2684fbb67e3SMatt Rushton 		WARN(1, "Failed to set m2p mapping for mfn=%ld pfn=%ld\n",
2694fbb67e3SMatt Rushton 		     mfn, pfn);
2701f3ac86bSJuergen Gross 		BUG();
2714fbb67e3SMatt Rushton 	}
2724fbb67e3SMatt Rushton 
2731f3ac86bSJuergen Gross 	if (HYPERVISOR_update_va_mapping((unsigned long)__va(pfn << PAGE_SHIFT),
2741f3ac86bSJuergen Gross 					 mfn_pte(mfn, PAGE_KERNEL), 0)) {
2751f3ac86bSJuergen Gross 		WARN(1, "Failed to update kernel mapping for mfn=%ld pfn=%ld\n",
2761f3ac86bSJuergen Gross 		      mfn, pfn);
2771f3ac86bSJuergen Gross 		BUG();
2781f3ac86bSJuergen Gross 	}
2794fbb67e3SMatt Rushton }
2804fbb67e3SMatt Rushton 
2814fbb67e3SMatt Rushton /*
2824fbb67e3SMatt Rushton  * This function updates the p2m and m2p tables with an identity map from
2831f3ac86bSJuergen Gross  * start_pfn to start_pfn+size and prepares remapping the underlying RAM of the
2841f3ac86bSJuergen Gross  * original allocation at remap_pfn. The information needed for remapping is
2851f3ac86bSJuergen Gross  * saved in the memory itself to avoid the need for allocating buffers. The
2861f3ac86bSJuergen Gross  * complete remap information is contained in a list of MFNs each containing
2871f3ac86bSJuergen Gross  * up to REMAP_SIZE MFNs and the start target PFN for doing the remap.
2881f3ac86bSJuergen Gross  * This enables us to preserve the original mfn sequence while doing the
2891f3ac86bSJuergen Gross  * remapping at a time when the memory management is capable of allocating
2901f3ac86bSJuergen Gross  * virtual and physical memory in arbitrary amounts, see 'xen_remap_memory' and
2911f3ac86bSJuergen Gross  * its callers.
2924fbb67e3SMatt Rushton  */
xen_do_set_identity_and_remap_chunk(unsigned long start_pfn,unsigned long size,unsigned long remap_pfn)2931f3ac86bSJuergen Gross static void __init xen_do_set_identity_and_remap_chunk(
2944fbb67e3SMatt Rushton         unsigned long start_pfn, unsigned long size, unsigned long remap_pfn)
2954fbb67e3SMatt Rushton {
2961f3ac86bSJuergen Gross 	unsigned long buf = (unsigned long)&xen_remap_buf;
2971f3ac86bSJuergen Gross 	unsigned long mfn_save, mfn;
2984fbb67e3SMatt Rushton 	unsigned long ident_pfn_iter, remap_pfn_iter;
2991f3ac86bSJuergen Gross 	unsigned long ident_end_pfn = start_pfn + size;
3004fbb67e3SMatt Rushton 	unsigned long left = size;
3011f3ac86bSJuergen Gross 	unsigned int i, chunk;
3024fbb67e3SMatt Rushton 
3034fbb67e3SMatt Rushton 	WARN_ON(size == 0);
3044fbb67e3SMatt Rushton 
305067e4f17SLinus Walleij 	mfn_save = virt_to_mfn((void *)buf);
3064fbb67e3SMatt Rushton 
3071f3ac86bSJuergen Gross 	for (ident_pfn_iter = start_pfn, remap_pfn_iter = remap_pfn;
3081f3ac86bSJuergen Gross 	     ident_pfn_iter < ident_end_pfn;
3091f3ac86bSJuergen Gross 	     ident_pfn_iter += REMAP_SIZE, remap_pfn_iter += REMAP_SIZE) {
3101f3ac86bSJuergen Gross 		chunk = (left < REMAP_SIZE) ? left : REMAP_SIZE;
3114fbb67e3SMatt Rushton 
3121f3ac86bSJuergen Gross 		/* Map first pfn to xen_remap_buf */
3131f3ac86bSJuergen Gross 		mfn = pfn_to_mfn(ident_pfn_iter);
3141f3ac86bSJuergen Gross 		set_pte_mfn(buf, mfn, PAGE_KERNEL);
3151f3ac86bSJuergen Gross 
3161f3ac86bSJuergen Gross 		/* Save mapping information in page */
3171f3ac86bSJuergen Gross 		xen_remap_buf.next_area_mfn = xen_remap_mfn;
3181f3ac86bSJuergen Gross 		xen_remap_buf.target_pfn = remap_pfn_iter;
3191f3ac86bSJuergen Gross 		xen_remap_buf.size = chunk;
3201f3ac86bSJuergen Gross 		for (i = 0; i < chunk; i++)
3211f3ac86bSJuergen Gross 			xen_remap_buf.mfns[i] = pfn_to_mfn(ident_pfn_iter + i);
3221f3ac86bSJuergen Gross 
3231f3ac86bSJuergen Gross 		/* Put remap buf into list. */
3241f3ac86bSJuergen Gross 		xen_remap_mfn = mfn;
3251f3ac86bSJuergen Gross 
3261f3ac86bSJuergen Gross 		/* Set identity map */
327bc7142cfSDavid Vrabel 		set_phys_range_identity(ident_pfn_iter, ident_pfn_iter + chunk);
3284fbb67e3SMatt Rushton 
3291f3ac86bSJuergen Gross 		left -= chunk;
3304fbb67e3SMatt Rushton 	}
3314fbb67e3SMatt Rushton 
3321f3ac86bSJuergen Gross 	/* Restore old xen_remap_buf mapping */
3331f3ac86bSJuergen Gross 	set_pte_mfn(buf, mfn_save, PAGE_KERNEL);
3344fbb67e3SMatt Rushton }
3354fbb67e3SMatt Rushton 
3364fbb67e3SMatt Rushton /*
3374fbb67e3SMatt Rushton  * This function takes a contiguous pfn range that needs to be identity mapped
3384fbb67e3SMatt Rushton  * and:
3394fbb67e3SMatt Rushton  *
3404fbb67e3SMatt Rushton  *  1) Finds a new range of pfns to use to remap based on E820 and remap_pfn.
3414fbb67e3SMatt Rushton  *  2) Calls the do_ function to actually do the mapping/remapping work.
3424fbb67e3SMatt Rushton  *
3434fbb67e3SMatt Rushton  * The goal is to not allocate additional memory but to remap the existing
3444fbb67e3SMatt Rushton  * pages. In the case of an error the underlying memory is simply released back
3454fbb67e3SMatt Rushton  * to Xen and not remapped.
3464fbb67e3SMatt Rushton  */
xen_set_identity_and_remap_chunk(unsigned long start_pfn,unsigned long end_pfn,unsigned long remap_pfn)34776f0a486SJuergen Gross static unsigned long __init xen_set_identity_and_remap_chunk(
348f12153eeSJuergen Gross 	unsigned long start_pfn, unsigned long end_pfn, unsigned long remap_pfn)
3494fbb67e3SMatt Rushton {
3504fbb67e3SMatt Rushton 	unsigned long pfn;
3514fbb67e3SMatt Rushton 	unsigned long i = 0;
3524fbb67e3SMatt Rushton 	unsigned long n = end_pfn - start_pfn;
3534fbb67e3SMatt Rushton 
354dd14be92SJuergen Gross 	if (remap_pfn == 0)
355f12153eeSJuergen Gross 		remap_pfn = ini_nr_pages;
356dd14be92SJuergen Gross 
3574fbb67e3SMatt Rushton 	while (i < n) {
3584fbb67e3SMatt Rushton 		unsigned long cur_pfn = start_pfn + i;
3594fbb67e3SMatt Rushton 		unsigned long left = n - i;
3604fbb67e3SMatt Rushton 		unsigned long size = left;
3614fbb67e3SMatt Rushton 		unsigned long remap_range_size;
3624fbb67e3SMatt Rushton 
3634fbb67e3SMatt Rushton 		/* Do not remap pages beyond the current allocation */
364f12153eeSJuergen Gross 		if (cur_pfn >= ini_nr_pages) {
3654fbb67e3SMatt Rushton 			/* Identity map remaining pages */
366bc7142cfSDavid Vrabel 			set_phys_range_identity(cur_pfn, cur_pfn + size);
3674fbb67e3SMatt Rushton 			break;
3684fbb67e3SMatt Rushton 		}
369f12153eeSJuergen Gross 		if (cur_pfn + size > ini_nr_pages)
370f12153eeSJuergen Gross 			size = ini_nr_pages - cur_pfn;
3714fbb67e3SMatt Rushton 
37269632ecfSJuergen Gross 		remap_range_size = xen_find_pfn_range(&remap_pfn);
3734fbb67e3SMatt Rushton 		if (!remap_range_size) {
3748d3bcc44SKefeng Wang 			pr_warn("Unable to find available pfn range, not remapping identity pages\n");
3754fbb67e3SMatt Rushton 			xen_set_identity_and_release_chunk(cur_pfn,
376f12153eeSJuergen Gross 							   cur_pfn + left);
3774fbb67e3SMatt Rushton 			break;
3784fbb67e3SMatt Rushton 		}
3794fbb67e3SMatt Rushton 		/* Adjust size to fit in current e820 RAM region */
3804fbb67e3SMatt Rushton 		if (size > remap_range_size)
3814fbb67e3SMatt Rushton 			size = remap_range_size;
3824fbb67e3SMatt Rushton 
3831f3ac86bSJuergen Gross 		xen_do_set_identity_and_remap_chunk(cur_pfn, size, remap_pfn);
3844fbb67e3SMatt Rushton 
3854fbb67e3SMatt Rushton 		/* Update variables to reflect new mappings. */
3864fbb67e3SMatt Rushton 		i += size;
3874fbb67e3SMatt Rushton 		remap_pfn += size;
3884fbb67e3SMatt Rushton 	}
3894fbb67e3SMatt Rushton 
3904fbb67e3SMatt Rushton 	/*
3919a58b352SJan Beulich 	 * If the PFNs are currently mapped, their VA mappings need to be
3929a58b352SJan Beulich 	 * zapped.
3934fbb67e3SMatt Rushton 	 */
3944fbb67e3SMatt Rushton 	for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++)
3954fbb67e3SMatt Rushton 		(void)HYPERVISOR_update_va_mapping(
3964fbb67e3SMatt Rushton 			(unsigned long)__va(pfn << PAGE_SHIFT),
3979a58b352SJan Beulich 			native_make_pte(0), 0);
3984fbb67e3SMatt Rushton 
3994fbb67e3SMatt Rushton 	return remap_pfn;
4004fbb67e3SMatt Rushton }
4014fbb67e3SMatt Rushton 
xen_count_remap_pages(unsigned long start_pfn,unsigned long end_pfn,unsigned long remap_pages)402dd14be92SJuergen Gross static unsigned long __init xen_count_remap_pages(
403f12153eeSJuergen Gross 	unsigned long start_pfn, unsigned long end_pfn,
404dd14be92SJuergen Gross 	unsigned long remap_pages)
405dd14be92SJuergen Gross {
406f12153eeSJuergen Gross 	if (start_pfn >= ini_nr_pages)
407dd14be92SJuergen Gross 		return remap_pages;
408dd14be92SJuergen Gross 
409f12153eeSJuergen Gross 	return remap_pages + min(end_pfn, ini_nr_pages) - start_pfn;
410dd14be92SJuergen Gross }
411dd14be92SJuergen Gross 
xen_foreach_remap_area(unsigned long (* func)(unsigned long start_pfn,unsigned long end_pfn,unsigned long last_val))412f12153eeSJuergen Gross static unsigned long __init xen_foreach_remap_area(
413dd14be92SJuergen Gross 	unsigned long (*func)(unsigned long start_pfn, unsigned long end_pfn,
414f12153eeSJuergen Gross 			      unsigned long last_val))
415093d7b46SMiroslav Rezanina {
416f3f436e3SDavid Vrabel 	phys_addr_t start = 0;
417dd14be92SJuergen Gross 	unsigned long ret_val = 0;
418e7dbf7adSIngo Molnar 	const struct e820_entry *entry = xen_e820_table.entries;
41968df0da7SKonrad Rzeszutek Wilk 	int i;
42068df0da7SKonrad Rzeszutek Wilk 
421f3f436e3SDavid Vrabel 	/*
422f3f436e3SDavid Vrabel 	 * Combine non-RAM regions and gaps until a RAM region (or the
423dd14be92SJuergen Gross 	 * end of the map) is reached, then call the provided function
424dd14be92SJuergen Gross 	 * to perform its duty on the non-RAM region.
425f3f436e3SDavid Vrabel 	 *
426f3f436e3SDavid Vrabel 	 * The combined non-RAM regions are rounded to a whole number
427f3f436e3SDavid Vrabel 	 * of pages so any partial pages are accessible via the 1:1
428f3f436e3SDavid Vrabel 	 * mapping.  This is needed for some BIOSes that put (for
429f3f436e3SDavid Vrabel 	 * example) the DMI tables in a reserved region that begins on
430f3f436e3SDavid Vrabel 	 * a non-page boundary.
431f3f436e3SDavid Vrabel 	 */
432e7dbf7adSIngo Molnar 	for (i = 0; i < xen_e820_table.nr_entries; i++, entry++) {
433f3f436e3SDavid Vrabel 		phys_addr_t end = entry->addr + entry->size;
434e7dbf7adSIngo Molnar 		if (entry->type == E820_TYPE_RAM || i == xen_e820_table.nr_entries - 1) {
435f3f436e3SDavid Vrabel 			unsigned long start_pfn = PFN_DOWN(start);
436f3f436e3SDavid Vrabel 			unsigned long end_pfn = PFN_UP(end);
43768df0da7SKonrad Rzeszutek Wilk 
43809821ff1SIngo Molnar 			if (entry->type == E820_TYPE_RAM)
439f3f436e3SDavid Vrabel 				end_pfn = PFN_UP(entry->addr);
44068df0da7SKonrad Rzeszutek Wilk 
44183d51ab4SDavid Vrabel 			if (start_pfn < end_pfn)
442f12153eeSJuergen Gross 				ret_val = func(start_pfn, end_pfn, ret_val);
443f3f436e3SDavid Vrabel 			start = end;
444f3f436e3SDavid Vrabel 		}
445f3f436e3SDavid Vrabel 	}
44668df0da7SKonrad Rzeszutek Wilk 
447dd14be92SJuergen Gross 	return ret_val;
44868df0da7SKonrad Rzeszutek Wilk }
4491f3ac86bSJuergen Gross 
4501f3ac86bSJuergen Gross /*
4511f3ac86bSJuergen Gross  * Remap the memory prepared in xen_do_set_identity_and_remap_chunk().
4521f3ac86bSJuergen Gross  * The remap information (which mfn remap to which pfn) is contained in the
4531f3ac86bSJuergen Gross  * to be remapped memory itself in a linked list anchored at xen_remap_mfn.
4541f3ac86bSJuergen Gross  * This scheme allows to remap the different chunks in arbitrary order while
455a97673a1SIngo Molnar  * the resulting mapping will be independent from the order.
4561f3ac86bSJuergen Gross  */
xen_remap_memory(void)4571f3ac86bSJuergen Gross void __init xen_remap_memory(void)
4581f3ac86bSJuergen Gross {
4591f3ac86bSJuergen Gross 	unsigned long buf = (unsigned long)&xen_remap_buf;
460bf1b9ddfSGustavo A. R. Silva 	unsigned long mfn_save, pfn;
4611f3ac86bSJuergen Gross 	unsigned long remapped = 0;
4621f3ac86bSJuergen Gross 	unsigned int i;
4631f3ac86bSJuergen Gross 	unsigned long pfn_s = ~0UL;
4641f3ac86bSJuergen Gross 	unsigned long len = 0;
4651f3ac86bSJuergen Gross 
466067e4f17SLinus Walleij 	mfn_save = virt_to_mfn((void *)buf);
4671f3ac86bSJuergen Gross 
4681f3ac86bSJuergen Gross 	while (xen_remap_mfn != INVALID_P2M_ENTRY) {
4691f3ac86bSJuergen Gross 		/* Map the remap information */
4701f3ac86bSJuergen Gross 		set_pte_mfn(buf, xen_remap_mfn, PAGE_KERNEL);
4711f3ac86bSJuergen Gross 
4721f3ac86bSJuergen Gross 		BUG_ON(xen_remap_mfn != xen_remap_buf.mfns[0]);
4731f3ac86bSJuergen Gross 
4741f3ac86bSJuergen Gross 		pfn = xen_remap_buf.target_pfn;
4751f3ac86bSJuergen Gross 		for (i = 0; i < xen_remap_buf.size; i++) {
476bf1b9ddfSGustavo A. R. Silva 			xen_update_mem_tables(pfn, xen_remap_buf.mfns[i]);
4771f3ac86bSJuergen Gross 			remapped++;
4781f3ac86bSJuergen Gross 			pfn++;
4791f3ac86bSJuergen Gross 		}
4801f3ac86bSJuergen Gross 		if (pfn_s == ~0UL || pfn == pfn_s) {
4811f3ac86bSJuergen Gross 			pfn_s = xen_remap_buf.target_pfn;
4821f3ac86bSJuergen Gross 			len += xen_remap_buf.size;
4831f3ac86bSJuergen Gross 		} else if (pfn_s + len == xen_remap_buf.target_pfn) {
4841f3ac86bSJuergen Gross 			len += xen_remap_buf.size;
4851f3ac86bSJuergen Gross 		} else {
486626d7508SJuergen Gross 			xen_del_extra_mem(pfn_s, len);
4871f3ac86bSJuergen Gross 			pfn_s = xen_remap_buf.target_pfn;
4881f3ac86bSJuergen Gross 			len = xen_remap_buf.size;
4891f3ac86bSJuergen Gross 		}
4901f3ac86bSJuergen Gross 		xen_remap_mfn = xen_remap_buf.next_area_mfn;
4911f3ac86bSJuergen Gross 	}
4921f3ac86bSJuergen Gross 
4931f3ac86bSJuergen Gross 	if (pfn_s != ~0UL && len)
494626d7508SJuergen Gross 		xen_del_extra_mem(pfn_s, len);
4951f3ac86bSJuergen Gross 
4961f3ac86bSJuergen Gross 	set_pte_mfn(buf, mfn_save, PAGE_KERNEL);
4971f3ac86bSJuergen Gross 
4981f3ac86bSJuergen Gross 	pr_info("Remapped %ld page(s)\n", remapped);
499ac8ec126SJuergen Gross 
500ac8ec126SJuergen Gross 	xen_do_remap_nonram();
5011f3ac86bSJuergen Gross }
5021f3ac86bSJuergen Gross 
xen_get_pages_limit(void)503c70727a5SJuergen Gross static unsigned long __init xen_get_pages_limit(void)
504c70727a5SJuergen Gross {
505c70727a5SJuergen Gross 	unsigned long limit;
506c70727a5SJuergen Gross 
507cb9e444bSJuergen Gross 	limit = MAXMEM / PAGE_SIZE;
508c70727a5SJuergen Gross 	if (!xen_initial_domain() && xen_512gb_limit)
509c70727a5SJuergen Gross 		limit = GB(512) / PAGE_SIZE;
510a13f2ef1SJuergen Gross 
511c70727a5SJuergen Gross 	return limit;
512c70727a5SJuergen Gross }
513c70727a5SJuergen Gross 
xen_get_max_pages(void)514d312ae87SDavid Vrabel static unsigned long __init xen_get_max_pages(void)
515d312ae87SDavid Vrabel {
516c70727a5SJuergen Gross 	unsigned long max_pages, limit;
517d312ae87SDavid Vrabel 	domid_t domid = DOMID_SELF;
51824f775a6SJuergen Gross 	long ret;
519d312ae87SDavid Vrabel 
520c70727a5SJuergen Gross 	limit = xen_get_pages_limit();
521c70727a5SJuergen Gross 	max_pages = limit;
522c70727a5SJuergen Gross 
523d3db7281SIan Campbell 	/*
524d3db7281SIan Campbell 	 * For the initial domain we use the maximum reservation as
525d3db7281SIan Campbell 	 * the maximum page.
526d3db7281SIan Campbell 	 *
527d3db7281SIan Campbell 	 * For guest domains the current maximum reservation reflects
528d3db7281SIan Campbell 	 * the current maximum rather than the static maximum. In this
529d3db7281SIan Campbell 	 * case the e820 map provided to us will cover the static
530d3db7281SIan Campbell 	 * maximum region.
531d3db7281SIan Campbell 	 */
532d3db7281SIan Campbell 	if (xen_initial_domain()) {
533d312ae87SDavid Vrabel 		ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
534d312ae87SDavid Vrabel 		if (ret > 0)
535d312ae87SDavid Vrabel 			max_pages = ret;
536d3db7281SIan Campbell 	}
537d3db7281SIan Campbell 
538c70727a5SJuergen Gross 	return min(max_pages, limit);
539d312ae87SDavid Vrabel }
540d312ae87SDavid Vrabel 
xen_align_and_add_e820_region(phys_addr_t start,phys_addr_t size,int type)541a3f52396SJuergen Gross static void __init xen_align_and_add_e820_region(phys_addr_t start,
542a3f52396SJuergen Gross 						 phys_addr_t size, int type)
543dc91c728SDavid Vrabel {
5443ba5c867SJuergen Gross 	phys_addr_t end = start + size;
545dc91c728SDavid Vrabel 
546dc91c728SDavid Vrabel 	/* Align RAM regions to page boundaries. */
54709821ff1SIngo Molnar 	if (type == E820_TYPE_RAM) {
548dc91c728SDavid Vrabel 		start = PAGE_ALIGN(start);
5493ba5c867SJuergen Gross 		end &= ~((phys_addr_t)PAGE_SIZE - 1);
5501d988ed4SJuergen Gross #ifdef CONFIG_MEMORY_HOTPLUG
5511d988ed4SJuergen Gross 		/*
5521d988ed4SJuergen Gross 		 * Don't allow adding memory not in E820 map while booting the
5531d988ed4SJuergen Gross 		 * system. Once the balloon driver is up it will remove that
5541d988ed4SJuergen Gross 		 * restriction again.
5551d988ed4SJuergen Gross 		 */
5561d988ed4SJuergen Gross 		max_mem_size = end;
5571d988ed4SJuergen Gross #endif
558dc91c728SDavid Vrabel 	}
559dc91c728SDavid Vrabel 
560ab6bc04cSIngo Molnar 	e820__range_add(start, end - start, type);
561dc91c728SDavid Vrabel }
562dc91c728SDavid Vrabel 
xen_ignore_unusable(void)56369632ecfSJuergen Gross static void __init xen_ignore_unusable(void)
5643bc38cbcSDavid Vrabel {
565e7dbf7adSIngo Molnar 	struct e820_entry *entry = xen_e820_table.entries;
5663bc38cbcSDavid Vrabel 	unsigned int i;
5673bc38cbcSDavid Vrabel 
568e7dbf7adSIngo Molnar 	for (i = 0; i < xen_e820_table.nr_entries; i++, entry++) {
56909821ff1SIngo Molnar 		if (entry->type == E820_TYPE_UNUSABLE)
57009821ff1SIngo Molnar 			entry->type = E820_TYPE_RAM;
5713bc38cbcSDavid Vrabel 	}
5723bc38cbcSDavid Vrabel }
5733bc38cbcSDavid Vrabel 
xen_is_e820_reserved(phys_addr_t start,phys_addr_t size)574242d0c3cSJuergen Gross static bool __init xen_is_e820_reserved(phys_addr_t start, phys_addr_t size)
575e612b4a7SJuergen Gross {
5768ec67d97SIngo Molnar 	struct e820_entry *entry;
577e612b4a7SJuergen Gross 	unsigned mapcnt;
578e612b4a7SJuergen Gross 	phys_addr_t end;
579e612b4a7SJuergen Gross 
580e612b4a7SJuergen Gross 	if (!size)
581e612b4a7SJuergen Gross 		return false;
582e612b4a7SJuergen Gross 
583e612b4a7SJuergen Gross 	end = start + size;
584e7dbf7adSIngo Molnar 	entry = xen_e820_table.entries;
585e612b4a7SJuergen Gross 
586e7dbf7adSIngo Molnar 	for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) {
58709821ff1SIngo Molnar 		if (entry->type == E820_TYPE_RAM && entry->addr <= start &&
588e612b4a7SJuergen Gross 		    (entry->addr + entry->size) >= end)
589e612b4a7SJuergen Gross 			return false;
590e612b4a7SJuergen Gross 
591e612b4a7SJuergen Gross 		entry++;
592e612b4a7SJuergen Gross 	}
593e612b4a7SJuergen Gross 
594e612b4a7SJuergen Gross 	return true;
595e612b4a7SJuergen Gross }
596e612b4a7SJuergen Gross 
5978f5b0c63SJuergen Gross /*
5989ddac5b7SJuergen Gross  * Find a free area in physical memory not yet reserved and compliant with
5999ddac5b7SJuergen Gross  * E820 map.
6009ddac5b7SJuergen Gross  * Used to relocate pre-allocated areas like initrd or p2m list which are in
6019ddac5b7SJuergen Gross  * conflict with the to be used E820 map.
6029ddac5b7SJuergen Gross  * In case no area is found, return 0. Otherwise return the physical address
6039ddac5b7SJuergen Gross  * of the area which is already reserved for convenience.
6049ddac5b7SJuergen Gross  */
xen_find_free_area(phys_addr_t size)6059ddac5b7SJuergen Gross phys_addr_t __init xen_find_free_area(phys_addr_t size)
6069ddac5b7SJuergen Gross {
6079ddac5b7SJuergen Gross 	unsigned mapcnt;
6089ddac5b7SJuergen Gross 	phys_addr_t addr, start;
609e7dbf7adSIngo Molnar 	struct e820_entry *entry = xen_e820_table.entries;
6109ddac5b7SJuergen Gross 
611e7dbf7adSIngo Molnar 	for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++, entry++) {
61209821ff1SIngo Molnar 		if (entry->type != E820_TYPE_RAM || entry->size < size)
6139ddac5b7SJuergen Gross 			continue;
6149ddac5b7SJuergen Gross 		start = entry->addr;
6159ddac5b7SJuergen Gross 		for (addr = start; addr < start + size; addr += PAGE_SIZE) {
6169ddac5b7SJuergen Gross 			if (!memblock_is_reserved(addr))
6179ddac5b7SJuergen Gross 				continue;
6189ddac5b7SJuergen Gross 			start = addr + PAGE_SIZE;
6199ddac5b7SJuergen Gross 			if (start + size > entry->addr + entry->size)
6209ddac5b7SJuergen Gross 				break;
6219ddac5b7SJuergen Gross 		}
6229ddac5b7SJuergen Gross 		if (addr >= start + size) {
6239ddac5b7SJuergen Gross 			memblock_reserve(start, size);
6249ddac5b7SJuergen Gross 			return start;
6259ddac5b7SJuergen Gross 		}
6269ddac5b7SJuergen Gross 	}
6279ddac5b7SJuergen Gross 
6289ddac5b7SJuergen Gross 	return 0;
6299ddac5b7SJuergen Gross }
6309ddac5b7SJuergen Gross 
6319ddac5b7SJuergen Gross /*
632ac8ec126SJuergen Gross  * Swap a non-RAM E820 map entry with RAM above ini_nr_pages.
633ac8ec126SJuergen Gross  * Note that the E820 map is modified accordingly, but the P2M map isn't yet.
634ac8ec126SJuergen Gross  * The adaption of the P2M must be deferred until page allocation is possible.
635ac8ec126SJuergen Gross  */
xen_e820_swap_entry_with_ram(struct e820_entry * swap_entry)636ac8ec126SJuergen Gross static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry)
637ac8ec126SJuergen Gross {
638ac8ec126SJuergen Gross 	struct e820_entry *entry;
639ac8ec126SJuergen Gross 	unsigned int mapcnt;
640ac8ec126SJuergen Gross 	phys_addr_t mem_end = PFN_PHYS(ini_nr_pages);
641ac8ec126SJuergen Gross 	phys_addr_t swap_addr, swap_size, entry_end;
642ac8ec126SJuergen Gross 
643ac8ec126SJuergen Gross 	swap_addr = PAGE_ALIGN_DOWN(swap_entry->addr);
644ac8ec126SJuergen Gross 	swap_size = PAGE_ALIGN(swap_entry->addr - swap_addr + swap_entry->size);
645ac8ec126SJuergen Gross 	entry = xen_e820_table.entries;
646ac8ec126SJuergen Gross 
647ac8ec126SJuergen Gross 	for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) {
648ac8ec126SJuergen Gross 		entry_end = entry->addr + entry->size;
649ac8ec126SJuergen Gross 		if (entry->type == E820_TYPE_RAM && entry->size >= swap_size &&
650ac8ec126SJuergen Gross 		    entry_end - swap_size >= mem_end) {
651ac8ec126SJuergen Gross 			/* Reduce RAM entry by needed space (whole pages). */
652ac8ec126SJuergen Gross 			entry->size -= swap_size;
653ac8ec126SJuergen Gross 
654ac8ec126SJuergen Gross 			/* Add new entry at the end of E820 map. */
655ac8ec126SJuergen Gross 			entry = xen_e820_table.entries +
656ac8ec126SJuergen Gross 				xen_e820_table.nr_entries;
657ac8ec126SJuergen Gross 			xen_e820_table.nr_entries++;
658ac8ec126SJuergen Gross 
659ac8ec126SJuergen Gross 			/* Fill new entry (keep size and page offset). */
660ac8ec126SJuergen Gross 			entry->type = swap_entry->type;
661ac8ec126SJuergen Gross 			entry->addr = entry_end - swap_size +
662ac8ec126SJuergen Gross 				      swap_addr - swap_entry->addr;
663ac8ec126SJuergen Gross 			entry->size = swap_entry->size;
664ac8ec126SJuergen Gross 
665ac8ec126SJuergen Gross 			/* Convert old entry to RAM, align to pages. */
666ac8ec126SJuergen Gross 			swap_entry->type = E820_TYPE_RAM;
667ac8ec126SJuergen Gross 			swap_entry->addr = swap_addr;
668ac8ec126SJuergen Gross 			swap_entry->size = swap_size;
669ac8ec126SJuergen Gross 
670ac8ec126SJuergen Gross 			/* Remember PFN<->MFN relation for P2M update. */
671ac8ec126SJuergen Gross 			xen_add_remap_nonram(swap_addr, entry_end - swap_size,
672ac8ec126SJuergen Gross 					     swap_size);
673ac8ec126SJuergen Gross 
674ac8ec126SJuergen Gross 			/* Order E820 table and merge entries. */
675ac8ec126SJuergen Gross 			e820__update_table(&xen_e820_table);
676ac8ec126SJuergen Gross 
677ac8ec126SJuergen Gross 			return;
678ac8ec126SJuergen Gross 		}
679ac8ec126SJuergen Gross 
680ac8ec126SJuergen Gross 		entry++;
681ac8ec126SJuergen Gross 	}
682ac8ec126SJuergen Gross 
683ac8ec126SJuergen Gross 	xen_raw_console_write("No suitable area found for required E820 entry remapping action\n");
684ac8ec126SJuergen Gross 	BUG();
685ac8ec126SJuergen Gross }
686ac8ec126SJuergen Gross 
687ac8ec126SJuergen Gross /*
688ac8ec126SJuergen Gross  * Look for non-RAM memory types in a specific guest physical area and move
689ac8ec126SJuergen Gross  * those away if possible (ACPI NVS only for now).
690ac8ec126SJuergen Gross  */
xen_e820_resolve_conflicts(phys_addr_t start,phys_addr_t size)691ac8ec126SJuergen Gross static void __init xen_e820_resolve_conflicts(phys_addr_t start,
692ac8ec126SJuergen Gross 					      phys_addr_t size)
693ac8ec126SJuergen Gross {
694ac8ec126SJuergen Gross 	struct e820_entry *entry;
695ac8ec126SJuergen Gross 	unsigned int mapcnt;
696ac8ec126SJuergen Gross 	phys_addr_t end;
697ac8ec126SJuergen Gross 
698ac8ec126SJuergen Gross 	if (!size)
699ac8ec126SJuergen Gross 		return;
700ac8ec126SJuergen Gross 
701ac8ec126SJuergen Gross 	end = start + size;
702ac8ec126SJuergen Gross 	entry = xen_e820_table.entries;
703ac8ec126SJuergen Gross 
704ac8ec126SJuergen Gross 	for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) {
705ac8ec126SJuergen Gross 		if (entry->addr >= end)
706ac8ec126SJuergen Gross 			return;
707ac8ec126SJuergen Gross 
708ac8ec126SJuergen Gross 		if (entry->addr + entry->size > start &&
709ac8ec126SJuergen Gross 		    entry->type == E820_TYPE_NVS)
710ac8ec126SJuergen Gross 			xen_e820_swap_entry_with_ram(entry);
711ac8ec126SJuergen Gross 
712ac8ec126SJuergen Gross 		entry++;
713ac8ec126SJuergen Gross 	}
714ac8ec126SJuergen Gross }
715ac8ec126SJuergen Gross 
716ac8ec126SJuergen Gross /*
717242d0c3cSJuergen Gross  * Check for an area in physical memory to be usable for non-movable purposes.
718ac8ec126SJuergen Gross  * An area is considered to usable if the used E820 map lists it to be RAM or
719ac8ec126SJuergen Gross  * some other type which can be moved to higher PFNs while keeping the MFNs.
720242d0c3cSJuergen Gross  * In case the area is not usable, crash the system with an error message.
721242d0c3cSJuergen Gross  */
xen_chk_is_e820_usable(phys_addr_t start,phys_addr_t size,const char * component)722242d0c3cSJuergen Gross void __init xen_chk_is_e820_usable(phys_addr_t start, phys_addr_t size,
723242d0c3cSJuergen Gross 				   const char *component)
724242d0c3cSJuergen Gross {
725ac8ec126SJuergen Gross 	xen_e820_resolve_conflicts(start, size);
726ac8ec126SJuergen Gross 
727242d0c3cSJuergen Gross 	if (!xen_is_e820_reserved(start, size))
728242d0c3cSJuergen Gross 		return;
729242d0c3cSJuergen Gross 
730242d0c3cSJuergen Gross 	xen_raw_console_write("Xen hypervisor allocated ");
731242d0c3cSJuergen Gross 	xen_raw_console_write(component);
732242d0c3cSJuergen Gross 	xen_raw_console_write(" memory conflicts with E820 map\n");
733242d0c3cSJuergen Gross 	BUG();
734242d0c3cSJuergen Gross }
735242d0c3cSJuergen Gross 
736242d0c3cSJuergen Gross /*
7374b9c1537SJuergen Gross  * Like memcpy, but with physical addresses for dest and src.
7384b9c1537SJuergen Gross  */
xen_phys_memcpy(phys_addr_t dest,phys_addr_t src,phys_addr_t n)7394b9c1537SJuergen Gross static void __init xen_phys_memcpy(phys_addr_t dest, phys_addr_t src,
7404b9c1537SJuergen Gross 				   phys_addr_t n)
7414b9c1537SJuergen Gross {
7424b9c1537SJuergen Gross 	phys_addr_t dest_off, src_off, dest_len, src_len, len;
7434b9c1537SJuergen Gross 	void *from, *to;
7444b9c1537SJuergen Gross 
7454b9c1537SJuergen Gross 	while (n) {
7464b9c1537SJuergen Gross 		dest_off = dest & ~PAGE_MASK;
7474b9c1537SJuergen Gross 		src_off = src & ~PAGE_MASK;
7484b9c1537SJuergen Gross 		dest_len = n;
7494b9c1537SJuergen Gross 		if (dest_len > (NR_FIX_BTMAPS << PAGE_SHIFT) - dest_off)
7504b9c1537SJuergen Gross 			dest_len = (NR_FIX_BTMAPS << PAGE_SHIFT) - dest_off;
7514b9c1537SJuergen Gross 		src_len = n;
7524b9c1537SJuergen Gross 		if (src_len > (NR_FIX_BTMAPS << PAGE_SHIFT) - src_off)
7534b9c1537SJuergen Gross 			src_len = (NR_FIX_BTMAPS << PAGE_SHIFT) - src_off;
7544b9c1537SJuergen Gross 		len = min(dest_len, src_len);
7554b9c1537SJuergen Gross 		to = early_memremap(dest - dest_off, dest_len + dest_off);
7564b9c1537SJuergen Gross 		from = early_memremap(src - src_off, src_len + src_off);
7574b9c1537SJuergen Gross 		memcpy(to, from, len);
7584b9c1537SJuergen Gross 		early_memunmap(to, dest_len + dest_off);
7594b9c1537SJuergen Gross 		early_memunmap(from, src_len + src_off);
7604b9c1537SJuergen Gross 		n -= len;
7614b9c1537SJuergen Gross 		dest += len;
7624b9c1537SJuergen Gross 		src += len;
7634b9c1537SJuergen Gross 	}
7644b9c1537SJuergen Gross }
7654b9c1537SJuergen Gross 
7664b9c1537SJuergen Gross /*
7678f5b0c63SJuergen Gross  * Reserve Xen mfn_list.
7688f5b0c63SJuergen Gross  */
xen_reserve_xen_mfnlist(void)7698f5b0c63SJuergen Gross static void __init xen_reserve_xen_mfnlist(void)
7708f5b0c63SJuergen Gross {
77170e61199SJuergen Gross 	phys_addr_t start, size;
77270e61199SJuergen Gross 
7738f5b0c63SJuergen Gross 	if (xen_start_info->mfn_list >= __START_KERNEL_map) {
77470e61199SJuergen Gross 		start = __pa(xen_start_info->mfn_list);
77570e61199SJuergen Gross 		size = PFN_ALIGN(xen_start_info->nr_pages *
77670e61199SJuergen Gross 				 sizeof(unsigned long));
77770e61199SJuergen Gross 	} else {
77870e61199SJuergen Gross 		start = PFN_PHYS(xen_start_info->first_p2m_pfn);
77970e61199SJuergen Gross 		size = PFN_PHYS(xen_start_info->nr_p2m_frames);
78070e61199SJuergen Gross 	}
78170e61199SJuergen Gross 
78270e61199SJuergen Gross 	memblock_reserve(start, size);
7837ecec850SRoss Lagerwall 	if (!xen_is_e820_reserved(start, size))
7848f5b0c63SJuergen Gross 		return;
7858f5b0c63SJuergen Gross 
78670e61199SJuergen Gross 	xen_relocate_p2m();
7873ecc6834SMike Rapoport 	memblock_phys_free(start, size);
7888f5b0c63SJuergen Gross }
7898f5b0c63SJuergen Gross 
7909702785aSThomas Gleixner /**
791b359b3a0SJiapeng Chong  * xen_memory_setup - Hook for machine specific memory setup.
7929702785aSThomas Gleixner  **/
xen_memory_setup(void)7939702785aSThomas Gleixner char * __init xen_memory_setup(void)
7949702785aSThomas Gleixner {
795f12153eeSJuergen Gross 	unsigned long pfn_s, n_pfns;
7965097cdf6SJuergen Gross 	phys_addr_t mem_end, addr, size, chunk_size;
7975097cdf6SJuergen Gross 	u32 type;
79835ae11fdSIan Campbell 	int rc;
79935ae11fdSIan Campbell 	struct xen_memory_map memmap;
800dc91c728SDavid Vrabel 	unsigned long max_pages;
80142ee1471SJeremy Fitzhardinge 	unsigned long extra_pages = 0;
80235a10211SLinus Torvalds 	unsigned long maxmem_pages;
80335ae11fdSIan Campbell 	int i;
8049e9a5fcbSIan Campbell 	int op;
8059702785aSThomas Gleixner 
806c70727a5SJuergen Gross 	xen_parse_512gb();
807f12153eeSJuergen Gross 	ini_nr_pages = min(xen_get_pages_limit(), xen_start_info->nr_pages);
808f12153eeSJuergen Gross 	mem_end = PFN_PHYS(ini_nr_pages);
80935ae11fdSIan Campbell 
810e7dbf7adSIngo Molnar 	memmap.nr_entries = ARRAY_SIZE(xen_e820_table.entries);
811e7dbf7adSIngo Molnar 	set_xen_guest_handle(memmap.buffer, xen_e820_table.entries);
81235ae11fdSIan Campbell 
8131d988ed4SJuergen Gross #if defined(CONFIG_MEMORY_HOTPLUG) && defined(CONFIG_XEN_BALLOON)
8141d988ed4SJuergen Gross 	xen_saved_max_mem_size = max_mem_size;
8151d988ed4SJuergen Gross #endif
8161d988ed4SJuergen Gross 
8179e9a5fcbSIan Campbell 	op = xen_initial_domain() ?
8189e9a5fcbSIan Campbell 		XENMEM_machine_memory_map :
8199e9a5fcbSIan Campbell 		XENMEM_memory_map;
8209e9a5fcbSIan Campbell 	rc = HYPERVISOR_memory_op(op, &memmap);
82135ae11fdSIan Campbell 	if (rc == -ENOSYS) {
8229ec23a7fSIan Campbell 		BUG_ON(xen_initial_domain());
82335ae11fdSIan Campbell 		memmap.nr_entries = 1;
824e7dbf7adSIngo Molnar 		xen_e820_table.entries[0].addr = 0ULL;
825e7dbf7adSIngo Molnar 		xen_e820_table.entries[0].size = mem_end;
82635ae11fdSIan Campbell 		/* 8MB slack (to balance backend allocations). */
827e7dbf7adSIngo Molnar 		xen_e820_table.entries[0].size += 8ULL << 20;
828e7dbf7adSIngo Molnar 		xen_e820_table.entries[0].type = E820_TYPE_RAM;
82935ae11fdSIan Campbell 		rc = 0;
83035ae11fdSIan Campbell 	}
83135ae11fdSIan Campbell 	BUG_ON(rc);
8321ea644c8SMartin Kelly 	BUG_ON(memmap.nr_entries == 0);
833e7dbf7adSIngo Molnar 	xen_e820_table.nr_entries = memmap.nr_entries;
8348006ec3eSJeremy Fitzhardinge 
8359338c223SRoss Lagerwall 	if (xen_initial_domain()) {
8363bc38cbcSDavid Vrabel 		/*
8373bc38cbcSDavid Vrabel 		 * Xen won't allow a 1:1 mapping to be created to UNUSABLE
8383bc38cbcSDavid Vrabel 		 * regions, so if we're using the machine memory map leave the
8393bc38cbcSDavid Vrabel 		 * region as RAM as it is in the pseudo-physical map.
8403bc38cbcSDavid Vrabel 		 *
8413bc38cbcSDavid Vrabel 		 * UNUSABLE regions in domUs are not handled and will need
8423bc38cbcSDavid Vrabel 		 * a patch in the future.
8433bc38cbcSDavid Vrabel 		 */
84469632ecfSJuergen Gross 		xen_ignore_unusable();
8453bc38cbcSDavid Vrabel 
8469338c223SRoss Lagerwall #ifdef CONFIG_ISCSI_IBFT_FIND
8479338c223SRoss Lagerwall 		/* Reserve 0.5 MiB to 1 MiB region so iBFT can be found */
8489338c223SRoss Lagerwall 		xen_e820_table.entries[xen_e820_table.nr_entries].addr = IBFT_START;
8499338c223SRoss Lagerwall 		xen_e820_table.entries[xen_e820_table.nr_entries].size = IBFT_END - IBFT_START;
8509338c223SRoss Lagerwall 		xen_e820_table.entries[xen_e820_table.nr_entries].type = E820_TYPE_RESERVED;
8519338c223SRoss Lagerwall 		xen_e820_table.nr_entries++;
8529338c223SRoss Lagerwall #endif
8539338c223SRoss Lagerwall 	}
8549338c223SRoss Lagerwall 
855dc91c728SDavid Vrabel 	/* Make sure the Xen-supplied memory map is well-ordered. */
856f9748fa0SIngo Molnar 	e820__update_table(&xen_e820_table);
857be5bf9faSJeremy Fitzhardinge 
858161fd691SJuergen Gross 	/*
859161fd691SJuergen Gross 	 * Check whether the kernel itself conflicts with the target E820 map.
860161fd691SJuergen Gross 	 * Failing now is better than running into weird problems later due
861161fd691SJuergen Gross 	 * to relocating (and even reusing) pages with kernel text or data.
862161fd691SJuergen Gross 	 */
863161fd691SJuergen Gross 	xen_chk_is_e820_usable(__pa_symbol(_text),
864161fd691SJuergen Gross 			       __pa_symbol(_end) - __pa_symbol(_text),
865161fd691SJuergen Gross 			       "kernel");
866161fd691SJuergen Gross 
867161fd691SJuergen Gross 	/*
868161fd691SJuergen Gross 	 * Check for a conflict of the xen_start_info memory with the target
869161fd691SJuergen Gross 	 * E820 map.
870161fd691SJuergen Gross 	 */
871161fd691SJuergen Gross 	xen_chk_is_e820_usable(__pa(xen_start_info), sizeof(*xen_start_info),
872161fd691SJuergen Gross 			       "xen_start_info");
873161fd691SJuergen Gross 
874161fd691SJuergen Gross 	/*
875161fd691SJuergen Gross 	 * Check for a conflict of the hypervisor supplied page tables with
876161fd691SJuergen Gross 	 * the target E820 map.
877161fd691SJuergen Gross 	 */
878161fd691SJuergen Gross 	xen_pt_check_e820();
879161fd691SJuergen Gross 
880dc91c728SDavid Vrabel 	max_pages = xen_get_max_pages();
8817cb31b75SStefano Stabellini 
8825097cdf6SJuergen Gross 	/* How many extra pages do we need due to remapping? */
883f12153eeSJuergen Gross 	max_pages += xen_foreach_remap_area(xen_count_remap_pages);
884eafd72e0SJuergen Gross 
885f12153eeSJuergen Gross 	if (max_pages > ini_nr_pages)
886f12153eeSJuergen Gross 		extra_pages += max_pages - ini_nr_pages;
8872e2fb754SKonrad Rzeszutek Wilk 
8882e2fb754SKonrad Rzeszutek Wilk 	/*
889af44a387SRoger Pau Monne 	 * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
89088221399SJuergen Gross 	 * factor the base size.
891dc91c728SDavid Vrabel 	 *
892c70727a5SJuergen Gross 	 * Make sure we have no memory above max_pages, as this area
893c70727a5SJuergen Gross 	 * isn't handled by the p2m management.
8942f14ddc3SZhang, Fengzhe 	 */
895f12153eeSJuergen Gross 	maxmem_pages = EXTRA_MEM_RATIO * min(ini_nr_pages, PFN_DOWN(MAXMEM));
896f12153eeSJuergen Gross 	extra_pages = min3(maxmem_pages, extra_pages, max_pages - ini_nr_pages);
897dc91c728SDavid Vrabel 	i = 0;
898e7dbf7adSIngo Molnar 	addr = xen_e820_table.entries[0].addr;
899e7dbf7adSIngo Molnar 	size = xen_e820_table.entries[0].size;
900e7dbf7adSIngo Molnar 	while (i < xen_e820_table.nr_entries) {
90112366410SIgor Druzhinin 		bool discard = false;
902f5775e0bSDavid Vrabel 
9035097cdf6SJuergen Gross 		chunk_size = size;
904e7dbf7adSIngo Molnar 		type = xen_e820_table.entries[i].type;
905dc91c728SDavid Vrabel 
906358cd9afSJuergen Gross 		if (type == E820_TYPE_RESERVED)
907358cd9afSJuergen Gross 			xen_pv_pci_possible = true;
908358cd9afSJuergen Gross 
90909821ff1SIngo Molnar 		if (type == E820_TYPE_RAM) {
910dc91c728SDavid Vrabel 			if (addr < mem_end) {
9115097cdf6SJuergen Gross 				chunk_size = min(size, mem_end - addr);
912dc91c728SDavid Vrabel 			} else if (extra_pages) {
9135097cdf6SJuergen Gross 				chunk_size = min(size, PFN_PHYS(extra_pages));
914626d7508SJuergen Gross 				pfn_s = PFN_UP(addr);
915626d7508SJuergen Gross 				n_pfns = PFN_DOWN(addr + chunk_size) - pfn_s;
916626d7508SJuergen Gross 				extra_pages -= n_pfns;
917626d7508SJuergen Gross 				xen_add_extra_mem(pfn_s, n_pfns);
918626d7508SJuergen Gross 				xen_max_p2m_pfn = pfn_s + n_pfns;
919dc91c728SDavid Vrabel 			} else
92012366410SIgor Druzhinin 				discard = true;
9213654581eSJeremy Fitzhardinge 		}
9223654581eSJeremy Fitzhardinge 
92312366410SIgor Druzhinin 		if (!discard)
9245097cdf6SJuergen Gross 			xen_align_and_add_e820_region(addr, chunk_size, type);
925b5b43cedSJeremy Fitzhardinge 
9265097cdf6SJuergen Gross 		addr += chunk_size;
9275097cdf6SJuergen Gross 		size -= chunk_size;
9285097cdf6SJuergen Gross 		if (size == 0) {
929dc91c728SDavid Vrabel 			i++;
930e7dbf7adSIngo Molnar 			if (i < xen_e820_table.nr_entries) {
931e7dbf7adSIngo Molnar 				addr = xen_e820_table.entries[i].addr;
932e7dbf7adSIngo Molnar 				size = xen_e820_table.entries[i].size;
9335097cdf6SJuergen Gross 			}
9345097cdf6SJuergen Gross 		}
93535ae11fdSIan Campbell 	}
936b792c755SJeremy Fitzhardinge 
937b792c755SJeremy Fitzhardinge 	/*
93825b884a8SDavid Vrabel 	 * Set the rest as identity mapped, in case PCI BARs are
93925b884a8SDavid Vrabel 	 * located here.
94025b884a8SDavid Vrabel 	 */
9415097cdf6SJuergen Gross 	set_phys_range_identity(addr / PAGE_SIZE, ~0ul);
94225b884a8SDavid Vrabel 
94325b884a8SDavid Vrabel 	/*
9449ec23a7fSIan Campbell 	 * In domU, the ISA region is normal, usable memory, but we
9459ec23a7fSIan Campbell 	 * reserve ISA memory anyway because too many things poke
946b792c755SJeremy Fitzhardinge 	 * about in there.
947b792c755SJeremy Fitzhardinge 	 */
948f9748fa0SIngo Molnar 	e820__range_add(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS, E820_TYPE_RESERVED);
9499702785aSThomas Gleixner 
950f9748fa0SIngo Molnar 	e820__update_table(e820_table);
951be5bf9faSJeremy Fitzhardinge 
9528f5b0c63SJuergen Gross 	xen_reserve_xen_mfnlist();
9538f5b0c63SJuergen Gross 
9544b9c1537SJuergen Gross 	/* Check for a conflict of the initrd with the target E820 map. */
9554b9c1537SJuergen Gross 	if (xen_is_e820_reserved(boot_params.hdr.ramdisk_image,
9564b9c1537SJuergen Gross 				 boot_params.hdr.ramdisk_size)) {
9574b9c1537SJuergen Gross 		phys_addr_t new_area, start, size;
9584b9c1537SJuergen Gross 
9594b9c1537SJuergen Gross 		new_area = xen_find_free_area(boot_params.hdr.ramdisk_size);
9604b9c1537SJuergen Gross 		if (!new_area) {
9614b9c1537SJuergen Gross 			xen_raw_console_write("Can't find new memory area for initrd needed due to E820 map conflict\n");
9624b9c1537SJuergen Gross 			BUG();
9634b9c1537SJuergen Gross 		}
9644b9c1537SJuergen Gross 
9654b9c1537SJuergen Gross 		start = boot_params.hdr.ramdisk_image;
9664b9c1537SJuergen Gross 		size = boot_params.hdr.ramdisk_size;
9674b9c1537SJuergen Gross 		xen_phys_memcpy(new_area, start, size);
9684b9c1537SJuergen Gross 		pr_info("initrd moved from [mem %#010llx-%#010llx] to [mem %#010llx-%#010llx]\n",
9694b9c1537SJuergen Gross 			start, start + size, new_area, new_area + size);
9703ecc6834SMike Rapoport 		memblock_phys_free(start, size);
9714b9c1537SJuergen Gross 		boot_params.hdr.ramdisk_image = new_area;
9724b9c1537SJuergen Gross 		boot_params.ext_ramdisk_image = new_area >> 32;
9734b9c1537SJuergen Gross 	}
9744b9c1537SJuergen Gross 
9755097cdf6SJuergen Gross 	/*
9765097cdf6SJuergen Gross 	 * Set identity map on non-RAM pages and prepare remapping the
9775097cdf6SJuergen Gross 	 * underlying RAM.
9785097cdf6SJuergen Gross 	 */
979f12153eeSJuergen Gross 	xen_foreach_remap_area(xen_set_identity_and_remap_chunk);
980dd14be92SJuergen Gross 
981dd14be92SJuergen Gross 	pr_info("Released %ld page(s)\n", xen_released_pages);
9825097cdf6SJuergen Gross 
9839702785aSThomas Gleixner 	return "Xen";
9849702785aSThomas Gleixner }
9859702785aSThomas Gleixner 
register_callback(unsigned type,const void * func)986148f9bb8SPaul Gortmaker static int register_callback(unsigned type, const void *func)
987e2a81bafSJeremy Fitzhardinge {
98888459d4cSJeremy Fitzhardinge 	struct callback_register callback = {
98988459d4cSJeremy Fitzhardinge 		.type = type,
99088459d4cSJeremy Fitzhardinge 		.address = XEN_CALLBACK(__KERNEL_CS, func),
991e2a81bafSJeremy Fitzhardinge 		.flags = CALLBACKF_mask_events,
992e2a81bafSJeremy Fitzhardinge 	};
993e2a81bafSJeremy Fitzhardinge 
99488459d4cSJeremy Fitzhardinge 	return HYPERVISOR_callback_op(CALLBACKOP_register, &callback);
99588459d4cSJeremy Fitzhardinge }
99688459d4cSJeremy Fitzhardinge 
xen_enable_sysenter(void)997148f9bb8SPaul Gortmaker void xen_enable_sysenter(void)
99888459d4cSJeremy Fitzhardinge {
9994bff677bSJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_SYSENTER32) &&
10004bff677bSJuergen Gross 	    register_callback(CALLBACKTYPE_sysenter, xen_entry_SYSENTER_compat))
10014bff677bSJuergen Gross 		setup_clear_cpu_cap(X86_FEATURE_SYSENTER32);
1002e2a81bafSJeremy Fitzhardinge }
1003e2a81bafSJeremy Fitzhardinge 
xen_enable_syscall(void)1004148f9bb8SPaul Gortmaker void xen_enable_syscall(void)
10056fcac6d3SJeremy Fitzhardinge {
10066fcac6d3SJeremy Fitzhardinge 	int ret;
10076fcac6d3SJeremy Fitzhardinge 
1008b75b7f8eSPeter Zijlstra 	ret = register_callback(CALLBACKTYPE_syscall, xen_entry_SYSCALL_64);
10096fcac6d3SJeremy Fitzhardinge 	if (ret != 0) {
1010d5303b81SJeremy Fitzhardinge 		printk(KERN_ERR "Failed to set syscall callback: %d\n", ret);
101162541c37SJeremy Fitzhardinge 		/* Pretty fatal; 64-bit userspace has no other
101262541c37SJeremy Fitzhardinge 		   mechanism for syscalls. */
101362541c37SJeremy Fitzhardinge 	}
101462541c37SJeremy Fitzhardinge 
10154bff677bSJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_SYSCALL32) &&
10164bff677bSJuergen Gross 	    register_callback(CALLBACKTYPE_syscall32, xen_entry_SYSCALL_compat))
101762541c37SJeremy Fitzhardinge 		setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
10186fcac6d3SJeremy Fitzhardinge }
1019ea9f9274SDavid Vrabel 
xen_pvmmu_arch_setup(void)10200e1b4271SJason Yan static void __init xen_pvmmu_arch_setup(void)
10219702785aSThomas Gleixner {
10229702785aSThomas Gleixner 	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
10239702785aSThomas Gleixner 
10242f6474e4SThomas Gleixner 	if (register_callback(CALLBACKTYPE_event,
10252f6474e4SThomas Gleixner 			      xen_asm_exc_xen_hypervisor_callback) ||
102688459d4cSJeremy Fitzhardinge 	    register_callback(CALLBACKTYPE_failsafe, xen_failsafe_callback))
102788459d4cSJeremy Fitzhardinge 		BUG();
10289702785aSThomas Gleixner 
1029e2a81bafSJeremy Fitzhardinge 	xen_enable_sysenter();
10306fcac6d3SJeremy Fitzhardinge 	xen_enable_syscall();
1031d285d683SMukesh Rathor }
1032d285d683SMukesh Rathor 
1033d285d683SMukesh Rathor /* This function is not called for HVM domains */
xen_arch_setup(void)1034d285d683SMukesh Rathor void __init xen_arch_setup(void)
1035d285d683SMukesh Rathor {
1036d285d683SMukesh Rathor 	xen_panic_handler_init();
1037d285d683SMukesh Rathor 	xen_pvmmu_arch_setup();
1038d285d683SMukesh Rathor 
10399702785aSThomas Gleixner #ifdef CONFIG_ACPI
10409702785aSThomas Gleixner 	if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
10419702785aSThomas Gleixner 		printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
10429702785aSThomas Gleixner 		disable_acpi();
10439702785aSThomas Gleixner 	}
10449702785aSThomas Gleixner #endif
10459702785aSThomas Gleixner 
10469702785aSThomas Gleixner 	memcpy(boot_command_line, xen_start_info->cmd_line,
10479702785aSThomas Gleixner 	       MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
10489702785aSThomas Gleixner 	       COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
10499702785aSThomas Gleixner 
1050bc15fde7SJeremy Fitzhardinge 	/* Set up idle, making sure it calls safe_halt() pvop */
1051d91ee586SLen Brown 	disable_cpuidle();
105248cdd828SKonrad Rzeszutek Wilk 	disable_cpufreq();
10536a377ddcSLen Brown 	WARN_ON(xen_set_default_idle());
10548d54db79SKonrad Rzeszutek Wilk #ifdef CONFIG_NUMA
10558d54db79SKonrad Rzeszutek Wilk 	numa_off = 1;
10568d54db79SKonrad Rzeszutek Wilk #endif
10579702785aSThomas Gleixner }
1058