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 * Jun Nakajima <jun.nakajima@intel.com>
31 * Added hypercalls for x86-64.
35 #include <linux/config.h>
36 #include <linux/sched.h>
38 #include <linux/vmalloc.h>
40 #include <asm/pgtable.h>
41 #include <asm/tlbflush.h>
42 #include <asm-xen/hypervisor.h>
43 #include <asm-xen/balloon.h>
44 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
45 #include <linux/percpu.h>
48 void xen_l1_entry_update(pte_t *ptr, unsigned long val)
51 u.ptr = virt_to_machine(ptr);
53 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
56 void xen_l2_entry_update(pmd_t *ptr, pmd_t val)
59 u.ptr = virt_to_machine(ptr);
61 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
64 void xen_l3_entry_update(pud_t *ptr, pud_t val)
67 u.ptr = virt_to_machine(ptr);
69 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
72 void xen_l4_entry_update(pgd_t *ptr, pgd_t val)
75 u.ptr = virt_to_machine(ptr);
77 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
80 void xen_pt_switch(unsigned long ptr)
83 op.cmd = MMUEXT_NEW_BASEPTR;
84 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
85 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
88 void xen_new_user_pt(unsigned long ptr)
91 op.cmd = MMUEXT_NEW_USER_BASEPTR;
92 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
93 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
96 void xen_tlb_flush(void)
99 op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
100 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
103 void xen_invlpg(unsigned long ptr)
106 op.cmd = MMUEXT_INVLPG_LOCAL;
107 op.linear_addr = ptr & PAGE_MASK;
108 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
112 void xen_tlb_flush_all(void)
115 op.cmd = MMUEXT_TLB_FLUSH_ALL;
116 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
119 void xen_tlb_flush_mask(cpumask_t mask)
122 op.cmd = MMUEXT_TLB_FLUSH_MULTI;
123 op.cpuset = mask.bits[0];
124 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
127 void xen_invlpg_all(unsigned long ptr)
130 op.cmd = MMUEXT_INVLPG_ALL;
131 op.linear_addr = ptr & PAGE_MASK;
132 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
135 void xen_invlpg_mask(cpumask_t mask, unsigned long ptr)
138 op.cmd = MMUEXT_INVLPG_MULTI;
139 op.cpuset = mask.bits[0];
140 op.linear_addr = ptr & PAGE_MASK;
141 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
145 void xen_pgd_pin(unsigned long ptr)
148 op.cmd = MMUEXT_PIN_L4_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_pgd_unpin(unsigned long ptr)
156 op.cmd = MMUEXT_UNPIN_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_pud_pin(unsigned long ptr)
164 op.cmd = MMUEXT_PIN_L3_TABLE;
165 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
166 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
169 void xen_pud_unpin(unsigned long ptr)
172 op.cmd = MMUEXT_UNPIN_TABLE;
173 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
174 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
177 void xen_pmd_pin(unsigned long ptr)
180 op.cmd = MMUEXT_PIN_L2_TABLE;
181 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
182 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
185 void xen_pmd_unpin(unsigned long ptr)
188 op.cmd = MMUEXT_UNPIN_TABLE;
189 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
190 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
193 void xen_pte_pin(unsigned long ptr)
196 op.cmd = MMUEXT_PIN_L1_TABLE;
197 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
198 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
202 void xen_pte_unpin(unsigned long ptr)
205 op.cmd = MMUEXT_UNPIN_TABLE;
206 op.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT);
207 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
210 void xen_set_ldt(unsigned long ptr, unsigned long len)
213 op.cmd = MMUEXT_SET_LDT;
214 op.linear_addr = ptr;
216 BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
219 void xen_machphys_update(unsigned long mfn, unsigned long pfn)
222 u.ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
224 BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
227 #ifdef CONFIG_XEN_PHYSDEV_ACCESS
228 unsigned long allocate_empty_lowmem_region(unsigned long pages)
234 unsigned long *pfn_array;
235 unsigned long vstart;
237 unsigned int order = get_order(pages*PAGE_SIZE);
239 vstart = __get_free_pages(GFP_KERNEL, order);
243 scrub_pages(vstart, 1 << order);
245 pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
246 if ( pfn_array == NULL )
249 for ( i = 0; i < (1<<order); i++ )
251 pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
252 pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
253 pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
254 pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
255 pfn_array[i] = pte->pte >> PAGE_SHIFT;
256 xen_l1_entry_update(pte, 0);
257 phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] =
258 (u32)INVALID_P2M_ENTRY;
261 /* Flush updates through and flush the TLB. */
264 balloon_put_pages(pfn_array, 1 << order);
271 #endif /* CONFIG_XEN_PHYSDEV_ACCESS */