1 #include <linux/kernel.h> 2 3 #include <asm/cputype.h> 4 #include <asm/pgalloc.h> 5 #include <asm/pgtable.h> 6 7 static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end, 8 unsigned long prot) 9 { 10 pmd_t *pmd = pmd_offset(pgd, addr); 11 12 addr = (addr & PMD_MASK) | prot; 13 pmd[0] = __pmd(addr); 14 addr += SECTION_SIZE; 15 pmd[1] = __pmd(addr); 16 flush_pmd_entry(pmd); 17 } 18 19 void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) 20 { 21 unsigned long prot, next; 22 23 prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE; 24 if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) 25 prot |= PMD_BIT4; 26 27 pgd += pgd_index(addr); 28 do { 29 next = pgd_addr_end(addr, end); 30 idmap_add_pmd(pgd, addr, next, prot); 31 } while (pgd++, addr = next, addr != end); 32 } 33 34 #ifdef CONFIG_SMP 35 static void idmap_del_pmd(pgd_t *pgd, unsigned long addr, unsigned long end) 36 { 37 pmd_t *pmd = pmd_offset(pgd, addr); 38 pmd_clear(pmd); 39 } 40 41 void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) 42 { 43 unsigned long next; 44 45 pgd += pgd_index(addr); 46 do { 47 next = pgd_addr_end(addr, end); 48 idmap_del_pmd(pgd, addr, next); 49 } while (pgd++, addr = next, addr != end); 50 } 51 #endif 52 53 /* 54 * In order to soft-boot, we need to insert a 1:1 mapping in place of 55 * the user-mode pages. This will then ensure that we have predictable 56 * results when turning the mmu off 57 */ 58 void setup_mm_for_reboot(char mode) 59 { 60 /* 61 * We need to access to user-mode page tables here. For kernel threads 62 * we don't have any user-mode mappings so we use the context that we 63 * "borrowed". 64 */ 65 identity_mapping_add(current->active_mm->pgd, 0, TASK_SIZE); 66 local_flush_tlb_all(); 67 } 68