fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / include / asm-x86_64 / mach-xen / asm / pgalloc.h
1 #ifndef _X86_64_PGALLOC_H
2 #define _X86_64_PGALLOC_H
3
4 #include <asm/fixmap.h>
5 #include <asm/pda.h>
6 #include <linux/threads.h>
7 #include <linux/mm.h>
8 #include <asm/io.h>             /* for phys_to_virt and page_to_pseudophys */
9
10 #include <xen/features.h>
11
12 #define arch_add_exec_range(mm, limit) \
13                 do { (void)(mm), (void)(limit); } while (0)
14 #define arch_flush_exec_range(mm) \
15                 do { (void)(mm); } while (0)
16 #define arch_remove_exec_range(mm, limit) \
17                 do { (void)(mm), (void)(limit); } while (0)
18
19 void make_page_readonly(void *va, unsigned int feature);
20 void make_page_writable(void *va, unsigned int feature);
21 void make_pages_readonly(void *va, unsigned int nr, unsigned int feature);
22 void make_pages_writable(void *va, unsigned int nr, unsigned int feature);
23
24 #define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD)
25
26 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
27 {
28         set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
29 }
30
31 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
32 {
33         if (unlikely((mm)->context.pinned)) {
34                 BUG_ON(HYPERVISOR_update_va_mapping(
35                                (unsigned long)pmd,
36                                pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, 
37                                        PAGE_KERNEL_RO), 0));
38                 set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
39         } else {
40                 *(pud) =  __pud(_PAGE_TABLE | __pa(pmd));
41         }
42 }
43
44 /*
45  * We need to use the batch mode here, but pgd_pupulate() won't be
46  * be called frequently.
47  */
48 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
49 {
50         if (unlikely((mm)->context.pinned)) {
51                 BUG_ON(HYPERVISOR_update_va_mapping(
52                                (unsigned long)pud,
53                                pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, 
54                                        PAGE_KERNEL_RO), 0));
55                 set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
56                 set_pgd(__user_pgd(pgd), __pgd(_PAGE_TABLE | __pa(pud)));
57         } else {
58                 *(pgd) =  __pgd(_PAGE_TABLE | __pa(pud));
59                 *(__user_pgd(pgd)) = *(pgd);
60         }
61 }
62
63 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
64 {
65         if (unlikely((mm)->context.pinned)) {
66                 BUG_ON(HYPERVISOR_update_va_mapping(
67                                (unsigned long)__va(page_to_pfn(pte) << PAGE_SHIFT),
68                                pfn_pte(page_to_pfn(pte), PAGE_KERNEL_RO), 0));
69                 set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
70         } else {
71                 *(pmd) = __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT));
72         }
73 }
74
75 static inline void pmd_free(pmd_t *pmd)
76 {
77         pte_t *ptep = virt_to_ptep(pmd);
78
79         if (!pte_write(*ptep)) {
80                 BUG_ON(HYPERVISOR_update_va_mapping(
81                         (unsigned long)pmd,
82                         pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, PAGE_KERNEL),
83                         0));
84         }
85         free_page((unsigned long)pmd);
86 }
87
88 static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
89 {
90         return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
91 }
92
93 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
94 {
95         return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
96 }
97
98 static inline void pud_free (pud_t *pud)
99 {
100         pte_t *ptep = virt_to_ptep(pud);
101
102         if (!pte_write(*ptep)) {
103                 BUG_ON(HYPERVISOR_update_va_mapping(
104                         (unsigned long)pud,
105                         pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, PAGE_KERNEL),
106                         0));
107         }
108         free_page((unsigned long)pud);
109 }
110
111 static inline void pgd_list_add(pgd_t *pgd)
112 {
113         struct page *page = virt_to_page(pgd);
114
115         spin_lock(&pgd_lock);
116         page->index = (pgoff_t)pgd_list;
117         if (pgd_list)
118                 pgd_list->private = (unsigned long)&page->index;
119         pgd_list = page;
120         page->private = (unsigned long)&pgd_list;
121         spin_unlock(&pgd_lock);
122 }
123
124 static inline void pgd_list_del(pgd_t *pgd)
125 {
126         struct page *next, **pprev, *page = virt_to_page(pgd);
127
128         spin_lock(&pgd_lock);
129         next = (struct page *)page->index;
130         pprev = (struct page **)page->private;
131         *pprev = next;
132         if (next)
133                 next->private = (unsigned long)pprev;
134         spin_unlock(&pgd_lock);
135 }
136
137 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
138 {
139         /*
140          * We allocate two contiguous pages for kernel and user.
141          */
142         unsigned boundary;
143         pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 1);
144
145         if (!pgd)
146                 return NULL;
147         pgd_list_add(pgd);
148         /*
149          * Copy kernel pointers in from init.
150          * Could keep a freelist or slab cache of those because the kernel
151          * part never changes.
152          */
153         boundary = pgd_index(__PAGE_OFFSET);
154         memset(pgd, 0, boundary * sizeof(pgd_t));
155         memcpy(pgd + boundary,
156                init_level4_pgt + boundary,
157                (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
158
159         memset(__user_pgd(pgd), 0, PAGE_SIZE); /* clean up user pgd */
160         /*
161          * Set level3_user_pgt for vsyscall area
162          */
163         set_pgd(__user_pgd(pgd) + pgd_index(VSYSCALL_START), 
164                 mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
165         return pgd;
166 }
167
168 static inline void pgd_free(pgd_t *pgd)
169 {
170         pte_t *ptep = virt_to_ptep(pgd);
171
172         if (!pte_write(*ptep)) {
173                 xen_pgd_unpin(__pa(pgd));
174                 BUG_ON(HYPERVISOR_update_va_mapping(
175                                (unsigned long)pgd,
176                                pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, PAGE_KERNEL),
177                                0));
178         }
179
180         ptep = virt_to_ptep(__user_pgd(pgd));
181
182         if (!pte_write(*ptep)) {
183                 xen_pgd_unpin(__pa(__user_pgd(pgd)));
184                 BUG_ON(HYPERVISOR_update_va_mapping(
185                                (unsigned long)__user_pgd(pgd),
186                                pfn_pte(virt_to_phys(__user_pgd(pgd))>>PAGE_SHIFT, 
187                                        PAGE_KERNEL),
188                                0));
189         }
190
191         pgd_list_del(pgd);
192         free_pages((unsigned long)pgd, 1);
193 }
194
195 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
196 {
197         pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
198         if (pte)
199                 make_page_readonly(pte, XENFEAT_writable_page_tables);
200
201         return pte;
202 }
203
204 static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
205 {
206         struct page *pte;
207
208         pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
209         return pte;
210 }
211
212 /* Should really implement gc for free page table pages. This could be
213    done with a reference count in struct page. */
214
215 static inline void pte_free_kernel(pte_t *pte)
216 {
217         BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
218         make_page_writable(pte, XENFEAT_writable_page_tables);
219         free_page((unsigned long)pte); 
220 }
221
222 extern void pte_free(struct page *pte);
223
224 //#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) 
225 //#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
226 //#define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
227
228 #define __pte_free_tlb(tlb,x)   pte_free((x))
229 #define __pmd_free_tlb(tlb,x)   pmd_free((x))
230 #define __pud_free_tlb(tlb,x)   pud_free((x))
231
232 #endif /* _X86_64_PGALLOC_H */