1 /******************************************************************************
4 * Update page tables via the hypervisor.
6 * Copyright (c) 2002-2004, K A Fraser
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
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:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
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
30 #include <linux/config.h>
31 #include <linux/sched.h>
33 #include <linux/vmalloc.h>
35 #include <asm/pgtable.h>
36 #include <asm-xen/hypervisor.h>
37 #include <asm-xen/balloon.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
39 #include <linux/percpu.h>
40 #include <asm/tlbflush.h>
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
44 #define pte_offset_kernel pte_offset
46 #define pud_offset(d, va) d
48 #define pmd_val_ma(v) (v).pud.pgd.pgd;
51 #ifndef CONFIG_XEN_SHADOW_MODE
52 void xen_l1_entry_update(pte_t *ptr, unsigned long val)
55 u.ptr = virt_to_machine(ptr);
57 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
60 void xen_l2_entry_update(pmd_t *ptr, pmd_t val)
63 u.ptr = virt_to_machine(ptr);
64 u.val = pmd_val_ma(val);
65 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
69 void xen_machphys_update(unsigned long mfn, unsigned long pfn)
72 u.ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
74 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
77 void xen_pt_switch(unsigned long ptr)
80 op.cmd = MMUEXT_NEW_BASEPTR;
81 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
82 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
85 void xen_tlb_flush(void)
88 op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
89 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
92 void xen_invlpg(unsigned long ptr)
95 op.cmd = MMUEXT_INVLPG_LOCAL;
96 op.linear_addr = ptr & PAGE_MASK;
97 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
102 void xen_tlb_flush_all(void)
105 op.cmd = MMUEXT_TLB_FLUSH_ALL;
106 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
109 void xen_tlb_flush_mask(cpumask_t mask)
112 op.cmd = MMUEXT_TLB_FLUSH_MULTI;
113 op.cpuset = mask.bits;
114 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
117 void xen_invlpg_all(unsigned long ptr)
120 op.cmd = MMUEXT_INVLPG_ALL;
121 op.linear_addr = ptr & PAGE_MASK;
122 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
125 void xen_invlpg_mask(cpumask_t mask, unsigned long ptr)
128 op.cmd = MMUEXT_INVLPG_MULTI;
129 op.cpuset = mask.bits;
130 op.linear_addr = ptr & PAGE_MASK;
131 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
134 #endif /* CONFIG_SMP */
136 #ifndef CONFIG_XEN_SHADOW_MODE
137 void xen_pgd_pin(unsigned long ptr)
140 op.cmd = MMUEXT_PIN_L2_TABLE;
141 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
142 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
145 void xen_pgd_unpin(unsigned long ptr)
148 op.cmd = MMUEXT_UNPIN_TABLE;
149 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
150 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
153 void xen_pte_pin(unsigned long ptr)
156 op.cmd = MMUEXT_PIN_L1_TABLE;
157 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
158 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
161 void xen_pte_unpin(unsigned long ptr)
164 op.cmd = MMUEXT_UNPIN_TABLE;
165 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
166 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
170 void xen_set_ldt(unsigned long ptr, unsigned long len)
173 op.cmd = MMUEXT_SET_LDT;
174 op.linear_addr = ptr;
176 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
179 #ifdef CONFIG_XEN_PHYSDEV_ACCESS
181 unsigned long allocate_empty_lowmem_region(unsigned long pages)
187 unsigned long *pfn_array;
188 unsigned long vstart;
190 unsigned int order = get_order(pages*PAGE_SIZE);
192 vstart = __get_free_pages(GFP_KERNEL, order);
196 scrub_pages(vstart, 1 << order);
198 pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
199 if ( pfn_array == NULL )
202 for ( i = 0; i < (1<<order); i++ )
204 pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
205 pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
206 pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
207 pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
208 pfn_array[i] = pte->pte_low >> PAGE_SHIFT;
209 HYPERVISOR_update_va_mapping(vstart + (i*PAGE_SIZE), __pte_ma(0), 0);
210 phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] =
216 balloon_put_pages(pfn_array, 1 << order);
223 #endif /* CONFIG_XEN_PHYSDEV_ACCESS */