Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * arch/alpha/boot/main.c
0004  *
0005  * Copyright (C) 1994, 1995 Linus Torvalds
0006  *
0007  * This file is the bootloader for the Linux/AXP kernel
0008  */
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011 #include <linux/string.h>
0012 #include <generated/utsrelease.h>
0013 #include <linux/mm.h>
0014 
0015 #include <asm/console.h>
0016 #include <asm/hwrpb.h>
0017 
0018 #include <stdarg.h>
0019 
0020 #include "ksize.h"
0021 
0022 extern unsigned long switch_to_osf_pal(unsigned long nr,
0023     struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
0024     unsigned long *vptb);
0025 struct hwrpb_struct *hwrpb = INIT_HWRPB;
0026 static struct pcb_struct pcb_va[1];
0027 
0028 /*
0029  * Find a physical address of a virtual object..
0030  *
0031  * This is easy using the virtual page table address.
0032  */
0033 
0034 static inline void *
0035 find_pa(unsigned long *vptb, void *ptr)
0036 {
0037     unsigned long address = (unsigned long) ptr;
0038     unsigned long result;
0039 
0040     result = vptb[address >> 13];
0041     result >>= 32;
0042     result <<= 13;
0043     result |= address & 0x1fff;
0044     return (void *) result;
0045 }   
0046 
0047 /*
0048  * This function moves into OSF/1 pal-code, and has a temporary
0049  * PCB for that. The kernel proper should replace this PCB with
0050  * the real one as soon as possible.
0051  *
0052  * The page table muckery in here depends on the fact that the boot
0053  * code has the L1 page table identity-map itself in the second PTE
0054  * in the L1 page table. Thus the L1-page is virtually addressable
0055  * itself (through three levels) at virtual address 0x200802000.
0056  */
0057 
0058 #define VPTB    ((unsigned long *) 0x200000000)
0059 #define L1  ((unsigned long *) 0x200802000)
0060 
0061 void
0062 pal_init(void)
0063 {
0064     unsigned long i, rev;
0065     struct percpu_struct * percpu;
0066     struct pcb_struct * pcb_pa;
0067 
0068     /* Create the dummy PCB.  */
0069     pcb_va->ksp = 0;
0070     pcb_va->usp = 0;
0071     pcb_va->ptbr = L1[1] >> 32;
0072     pcb_va->asn = 0;
0073     pcb_va->pcc = 0;
0074     pcb_va->unique = 0;
0075     pcb_va->flags = 1;
0076     pcb_va->res1 = 0;
0077     pcb_va->res2 = 0;
0078     pcb_pa = find_pa(VPTB, pcb_va);
0079 
0080     /*
0081      * a0 = 2 (OSF)
0082      * a1 = return address, but we give the asm the vaddr of the PCB
0083      * a2 = physical addr of PCB
0084      * a3 = new virtual page table pointer
0085      * a4 = KSP (but the asm sets it)
0086      */
0087     srm_printk("Switching to OSF PAL-code .. ");
0088 
0089     i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
0090     if (i) {
0091         srm_printk("failed, code %ld\n", i);
0092         __halt();
0093     }
0094 
0095     percpu = (struct percpu_struct *)
0096         (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
0097     rev = percpu->pal_revision = percpu->palcode_avail[2];
0098 
0099     srm_printk("Ok (rev %lx)\n", rev);
0100 
0101     tbia(); /* do it directly in case we are SMP */
0102 }
0103 
0104 static inline long openboot(void)
0105 {
0106     char bootdev[256];
0107     long result;
0108 
0109     result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255);
0110     if (result < 0)
0111         return result;
0112     return callback_open(bootdev, result & 255);
0113 }
0114 
0115 static inline long close(long dev)
0116 {
0117     return callback_close(dev);
0118 }
0119 
0120 static inline long load(long dev, unsigned long addr, unsigned long count)
0121 {
0122     char bootfile[256];
0123     extern char _end;
0124     long result, boot_size = &_end - (char *) BOOT_ADDR;
0125 
0126     result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255);
0127     if (result < 0)
0128         return result;
0129     result &= 255;
0130     bootfile[result] = '\0';
0131     if (result)
0132         srm_printk("Boot file specification (%s) not implemented\n",
0133                bootfile);
0134     return callback_read(dev, count, (void *)addr, boot_size/512 + 1);
0135 }
0136 
0137 /*
0138  * Start the kernel.
0139  */
0140 static void runkernel(void)
0141 {
0142     __asm__ __volatile__(
0143         "bis %1,%1,$30\n\t"
0144         "bis %0,%0,$26\n\t"
0145         "ret ($26)"
0146         : /* no outputs: it doesn't even return */
0147         : "r" (START_ADDR),
0148           "r" (PAGE_SIZE + INIT_STACK));
0149 }
0150 
0151 void start_kernel(void)
0152 {
0153     long i;
0154     long dev;
0155     int nbytes;
0156     char envval[256];
0157 
0158     srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
0159     if (INIT_HWRPB->pagesize != 8192) {
0160         srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10);
0161         return;
0162     }
0163     pal_init();
0164     dev = openboot();
0165     if (dev < 0) {
0166         srm_printk("Unable to open boot device: %016lx\n", dev);
0167         return;
0168     }
0169     dev &= 0xffffffff;
0170     srm_printk("Loading vmlinux ...");
0171     i = load(dev, START_ADDR, KERNEL_SIZE);
0172     close(dev);
0173     if (i != KERNEL_SIZE) {
0174         srm_printk("Failed (%lx)\n", i);
0175         return;
0176     }
0177 
0178     nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
0179     if (nbytes < 0) {
0180         nbytes = 0;
0181     }
0182     envval[nbytes] = '\0';
0183     strcpy((char*)ZERO_PGE, envval);
0184 
0185     srm_printk(" Ok\nNow booting the kernel\n");
0186     runkernel();
0187     for (i = 0 ; i < 0x100000000 ; i++)
0188         /* nothing */;
0189     __halt();
0190 }