linux/arch/alpha/boot/main.c
<<
>>
Prefs
   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/slab.h>
  10#include <linux/string.h>
  11#include <generated/utsrelease.h>
  12#include <linux/mm.h>
  13
  14#include <asm/system.h>
  15#include <asm/console.h>
  16#include <asm/hwrpb.h>
  17#include <asm/pgtable.h>
  18
  19#include <stdarg.h>
  20
  21#include "ksize.h"
  22
  23extern int vsprintf(char *, const char *, va_list);
  24extern unsigned long switch_to_osf_pal(unsigned long nr,
  25        struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
  26        unsigned long *vptb);
  27struct hwrpb_struct *hwrpb = INIT_HWRPB;
  28static struct pcb_struct pcb_va[1];
  29
  30/*
  31 * Find a physical address of a virtual object..
  32 *
  33 * This is easy using the virtual page table address.
  34 */
  35
  36static inline void *
  37find_pa(unsigned long *vptb, void *ptr)
  38{
  39        unsigned long address = (unsigned long) ptr;
  40        unsigned long result;
  41
  42        result = vptb[address >> 13];
  43        result >>= 32;
  44        result <<= 13;
  45        result |= address & 0x1fff;
  46        return (void *) result;
  47}       
  48
  49/*
  50 * This function moves into OSF/1 pal-code, and has a temporary
  51 * PCB for that. The kernel proper should replace this PCB with
  52 * the real one as soon as possible.
  53 *
  54 * The page table muckery in here depends on the fact that the boot
  55 * code has the L1 page table identity-map itself in the second PTE
  56 * in the L1 page table. Thus the L1-page is virtually addressable
  57 * itself (through three levels) at virtual address 0x200802000.
  58 */
  59
  60#define VPTB    ((unsigned long *) 0x200000000)
  61#define L1      ((unsigned long *) 0x200802000)
  62
  63void
  64pal_init(void)
  65{
  66        unsigned long i, rev;
  67        struct percpu_struct * percpu;
  68        struct pcb_struct * pcb_pa;
  69
  70        /* Create the dummy PCB.  */
  71        pcb_va->ksp = 0;
  72        pcb_va->usp = 0;
  73        pcb_va->ptbr = L1[1] >> 32;
  74        pcb_va->asn = 0;
  75        pcb_va->pcc = 0;
  76        pcb_va->unique = 0;
  77        pcb_va->flags = 1;
  78        pcb_va->res1 = 0;
  79        pcb_va->res2 = 0;
  80        pcb_pa = find_pa(VPTB, pcb_va);
  81
  82        /*
  83         * a0 = 2 (OSF)
  84         * a1 = return address, but we give the asm the vaddr of the PCB
  85         * a2 = physical addr of PCB
  86         * a3 = new virtual page table pointer
  87         * a4 = KSP (but the asm sets it)
  88         */
  89        srm_printk("Switching to OSF PAL-code .. ");
  90
  91        i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
  92        if (i) {
  93                srm_printk("failed, code %ld\n", i);
  94                __halt();
  95        }
  96
  97        percpu = (struct percpu_struct *)
  98                (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
  99        rev = percpu->pal_revision = percpu->palcode_avail[2];
 100
 101        srm_printk("Ok (rev %lx)\n", rev);
 102
 103        tbia(); /* do it directly in case we are SMP */
 104}
 105
 106static inline long openboot(void)
 107{
 108        char bootdev[256];
 109        long result;
 110
 111        result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255);
 112        if (result < 0)
 113                return result;
 114        return callback_open(bootdev, result & 255);
 115}
 116
 117static inline long close(long dev)
 118{
 119        return callback_close(dev);
 120}
 121
 122static inline long load(long dev, unsigned long addr, unsigned long count)
 123{
 124        char bootfile[256];
 125        extern char _end;
 126        long result, boot_size = &_end - (char *) BOOT_ADDR;
 127
 128        result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255);
 129        if (result < 0)
 130                return result;
 131        result &= 255;
 132        bootfile[result] = '\0';
 133        if (result)
 134                srm_printk("Boot file specification (%s) not implemented\n",
 135                       bootfile);
 136        return callback_read(dev, count, (void *)addr, boot_size/512 + 1);
 137}
 138
 139/*
 140 * Start the kernel.
 141 */
 142static void runkernel(void)
 143{
 144        __asm__ __volatile__(
 145                "bis %1,%1,$30\n\t"
 146                "bis %0,%0,$26\n\t"
 147                "ret ($26)"
 148                : /* no outputs: it doesn't even return */
 149                : "r" (START_ADDR),
 150                  "r" (PAGE_SIZE + INIT_STACK));
 151}
 152
 153void start_kernel(void)
 154{
 155        long i;
 156        long dev;
 157        int nbytes;
 158        char envval[256];
 159
 160        srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
 161        if (INIT_HWRPB->pagesize != 8192) {
 162                srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10);
 163                return;
 164        }
 165        pal_init();
 166        dev = openboot();
 167        if (dev < 0) {
 168                srm_printk("Unable to open boot device: %016lx\n", dev);
 169                return;
 170        }
 171        dev &= 0xffffffff;
 172        srm_printk("Loading vmlinux ...");
 173        i = load(dev, START_ADDR, KERNEL_SIZE);
 174        close(dev);
 175        if (i != KERNEL_SIZE) {
 176                srm_printk("Failed (%lx)\n", i);
 177                return;
 178        }
 179
 180        nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
 181        if (nbytes < 0) {
 182                nbytes = 0;
 183        }
 184        envval[nbytes] = '\0';
 185        strcpy((char*)ZERO_PGE, envval);
 186
 187        srm_printk(" Ok\nNow booting the kernel\n");
 188        runkernel();
 189        for (i = 0 ; i < 0x100000000 ; i++)
 190                /* nothing */;
 191        __halt();
 192}
 193