This commit was generated by cvs2svn to compensate for changes in r925,
[linux-2.6.git] / arch / xen / x86_64 / mm / hypervisor.c
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  */
29 /*
30  * Jun Nakajima <jun.nakajima@intel.com>
31  *   Added hypercalls for x86-64.
32  *
33  */
34
35 #include <linux/config.h>
36 #include <linux/sched.h>
37 #include <linux/mm.h>
38 #include <linux/vmalloc.h>
39 #include <asm/page.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>
46 #endif
47
48 void xen_l1_entry_update(pte_t *ptr, unsigned long val)
49 {
50     mmu_update_t u;
51     u.ptr = virt_to_machine(ptr);
52     u.val = val;
53     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
54 }
55
56 void xen_l2_entry_update(pmd_t *ptr, pmd_t val)
57 {
58     mmu_update_t u;
59     u.ptr = virt_to_machine(ptr);
60     u.val = val.pmd;
61     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
62 }
63
64 void xen_l3_entry_update(pud_t *ptr, pud_t val)
65 {
66     mmu_update_t u;
67     u.ptr = virt_to_machine(ptr);
68     u.val = val.pud;
69     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
70 }
71
72 void xen_l4_entry_update(pgd_t *ptr, pgd_t val)
73 {
74     mmu_update_t u;
75     u.ptr = virt_to_machine(ptr);
76     u.val = val.pgd;
77     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
78 }
79
80 void xen_pt_switch(unsigned long ptr)
81 {
82     struct mmuext_op op;
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);
86 }
87
88 void xen_new_user_pt(unsigned long ptr)
89 {
90     struct mmuext_op op;
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);
94 }
95
96 void xen_tlb_flush(void)
97 {
98     struct mmuext_op op;
99     op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
100     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
101 }
102
103 void xen_invlpg(unsigned long ptr)
104 {
105     struct mmuext_op op;
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);
109 }
110
111 #ifdef CONFIG_SMP
112 void xen_tlb_flush_all(void)
113 {
114     struct mmuext_op op;
115     op.cmd = MMUEXT_TLB_FLUSH_ALL;
116     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
117 }
118
119 void xen_tlb_flush_mask(cpumask_t mask)
120 {
121     struct mmuext_op op;
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);
125 }
126
127 void xen_invlpg_all(unsigned long ptr)
128 {
129     struct mmuext_op op;
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);
133 }
134
135 void xen_invlpg_mask(cpumask_t mask, unsigned long ptr)
136 {
137     struct mmuext_op op;
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);
142 }
143 #endif
144
145 void xen_pgd_pin(unsigned long ptr)
146 {
147     struct mmuext_op op;
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);
151 }
152
153 void xen_pgd_unpin(unsigned long ptr)
154 {
155     struct mmuext_op op;
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);
159 }
160
161 void xen_pud_pin(unsigned long ptr)
162 {
163     struct mmuext_op op;
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);
167 }
168
169 void xen_pud_unpin(unsigned long ptr)
170 {
171     struct mmuext_op op;
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);
175 }
176
177 void xen_pmd_pin(unsigned long ptr)
178 {
179     struct mmuext_op op;
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);
183 }
184
185 void xen_pmd_unpin(unsigned long ptr)
186 {
187     struct mmuext_op op;
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);
191 }
192
193 void xen_pte_pin(unsigned long ptr)
194 {
195     struct mmuext_op op;
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);
199
200 }
201
202 void xen_pte_unpin(unsigned long ptr)
203 {
204     struct mmuext_op op;
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);
208 }
209
210 void xen_set_ldt(unsigned long ptr, unsigned long len)
211 {
212     struct mmuext_op op;
213     op.cmd = MMUEXT_SET_LDT;
214     op.linear_addr = ptr;
215     op.nr_ents = len;
216     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
217 }
218
219 void xen_machphys_update(unsigned long mfn, unsigned long pfn)
220 {
221     mmu_update_t u;
222     u.ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
223     u.val = pfn;
224     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
225 }
226
227 #ifdef CONFIG_XEN_PHYSDEV_ACCESS
228 unsigned long allocate_empty_lowmem_region(unsigned long pages)
229 {
230     pgd_t         *pgd;
231     pud_t         *pud; 
232     pmd_t         *pmd;
233     pte_t         *pte;
234     unsigned long *pfn_array;
235     unsigned long  vstart;
236     unsigned long  i;
237     unsigned int   order = get_order(pages*PAGE_SIZE);
238
239     vstart = __get_free_pages(GFP_KERNEL, order);
240     if ( vstart == 0 )
241         return 0UL;
242
243     scrub_pages(vstart, 1 << order);
244
245     pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
246     if ( pfn_array == NULL )
247         BUG();
248
249     for ( i = 0; i < (1<<order); i++ )
250     {
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;
259     }
260
261     /* Flush updates through and flush the TLB. */
262     flush_tlb_all();
263
264     balloon_put_pages(pfn_array, 1 << order);
265
266     vfree(pfn_array);
267
268     return vstart;
269 }
270
271 #endif /* CONFIG_XEN_PHYSDEV_ACCESS */