2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL
7 #include "asm/pgtable.h"
8 #include "asm/tlbflush.h"
15 struct host_vm_change
{
17 enum { NONE
, MMAP
, MUNMAP
, MPROTECT
} type
;
43 #define INIT_HVC(mm, force) \
44 ((struct host_vm_change) \
45 { .ops = { { .type = NONE } }, \
46 .id = &mm->context.id, \
51 static int do_ops(struct host_vm_change
*hvc
, int end
,
54 struct host_vm_op
*op
;
57 for (i
= 0; i
< end
&& !ret
; i
++) {
61 ret
= map(hvc
->id
, op
->u
.mmap
.addr
, op
->u
.mmap
.len
,
62 op
->u
.mmap
.prot
, op
->u
.mmap
.fd
,
63 op
->u
.mmap
.offset
, finished
, &hvc
->data
);
66 ret
= unmap(hvc
->id
, op
->u
.munmap
.addr
,
67 op
->u
.munmap
.len
, finished
, &hvc
->data
);
70 ret
= protect(hvc
->id
, op
->u
.mprotect
.addr
,
71 op
->u
.mprotect
.len
, op
->u
.mprotect
.prot
,
72 finished
, &hvc
->data
);
75 printk(KERN_ERR
"Unknown op type %d in do_ops\n",
84 static int add_mmap(unsigned long virt
, unsigned long phys
, unsigned long len
,
85 unsigned int prot
, struct host_vm_change
*hvc
)
88 struct host_vm_op
*last
;
91 fd
= phys_mapping(phys
, &offset
);
92 if (hvc
->index
!= 0) {
93 last
= &hvc
->ops
[hvc
->index
- 1];
94 if ((last
->type
== MMAP
) &&
95 (last
->u
.mmap
.addr
+ last
->u
.mmap
.len
== virt
) &&
96 (last
->u
.mmap
.prot
== prot
) && (last
->u
.mmap
.fd
== fd
) &&
97 (last
->u
.mmap
.offset
+ last
->u
.mmap
.len
== offset
)) {
98 last
->u
.mmap
.len
+= len
;
103 if (hvc
->index
== ARRAY_SIZE(hvc
->ops
)) {
104 ret
= do_ops(hvc
, ARRAY_SIZE(hvc
->ops
), 0);
108 hvc
->ops
[hvc
->index
++] = ((struct host_vm_op
)
110 .u
= { .mmap
= { .addr
= virt
,
119 static int add_munmap(unsigned long addr
, unsigned long len
,
120 struct host_vm_change
*hvc
)
122 struct host_vm_op
*last
;
125 if (hvc
->index
!= 0) {
126 last
= &hvc
->ops
[hvc
->index
- 1];
127 if ((last
->type
== MUNMAP
) &&
128 (last
->u
.munmap
.addr
+ last
->u
.mmap
.len
== addr
)) {
129 last
->u
.munmap
.len
+= len
;
134 if (hvc
->index
== ARRAY_SIZE(hvc
->ops
)) {
135 ret
= do_ops(hvc
, ARRAY_SIZE(hvc
->ops
), 0);
139 hvc
->ops
[hvc
->index
++] = ((struct host_vm_op
)
141 .u
= { .munmap
= { .addr
= addr
,
146 static int add_mprotect(unsigned long addr
, unsigned long len
,
147 unsigned int prot
, struct host_vm_change
*hvc
)
149 struct host_vm_op
*last
;
152 if (hvc
->index
!= 0) {
153 last
= &hvc
->ops
[hvc
->index
- 1];
154 if ((last
->type
== MPROTECT
) &&
155 (last
->u
.mprotect
.addr
+ last
->u
.mprotect
.len
== addr
) &&
156 (last
->u
.mprotect
.prot
== prot
)) {
157 last
->u
.mprotect
.len
+= len
;
162 if (hvc
->index
== ARRAY_SIZE(hvc
->ops
)) {
163 ret
= do_ops(hvc
, ARRAY_SIZE(hvc
->ops
), 0);
167 hvc
->ops
[hvc
->index
++] = ((struct host_vm_op
)
169 .u
= { .mprotect
= { .addr
= addr
,
175 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
177 static inline int update_pte_range(pmd_t
*pmd
, unsigned long addr
,
179 struct host_vm_change
*hvc
)
182 int r
, w
, x
, prot
, ret
= 0;
184 pte
= pte_offset_kernel(pmd
, addr
);
189 if (!pte_young(*pte
)) {
192 } else if (!pte_dirty(*pte
)) {
195 prot
= ((r
? UM_PROT_READ
: 0) | (w
? UM_PROT_WRITE
: 0) |
196 (x
? UM_PROT_EXEC
: 0));
197 if (hvc
->force
|| pte_newpage(*pte
)) {
198 if (pte_present(*pte
))
199 ret
= add_mmap(addr
, pte_val(*pte
) & PAGE_MASK
,
200 PAGE_SIZE
, prot
, hvc
);
201 else ret
= add_munmap(addr
, PAGE_SIZE
, hvc
);
203 else if (pte_newprot(*pte
))
204 ret
= add_mprotect(addr
, PAGE_SIZE
, prot
, hvc
);
205 *pte
= pte_mkuptodate(*pte
);
206 } while (pte
++, addr
+= PAGE_SIZE
, ((addr
!= end
) && !ret
));
210 static inline int update_pmd_range(pud_t
*pud
, unsigned long addr
,
212 struct host_vm_change
*hvc
)
218 pmd
= pmd_offset(pud
, addr
);
220 next
= pmd_addr_end(addr
, end
);
221 if (!pmd_present(*pmd
)) {
222 if (hvc
->force
|| pmd_newpage(*pmd
)) {
223 ret
= add_munmap(addr
, next
- addr
, hvc
);
224 pmd_mkuptodate(*pmd
);
227 else ret
= update_pte_range(pmd
, addr
, next
, hvc
);
228 } while (pmd
++, addr
= next
, ((addr
!= end
) && !ret
));
232 static inline int update_pud_range(pgd_t
*pgd
, unsigned long addr
,
234 struct host_vm_change
*hvc
)
240 pud
= pud_offset(pgd
, addr
);
242 next
= pud_addr_end(addr
, end
);
243 if (!pud_present(*pud
)) {
244 if (hvc
->force
|| pud_newpage(*pud
)) {
245 ret
= add_munmap(addr
, next
- addr
, hvc
);
246 pud_mkuptodate(*pud
);
249 else ret
= update_pmd_range(pud
, addr
, next
, hvc
);
250 } while (pud
++, addr
= next
, ((addr
!= end
) && !ret
));
254 void fix_range_common(struct mm_struct
*mm
, unsigned long start_addr
,
255 unsigned long end_addr
, int force
)
258 struct host_vm_change hvc
;
259 unsigned long addr
= start_addr
, next
;
262 hvc
= INIT_HVC(mm
, force
);
263 pgd
= pgd_offset(mm
, addr
);
265 next
= pgd_addr_end(addr
, end_addr
);
266 if (!pgd_present(*pgd
)) {
267 if (force
|| pgd_newpage(*pgd
)) {
268 ret
= add_munmap(addr
, next
- addr
, &hvc
);
269 pgd_mkuptodate(*pgd
);
272 else ret
= update_pud_range(pgd
, addr
, next
, &hvc
);
273 } while (pgd
++, addr
= next
, ((addr
!= end_addr
) && !ret
));
276 ret
= do_ops(&hvc
, hvc
.index
, 1);
278 /* This is not an else because ret is modified above */
280 printk(KERN_ERR
"fix_range_common: failed, killing current "
282 force_sig(SIGKILL
, current
);
286 int flush_tlb_kernel_range_common(unsigned long start
, unsigned long end
)
288 struct mm_struct
*mm
;
293 unsigned long addr
, last
;
294 int updated
= 0, err
;
297 for (addr
= start
; addr
< end
;) {
298 pgd
= pgd_offset(mm
, addr
);
299 if (!pgd_present(*pgd
)) {
300 last
= ADD_ROUND(addr
, PGDIR_SIZE
);
303 if (pgd_newpage(*pgd
)) {
305 err
= os_unmap_memory((void *) addr
,
308 panic("munmap failed, errno = %d\n",
315 pud
= pud_offset(pgd
, addr
);
316 if (!pud_present(*pud
)) {
317 last
= ADD_ROUND(addr
, PUD_SIZE
);
320 if (pud_newpage(*pud
)) {
322 err
= os_unmap_memory((void *) addr
,
325 panic("munmap failed, errno = %d\n",
332 pmd
= pmd_offset(pud
, addr
);
333 if (!pmd_present(*pmd
)) {
334 last
= ADD_ROUND(addr
, PMD_SIZE
);
337 if (pmd_newpage(*pmd
)) {
339 err
= os_unmap_memory((void *) addr
,
342 panic("munmap failed, errno = %d\n",
349 pte
= pte_offset_kernel(pmd
, addr
);
350 if (!pte_present(*pte
) || pte_newpage(*pte
)) {
352 err
= os_unmap_memory((void *) addr
,
355 panic("munmap failed, errno = %d\n",
357 if (pte_present(*pte
))
359 pte_val(*pte
) & PAGE_MASK
,
362 else if (pte_newprot(*pte
)) {
364 os_protect_memory((void *) addr
, PAGE_SIZE
, 1, 1, 1);
371 void flush_tlb_page(struct vm_area_struct
*vma
, unsigned long address
)
377 struct mm_struct
*mm
= vma
->vm_mm
;
379 int r
, w
, x
, prot
, err
= 0;
382 address
&= PAGE_MASK
;
383 pgd
= pgd_offset(mm
, address
);
384 if (!pgd_present(*pgd
))
387 pud
= pud_offset(pgd
, address
);
388 if (!pud_present(*pud
))
391 pmd
= pmd_offset(pud
, address
);
392 if (!pmd_present(*pmd
))
395 pte
= pte_offset_kernel(pmd
, address
);
400 if (!pte_young(*pte
)) {
403 } else if (!pte_dirty(*pte
)) {
407 mm_id
= &mm
->context
.id
;
408 prot
= ((r
? UM_PROT_READ
: 0) | (w
? UM_PROT_WRITE
: 0) |
409 (x
? UM_PROT_EXEC
: 0));
410 if (pte_newpage(*pte
)) {
411 if (pte_present(*pte
)) {
412 unsigned long long offset
;
415 fd
= phys_mapping(pte_val(*pte
) & PAGE_MASK
, &offset
);
416 err
= map(mm_id
, address
, PAGE_SIZE
, prot
, fd
, offset
,
419 else err
= unmap(mm_id
, address
, PAGE_SIZE
, 1, &flush
);
421 else if (pte_newprot(*pte
))
422 err
= protect(mm_id
, address
, PAGE_SIZE
, prot
, 1, &flush
);
427 *pte
= pte_mkuptodate(*pte
);
432 printk(KERN_ERR
"Failed to flush page for address 0x%lx\n", address
);
433 force_sig(SIGKILL
, current
);
436 pgd_t
*pgd_offset_proc(struct mm_struct
*mm
, unsigned long address
)
438 return pgd_offset(mm
, address
);
441 pud_t
*pud_offset_proc(pgd_t
*pgd
, unsigned long address
)
443 return pud_offset(pgd
, address
);
446 pmd_t
*pmd_offset_proc(pud_t
*pud
, unsigned long address
)
448 return pmd_offset(pud
, address
);
451 pte_t
*pte_offset_proc(pmd_t
*pmd
, unsigned long address
)
453 return pte_offset_kernel(pmd
, address
);
456 pte_t
*addr_pte(struct task_struct
*task
, unsigned long addr
)
458 pgd_t
*pgd
= pgd_offset(task
->mm
, addr
);
459 pud_t
*pud
= pud_offset(pgd
, addr
);
460 pmd_t
*pmd
= pmd_offset(pud
, addr
);
462 return pte_offset_map(pmd
, addr
);
465 void flush_tlb_all(void)
467 flush_tlb_mm(current
->mm
);
470 void flush_tlb_kernel_range(unsigned long start
, unsigned long end
)
472 flush_tlb_kernel_range_common(start
, end
);
475 void flush_tlb_kernel_vm(void)
477 flush_tlb_kernel_range_common(start_vm
, end_vm
);
480 void __flush_tlb_one(unsigned long addr
)
482 flush_tlb_kernel_range_common(addr
, addr
+ PAGE_SIZE
);
485 static void fix_range(struct mm_struct
*mm
, unsigned long start_addr
,
486 unsigned long end_addr
, int force
)
488 if (!proc_mm
&& (end_addr
> STUB_START
))
489 end_addr
= STUB_START
;
491 fix_range_common(mm
, start_addr
, end_addr
, force
);
494 void flush_tlb_range(struct vm_area_struct
*vma
, unsigned long start
,
497 if (vma
->vm_mm
== NULL
)
498 flush_tlb_kernel_range_common(start
, end
);
499 else fix_range(vma
->vm_mm
, start
, end
, 0);
502 void flush_tlb_mm(struct mm_struct
*mm
)
507 * Don't bother flushing if this address space is about to be
510 if (atomic_read(&mm
->mm_users
) == 0)
513 end
= proc_mm
? task_size
: STUB_START
;
514 fix_range(mm
, 0, end
, 0);
517 void force_flush_all(void)
519 struct mm_struct
*mm
= current
->mm
;
520 struct vm_area_struct
*vma
= mm
->mmap
;
522 while (vma
!= NULL
) {
523 fix_range(mm
, vma
->vm_start
, vma
->vm_end
, 1);