linux/arch/um/kernel/mem.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <linux/stddef.h>
   7#include <linux/module.h>
   8#include <linux/bootmem.h>
   9#include <linux/highmem.h>
  10#include <linux/mm.h>
  11#include <linux/swap.h>
  12#include <linux/slab.h>
  13#include <asm/fixmap.h>
  14#include <asm/page.h>
  15#include <as-layout.h>
  16#include <init.h>
  17#include <kern.h>
  18#include <kern_util.h>
  19#include <mem_user.h>
  20#include <os.h>
  21
  22/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
  23unsigned long *empty_zero_page = NULL;
  24EXPORT_SYMBOL(empty_zero_page);
  25/* allocated in paging_init and unchanged thereafter */
  26static unsigned long *empty_bad_page = NULL;
  27
  28/*
  29 * Initialized during boot, and readonly for initializing page tables
  30 * afterwards
  31 */
  32pgd_t swapper_pg_dir[PTRS_PER_PGD];
  33
  34/* Initialized at boot time, and readonly after that */
  35unsigned long long highmem;
  36int kmalloc_ok = 0;
  37
  38/* Used during early boot */
  39static unsigned long brk_end;
  40
  41#ifdef CONFIG_HIGHMEM
  42static void setup_highmem(unsigned long highmem_start,
  43                          unsigned long highmem_len)
  44{
  45        unsigned long highmem_pfn;
  46        int i;
  47
  48        highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
  49        for (i = 0; i < highmem_len >> PAGE_SHIFT; i++)
  50                free_highmem_page(&mem_map[highmem_pfn + i]);
  51}
  52#endif
  53
  54void __init mem_init(void)
  55{
  56        /* clear the zero-page */
  57        memset(empty_zero_page, 0, PAGE_SIZE);
  58
  59        /* Map in the area just after the brk now that kmalloc is about
  60         * to be turned on.
  61         */
  62        brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
  63        map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
  64        free_bootmem(__pa(brk_end), uml_reserved - brk_end);
  65        uml_reserved = brk_end;
  66
  67        /* this will put all low memory onto the freelists */
  68        free_all_bootmem();
  69        max_low_pfn = totalram_pages;
  70#ifdef CONFIG_HIGHMEM
  71        setup_highmem(end_iomem, highmem);
  72#endif
  73        max_pfn = totalram_pages;
  74        mem_init_print_info(NULL);
  75        kmalloc_ok = 1;
  76}
  77
  78/*
  79 * Create a page table and place a pointer to it in a middle page
  80 * directory entry.
  81 */
  82static void __init one_page_table_init(pmd_t *pmd)
  83{
  84        if (pmd_none(*pmd)) {
  85                pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
  86                set_pmd(pmd, __pmd(_KERNPG_TABLE +
  87                                           (unsigned long) __pa(pte)));
  88                if (pte != pte_offset_kernel(pmd, 0))
  89                        BUG();
  90        }
  91}
  92
  93static void __init one_md_table_init(pud_t *pud)
  94{
  95#ifdef CONFIG_3_LEVEL_PGTABLES
  96        pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
  97        set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table)));
  98        if (pmd_table != pmd_offset(pud, 0))
  99                BUG();
 100#endif
 101}
 102
 103static void __init fixrange_init(unsigned long start, unsigned long end,
 104                                 pgd_t *pgd_base)
 105{
 106        pgd_t *pgd;
 107        pud_t *pud;
 108        pmd_t *pmd;
 109        int i, j;
 110        unsigned long vaddr;
 111
 112        vaddr = start;
 113        i = pgd_index(vaddr);
 114        j = pmd_index(vaddr);
 115        pgd = pgd_base + i;
 116
 117        for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
 118                pud = pud_offset(pgd, vaddr);
 119                if (pud_none(*pud))
 120                        one_md_table_init(pud);
 121                pmd = pmd_offset(pud, vaddr);
 122                for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) {
 123                        one_page_table_init(pmd);
 124                        vaddr += PMD_SIZE;
 125                }
 126                j = 0;
 127        }
 128}
 129
 130#ifdef CONFIG_HIGHMEM
 131pte_t *kmap_pte;
 132pgprot_t kmap_prot;
 133
 134#define kmap_get_fixmap_pte(vaddr)                                      \
 135        pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
 136                                     (vaddr)), (vaddr))
 137
 138static void __init kmap_init(void)
 139{
 140        unsigned long kmap_vstart;
 141
 142        /* cache the first kmap pte */
 143        kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
 144        kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
 145
 146        kmap_prot = PAGE_KERNEL;
 147}
 148
 149static void __init init_highmem(void)
 150{
 151        pgd_t *pgd;
 152        pud_t *pud;
 153        pmd_t *pmd;
 154        pte_t *pte;
 155        unsigned long vaddr;
 156
 157        /*
 158         * Permanent kmaps:
 159         */
 160        vaddr = PKMAP_BASE;
 161        fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
 162
 163        pgd = swapper_pg_dir + pgd_index(vaddr);
 164        pud = pud_offset(pgd, vaddr);
 165        pmd = pmd_offset(pud, vaddr);
 166        pte = pte_offset_kernel(pmd, vaddr);
 167        pkmap_page_table = pte;
 168
 169        kmap_init();
 170}
 171#endif /* CONFIG_HIGHMEM */
 172
 173static void __init fixaddr_user_init( void)
 174{
 175#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
 176        long size = FIXADDR_USER_END - FIXADDR_USER_START;
 177        pgd_t *pgd;
 178        pud_t *pud;
 179        pmd_t *pmd;
 180        pte_t *pte;
 181        phys_t p;
 182        unsigned long v, vaddr = FIXADDR_USER_START;
 183
 184        if (!size)
 185                return;
 186
 187        fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
 188        v = (unsigned long) alloc_bootmem_low_pages(size);
 189        memcpy((void *) v , (void *) FIXADDR_USER_START, size);
 190        p = __pa(v);
 191        for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
 192                      p += PAGE_SIZE) {
 193                pgd = swapper_pg_dir + pgd_index(vaddr);
 194                pud = pud_offset(pgd, vaddr);
 195                pmd = pmd_offset(pud, vaddr);
 196                pte = pte_offset_kernel(pmd, vaddr);
 197                pte_set_val(*pte, p, PAGE_READONLY);
 198        }
 199#endif
 200}
 201
 202void __init paging_init(void)
 203{
 204        unsigned long zones_size[MAX_NR_ZONES], vaddr;
 205        int i;
 206
 207        empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
 208        empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
 209        for (i = 0; i < ARRAY_SIZE(zones_size); i++)
 210                zones_size[i] = 0;
 211
 212        zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
 213                (uml_physmem >> PAGE_SHIFT);
 214#ifdef CONFIG_HIGHMEM
 215        zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
 216#endif
 217        free_area_init(zones_size);
 218
 219        /*
 220         * Fixed mappings, only the page table structure has to be
 221         * created - mappings will be set by set_fixmap():
 222         */
 223        vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
 224        fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
 225
 226        fixaddr_user_init();
 227
 228#ifdef CONFIG_HIGHMEM
 229        init_highmem();
 230#endif
 231}
 232
 233/*
 234 * This can't do anything because nothing in the kernel image can be freed
 235 * since it's not in kernel physical memory.
 236 */
 237
 238void free_initmem(void)
 239{
 240}
 241
 242#ifdef CONFIG_BLK_DEV_INITRD
 243void free_initrd_mem(unsigned long start, unsigned long end)
 244{
 245        free_reserved_area((void *)start, (void *)end, -1, "initrd");
 246}
 247#endif
 248
 249/* Allocate and free page tables. */
 250
 251pgd_t *pgd_alloc(struct mm_struct *mm)
 252{
 253        pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
 254
 255        if (pgd) {
 256                memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
 257                memcpy(pgd + USER_PTRS_PER_PGD,
 258                       swapper_pg_dir + USER_PTRS_PER_PGD,
 259                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 260        }
 261        return pgd;
 262}
 263
 264void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 265{
 266        free_page((unsigned long) pgd);
 267}
 268
 269pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 270{
 271        pte_t *pte;
 272
 273        pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
 274        return pte;
 275}
 276
 277pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
 278{
 279        struct page *pte;
 280
 281        pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
 282        if (pte)
 283                pgtable_page_ctor(pte);
 284        return pte;
 285}
 286
 287#ifdef CONFIG_3_LEVEL_PGTABLES
 288pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 289{
 290        pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
 291
 292        if (pmd)
 293                memset(pmd, 0, PAGE_SIZE);
 294
 295        return pmd;
 296}
 297#endif
 298
 299void *uml_kmalloc(int size, int flags)
 300{
 301        return kmalloc(size, flags);
 302}
 303