ia64/xen-unstable

view xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_memory.c @ 83:7c48a158429c

bitkeeper revision 1.7.3.58 (3e14aa78jPxKgtkJQt93U8n0Lfr_Og)

debug
author lynx@idefix.cl.cam.ac.uk
date Thu Jan 02 21:09:12 2003 +0000 (2003-01-02)
parents 29334f27f404
children 336647fd8f40
line source
2 #include <linux/slab.h>
3 #include <linux/mm.h>
4 #include <linux/mman.h>
5 #include <linux/swap.h>
6 #include <linux/smp_lock.h>
7 #include <linux/swapctl.h>
8 #include <linux/iobuf.h>
9 #include <linux/highmem.h>
10 #include <linux/pagemap.h>
11 #include <linux/list.h>
13 #include <asm/pgalloc.h>
14 #include <asm/uaccess.h>
15 #include <asm/tlb.h>
16 #include <asm/mmu.h>
18 #include "hypervisor_defs.h"
20 #define MAP_CONT 0
21 #define MAP_DISCONT 1
23 extern struct list_head * find_direct(struct list_head *, unsigned long);
25 /* bd240: functions below perform direct mapping to the real physical pages needed for
26 * mapping various hypervisor specific structures needed in dom0 userspace by various
27 * management applications such as domain builder etc.
28 */
30 #define direct_set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr) | PGREQ_UNCHECKED_UPDATE, (pteval).pte_low)
32 #define direct_pte_clear(pteptr) queue_l1_entry_update(__pa(pteptr) | PGREQ_UNCHECKED_UPDATE, 0)
34 #define __direct_pte(x) ((pte_t) { (x) } )
35 #define __direct_mk_pte(page_nr,pgprot) __direct_pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
36 #define direct_mk_pte_phys(physpage, pgprot) __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
38 static inline void forget_pte(pte_t page)
39 {
40 if (!pte_none(page)) {
41 printk("forget_pte: old mapping existed!\n");
42 BUG();
43 }
44 }
46 static inline void direct_remappte_range(pte_t * pte, unsigned long address, unsigned long size,
47 unsigned long phys_addr, pgprot_t prot)
48 {
49 unsigned long end;
51 address &= ~PMD_MASK;
52 end = address + size;
53 if (end > PMD_SIZE)
54 end = PMD_SIZE;
55 do {
56 pte_t oldpage;
57 oldpage = ptep_get_and_clear(pte);
58 /*
59 printk(KERN_ALERT "bd240 debug: %lx - %lx\n", pte, phys_addr);
60 */
61 direct_set_pte(pte, direct_mk_pte_phys(phys_addr, prot));
63 forget_pte(oldpage);
64 address += PAGE_SIZE;
65 phys_addr += PAGE_SIZE;
66 pte++;
67 } while (address && (address < end));
69 }
71 static inline int direct_remappmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
72 unsigned long phys_addr, pgprot_t prot)
73 {
74 unsigned long end;
76 address &= ~PGDIR_MASK;
77 end = address + size;
78 if (end > PGDIR_SIZE)
79 end = PGDIR_SIZE;
80 phys_addr -= address;
81 do {
82 pte_t * pte = pte_alloc(mm, pmd, address);
83 if (!pte)
84 return -ENOMEM;
85 direct_remappte_range(pte, address, end - address, address + phys_addr, prot);
86 address = (address + PMD_SIZE) & PMD_MASK;
87 pmd++;
88 } while (address && (address < end));
89 return 0;
90 }
92 /* Note: this is only safe if the mm semaphore is held when called. */
93 int direct_remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
94 {
95 int error = 0;
96 pgd_t * dir;
97 unsigned long beg = from;
98 unsigned long end = from + size;
99 struct mm_struct *mm = current->mm;
101 phys_addr -= from;
102 dir = pgd_offset(mm, from);
103 flush_cache_range(mm, beg, end);
104 if (from >= end)
105 BUG();
107 spin_lock(&mm->page_table_lock);
108 do {
109 pmd_t *pmd = pmd_alloc(mm, dir, from);
110 error = -ENOMEM;
111 if (!pmd)
112 break;
113 error = direct_remappmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
114 if (error)
115 break;
116 from = (from + PGDIR_SIZE) & PGDIR_MASK;
117 dir++;
118 } while (from && (from < end));
119 spin_unlock(&mm->page_table_lock);
120 flush_tlb_range(mm, beg, end);
121 return error;
122 }
124 /*
125 * used for remapping discontiguous bits of domain's memory, pages to map are
126 * found from frame table beginning at the given first_pg index
127 */
128 int direct_remap_disc_page_range(unsigned long from, unsigned long first_pg,
129 int tot_pages, pgprot_t prot)
130 {
131 frame_table_t * current_ft;
132 unsigned long current_pfn;
133 unsigned long start = from;
134 int count = 0;
136 current_ft = (frame_table_t *)(frame_table + first_pg);
137 current_pfn = first_pg;
138 while(count < tot_pages){
139 if(direct_remap_page_range(start, current_pfn << PAGE_SHIFT, PAGE_SIZE, prot))
140 goto out;
141 start += PAGE_SIZE;
142 current_pfn = current_ft->next;
143 current_ft = (frame_table_t *)(frame_table + current_pfn);
144 count++;
145 }
147 out:
149 return tot_pages - count;
150 }
152 /* below functions replace standard sys_mmap and sys_munmap which are absolutely useless
153 * for direct memory mapping. direct_zap* functions are minor ammendments to the
154 * original versions in mm/memory.c. the changes are to enable unmapping of real physical
155 * addresses.
156 */
158 unsigned long direct_mmap(unsigned long phys_addr, unsigned long size,
159 pgprot_t prot, int flag, int tot_pages)
160 {
161 direct_mmap_node_t * dmmap;
162 struct list_head * entry;
163 unsigned long addr;
164 int ret = 0;
166 if(!capable(CAP_SYS_ADMIN)){
167 ret = -EPERM;
168 goto out;
169 }
171 /* get unmapped area invokes xen specific arch_get_unmapped_area */
172 addr = get_unmapped_area(NULL, 0, size, 0, 0);
173 if(addr & ~PAGE_MASK){
174 ret = -ENOMEM;
175 goto out;
176 }
178 /* add node on the list of directly mapped areas, make sure the
179 * list remains sorted.
180 */
181 dmmap = (direct_mmap_node_t *)kmalloc(sizeof(direct_mmap_node_t), GFP_KERNEL);
182 dmmap->vm_start = addr;
183 dmmap->vm_end = addr + size;
184 entry = find_direct(&current->mm->context.direct_list, addr);
185 if(entry != &current->mm->context.direct_list){
186 list_add_tail(&dmmap->list, entry);
187 printk(KERN_ALERT "bd240 debug: added node %lx, size %lx in the middle\n", dmmap->vm_start, size);
188 } else {
189 list_add_tail(&dmmap->list, &current->mm->context.direct_list);
190 printk(KERN_ALERT "bd240 debug: added node %lx, size %lx at tail\n", dmmap->vm_start, size);
191 }
193 /* and perform the mapping */
194 if(flag == MAP_DISCONT){
195 ret = direct_remap_disc_page_range(addr, phys_addr, tot_pages, prot);
196 } else {
197 ret = direct_remap_page_range(addr, phys_addr, size, prot);
198 }
200 if(ret == 0)
201 ret = addr;
203 out:
204 return ret;
205 }
207 /* most of the checks, refcnt updates, cache stuff have been thrown out as they are not
208 * needed
209 */
210 static inline int direct_zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address,
211 unsigned long size)
212 {
213 unsigned long offset;
214 pte_t * ptep;
215 int freed = 0;
217 if (pmd_none(*pmd))
218 return 0;
219 if (pmd_bad(*pmd)) {
220 pmd_ERROR(*pmd);
221 pmd_clear(pmd);
222 return 0;
223 }
224 ptep = pte_offset(pmd, address);
225 offset = address & ~PMD_MASK;
226 if (offset + size > PMD_SIZE)
227 size = PMD_SIZE - offset;
228 size &= PAGE_MASK;
229 for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
230 pte_t pte = *ptep;
231 if (pte_none(pte))
232 continue;
233 freed ++;
234 direct_pte_clear(ptep);
235 }
237 return freed;
238 }
240 static inline int direct_zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir,
241 unsigned long address, unsigned long size)
242 {
243 pmd_t * pmd;
244 unsigned long end;
245 int freed;
247 if (pgd_none(*dir))
248 return 0;
249 if (pgd_bad(*dir)) {
250 pgd_ERROR(*dir);
251 pgd_clear(dir);
252 return 0;
253 }
254 pmd = pmd_offset(dir, address);
255 end = address + size;
256 if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
257 end = ((address + PGDIR_SIZE) & PGDIR_MASK);
258 freed = 0;
259 do {
260 freed += direct_zap_pte_range(tlb, pmd, address, end - address);
261 address = (address + PMD_SIZE) & PMD_MASK;
262 pmd++;
263 } while (address < end);
264 return freed;
265 }
267 /*
268 * remove user pages in a given range.
269 */
270 void direct_zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
271 {
272 mmu_gather_t *tlb;
273 pgd_t * dir;
274 unsigned long start = address, end = address + size;
275 int freed = 0;
277 dir = pgd_offset(mm, address);
279 /*
280 * This is a long-lived spinlock. That's fine.
281 * There's no contention, because the page table
282 * lock only protects against kswapd anyway, and
283 * even if kswapd happened to be looking at this
284 * process we _want_ it to get stuck.
285 */
286 if (address >= end)
287 BUG();
288 spin_lock(&mm->page_table_lock);
289 flush_cache_range(mm, address, end);
290 tlb = tlb_gather_mmu(mm);
292 do {
293 freed += direct_zap_pmd_range(tlb, dir, address, end - address);
294 address = (address + PGDIR_SIZE) & PGDIR_MASK;
295 dir++;
296 } while (address && (address < end));
298 /* this will flush any remaining tlb entries */
299 tlb_finish_mmu(tlb, start, end);
301 /* decrementing rss removed */
303 spin_unlock(&mm->page_table_lock);
304 }
306 int direct_unmap(unsigned long addr, unsigned long size)
307 {
308 direct_mmap_node_t * node;
309 struct list_head * curr;
310 struct list_head * direct_list = &current->mm->context.direct_list;
312 curr = direct_list->next;
313 while(curr != direct_list){
314 node = list_entry(curr, direct_mmap_node_t, list);
315 if(node->vm_start == addr)
316 break;
317 curr = curr->next;
318 }
320 if(curr == direct_list)
321 return -1;
323 list_del(&node->list);
324 printk(KERN_ALERT "bd240 debug: delisted %lx from dlist\n", node->vm_start);
325 kfree(node);
327 direct_zap_page_range(current->mm, addr, size);
329 return 0;
330 }
332 int direct_disc_unmap(unsigned long from, unsigned long first_pg, int tot_pages)
333 {
334 int count = 0;
335 direct_mmap_node_t * node;
336 struct list_head * curr;
337 struct list_head * direct_list = &current->mm->context.direct_list;
339 printk(KERN_ALERT "bd240 debug: direct_disc_unmap\n");
341 curr = direct_list->next;
342 while(curr != direct_list){
343 node = list_entry(curr, direct_mmap_node_t, list);
345 if(node->vm_start == from)
346 break;
347 curr = curr->next;
348 }
350 if(curr == direct_list)
351 return -1;
353 printk(KERN_ALERT "bd240 debug: direct_disc_unmap, deleted from direct_list\n");
355 list_del(&node->list);
356 kfree(node);
358 printk(KERN_ALERT "bd240 debug: direct_disc_unmap, from %lx, tot_pages %lx\n", from, tot_pages);
360 while(count < tot_pages){
361 direct_zap_page_range(current->mm, from, PAGE_SIZE);
362 from += PAGE_SIZE;
363 count++;
364 }
366 return 0;
367 }