2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
8 #include "asm/pgalloc.h"
9 #include "asm/tlbflush.h"
10 #include "choose-mode.h"
11 #include "mode_kern.h"
12 #include "user_util.h"
18 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
20 void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
21 unsigned long end_addr, int force, int data,
22 void (*do_ops)(int, struct host_vm_op *, int))
28 unsigned long addr, end;
30 struct host_vm_op ops[16];
31 int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
33 if(mm == NULL) return;
35 for(addr = start_addr; addr < end_addr;){
36 npgd = pgd_offset(mm, addr);
37 if(!pgd_present(*npgd)){
38 end = ADD_ROUND(addr, PGDIR_SIZE);
41 if(force || pgd_newpage(*npgd)){
42 op_index = add_munmap(addr, end - addr, ops,
43 op_index, last_op, data,
45 pgd_mkuptodate(*npgd);
51 npud = pud_offset(npgd, addr);
52 if(!pud_present(*npud)){
53 end = ADD_ROUND(addr, PUD_SIZE);
56 if(force || pud_newpage(*npud)){
57 op_index = add_munmap(addr, end - addr, ops,
58 op_index, last_op, data,
60 pud_mkuptodate(*npud);
66 npmd = pmd_offset(npud, addr);
67 if(!pmd_present(*npmd)){
68 end = ADD_ROUND(addr, PMD_SIZE);
71 if(force || pmd_newpage(*npmd)){
72 op_index = add_munmap(addr, end - addr, ops,
73 op_index, last_op, data,
75 pmd_mkuptodate(*npmd);
81 npte = pte_offset_kernel(npmd, addr);
87 if(!pte_young(*npte)){
91 if(force || pte_newpage(*npte)){
92 if(pte_present(*npte))
93 op_index = add_mmap(addr,
94 pte_val(*npte) & PAGE_MASK,
95 PAGE_SIZE, r, w, x, ops,
96 op_index, last_op, data,
98 else op_index = add_munmap(addr, PAGE_SIZE, ops,
99 op_index, last_op, data,
102 else if(pte_newprot(*npte))
103 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
104 op_index, last_op, data,
107 *npte = pte_mkuptodate(*npte);
110 (*do_ops)(data, ops, op_index);
113 int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
115 struct mm_struct *mm;
120 unsigned long addr, last;
121 int updated = 0, err;
124 for(addr = start; addr < end;){
125 pgd = pgd_offset(mm, addr);
126 if(!pgd_present(*pgd)){
127 last = ADD_ROUND(addr, PGDIR_SIZE);
130 if(pgd_newpage(*pgd)){
132 err = os_unmap_memory((void *) addr,
135 panic("munmap failed, errno = %d\n",
142 pud = pud_offset(pgd, addr);
143 if(!pud_present(*pud)){
144 last = ADD_ROUND(addr, PUD_SIZE);
147 if(pud_newpage(*pud)){
149 err = os_unmap_memory((void *) addr,
152 panic("munmap failed, errno = %d\n",
159 pmd = pmd_offset(pud, addr);
160 if(!pmd_present(*pmd)){
161 last = ADD_ROUND(addr, PMD_SIZE);
164 if(pmd_newpage(*pmd)){
166 err = os_unmap_memory((void *) addr,
169 panic("munmap failed, errno = %d\n",
176 pte = pte_offset_kernel(pmd, addr);
177 if(!pte_present(*pte) || pte_newpage(*pte)){
179 err = os_unmap_memory((void *) addr,
182 panic("munmap failed, errno = %d\n",
184 if(pte_present(*pte))
186 pte_val(*pte) & PAGE_MASK,
189 else if(pte_newprot(*pte)){
191 protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
198 void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
200 address &= PAGE_MASK;
201 flush_tlb_range(vma, address, address + PAGE_SIZE);
204 void flush_tlb_all(void)
206 flush_tlb_mm(current->mm);
209 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
211 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
212 flush_tlb_kernel_range_common, start, end);
215 void flush_tlb_kernel_vm(void)
217 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
218 flush_tlb_kernel_range_common(start_vm, end_vm));
221 void __flush_tlb_one(unsigned long addr)
223 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
226 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
229 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
233 void flush_tlb_mm(struct mm_struct *mm)
235 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
238 void force_flush_all(void)
240 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
243 pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
245 return(pgd_offset(mm, address));
248 pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
250 return(pud_offset(pgd, address));
253 pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
255 return(pmd_offset(pud, address));
258 pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
260 return(pte_offset_kernel(pmd, address));
263 pte_t *addr_pte(struct task_struct *task, unsigned long addr)
265 pgd_t *pgd = pgd_offset(task->mm, addr);
266 pud_t *pud = pud_offset(pgd, addr);
267 pmd_t *pmd = pmd_offset(pud, addr);
269 return(pte_offset_map(pmd, addr));
272 int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
273 int r, int w, int x, struct host_vm_op *ops, int index,
274 int last_filled, int data,
275 void (*do_ops)(int, struct host_vm_op *, int))
278 struct host_vm_op *last;
281 fd = phys_mapping(phys, &offset);
284 if((last->type == MMAP) &&
285 (last->u.mmap.addr + last->u.mmap.len == virt) &&
286 (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
287 (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
288 (last->u.mmap.offset + last->u.mmap.len == offset)){
289 last->u.mmap.len += len;
294 if(index == last_filled){
295 (*do_ops)(data, ops, last_filled);
299 ops[++index] = ((struct host_vm_op) { .type = MMAP,
312 int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
313 int index, int last_filled, int data,
314 void (*do_ops)(int, struct host_vm_op *, int))
316 struct host_vm_op *last;
320 if((last->type == MUNMAP) &&
321 (last->u.munmap.addr + last->u.mmap.len == addr)){
322 last->u.munmap.len += len;
327 if(index == last_filled){
328 (*do_ops)(data, ops, last_filled);
332 ops[++index] = ((struct host_vm_op) { .type = MUNMAP,
339 int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
340 struct host_vm_op *ops, int index, int last_filled, int data,
341 void (*do_ops)(int, struct host_vm_op *, int))
343 struct host_vm_op *last;
347 if((last->type == MPROTECT) &&
348 (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
349 (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
350 (last->u.mprotect.x == x)){
351 last->u.mprotect.len += len;
356 if(index == last_filled){
357 (*do_ops)(data, ops, last_filled);
361 ops[++index] = ((struct host_vm_op) { .type = MPROTECT,