linux/arch/alpha/mm/init.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/alpha/mm/init.c
   3 *
   4 *  Copyright (C) 1995  Linus Torvalds
   5 */
   6
   7/* 2.3.x zone allocator, 1999 Andrea Arcangeli <andrea@suse.de> */
   8
   9#include <linux/pagemap.h>
  10#include <linux/signal.h>
  11#include <linux/sched.h>
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/string.h>
  15#include <linux/types.h>
  16#include <linux/ptrace.h>
  17#include <linux/mman.h>
  18#include <linux/mm.h>
  19#include <linux/swap.h>
  20#include <linux/init.h>
  21#include <linux/bootmem.h> /* max_low_pfn */
  22#include <linux/vmalloc.h>
  23#include <linux/gfp.h>
  24
  25#include <asm/system.h>
  26#include <asm/uaccess.h>
  27#include <asm/pgtable.h>
  28#include <asm/pgalloc.h>
  29#include <asm/hwrpb.h>
  30#include <asm/dma.h>
  31#include <asm/mmu_context.h>
  32#include <asm/console.h>
  33#include <asm/tlb.h>
  34
  35DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
  36
  37extern void die_if_kernel(char *,struct pt_regs *,long);
  38
  39static struct pcb_struct original_pcb;
  40
  41pgd_t *
  42pgd_alloc(struct mm_struct *mm)
  43{
  44        pgd_t *ret, *init;
  45
  46        ret = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
  47        init = pgd_offset(&init_mm, 0UL);
  48        if (ret) {
  49#ifdef CONFIG_ALPHA_LARGE_VMALLOC
  50                memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
  51                        (PTRS_PER_PGD - USER_PTRS_PER_PGD - 1)*sizeof(pgd_t));
  52#else
  53                pgd_val(ret[PTRS_PER_PGD-2]) = pgd_val(init[PTRS_PER_PGD-2]);
  54#endif
  55
  56                /* The last PGD entry is the VPTB self-map.  */
  57                pgd_val(ret[PTRS_PER_PGD-1])
  58                  = pte_val(mk_pte(virt_to_page(ret), PAGE_KERNEL));
  59        }
  60        return ret;
  61}
  62
  63
  64/*
  65 * BAD_PAGE is the page that is used for page faults when linux
  66 * is out-of-memory. Older versions of linux just did a
  67 * do_exit(), but using this instead means there is less risk
  68 * for a process dying in kernel mode, possibly leaving an inode
  69 * unused etc..
  70 *
  71 * BAD_PAGETABLE is the accompanying page-table: it is initialized
  72 * to point to BAD_PAGE entries.
  73 *
  74 * ZERO_PAGE is a special page that is used for zero-initialized
  75 * data and COW.
  76 */
  77pmd_t *
  78__bad_pagetable(void)
  79{
  80        memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
  81        return (pmd_t *) EMPTY_PGT;
  82}
  83
  84pte_t
  85__bad_page(void)
  86{
  87        memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
  88        return pte_mkdirty(mk_pte(virt_to_page(EMPTY_PGE), PAGE_SHARED));
  89}
  90
  91static inline unsigned long
  92load_PCB(struct pcb_struct *pcb)
  93{
  94        register unsigned long sp __asm__("$30");
  95        pcb->ksp = sp;
  96        return __reload_thread(pcb);
  97}
  98
  99/* Set up initial PCB, VPTB, and other such nicities.  */
 100
 101static inline void
 102switch_to_system_map(void)
 103{
 104        unsigned long newptbr;
 105        unsigned long original_pcb_ptr;
 106
 107        /* Initialize the kernel's page tables.  Linux puts the vptb in
 108           the last slot of the L1 page table.  */
 109        memset(swapper_pg_dir, 0, PAGE_SIZE);
 110        newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
 111        pgd_val(swapper_pg_dir[1023]) =
 112                (newptbr << 32) | pgprot_val(PAGE_KERNEL);
 113
 114        /* Set the vptb.  This is often done by the bootloader, but 
 115           shouldn't be required.  */
 116        if (hwrpb->vptb != 0xfffffffe00000000UL) {
 117                wrvptptr(0xfffffffe00000000UL);
 118                hwrpb->vptb = 0xfffffffe00000000UL;
 119                hwrpb_update_checksum(hwrpb);
 120        }
 121
 122        /* Also set up the real kernel PCB while we're at it.  */
 123        init_thread_info.pcb.ptbr = newptbr;
 124        init_thread_info.pcb.flags = 1; /* set FEN, clear everything else */
 125        original_pcb_ptr = load_PCB(&init_thread_info.pcb);
 126        tbia();
 127
 128        /* Save off the contents of the original PCB so that we can
 129           restore the original console's page tables for a clean reboot.
 130
 131           Note that the PCB is supposed to be a physical address, but
 132           since KSEG values also happen to work, folks get confused.
 133           Check this here.  */
 134
 135        if (original_pcb_ptr < PAGE_OFFSET) {
 136                original_pcb_ptr = (unsigned long)
 137                        phys_to_virt(original_pcb_ptr);
 138        }
 139        original_pcb = *(struct pcb_struct *) original_pcb_ptr;
 140}
 141
 142int callback_init_done;
 143
 144void * __init
 145callback_init(void * kernel_end)
 146{
 147        struct crb_struct * crb;
 148        pgd_t *pgd;
 149        pmd_t *pmd;
 150        void *two_pages;
 151
 152        /* Starting at the HWRPB, locate the CRB. */
 153        crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset);
 154
 155        if (alpha_using_srm) {
 156                /* Tell the console whither it is to be remapped. */
 157                if (srm_fixup(VMALLOC_START, (unsigned long)hwrpb))
 158                        __halt();               /* "We're boned."  --Bender */
 159
 160                /* Edit the procedure descriptors for DISPATCH and FIXUP. */
 161                crb->dispatch_va = (struct procdesc_struct *)
 162                        (VMALLOC_START + (unsigned long)crb->dispatch_va
 163                         - crb->map[0].va);
 164                crb->fixup_va = (struct procdesc_struct *)
 165                        (VMALLOC_START + (unsigned long)crb->fixup_va
 166                         - crb->map[0].va);
 167        }
 168
 169        switch_to_system_map();
 170
 171        /* Allocate one PGD and one PMD.  In the case of SRM, we'll need
 172           these to actually remap the console.  There is an assumption
 173           here that only one of each is needed, and this allows for 8MB.
 174           On systems with larger consoles, additional pages will be
 175           allocated as needed during the mapping process.
 176
 177           In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
 178           we need to allocate the PGD we use for vmalloc before we start
 179           forking other tasks.  */
 180
 181        two_pages = (void *)
 182          (((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK);
 183        kernel_end = two_pages + 2*PAGE_SIZE;
 184        memset(two_pages, 0, 2*PAGE_SIZE);
 185
 186        pgd = pgd_offset_k(VMALLOC_START);
 187        pgd_set(pgd, (pmd_t *)two_pages);
 188        pmd = pmd_offset(pgd, VMALLOC_START);
 189        pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));
 190
 191        if (alpha_using_srm) {
 192                static struct vm_struct console_remap_vm;
 193                unsigned long nr_pages = 0;
 194                unsigned long vaddr;
 195                unsigned long i, j;
 196
 197                /* calculate needed size */
 198                for (i = 0; i < crb->map_entries; ++i)
 199                        nr_pages += crb->map[i].count;
 200
 201                /* register the vm area */
 202                console_remap_vm.flags = VM_ALLOC;
 203                console_remap_vm.size = nr_pages << PAGE_SHIFT;
 204                vm_area_register_early(&console_remap_vm, PAGE_SIZE);
 205
 206                vaddr = (unsigned long)console_remap_vm.addr;
 207
 208                /* Set up the third level PTEs and update the virtual
 209                   addresses of the CRB entries.  */
 210                for (i = 0; i < crb->map_entries; ++i) {
 211                        unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
 212                        crb->map[i].va = vaddr;
 213                        for (j = 0; j < crb->map[i].count; ++j) {
 214                                /* Newer consoles (especially on larger
 215                                   systems) may require more pages of
 216                                   PTEs. Grab additional pages as needed. */
 217                                if (pmd != pmd_offset(pgd, vaddr)) {
 218                                        memset(kernel_end, 0, PAGE_SIZE);
 219                                        pmd = pmd_offset(pgd, vaddr);
 220                                        pmd_set(pmd, (pte_t *)kernel_end);
 221                                        kernel_end += PAGE_SIZE;
 222                                }
 223                                set_pte(pte_offset_kernel(pmd, vaddr),
 224                                        pfn_pte(pfn, PAGE_KERNEL));
 225                                pfn++;
 226                                vaddr += PAGE_SIZE;
 227                        }
 228                }
 229        }
 230
 231        callback_init_done = 1;
 232        return kernel_end;
 233}
 234
 235
 236#ifndef CONFIG_DISCONTIGMEM
 237/*
 238 * paging_init() sets up the memory map.
 239 */
 240void __init paging_init(void)
 241{
 242        unsigned long zones_size[MAX_NR_ZONES] = {0, };
 243        unsigned long dma_pfn, high_pfn;
 244
 245        dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 246        high_pfn = max_pfn = max_low_pfn;
 247
 248        if (dma_pfn >= high_pfn)
 249                zones_size[ZONE_DMA] = high_pfn;
 250        else {
 251                zones_size[ZONE_DMA] = dma_pfn;
 252                zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
 253        }
 254
 255        /* Initialize mem_map[].  */
 256        free_area_init(zones_size);
 257
 258        /* Initialize the kernel's ZERO_PGE. */
 259        memset((void *)ZERO_PGE, 0, PAGE_SIZE);
 260}
 261#endif /* CONFIG_DISCONTIGMEM */
 262
 263#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 264void
 265srm_paging_stop (void)
 266{
 267        /* Move the vptb back to where the SRM console expects it.  */
 268        swapper_pg_dir[1] = swapper_pg_dir[1023];
 269        tbia();
 270        wrvptptr(0x200000000UL);
 271        hwrpb->vptb = 0x200000000UL;
 272        hwrpb_update_checksum(hwrpb);
 273
 274        /* Reload the page tables that the console had in use.  */
 275        load_PCB(&original_pcb);
 276        tbia();
 277}
 278#endif
 279
 280#ifndef CONFIG_DISCONTIGMEM
 281static void __init
 282printk_memory_info(void)
 283{
 284        unsigned long codesize, reservedpages, datasize, initsize, tmp;
 285        extern int page_is_ram(unsigned long) __init;
 286        extern char _text, _etext, _data, _edata;
 287        extern char __init_begin, __init_end;
 288
 289        /* printk all informations */
 290        reservedpages = 0;
 291        for (tmp = 0; tmp < max_low_pfn; tmp++)
 292                /*
 293                 * Only count reserved RAM pages
 294                 */
 295                if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
 296                        reservedpages++;
 297
 298        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 299        datasize =  (unsigned long) &_edata - (unsigned long) &_data;
 300        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 301
 302        printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n",
 303               nr_free_pages() << (PAGE_SHIFT-10),
 304               max_mapnr << (PAGE_SHIFT-10),
 305               codesize >> 10,
 306               reservedpages << (PAGE_SHIFT-10),
 307               datasize >> 10,
 308               initsize >> 10);
 309}
 310
 311void __init
 312mem_init(void)
 313{
 314        max_mapnr = num_physpages = max_low_pfn;
 315        totalram_pages += free_all_bootmem();
 316        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 317
 318        printk_memory_info();
 319}
 320#endif /* CONFIG_DISCONTIGMEM */
 321
 322void
 323free_reserved_mem(void *start, void *end)
 324{
 325        void *__start = start;
 326        for (; __start < end; __start += PAGE_SIZE) {
 327                ClearPageReserved(virt_to_page(__start));
 328                init_page_count(virt_to_page(__start));
 329                free_page((long)__start);
 330                totalram_pages++;
 331        }
 332}
 333
 334void
 335free_initmem(void)
 336{
 337        extern char __init_begin, __init_end;
 338
 339        free_reserved_mem(&__init_begin, &__init_end);
 340        printk ("Freeing unused kernel memory: %ldk freed\n",
 341                (&__init_end - &__init_begin) >> 10);
 342}
 343
 344#ifdef CONFIG_BLK_DEV_INITRD
 345void
 346free_initrd_mem(unsigned long start, unsigned long end)
 347{
 348        free_reserved_mem((void *)start, (void *)end);
 349        printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 350}
 351#endif
 352