diff options
Diffstat (limited to 'arch/x86/xen/mmu.c')
| -rw-r--r-- | arch/x86/xen/mmu.c | 201 |
1 files changed, 201 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 */ | ||
| 2033 | static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER]; | ||
| 2034 | |||
| 2035 | #define VOID_PTE (mfn_pte(0, __pgprot(0))) | ||
| 2036 | static 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 | */ | ||
| 2064 | static 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 | */ | ||
| 2110 | static 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 | |||
| 2147 | int 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 | } | ||
| 2191 | EXPORT_SYMBOL_GPL(xen_create_contiguous_region); | ||
| 2192 | |||
| 2193 | void 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 | } | ||
| 2229 | EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); | ||
| 2230 | |||
| 2030 | #ifdef CONFIG_XEN_DEBUG_FS | 2231 | #ifdef CONFIG_XEN_DEBUG_FS |
| 2031 | 2232 | ||
| 2032 | static struct dentry *d_mmu_debug; | 2233 | static struct dentry *d_mmu_debug; |
