X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fum%2Fkernel%2Fskas%2Ftlb.c;h=956fb0102a1ee43f459a7141b8f2b1149f60f9fb;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=02e3e06bb03313b99b3aa1a10c7df57c5f79bef9;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 02e3e06bb..956fb0102 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ @@ -18,52 +19,86 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { pgd_t *npgd; + pud_t *npud; pmd_t *npmd; pte_t *npte; - unsigned long addr; + unsigned long addr, end; int r, w, x, err, fd; if(mm == NULL) return; fd = mm->context.skas.mm_fd; for(addr = start_addr; addr < end_addr;){ npgd = pgd_offset(mm, addr); - npmd = pmd_offset(npgd, addr); - if(pmd_present(*npmd)){ - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if(!pte_dirty(*npte)) w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } - if(force || pte_newpage(*npte)){ - err = unmap(fd, (void *) addr, PAGE_SIZE); + if(!pgd_present(*npgd)){ + if(force || pgd_newpage(*npgd)){ + end = addr + PGDIR_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*npte)) - map(fd, addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); + pgd_mkuptodate(*npgd); } - else if(pte_newprot(*npte)){ - protect(fd, addr, PAGE_SIZE, r, w, x, 1); + addr += PGDIR_SIZE; + continue; + } + + npud = pud_offset(npgd, addr); + if(!pud_present(*npud)){ + if(force || pud_newpage(*npud)){ + end = addr + PUD_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pud_mkuptodate(*npud); } - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + npmd = pmd_offset(npud, addr); + if(!pmd_present(*npmd)){ if(force || pmd_newpage(*npmd)){ - err = unmap(fd, (void *) addr, PMD_SIZE); + end = addr + PMD_SIZE; + if(end > end_addr) + end = end_addr; + err = unmap(fd, (void *) addr, end - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); pmd_mkuptodate(*npmd); } addr += PMD_SIZE; + continue; + } + + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) + w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = unmap(fd, (void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", -err); + if(pte_present(*npte)) + map(fd, addr, pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); } + else if(pte_newprot(*npte)) + protect(fd, addr, PAGE_SIZE, r, w, x, 1); + + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; } } @@ -71,45 +106,82 @@ void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end) { struct mm_struct *mm; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; - unsigned long addr; + unsigned long addr, last; int updated = 0, err; mm = &init_mm; for(addr = start; addr < end;){ pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + if(!pgd_present(*pgd)){ + if(pgd_newpage(*pgd)){ updated = 1; + last = addr + PGDIR_SIZE; + if(last > end) + last = end; err = os_unmap_memory((void *) addr, - PAGE_SIZE); + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); } - else if(pte_newprot(*pte)){ + addr += PGDIR_SIZE; + continue; + } + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)){ + if(pud_newpage(*pud)){ updated = 1; - protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + last = addr + PUD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); } - addr += PAGE_SIZE; + addr += PUD_SIZE; + continue; } - else { + + pmd = pmd_offset(pud, addr); + if(!pmd_present(*pmd)){ if(pmd_newpage(*pmd)){ updated = 1; - err = os_unmap_memory((void *) addr, PMD_SIZE); + last = addr + PMD_SIZE; + if(last > end) + last = end; + err = os_unmap_memory((void *) addr, + last - addr); if(err < 0) panic("munmap failed, errno = %d\n", -err); } addr += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", -err); + if(pte_present(*pte)) + map_memory(addr, pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); } + else if(pte_newprot(*pte)){ + updated = 1; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; } }