| /* |
| * linux/arch/arm/mm/mmu.c |
| * |
| * Copyright (C) 1995-2005 Russell King |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| #include <linux/kernel.h> |
| #include <linux/errno.h> |
| #include <linux/init.h> |
| #include <linux/bootmem.h> |
| #include <linux/mman.h> |
| #include <linux/nodemask.h> |
| |
| #include <asm/mach-types.h> |
| #include <asm/setup.h> |
| #include <asm/sizes.h> |
| #include <asm/tlb.h> |
| |
| #include <asm/mach/arch.h> |
| #include <asm/mach/map.h> |
| |
| #include "mm.h" |
| |
| DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
| |
| extern void _stext, __data_start, _end; |
| extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; |
| |
| /* |
| * empty_zero_page is a special page that is used for |
| * zero-initialized data and COW. |
| */ |
| struct page *empty_zero_page; |
| |
| /* |
| * The pmd table for the upper-most set of pages. |
| */ |
| pmd_t *top_pmd; |
| |
| static inline void prepare_page_table(struct meminfo *mi) |
| { |
| unsigned long addr; |
| |
| /* |
| * Clear out all the mappings below the kernel image. |
| */ |
| for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE) |
| pmd_clear(pmd_off_k(addr)); |
| |
| #ifdef CONFIG_XIP_KERNEL |
| /* The XIP kernel is mapped in the module area -- skip over it */ |
| addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK; |
| #endif |
| for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE) |
| pmd_clear(pmd_off_k(addr)); |
| |
| /* |
| * Clear out all the kernel space mappings, except for the first |
| * memory bank, up to the end of the vmalloc region. |
| */ |
| for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size); |
| addr < VMALLOC_END; addr += PGDIR_SIZE) |
| pmd_clear(pmd_off_k(addr)); |
| } |
| |
| /* |
| * Reserve the various regions of node 0 |
| */ |
| void __init reserve_node_zero(pg_data_t *pgdat) |
| { |
| unsigned long res_size = 0; |
| |
| /* |
| * Register the kernel text and data with bootmem. |
| * Note that this can only be in node 0. |
| */ |
| #ifdef CONFIG_XIP_KERNEL |
| reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start); |
| #else |
| reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); |
| #endif |
| |
| /* |
| * Reserve the page tables. These are already in use, |
| * and can only be in node 0. |
| */ |
| reserve_bootmem_node(pgdat, __pa(swapper_pg_dir), |
| PTRS_PER_PGD * sizeof(pgd_t)); |
| |
| /* |
| * Hmm... This should go elsewhere, but we really really need to |
| * stop things allocating the low memory; ideally we need a better |
| * implementation of GFP_DMA which does not assume that DMA-able |
| * memory starts at zero. |
| */ |
| if (machine_is_integrator() || machine_is_cintegrator()) |
| res_size = __pa(swapper_pg_dir) - PHYS_OFFSET; |
| |
| /* |
| * These should likewise go elsewhere. They pre-reserve the |
| * screen memory region at the start of main system memory. |
| */ |
| if (machine_is_edb7211()) |
| res_size = 0x00020000; |
| if (machine_is_p720t()) |
| res_size = 0x00014000; |
| |
| #ifdef CONFIG_SA1111 |
| /* |
| * Because of the SA1111 DMA bug, we want to preserve our |
| * precious DMA-able memory... |
| */ |
| res_size = __pa(swapper_pg_dir) - PHYS_OFFSET; |
| #endif |
| if (res_size) |
| reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size); |
| } |
| |
| /* |
| * Set up device the mappings. Since we clear out the page tables for all |
| * mappings above VMALLOC_END, we will remove any debug device mappings. |
| * This means you have to be careful how you debug this function, or any |
| * called function. This means you can't use any function or debugging |
| * method which may touch any device, otherwise the kernel _will_ crash. |
| */ |
| static void __init devicemaps_init(struct machine_desc *mdesc) |
| { |
| struct map_desc map; |
| unsigned long addr; |
| void *vectors; |
| |
| /* |
| * Allocate the vector page early. |
| */ |
| vectors = alloc_bootmem_low_pages(PAGE_SIZE); |
| BUG_ON(!vectors); |
| |
| for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) |
| pmd_clear(pmd_off_k(addr)); |
| |
| /* |
| * Map the kernel if it is XIP. |
| * It is always first in the modulearea. |
| */ |
| #ifdef CONFIG_XIP_KERNEL |
| map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK); |
| map.virtual = MODULE_START; |
| map.length = ((unsigned long)&_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK; |
| map.type = MT_ROM; |
| create_mapping(&map); |
| #endif |
| |
| /* |
| * Map the cache flushing regions. |
| */ |
| #ifdef FLUSH_BASE |
| map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS); |
| map.virtual = FLUSH_BASE; |
| map.length = SZ_1M; |
| map.type = MT_CACHECLEAN; |
| create_mapping(&map); |
| #endif |
| #ifdef FLUSH_BASE_MINICACHE |
| map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M); |
| map.virtual = FLUSH_BASE_MINICACHE; |
| map.length = SZ_1M; |
| map.type = MT_MINICLEAN; |
| create_mapping(&map); |
| #endif |
| |
| /* |
| * Create a mapping for the machine vectors at the high-vectors |
| * location (0xffff0000). If we aren't using high-vectors, also |
| * create a mapping at the low-vectors virtual address. |
| */ |
| map.pfn = __phys_to_pfn(virt_to_phys(vectors)); |
| map.virtual = 0xffff0000; |
| map.length = PAGE_SIZE; |
| map.type = MT_HIGH_VECTORS; |
| create_mapping(&map); |
| |
| if (!vectors_high()) { |
| map.virtual = 0; |
| map.type = MT_LOW_VECTORS; |
| create_mapping(&map); |
| } |
| |
| /* |
| * Ask the machine support to map in the statically mapped devices. |
| */ |
| if (mdesc->map_io) |
| mdesc->map_io(); |
| |
| /* |
| * Finally flush the caches and tlb to ensure that we're in a |
| * consistent state wrt the writebuffer. This also ensures that |
| * any write-allocated cache lines in the vector page are written |
| * back. After this point, we can start to touch devices again. |
| */ |
| local_flush_tlb_all(); |
| flush_cache_all(); |
| } |
| |
| /* |
| * paging_init() sets up the page tables, initialises the zone memory |
| * maps, and sets up the zero page, bad page and bad page tables. |
| */ |
| void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) |
| { |
| void *zero_page; |
| |
| build_mem_type_table(); |
| prepare_page_table(mi); |
| bootmem_init(mi); |
| devicemaps_init(mdesc); |
| |
| top_pmd = pmd_off_k(0xffff0000); |
| |
| /* |
| * allocate the zero page. Note that we count on this going ok. |
| */ |
| zero_page = alloc_bootmem_low_pages(PAGE_SIZE); |
| memzero(zero_page, PAGE_SIZE); |
| empty_zero_page = virt_to_page(zero_page); |
| flush_dcache_page(empty_zero_page); |
| } |