diff options
Diffstat (limited to 'arch/arm/mm/init.c')
| -rw-r--r-- | arch/arm/mm/init.c | 155 |
1 files changed, 127 insertions, 28 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index c29ad610311b..4d58a6eca48e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -466,6 +466,54 @@ static void __init free_highpages(void) #endif } +#define MLK(b, t) (b), (t), (((t) - (b)) >> 10) +#define MLM(b, t) (b), (t), (((t) - (b)) >> 20) +#define MLK_ROUNDUP(b, t) (b), (t), (DIV_ROUND_UP(((t) - (b)), SZ_1K)) + +#ifdef CONFIG_ENABLE_VMALLOC_SAVING +static void print_vmalloc_lowmem_info(void) +{ + struct memblock_region *reg, *prev_reg = NULL; + + pr_notice( + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)high_memory, VMALLOC_END)); + + for_each_memblock_rev(memory, reg) { + phys_addr_t start_phys = reg->base; + phys_addr_t end_phys = reg->base + reg->size; + + if (start_phys > arm_lowmem_limit) + continue; + + if (end_phys > arm_lowmem_limit) + end_phys = arm_lowmem_limit; + + if (prev_reg == NULL) { + prev_reg = reg; + + pr_notice( + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(start_phys), + (unsigned long)__va(end_phys))); + + continue; + } + + pr_notice( + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(end_phys), + (unsigned long)__va(prev_reg->base))); + + + pr_notice( + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(start_phys), + (unsigned long)__va(end_phys))); + } +} +#endif + /* * mem_init() marks the free areas in the mem_map and tells us how much * memory is free. This is done after various parts of the system have @@ -494,39 +542,40 @@ void __init mem_init(void) mem_init_print_info(NULL); -#define MLK(b, t) b, t, ((t) - (b)) >> 10 -#define MLM(b, t) b, t, ((t) - (b)) >> 20 -#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) - pr_notice("Virtual kernel memory layout:\n" " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" #ifdef CONFIG_HAVE_TCM " DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n" " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n" #endif - " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" - " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" - " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" -#ifdef CONFIG_HIGHMEM - " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" -#endif -#ifdef CONFIG_MODULES - " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" -#endif - " .text : 0x%p" " - 0x%p" " (%4td kB)\n" - " .init : 0x%p" " - 0x%p" " (%4td kB)\n" - " .data : 0x%p" " - 0x%p" " (%4td kB)\n" - " .bss : 0x%p" " - 0x%p" " (%4td kB)\n", - + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n", MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + (PAGE_SIZE)), #ifdef CONFIG_HAVE_TCM MLK(DTCM_OFFSET, (unsigned long) dtcm_end), MLK(ITCM_OFFSET, (unsigned long) itcm_end), #endif - MLK(FIXADDR_START, FIXADDR_END), + MLK(FIXADDR_START, FIXADDR_END)); +#ifdef CONFIG_ENABLE_VMALLOC_SAVING + print_vmalloc_lowmem_info(); +#else + printk(KERN_NOTICE + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", MLM(VMALLOC_START, VMALLOC_END), - MLM(PAGE_OFFSET, (unsigned long)high_memory), + MLM(PAGE_OFFSET, (unsigned long)high_memory)); +#endif + printk(KERN_NOTICE +#ifdef CONFIG_HIGHMEM + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif +#ifdef CONFIG_MODULES + " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif + " .text : 0x%p" " - 0x%p" " (%4d kB)\n" + " .init : 0x%p" " - 0x%p" " (%4d kB)\n" + " .data : 0x%p" " - 0x%p" " (%4d kB)\n" + " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", #ifdef CONFIG_HIGHMEM MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) * (PAGE_SIZE)), @@ -540,10 +589,6 @@ void __init mem_init(void) MLK_ROUNDUP(_sdata, _edata), MLK_ROUNDUP(__bss_start, __bss_stop)); -#undef MLK -#undef MLM -#undef MLK_ROUNDUP - /* * Check boundaries twice: Some fundamental inconsistencies can * be detected at build time already. @@ -569,6 +614,10 @@ void __init mem_init(void) } } +#undef MLK +#undef MLM +#undef MLK_ROUNDUP + #ifdef CONFIG_ARM_KERNMEM_PERMS struct section_perm { unsigned long start; @@ -576,6 +625,9 @@ struct section_perm { pmdval_t mask; pmdval_t prot; pmdval_t clear; + pteval_t ptemask; + pteval_t pteprot; + pteval_t pteclear; }; static struct section_perm nx_perms[] = { @@ -585,6 +637,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_stext, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, /* Make init RW (set NX). */ { @@ -592,6 +646,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_sdata, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, #ifdef CONFIG_DEBUG_RODATA /* Make rodata NX (set RO in ro_perms below). */ @@ -600,6 +656,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)__init_begin, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, #endif }; @@ -618,6 +676,8 @@ static struct section_perm ro_perms[] = { .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, .clear = PMD_SECT_AP_WRITE, #endif + .ptemask = ~L_PTE_RDONLY, + .pteprot = L_PTE_RDONLY, }, }; #endif @@ -627,6 +687,35 @@ static struct section_perm ro_perms[] = { * copied into each mm). During startup, this is the init_mm. Is only * safe to be called with preemption disabled, as under stop_machine(). */ +struct pte_data { + pteval_t mask; + pteval_t val; +}; + +static int __pte_update(pte_t *ptep, pgtable_t token, unsigned long addr, + void *d) +{ + struct pte_data *data = d; + pte_t pte = *ptep; + + pte = __pte((pte_val(*ptep) & data->mask) | data->val); + set_pte_ext(ptep, pte, 0); + + return 0; +} + +static inline void pte_update(unsigned long addr, pteval_t mask, + pteval_t prot, struct mm_struct *mm) +{ + struct pte_data data; + + data.mask = mask; + data.val = prot; + + apply_to_page_range(mm, addr, SECTION_SIZE, __pte_update, &data); + flush_tlb_kernel_range(addr, addr + SECTION_SIZE); +} + static inline void section_update(unsigned long addr, pmdval_t mask, pmdval_t prot, struct mm_struct *mm) { @@ -675,11 +764,21 @@ void set_section_perms(struct section_perm *perms, int n, bool set, for (addr = perms[i].start; addr < perms[i].end; - addr += SECTION_SIZE) - section_update(addr, perms[i].mask, - set ? perms[i].prot : perms[i].clear, mm); + addr += SECTION_SIZE) { + pmd_t *pmd; + + pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), + addr), addr); + if (pmd_bad(*pmd)) + section_update(addr, perms[i].mask, + set ? perms[i].prot : perms[i].clear, + mm); + else + pte_update(addr, perms[i].ptemask, + set ? perms[i].pteprot : perms[i].pteclear, + mm); + } } - } static void update_sections_early(struct section_perm perms[], int n) |
