This commit was generated by cvs2svn to compensate for changes in r925,
[linux-2.6.git] / arch / xen / i386 / 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 #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/balloon.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
39 #include <linux/percpu.h>
40 #include <asm/tlbflush.h>
41 #endif
42
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
44 #define pte_offset_kernel pte_offset
45 #define pud_t pgd_t
46 #define pud_offset(d, va) d
47 #else
48 #define pmd_val_ma(v) (v).pud.pgd.pgd;
49 #endif
50
51 #ifndef CONFIG_XEN_SHADOW_MODE
52 void xen_l1_entry_update(pte_t *ptr, unsigned long val)
53 {
54     mmu_update_t u;
55     u.ptr = virt_to_machine(ptr);
56     u.val = val;
57     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
58 }
59
60 void xen_l2_entry_update(pmd_t *ptr, pmd_t val)
61 {
62     mmu_update_t u;
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);
66 }
67 #endif
68
69 void xen_machphys_update(unsigned long mfn, unsigned long pfn)
70 {
71     mmu_update_t u;
72     u.ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
73     u.val = pfn;
74     BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
75 }
76
77 void xen_pt_switch(unsigned long ptr)
78 {
79     struct mmuext_op op;
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);
83 }
84
85 void xen_tlb_flush(void)
86 {
87     struct mmuext_op op;
88     op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
89     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
90 }
91
92 void xen_invlpg(unsigned long ptr)
93 {
94     struct mmuext_op op;
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);
98 }
99
100 #ifdef CONFIG_SMP
101
102 void xen_tlb_flush_all(void)
103 {
104     struct mmuext_op op;
105     op.cmd = MMUEXT_TLB_FLUSH_ALL;
106     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
107 }
108
109 void xen_tlb_flush_mask(cpumask_t mask)
110 {
111     struct mmuext_op op;
112     op.cmd = MMUEXT_TLB_FLUSH_MULTI;
113     op.cpuset = mask.bits;
114     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
115 }
116
117 void xen_invlpg_all(unsigned long ptr)
118 {
119     struct mmuext_op op;
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);
123 }
124
125 void xen_invlpg_mask(cpumask_t mask, unsigned long ptr)
126 {
127     struct mmuext_op op;
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);
132 }
133
134 #endif /* CONFIG_SMP */
135
136 #ifndef CONFIG_XEN_SHADOW_MODE
137 void xen_pgd_pin(unsigned long ptr)
138 {
139     struct mmuext_op op;
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);
143 }
144
145 void xen_pgd_unpin(unsigned long ptr)
146 {
147     struct mmuext_op op;
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);
151 }
152
153 void xen_pte_pin(unsigned long ptr)
154 {
155     struct mmuext_op op;
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);
159 }
160
161 void xen_pte_unpin(unsigned long ptr)
162 {
163     struct mmuext_op op;
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);
167 }
168 #endif
169
170 void xen_set_ldt(unsigned long ptr, unsigned long len)
171 {
172     struct mmuext_op op;
173     op.cmd = MMUEXT_SET_LDT;
174     op.linear_addr = ptr;
175     op.nr_ents = len;
176     BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
177 }
178
179 #ifdef CONFIG_XEN_PHYSDEV_ACCESS
180
181 unsigned long allocate_empty_lowmem_region(unsigned long pages)
182 {
183     pgd_t         *pgd; 
184     pud_t         *pud; 
185     pmd_t         *pmd;
186     pte_t         *pte;
187     unsigned long *pfn_array;
188     unsigned long  vstart;
189     unsigned long  i;
190     unsigned int   order = get_order(pages*PAGE_SIZE);
191
192     vstart = __get_free_pages(GFP_KERNEL, order);
193     if ( vstart == 0 )
194         return 0UL;
195
196     scrub_pages(vstart, 1 << order);
197
198     pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
199     if ( pfn_array == NULL )
200         BUG();
201
202     for ( i = 0; i < (1<<order); i++ )
203     {
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] =
211             INVALID_P2M_ENTRY;
212     }
213
214     flush_tlb_all();
215
216     balloon_put_pages(pfn_array, 1 << order);
217
218     vfree(pfn_array);
219
220     return vstart;
221 }
222
223 #endif /* CONFIG_XEN_PHYSDEV_ACCESS */