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