root/arch/alpha/boot/main.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. printk
  2. find_pa
  3. pal_init
  4. openboot
  5. close
  6. load
  7. runkernel
  8. start_kernel

   1 /*
   2  * arch/alpha/boot/main.c
   3  *
   4  * Copyright (C) 1994, 1995 Linus Torvalds
   5  *
   6  * This file is the bootloader for the Linux/AXP kernel
   7  */
   8 #include <linux/kernel.h>
   9 #include <linux/string.h>
  10 #include <linux/version.h>
  11 #include <linux/mm.h>
  12 
  13 #include <asm/system.h>
  14 #include <asm/console.h>
  15 #include <asm/hwrpb.h>
  16 
  17 #include <stdarg.h>
  18 
  19 extern int vsprintf(char *, const char *, va_list);
  20 extern unsigned long switch_to_osf_pal(unsigned long nr,
  21         struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
  22         unsigned long vptb, unsigned long *kstk);
  23 
  24 int printk(const char * fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26         va_list args;
  27         int i;
  28         static char buf[1024];
  29 
  30         va_start(args, fmt);
  31         i = vsprintf(buf, fmt, args);
  32         va_end(args);
  33         puts(buf,i);
  34         return i;
  35 }
  36 
  37 #define hwrpb (*INIT_HWRPB)
  38 
  39 /*
  40  * Find a physical address of a virtual object..
  41  *
  42  * This is easy using the virtual page table address.
  43  */
  44 struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46         unsigned long address = (unsigned long) pcb;
  47         unsigned long result;
  48 
  49         result = vptb[address >> 13];
  50         result >>= 32;
  51         result <<= 13;
  52         result |= address & 0x1fff;
  53         return (struct pcb_struct *) result;
  54 }       
  55 
  56 /*
  57  * This function moves into OSF/1 pal-code, and has a temporary
  58  * PCB for that. The kernel proper should replace this PCB with
  59  * the real one as soon as possible.
  60  *
  61  * The page table muckery in here depends on the fact that the boot
  62  * code has the L1 page table identity-map itself in the second PTE
  63  * in the L1 page table. Thus the L1-page is virtually addressable
  64  * itself (through three levels) at virtual address 0x200802000.
  65  *
  66  * As we don't want it there anyway, we also move the L1 self-map
  67  * up as high as we can, so that the last entry in the L1 page table
  68  * maps the page tables.
  69  *
  70  * As a result, the OSF/1 pal-code will instead use a virtual page table
  71  * map located at 0xffffffe00000000.
  72  */
  73 #define pcb_va ((struct pcb_struct *) 0x20000000)
  74 #define old_vptb (0x0000000200000000UL)
  75 #define new_vptb (0xfffffffe00000000UL)
  76 void pal_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         unsigned long i, rev, sum;
  79         unsigned long *L1, *l;
  80         struct percpu_struct * percpu;
  81         struct pcb_struct * pcb_pa;
  82 
  83         /* Find the level 1 page table and duplicate it in high memory */
  84         L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
  85         L1[1023] = L1[1];
  86 
  87         percpu = (struct percpu_struct *) (hwrpb.processor_offset + (unsigned long) &hwrpb),
  88                 
  89         pcb_va->ksp = 0;
  90         pcb_va->usp = 0;
  91         pcb_va->ptbr = L1[1] >> 32;
  92         pcb_va->asn = 0;
  93         pcb_va->pcc = 0;
  94         pcb_va->unique = 0;
  95         pcb_va->flags = 1;
  96         pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
  97         printk("Switching to OSF PAL-code .. ");
  98         /*
  99          * a0 = 2 (OSF)
 100          * a1 = return address, but we give the asm the virtual addr of the PCB
 101          * a2 = physical addr of PCB
 102          * a3 = new virtual page table pointer
 103          * a4 = KSP (but we give it 0, asm sets it)
 104          */
 105         i = switch_to_osf_pal(
 106                 2,
 107                 pcb_va,
 108                 pcb_pa,
 109                 new_vptb,
 110                 0);
 111         if (i) {
 112                 printk("failed, code %ld\n", i);
 113                 halt();
 114         }
 115         rev = percpu->pal_revision = percpu->palcode_avail[2];
 116 
 117         hwrpb.vptb = new_vptb;
 118 
 119         /* update checksum: */
 120         sum = 0;
 121         for (l = (unsigned long *) &hwrpb; l < (unsigned long *) &hwrpb.chksum; ++l)
 122                 sum += *l;
 123         hwrpb.chksum = sum;
 124 
 125         printk("Ok (rev %lx)\n", rev);
 126         /* remove the old virtual page-table mapping */
 127         L1[1] = 0;
 128         invalidate_all();
 129 }
 130 
 131 extern int _end;
 132 
 133 static inline long openboot(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         char bootdev[256];
 136         long result;
 137 
 138         result = dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255);
 139         if (result < 0)
 140                 return result;
 141         return dispatch(CCB_OPEN, bootdev, result & 255);
 142 }
 143 
 144 static inline long close(long dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         return dispatch(CCB_CLOSE, dev);
 147 }
 148 
 149 static inline long load(long dev, unsigned long addr, unsigned long count)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151         char bootfile[256];
 152         long result;
 153 
 154         result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255);
 155         if (result < 0)
 156                 return result;
 157         result &= 255;
 158         bootfile[result] = '\0';
 159         if (result)
 160                 printk("Boot file specification (%s) not implemented\n", bootfile);
 161         return dispatch(CCB_READ, dev, count, addr, BOOT_SIZE/512 + 1);
 162 }
 163 
 164 /*
 165  * Start the kernel:
 166  * - switch to the proper PCB structure
 167  * - switch to the proper ptbr
 168  * - switch to the new kernel stack
 169  */
 170 static void runkernel(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172         struct pcb_struct * init_pcb = (struct pcb_struct *) INIT_PCB;
 173         unsigned long oldptbr, *oldL1;
 174         unsigned long newptbr, *newL1;
 175 
 176         oldptbr = pcb_va->ptbr;
 177         oldL1 = (unsigned long *) (PAGE_OFFSET + (oldptbr << PAGE_SHIFT));
 178 
 179         newptbr = (SWAPPER_PGD - PAGE_OFFSET) >> PAGE_SHIFT;
 180         newL1 = (unsigned long *) SWAPPER_PGD;
 181 
 182         memcpy(newL1, oldL1, PAGE_SIZE);
 183         newL1[1023] = (newptbr << 32) | pgprot_val(PAGE_KERNEL);
 184 
 185         *init_pcb = *pcb_va;
 186         init_pcb->ksp = PAGE_SIZE + INIT_STACK;
 187         init_pcb->ptbr = newptbr;
 188         
 189         __asm__ __volatile__(
 190                 "bis %0,%0,$26\n\t"
 191                 "bis %1,%1,$16\n\t"
 192                 ".long %2\n\t"
 193                 "lda $16,-2($31)\n\t"
 194                 ".long 51\n\t"
 195                 "ret ($26)"
 196                 : /* no outputs: it doesn't even return */
 197                 : "r" (START_ADDR),
 198                   "r" (init_pcb),
 199                   "i" (PAL_swpctx)
 200                 : "$16","$26");
 201 }
 202 
 203 void start_kernel(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 204 {
 205         long i;
 206         long dev;
 207 
 208         printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
 209         if (hwrpb.pagesize != 8192) {
 210                 printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10);
 211                 return;
 212         }
 213         pal_init();
 214         dev = openboot();
 215         if (dev < 0) {
 216                 printk("Unable to open boot device: %016lx\n", dev);
 217                 return;
 218         }
 219         dev &= 0xffffffff;
 220         printk("Loading vmlinux ...");
 221         i = load(dev, START_ADDR, START_SIZE);
 222         close(dev);
 223         if (i != START_SIZE) {
 224                 printk("Failed (%lx)\n", i);
 225                 return;
 226         }
 227         printk(" Ok\nNow booting the kernel\n");
 228         runkernel();
 229         for (i = 0 ; i < 0x100000000 ; i++)
 230                 /* nothing */;
 231         halt();
 232 }

/* [previous][next][first][last][top][bottom][index][help] */