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