debuggers.hg

view linux-2.6.10-rc2-xen-sparse/arch/xen/i386/mm/hypervisor.c @ 3289:a169836882cb

bitkeeper revision 1.1159.170.59 (41b4c2fdJ2gj_BWy27Vj3ptayZp_yg)

sync w/ head.
author cl349@arcadians.cl.cam.ac.uk
date Mon Dec 06 20:37:17 2004 +0000 (2004-12-06)
parents f65b65977b19
children
line source
1 /******************************************************************************
2 * mm/hypervisor.c
3 *
4 * Update page tables via the hypervisor.
5 *
6 * Copyright (c) 2002-2004, K A Fraser
7 *
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this source file (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy, modify,
14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 * and to permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 * IN THE SOFTWARE.
28 */
30 #include <linux/config.h>
31 #include <linux/sched.h>
32 #include <linux/mm.h>
33 #include <linux/vmalloc.h>
34 #include <asm/page.h>
35 #include <asm/pgtable.h>
36 #include <asm-xen/hypervisor.h>
37 #include <asm-xen/multicall.h>
38 #include <asm-xen/balloon.h>
40 /*
41 * This suffices to protect us if we ever move to SMP domains.
42 * Further, it protects us against interrupts. At the very least, this is
43 * required for the network driver which flushes the update queue before
44 * pushing new receive buffers.
45 */
46 static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
48 /* Linux 2.6 isn't using the traditional batched interface. */
49 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
50 #define QUEUE_SIZE 2048
51 #define pte_offset_kernel pte_offset
52 #else
53 #define QUEUE_SIZE 128
54 #endif
56 static mmu_update_t update_queue[QUEUE_SIZE];
57 unsigned int mmu_update_queue_idx = 0;
58 #define idx mmu_update_queue_idx
60 /*
61 * MULTICALL_flush_page_update_queue:
62 * This is a version of the flush which queues as part of a multicall.
63 */
64 void MULTICALL_flush_page_update_queue(void)
65 {
66 unsigned long flags;
67 unsigned int _idx;
68 spin_lock_irqsave(&update_lock, flags);
69 if ( (_idx = idx) != 0 )
70 {
71 idx = 0;
72 wmb(); /* Make sure index is cleared first to avoid double updates. */
73 queue_multicall3(__HYPERVISOR_mmu_update,
74 (unsigned long)update_queue,
75 (unsigned long)_idx,
76 (unsigned long)NULL);
77 }
78 spin_unlock_irqrestore(&update_lock, flags);
79 }
81 static inline void __flush_page_update_queue(void)
82 {
83 unsigned int _idx = idx;
84 idx = 0;
85 wmb(); /* Make sure index is cleared first to avoid double updates. */
86 if ( unlikely(HYPERVISOR_mmu_update(update_queue, _idx, NULL) < 0) )
87 {
88 printk(KERN_ALERT "Failed to execute MMU updates.\n");
89 BUG();
90 }
91 }
93 void _flush_page_update_queue(void)
94 {
95 unsigned long flags;
96 spin_lock_irqsave(&update_lock, flags);
97 if ( idx != 0 ) __flush_page_update_queue();
98 spin_unlock_irqrestore(&update_lock, flags);
99 }
101 static inline void increment_index(void)
102 {
103 idx++;
104 if ( unlikely(idx == QUEUE_SIZE) ) __flush_page_update_queue();
105 }
107 static inline void increment_index_and_flush(void)
108 {
109 idx++;
110 __flush_page_update_queue();
111 }
113 void queue_l1_entry_update(pte_t *ptr, unsigned long val)
114 {
115 unsigned long flags;
116 spin_lock_irqsave(&update_lock, flags);
117 update_queue[idx].ptr = virt_to_machine(ptr);
118 update_queue[idx].val = val;
119 increment_index();
120 spin_unlock_irqrestore(&update_lock, flags);
121 }
123 void queue_l2_entry_update(pmd_t *ptr, unsigned long val)
124 {
125 unsigned long flags;
126 spin_lock_irqsave(&update_lock, flags);
127 update_queue[idx].ptr = virt_to_machine(ptr);
128 update_queue[idx].val = val;
129 increment_index();
130 spin_unlock_irqrestore(&update_lock, flags);
131 }
133 void queue_pt_switch(unsigned long ptr)
134 {
135 unsigned long flags;
136 spin_lock_irqsave(&update_lock, flags);
137 update_queue[idx].ptr = phys_to_machine(ptr);
138 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
139 update_queue[idx].val = MMUEXT_NEW_BASEPTR;
140 increment_index();
141 spin_unlock_irqrestore(&update_lock, flags);
142 }
144 void queue_tlb_flush(void)
145 {
146 unsigned long flags;
147 spin_lock_irqsave(&update_lock, flags);
148 update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
149 update_queue[idx].val = MMUEXT_TLB_FLUSH;
150 increment_index();
151 spin_unlock_irqrestore(&update_lock, flags);
152 }
154 void queue_invlpg(unsigned long ptr)
155 {
156 unsigned long flags;
157 spin_lock_irqsave(&update_lock, flags);
158 update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
159 update_queue[idx].ptr |= ptr & PAGE_MASK;
160 update_queue[idx].val = MMUEXT_INVLPG;
161 increment_index();
162 spin_unlock_irqrestore(&update_lock, flags);
163 }
165 void queue_pgd_pin(unsigned long ptr)
166 {
167 unsigned long flags;
168 spin_lock_irqsave(&update_lock, flags);
169 update_queue[idx].ptr = phys_to_machine(ptr);
170 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
171 update_queue[idx].val = MMUEXT_PIN_L2_TABLE;
172 increment_index();
173 spin_unlock_irqrestore(&update_lock, flags);
174 }
176 void queue_pgd_unpin(unsigned long ptr)
177 {
178 unsigned long flags;
179 spin_lock_irqsave(&update_lock, flags);
180 update_queue[idx].ptr = phys_to_machine(ptr);
181 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
182 update_queue[idx].val = MMUEXT_UNPIN_TABLE;
183 increment_index();
184 spin_unlock_irqrestore(&update_lock, flags);
185 }
187 void queue_pte_pin(unsigned long ptr)
188 {
189 unsigned long flags;
190 spin_lock_irqsave(&update_lock, flags);
191 update_queue[idx].ptr = phys_to_machine(ptr);
192 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
193 update_queue[idx].val = MMUEXT_PIN_L1_TABLE;
194 increment_index();
195 spin_unlock_irqrestore(&update_lock, flags);
196 }
198 void queue_pte_unpin(unsigned long ptr)
199 {
200 unsigned long flags;
201 spin_lock_irqsave(&update_lock, flags);
202 update_queue[idx].ptr = phys_to_machine(ptr);
203 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
204 update_queue[idx].val = MMUEXT_UNPIN_TABLE;
205 increment_index();
206 spin_unlock_irqrestore(&update_lock, flags);
207 }
209 void queue_set_ldt(unsigned long ptr, unsigned long len)
210 {
211 unsigned long flags;
212 spin_lock_irqsave(&update_lock, flags);
213 update_queue[idx].ptr = MMU_EXTENDED_COMMAND | ptr;
214 update_queue[idx].val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
215 increment_index();
216 spin_unlock_irqrestore(&update_lock, flags);
217 }
219 void queue_machphys_update(unsigned long mfn, unsigned long pfn)
220 {
221 unsigned long flags;
222 spin_lock_irqsave(&update_lock, flags);
223 update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
224 update_queue[idx].val = pfn;
225 increment_index();
226 spin_unlock_irqrestore(&update_lock, flags);
227 }
229 /* queue and flush versions of the above */
230 void xen_l1_entry_update(pte_t *ptr, unsigned long val)
231 {
232 unsigned long flags;
233 spin_lock_irqsave(&update_lock, flags);
234 update_queue[idx].ptr = virt_to_machine(ptr);
235 update_queue[idx].val = val;
236 increment_index_and_flush();
237 spin_unlock_irqrestore(&update_lock, flags);
238 }
240 void xen_l2_entry_update(pmd_t *ptr, unsigned long val)
241 {
242 unsigned long flags;
243 spin_lock_irqsave(&update_lock, flags);
244 update_queue[idx].ptr = virt_to_machine(ptr);
245 update_queue[idx].val = val;
246 increment_index_and_flush();
247 spin_unlock_irqrestore(&update_lock, flags);
248 }
250 void xen_pt_switch(unsigned long ptr)
251 {
252 unsigned long flags;
253 spin_lock_irqsave(&update_lock, flags);
254 update_queue[idx].ptr = phys_to_machine(ptr);
255 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
256 update_queue[idx].val = MMUEXT_NEW_BASEPTR;
257 increment_index_and_flush();
258 spin_unlock_irqrestore(&update_lock, flags);
259 }
261 void xen_tlb_flush(void)
262 {
263 unsigned long flags;
264 spin_lock_irqsave(&update_lock, flags);
265 update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
266 update_queue[idx].val = MMUEXT_TLB_FLUSH;
267 increment_index_and_flush();
268 spin_unlock_irqrestore(&update_lock, flags);
269 }
271 void xen_invlpg(unsigned long ptr)
272 {
273 unsigned long flags;
274 spin_lock_irqsave(&update_lock, flags);
275 update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
276 update_queue[idx].ptr |= ptr & PAGE_MASK;
277 update_queue[idx].val = MMUEXT_INVLPG;
278 increment_index_and_flush();
279 spin_unlock_irqrestore(&update_lock, flags);
280 }
282 void xen_pgd_pin(unsigned long ptr)
283 {
284 unsigned long flags;
285 spin_lock_irqsave(&update_lock, flags);
286 update_queue[idx].ptr = phys_to_machine(ptr);
287 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
288 update_queue[idx].val = MMUEXT_PIN_L2_TABLE;
289 increment_index_and_flush();
290 spin_unlock_irqrestore(&update_lock, flags);
291 }
293 void xen_pgd_unpin(unsigned long ptr)
294 {
295 unsigned long flags;
296 spin_lock_irqsave(&update_lock, flags);
297 update_queue[idx].ptr = phys_to_machine(ptr);
298 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
299 update_queue[idx].val = MMUEXT_UNPIN_TABLE;
300 increment_index_and_flush();
301 spin_unlock_irqrestore(&update_lock, flags);
302 }
304 void xen_pte_pin(unsigned long ptr)
305 {
306 unsigned long flags;
307 spin_lock_irqsave(&update_lock, flags);
308 update_queue[idx].ptr = phys_to_machine(ptr);
309 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
310 update_queue[idx].val = MMUEXT_PIN_L1_TABLE;
311 increment_index_and_flush();
312 spin_unlock_irqrestore(&update_lock, flags);
313 }
315 void xen_pte_unpin(unsigned long ptr)
316 {
317 unsigned long flags;
318 spin_lock_irqsave(&update_lock, flags);
319 update_queue[idx].ptr = phys_to_machine(ptr);
320 update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
321 update_queue[idx].val = MMUEXT_UNPIN_TABLE;
322 increment_index_and_flush();
323 spin_unlock_irqrestore(&update_lock, flags);
324 }
326 void xen_set_ldt(unsigned long ptr, unsigned long len)
327 {
328 unsigned long flags;
329 spin_lock_irqsave(&update_lock, flags);
330 update_queue[idx].ptr = MMU_EXTENDED_COMMAND | ptr;
331 update_queue[idx].val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
332 increment_index_and_flush();
333 spin_unlock_irqrestore(&update_lock, flags);
334 }
336 void xen_machphys_update(unsigned long mfn, unsigned long pfn)
337 {
338 unsigned long flags;
339 spin_lock_irqsave(&update_lock, flags);
340 update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
341 update_queue[idx].val = pfn;
342 increment_index_and_flush();
343 spin_unlock_irqrestore(&update_lock, flags);
344 }
346 #ifdef CONFIG_XEN_PHYSDEV_ACCESS
348 unsigned long allocate_empty_lowmem_region(unsigned long pages)
349 {
350 pgd_t *pgd;
351 pmd_t *pmd;
352 pte_t *pte;
353 unsigned long *pfn_array;
354 unsigned long vstart;
355 unsigned long i;
356 unsigned int order = get_order(pages*PAGE_SIZE);
358 vstart = __get_free_pages(GFP_KERNEL, order);
359 if ( vstart == 0 )
360 return 0UL;
362 scrub_pages(vstart, 1 << order);
364 pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
365 if ( pfn_array == NULL )
366 BUG();
368 for ( i = 0; i < (1<<order); i++ )
369 {
370 pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
371 pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE)));
372 pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
373 pfn_array[i] = pte->pte_low >> PAGE_SHIFT;
374 queue_l1_entry_update(pte, 0);
375 phys_to_machine_mapping[__pa(vstart)>>PAGE_SHIFT] = INVALID_P2M_ENTRY;
376 }
378 /* Flush updates through and flush the TLB. */
379 xen_tlb_flush();
381 balloon_put_pages(pfn_array, 1 << order);
383 vfree(pfn_array);
385 return vstart;
386 }
388 #endif /* CONFIG_XEN_PHYSDEV_ACCESS */