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