1 /* 2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) 3 * Licensed under the GPL 4 */ 5 6 #include "linux/mm.h" 7 #include "asm/page.h" 8 #include "asm/pgalloc.h" 9 #include "asm/pgtable.h" 10 #include "asm/tlbflush.h" 11 #include "as-layout.h" 12 #include "tlb.h" 13 #include "mem.h" 14 #include "mem_user.h" 15 #include "os.h" 16 #include "skas.h" 17 18 static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, 19 unsigned int prot, struct host_vm_op *ops, int *index, 20 int last_filled, union mm_context *mmu, void **flush, 21 int (*do_ops)(union mm_context *, struct host_vm_op *, 22 int, int, void **)) 23 { 24 __u64 offset; 25 struct host_vm_op *last; 26 int fd, ret = 0; 27 28 fd = phys_mapping(phys, &offset); 29 if(*index != -1){ 30 last = &ops[*index]; 31 if((last->type == MMAP) && 32 (last->u.mmap.addr + last->u.mmap.len == virt) && 33 (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) && 34 (last->u.mmap.offset + last->u.mmap.len == offset)){ 35 last->u.mmap.len += len; 36 return 0; 37 } 38 } 39 40 if(*index == last_filled){ 41 ret = (*do_ops)(mmu, ops, last_filled, 0, flush); 42 *index = -1; 43 } 44 45 ops[++*index] = ((struct host_vm_op) { .type = MMAP, 46 .u = { .mmap = { 47 .addr = virt, 48 .len = len, 49 .prot = prot, 50 .fd = fd, 51 .offset = offset } 52 } }); 53 return ret; 54 } 55 56 static int add_munmap(unsigned long addr, unsigned long len, 57 struct host_vm_op *ops, int *index, int last_filled, 58 union mm_context *mmu, void **flush, 59 int (*do_ops)(union mm_context *, struct host_vm_op *, 60 int, int, void **)) 61 { 62 struct host_vm_op *last; 63 int ret = 0; 64 65 if(*index != -1){ 66 last = &ops[*index]; 67 if((last->type == MUNMAP) && 68 (last->u.munmap.addr + last->u.mmap.len == addr)){ 69 last->u.munmap.len += len; 70 return 0; 71 } 72 } 73 74 if(*index == last_filled){ 75 ret = (*do_ops)(mmu, ops, last_filled, 0, flush); 76 *index = -1; 77 } 78 79 ops[++*index] = ((struct host_vm_op) { .type = MUNMAP, 80 .u = { .munmap = { 81 .addr = addr, 82 .len = len } } }); 83 return ret; 84 } 85 86 static int add_mprotect(unsigned long addr, unsigned long len, 87 unsigned int prot, struct host_vm_op *ops, int *index, 88 int last_filled, union mm_context *mmu, void **flush, 89 int (*do_ops)(union mm_context *, struct host_vm_op *, 90 int, int, void **)) 91 { 92 struct host_vm_op *last; 93 int ret = 0; 94 95 if(*index != -1){ 96 last = &ops[*index]; 97 if((last->type == MPROTECT) && 98 (last->u.mprotect.addr + last->u.mprotect.len == addr) && 99 (last->u.mprotect.prot == prot)){ 100 last->u.mprotect.len += len; 101 return 0; 102 } 103 } 104 105 if(*index == last_filled){ 106 ret = (*do_ops)(mmu, ops, last_filled, 0, flush); 107 *index = -1; 108 } 109 110 ops[++*index] = ((struct host_vm_op) { .type = MPROTECT, 111 .u = { .mprotect = { 112 .addr = addr, 113 .len = len, 114 .prot = prot } } }); 115 return ret; 116 } 117 118 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) 119 120 static inline int update_pte_range(pmd_t *pmd, unsigned long addr, 121 unsigned long end, struct host_vm_op *ops, 122 int last_op, int *op_index, int force, 123 union mm_context *mmu, void **flush, 124 int (*do_ops)(union mm_context *, 125 struct host_vm_op *, int, int, 126 void **)) 127 { 128 pte_t *pte; 129 int r, w, x, prot, ret = 0; 130 131 pte = pte_offset_kernel(pmd, addr); 132 do { 133 r = pte_read(*pte); 134 w = pte_write(*pte); 135 x = pte_exec(*pte); 136 if (!pte_young(*pte)) { 137 r = 0; 138 w = 0; 139 } else if (!pte_dirty(*pte)) { 140 w = 0; 141 } 142 prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | 143 (x ? UM_PROT_EXEC : 0)); 144 if(force || pte_newpage(*pte)){ 145 if(pte_present(*pte)) 146 ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, 147 PAGE_SIZE, prot, ops, op_index, 148 last_op, mmu, flush, do_ops); 149 else ret = add_munmap(addr, PAGE_SIZE, ops, op_index, 150 last_op, mmu, flush, do_ops); 151 } 152 else if(pte_newprot(*pte)) 153 ret = add_mprotect(addr, PAGE_SIZE, prot, ops, op_index, 154 last_op, mmu, flush, do_ops); 155 *pte = pte_mkuptodate(*pte); 156 } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret)); 157 return ret; 158 } 159 160 static inline int update_pmd_range(pud_t *pud, unsigned long addr, 161 unsigned long end, struct host_vm_op *ops, 162 int last_op, int *op_index, int force, 163 union mm_context *mmu, void **flush, 164 int (*do_ops)(union mm_context *, 165 struct host_vm_op *, int, int, 166 void **)) 167 { 168 pmd_t *pmd; 169 unsigned long next; 170 int ret = 0; 171 172 pmd = pmd_offset(pud, addr); 173 do { 174 next = pmd_addr_end(addr, end); 175 if(!pmd_present(*pmd)){ 176 if(force || pmd_newpage(*pmd)){ 177 ret = add_munmap(addr, next - addr, ops, 178 op_index, last_op, mmu, 179 flush, do_ops); 180 pmd_mkuptodate(*pmd); 181 } 182 } 183 else ret = update_pte_range(pmd, addr, next, ops, last_op, 184 op_index, force, mmu, flush, 185 do_ops); 186 } while (pmd++, addr = next, ((addr != end) && !ret)); 187 return ret; 188 } 189 190 static inline int update_pud_range(pgd_t *pgd, unsigned long addr, 191 unsigned long end, struct host_vm_op *ops, 192 int last_op, int *op_index, int force, 193 union mm_context *mmu, void **flush, 194 int (*do_ops)(union mm_context *, 195 struct host_vm_op *, int, int, 196 void **)) 197 { 198 pud_t *pud; 199 unsigned long next; 200 int ret = 0; 201 202 pud = pud_offset(pgd, addr); 203 do { 204 next = pud_addr_end(addr, end); 205 if(!pud_present(*pud)){ 206 if(force || pud_newpage(*pud)){ 207 ret = add_munmap(addr, next - addr, ops, 208 op_index, last_op, mmu, 209 flush, do_ops); 210 pud_mkuptodate(*pud); 211 } 212 } 213 else ret = update_pmd_range(pud, addr, next, ops, last_op, 214 op_index, force, mmu, flush, 215 do_ops); 216 } while (pud++, addr = next, ((addr != end) && !ret)); 217 return ret; 218 } 219 220 void fix_range_common(struct mm_struct *mm, unsigned long start_addr, 221 unsigned long end_addr, int force, 222 int (*do_ops)(union mm_context *, struct host_vm_op *, 223 int, int, void **)) 224 { 225 pgd_t *pgd; 226 union mm_context *mmu = &mm->context; 227 struct host_vm_op ops[1]; 228 unsigned long addr = start_addr, next; 229 int ret = 0, last_op = ARRAY_SIZE(ops) - 1, op_index = -1; 230 void *flush = NULL; 231 232 ops[0].type = NONE; 233 pgd = pgd_offset(mm, addr); 234 do { 235 next = pgd_addr_end(addr, end_addr); 236 if(!pgd_present(*pgd)){ 237 if (force || pgd_newpage(*pgd)){ 238 ret = add_munmap(addr, next - addr, ops, 239 &op_index, last_op, mmu, 240 &flush, do_ops); 241 pgd_mkuptodate(*pgd); 242 } 243 } 244 else ret = update_pud_range(pgd, addr, next, ops, last_op, 245 &op_index, force, mmu, &flush, 246 do_ops); 247 } while (pgd++, addr = next, ((addr != end_addr) && !ret)); 248 249 if(!ret) 250 ret = (*do_ops)(mmu, ops, op_index, 1, &flush); 251 252 /* This is not an else because ret is modified above */ 253 if(ret) { 254 printk("fix_range_common: failed, killing current process\n"); 255 force_sig(SIGKILL, current); 256 } 257 } 258 259 int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) 260 { 261 struct mm_struct *mm; 262 pgd_t *pgd; 263 pud_t *pud; 264 pmd_t *pmd; 265 pte_t *pte; 266 unsigned long addr, last; 267 int updated = 0, err; 268 269 mm = &init_mm; 270 for(addr = start; addr < end;){ 271 pgd = pgd_offset(mm, addr); 272 if(!pgd_present(*pgd)){ 273 last = ADD_ROUND(addr, PGDIR_SIZE); 274 if(last > end) 275 last = end; 276 if(pgd_newpage(*pgd)){ 277 updated = 1; 278 err = os_unmap_memory((void *) addr, 279 last - addr); 280 if(err < 0) 281 panic("munmap failed, errno = %d\n", 282 -err); 283 } 284 addr = last; 285 continue; 286 } 287 288 pud = pud_offset(pgd, addr); 289 if(!pud_present(*pud)){ 290 last = ADD_ROUND(addr, PUD_SIZE); 291 if(last > end) 292 last = end; 293 if(pud_newpage(*pud)){ 294 updated = 1; 295 err = os_unmap_memory((void *) addr, 296 last - addr); 297 if(err < 0) 298 panic("munmap failed, errno = %d\n", 299 -err); 300 } 301 addr = last; 302 continue; 303 } 304 305 pmd = pmd_offset(pud, addr); 306 if(!pmd_present(*pmd)){ 307 last = ADD_ROUND(addr, PMD_SIZE); 308 if(last > end) 309 last = end; 310 if(pmd_newpage(*pmd)){ 311 updated = 1; 312 err = os_unmap_memory((void *) addr, 313 last - addr); 314 if(err < 0) 315 panic("munmap failed, errno = %d\n", 316 -err); 317 } 318 addr = last; 319 continue; 320 } 321 322 pte = pte_offset_kernel(pmd, addr); 323 if(!pte_present(*pte) || pte_newpage(*pte)){ 324 updated = 1; 325 err = os_unmap_memory((void *) addr, 326 PAGE_SIZE); 327 if(err < 0) 328 panic("munmap failed, errno = %d\n", 329 -err); 330 if(pte_present(*pte)) 331 map_memory(addr, 332 pte_val(*pte) & PAGE_MASK, 333 PAGE_SIZE, 1, 1, 1); 334 } 335 else if(pte_newprot(*pte)){ 336 updated = 1; 337 os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); 338 } 339 addr += PAGE_SIZE; 340 } 341 return(updated); 342 } 343 344 void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) 345 { 346 pgd_t *pgd; 347 pud_t *pud; 348 pmd_t *pmd; 349 pte_t *pte; 350 struct mm_struct *mm = vma->vm_mm; 351 void *flush = NULL; 352 int r, w, x, prot, err = 0; 353 struct mm_id *mm_id; 354 355 address &= PAGE_MASK; 356 pgd = pgd_offset(mm, address); 357 if(!pgd_present(*pgd)) 358 goto kill; 359 360 pud = pud_offset(pgd, address); 361 if(!pud_present(*pud)) 362 goto kill; 363 364 pmd = pmd_offset(pud, address); 365 if(!pmd_present(*pmd)) 366 goto kill; 367 368 pte = pte_offset_kernel(pmd, address); 369 370 r = pte_read(*pte); 371 w = pte_write(*pte); 372 x = pte_exec(*pte); 373 if (!pte_young(*pte)) { 374 r = 0; 375 w = 0; 376 } else if (!pte_dirty(*pte)) { 377 w = 0; 378 } 379 380 mm_id = &mm->context.skas.id; 381 prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | 382 (x ? UM_PROT_EXEC : 0)); 383 if(pte_newpage(*pte)){ 384 if(pte_present(*pte)){ 385 unsigned long long offset; 386 int fd; 387 388 fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); 389 err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, 390 1, &flush); 391 } 392 else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); 393 } 394 else if(pte_newprot(*pte)) 395 err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush); 396 397 if(err) 398 goto kill; 399 400 *pte = pte_mkuptodate(*pte); 401 402 return; 403 404 kill: 405 printk("Failed to flush page for address 0x%lx\n", address); 406 force_sig(SIGKILL, current); 407 } 408 409 pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) 410 { 411 return(pgd_offset(mm, address)); 412 } 413 414 pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) 415 { 416 return(pud_offset(pgd, address)); 417 } 418 419 pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) 420 { 421 return(pmd_offset(pud, address)); 422 } 423 424 pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) 425 { 426 return(pte_offset_kernel(pmd, address)); 427 } 428 429 pte_t *addr_pte(struct task_struct *task, unsigned long addr) 430 { 431 pgd_t *pgd = pgd_offset(task->mm, addr); 432 pud_t *pud = pud_offset(pgd, addr); 433 pmd_t *pmd = pmd_offset(pud, addr); 434 435 return(pte_offset_map(pmd, addr)); 436 } 437 438 void flush_tlb_all(void) 439 { 440 flush_tlb_mm(current->mm); 441 } 442 443 void flush_tlb_kernel_range(unsigned long start, unsigned long end) 444 { 445 flush_tlb_kernel_range_common(start, end); 446 } 447 448 void flush_tlb_kernel_vm(void) 449 { 450 flush_tlb_kernel_range_common(start_vm, end_vm); 451 } 452 453 void __flush_tlb_one(unsigned long addr) 454 { 455 flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE); 456 } 457 458 static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, 459 int finished, void **flush) 460 { 461 struct host_vm_op *op; 462 int i, ret = 0; 463 464 for(i = 0; i <= last && !ret; i++){ 465 op = &ops[i]; 466 switch(op->type){ 467 case MMAP: 468 ret = map(&mmu->skas.id, op->u.mmap.addr, 469 op->u.mmap.len, op->u.mmap.prot, 470 op->u.mmap.fd, op->u.mmap.offset, finished, 471 flush); 472 break; 473 case MUNMAP: 474 ret = unmap(&mmu->skas.id, op->u.munmap.addr, 475 op->u.munmap.len, finished, flush); 476 break; 477 case MPROTECT: 478 ret = protect(&mmu->skas.id, op->u.mprotect.addr, 479 op->u.mprotect.len, op->u.mprotect.prot, 480 finished, flush); 481 break; 482 default: 483 printk("Unknown op type %d in do_ops\n", op->type); 484 break; 485 } 486 } 487 488 return ret; 489 } 490 491 static void fix_range(struct mm_struct *mm, unsigned long start_addr, 492 unsigned long end_addr, int force) 493 { 494 if(!proc_mm && (end_addr > CONFIG_STUB_START)) 495 end_addr = CONFIG_STUB_START; 496 497 fix_range_common(mm, start_addr, end_addr, force, do_ops); 498 } 499 500 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 501 unsigned long end) 502 { 503 if(vma->vm_mm == NULL) 504 flush_tlb_kernel_range_common(start, end); 505 else fix_range(vma->vm_mm, start, end, 0); 506 } 507 508 void flush_tlb_mm(struct mm_struct *mm) 509 { 510 unsigned long end; 511 512 /* Don't bother flushing if this address space is about to be 513 * destroyed. 514 */ 515 if(atomic_read(&mm->mm_users) == 0) 516 return; 517 518 end = proc_mm ? task_size : CONFIG_STUB_START; 519 fix_range(mm, 0, end, 0); 520 } 521 522 void force_flush_all(void) 523 { 524 struct mm_struct *mm = current->mm; 525 struct vm_area_struct *vma = mm->mmap; 526 527 while(vma != NULL) { 528 fix_range(mm, vma->vm_start, vma->vm_end, 1); 529 vma = vma->vm_next; 530 } 531 } 532