- struct mm_struct *mm;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long addr, last;
- int updated = 0, err;
-
- mm = &init_mm;
- for(addr = start; addr < end;){
- pgd = pgd_offset(mm, addr);
- if(!pgd_present(*pgd)){
- last = ADD_ROUND(addr, PGDIR_SIZE);
- if(last > end)
- last = end;
- if(pgd_newpage(*pgd)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- continue;
- }
-
- pud = pud_offset(pgd, addr);
- if(!pud_present(*pud)){
- last = ADD_ROUND(addr, PUD_SIZE);
- if(last > end)
- last = end;
- if(pud_newpage(*pud)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- continue;
- }
-
- pmd = pmd_offset(pud, addr);
- if(!pmd_present(*pmd)){
- last = ADD_ROUND(addr, PMD_SIZE);
- if(last > end)
- last = end;
- if(pmd_newpage(*pmd)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- 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;
- os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
- }
- addr += PAGE_SIZE;
- }
- return(updated);
+ struct mm_struct *mm;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr, last;
+ int updated = 0, err;
+
+ mm = &init_mm;
+ for (addr = start; addr < end;) {
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd)) {
+ last = ADD_ROUND(addr, PGDIR_SIZE);
+ if (last > end)
+ last = end;
+ if (pgd_newpage(*pgd)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ continue;
+ }
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud)) {
+ last = ADD_ROUND(addr, PUD_SIZE);
+ if (last > end)
+ last = end;
+ if (pud_newpage(*pud)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ continue;
+ }
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd)) {
+ last = ADD_ROUND(addr, PMD_SIZE);
+ if (last > end)
+ last = end;
+ if (pmd_newpage(*pmd)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ 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;
+ os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
+ }
+ addr += PAGE_SIZE;
+ }
+ return updated;
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ struct mm_struct *mm = vma->vm_mm;
+ void *flush = NULL;
+ int r, w, x, prot, err = 0;
+ struct mm_id *mm_id;
+
+ address &= PAGE_MASK;
+ pgd = pgd_offset(mm, address);
+ if (!pgd_present(*pgd))
+ goto kill;
+
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ goto kill;
+
+ pmd = pmd_offset(pud, address);
+ if (!pmd_present(*pmd))
+ goto kill;
+
+ pte = pte_offset_kernel(pmd, address);
+
+ r = pte_read(*pte);
+ w = pte_write(*pte);
+ x = pte_exec(*pte);
+ if (!pte_young(*pte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*pte)) {
+ w = 0;
+ }
+
+ mm_id = &mm->context.id;
+ prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+ (x ? UM_PROT_EXEC : 0));
+ if (pte_newpage(*pte)) {
+ if (pte_present(*pte)) {
+ unsigned long long offset;
+ int fd;
+
+ fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
+ err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
+ 1, &flush);
+ }
+ else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
+ }
+ else if (pte_newprot(*pte))
+ err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+
+ if (err)
+ goto kill;
+
+ *pte = pte_mkuptodate(*pte);
+
+ return;
+
+kill:
+ printk(KERN_ERR "Failed to flush page for address 0x%lx\n", address);
+ force_sig(SIGKILL, current);