aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/xen/mmu.c201
-rw-r--r--include/xen/interface/memory.h42
-rw-r--r--include/xen/xen-ops.h6
3 files changed, 249 insertions, 0 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 9e0d82fc21e4..eb51402dd99a 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -53,6 +53,7 @@
53#include <asm/paravirt.h> 53#include <asm/paravirt.h>
54#include <asm/e820.h> 54#include <asm/e820.h>
55#include <asm/linkage.h> 55#include <asm/linkage.h>
56#include <asm/page.h>
56 57
57#include <asm/xen/hypercall.h> 58#include <asm/xen/hypercall.h>
58#include <asm/xen/hypervisor.h> 59#include <asm/xen/hypervisor.h>
@@ -2027,6 +2028,206 @@ void __init xen_init_mmu_ops(void)
2027 pv_mmu_ops = xen_mmu_ops; 2028 pv_mmu_ops = xen_mmu_ops;
2028} 2029}
2029 2030
2031/* Protected by xen_reservation_lock. */
2032#define MAX_CONTIG_ORDER 9 /* 2MB */
2033static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
2034
2035#define VOID_PTE (mfn_pte(0, __pgprot(0)))
2036static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order,
2037 unsigned long *in_frames,
2038 unsigned long *out_frames)
2039{
2040 int i;
2041 struct multicall_space mcs;
2042
2043 xen_mc_batch();
2044 for (i = 0; i < (1UL<<order); i++, vaddr += PAGE_SIZE) {
2045 mcs = __xen_mc_entry(0);
2046
2047 if (in_frames)
2048 in_frames[i] = virt_to_mfn(vaddr);
2049
2050 MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
2051 set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
2052
2053 if (out_frames)
2054 out_frames[i] = virt_to_pfn(vaddr);
2055 }
2056 xen_mc_issue(0);
2057}
2058
2059/*
2060 * Update the pfn-to-mfn mappings for a virtual address range, either to
2061 * point to an array of mfns, or contiguously from a single starting
2062 * mfn.
2063 */
2064static void xen_remap_exchanged_ptes(unsigned long vaddr, int order,
2065 unsigned long *mfns,
2066 unsigned long first_mfn)
2067{
2068 unsigned i, limit;
2069 unsigned long mfn;
2070
2071 xen_mc_batch();
2072
2073 limit = 1u << order;
2074 for (i = 0; i < limit; i++, vaddr += PAGE_SIZE) {
2075 struct multicall_space mcs;
2076 unsigned flags;
2077
2078 mcs = __xen_mc_entry(0);
2079 if (mfns)
2080 mfn = mfns[i];
2081 else
2082 mfn = first_mfn + i;
2083
2084 if (i < (limit - 1))
2085 flags = 0;
2086 else {
2087 if (order == 0)
2088 flags = UVMF_INVLPG | UVMF_ALL;
2089 else
2090 flags = UVMF_TLB_FLUSH | UVMF_ALL;
2091 }
2092
2093 MULTI_update_va_mapping(mcs.mc, vaddr,
2094 mfn_pte(mfn, PAGE_KERNEL), flags);
2095
2096 set_phys_to_machine(virt_to_pfn(vaddr), mfn);
2097 }
2098
2099 xen_mc_issue(0);
2100}
2101
2102/*
2103 * Perform the hypercall to exchange a region of our pfns to point to
2104 * memory with the required contiguous alignment. Takes the pfns as
2105 * input, and populates mfns as output.
2106 *
2107 * Returns a success code indicating whether the hypervisor was able to
2108 * satisfy the request or not.
2109 */
2110static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
2111 unsigned long *pfns_in,
2112 unsigned long extents_out,
2113 unsigned int order_out,
2114 unsigned long *mfns_out,
2115 unsigned int address_bits)
2116{
2117 long rc;
2118 int success;
2119
2120 struct xen_memory_exchange exchange = {
2121 .in = {
2122 .nr_extents = extents_in,
2123 .extent_order = order_in,
2124 .extent_start = pfns_in,
2125 .domid = DOMID_SELF
2126 },
2127 .out = {
2128 .nr_extents = extents_out,
2129 .extent_order = order_out,
2130 .extent_start = mfns_out,
2131 .address_bits = address_bits,
2132 .domid = DOMID_SELF
2133 }
2134 };
2135
2136 BUG_ON(extents_in << order_in != extents_out << order_out);
2137
2138 rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
2139 success = (exchange.nr_exchanged == extents_in);
2140
2141 BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
2142 BUG_ON(success && (rc != 0));
2143
2144 return success;
2145}
2146
2147int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
2148 unsigned int address_bits)
2149{
2150 unsigned long *in_frames = discontig_frames, out_frame;
2151 unsigned long flags;
2152 int success;
2153
2154 /*
2155 * Currently an auto-translated guest will not perform I/O, nor will
2156 * it require PAE page directories below 4GB. Therefore any calls to
2157 * this function are redundant and can be ignored.
2158 */
2159
2160 if (xen_feature(XENFEAT_auto_translated_physmap))
2161 return 0;
2162
2163 if (unlikely(order > MAX_CONTIG_ORDER))
2164 return -ENOMEM;
2165
2166 memset((void *) vstart, 0, PAGE_SIZE << order);
2167
2168 vm_unmap_aliases();
2169
2170 spin_lock_irqsave(&xen_reservation_lock, flags);
2171
2172 /* 1. Zap current PTEs, remembering MFNs. */
2173 xen_zap_pfn_range(vstart, order, in_frames, NULL);
2174
2175 /* 2. Get a new contiguous memory extent. */
2176 out_frame = virt_to_pfn(vstart);
2177 success = xen_exchange_memory(1UL << order, 0, in_frames,
2178 1, order, &out_frame,
2179 address_bits);
2180
2181 /* 3. Map the new extent in place of old pages. */
2182 if (success)
2183 xen_remap_exchanged_ptes(vstart, order, NULL, out_frame);
2184 else
2185 xen_remap_exchanged_ptes(vstart, order, in_frames, 0);
2186
2187 spin_unlock_irqrestore(&xen_reservation_lock, flags);
2188
2189 return success ? 0 : -ENOMEM;
2190}
2191EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
2192
2193void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
2194{
2195 unsigned long *out_frames = discontig_frames, in_frame;
2196 unsigned long flags;
2197 int success;
2198
2199 if (xen_feature(XENFEAT_auto_translated_physmap))
2200 return;
2201
2202 if (unlikely(order > MAX_CONTIG_ORDER))
2203 return;
2204
2205 memset((void *) vstart, 0, PAGE_SIZE << order);
2206
2207 vm_unmap_aliases();
2208
2209 spin_lock_irqsave(&xen_reservation_lock, flags);
2210
2211 /* 1. Find start MFN of contiguous extent. */
2212 in_frame = virt_to_mfn(vstart);
2213
2214 /* 2. Zap current PTEs. */
2215 xen_zap_pfn_range(vstart, order, NULL, out_frames);
2216
2217 /* 3. Do the exchange for non-contiguous MFNs. */
2218 success = xen_exchange_memory(1, order, &in_frame, 1UL << order,
2219 0, out_frames, 0);
2220
2221 /* 4. Map new pages in place of old pages. */
2222 if (success)
2223 xen_remap_exchanged_ptes(vstart, order, out_frames, 0);
2224 else
2225 xen_remap_exchanged_ptes(vstart, order, NULL, in_frame);
2226
2227 spin_unlock_irqrestore(&xen_reservation_lock, flags);
2228}
2229EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
2230
2030#ifdef CONFIG_XEN_DEBUG_FS 2231#ifdef CONFIG_XEN_DEBUG_FS
2031 2232
2032static struct dentry *d_mmu_debug; 2233static struct dentry *d_mmu_debug;
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index e6adce6bc75c..d3938d3e71f8 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -55,6 +55,48 @@ struct xen_memory_reservation {
55DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation); 55DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
56 56
57/* 57/*
58 * An atomic exchange of memory pages. If return code is zero then
59 * @out.extent_list provides GMFNs of the newly-allocated memory.
60 * Returns zero on complete success, otherwise a negative error code.
61 * On complete success then always @nr_exchanged == @in.nr_extents.
62 * On partial success @nr_exchanged indicates how much work was done.
63 */
64#define XENMEM_exchange 11
65struct xen_memory_exchange {
66 /*
67 * [IN] Details of memory extents to be exchanged (GMFN bases).
68 * Note that @in.address_bits is ignored and unused.
69 */
70 struct xen_memory_reservation in;
71
72 /*
73 * [IN/OUT] Details of new memory extents.
74 * We require that:
75 * 1. @in.domid == @out.domid
76 * 2. @in.nr_extents << @in.extent_order ==
77 * @out.nr_extents << @out.extent_order
78 * 3. @in.extent_start and @out.extent_start lists must not overlap
79 * 4. @out.extent_start lists GPFN bases to be populated
80 * 5. @out.extent_start is overwritten with allocated GMFN bases
81 */
82 struct xen_memory_reservation out;
83
84 /*
85 * [OUT] Number of input extents that were successfully exchanged:
86 * 1. The first @nr_exchanged input extents were successfully
87 * deallocated.
88 * 2. The corresponding first entries in the output extent list correctly
89 * indicate the GMFNs that were successfully exchanged.
90 * 3. All other input and output extents are untouched.
91 * 4. If not all input exents are exchanged then the return code of this
92 * command will be non-zero.
93 * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
94 */
95 unsigned long nr_exchanged;
96};
97
98DEFINE_GUEST_HANDLE_STRUCT(xen_memory_exchange);
99/*
58 * Returns the maximum machine frame number of mapped RAM in this system. 100 * Returns the maximum machine frame number of mapped RAM in this system.
59 * This command always succeeds (it never returns an error code). 101 * This command always succeeds (it never returns an error code).
60 * arg == NULL. 102 * arg == NULL.
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 883a21bba24b..d789c937c48a 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -14,4 +14,10 @@ void xen_mm_unpin_all(void);
14void xen_timer_resume(void); 14void xen_timer_resume(void);
15void xen_arch_resume(void); 15void xen_arch_resume(void);
16 16
17extern unsigned long *xen_contiguous_bitmap;
18int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
19 unsigned int address_bits);
20
21void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
22
17#endif /* INCLUDE_XEN_OPS_H */ 23#endif /* INCLUDE_XEN_OPS_H */