Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * arch/alpha/boot/bootpz.c
0004  *
0005  * Copyright (C) 1997 Jay Estabrook
0006  *
0007  * This file is used for creating a compressed BOOTP file for the
0008  * Linux/AXP kernel
0009  *
0010  * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
0011  * and the decompression code from MILO.
0012  */
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/string.h>
0016 #include <generated/utsrelease.h>
0017 #include <linux/mm.h>
0018 
0019 #include <asm/console.h>
0020 #include <asm/hwrpb.h>
0021 #include <asm/io.h>
0022 
0023 #include <stdarg.h>
0024 
0025 #include "kzsize.h"
0026 
0027 /* FIXME FIXME FIXME */
0028 #define MALLOC_AREA_SIZE 0x200000 /* 2MB for now */
0029 /* FIXME FIXME FIXME */
0030 
0031 
0032 /*
0033   WARNING NOTE
0034 
0035   It is very possible that turning on additional messages may cause
0036   kernel image corruption due to stack usage to do the printing.
0037 
0038 */
0039 
0040 #undef DEBUG_CHECK_RANGE
0041 #undef DEBUG_ADDRESSES
0042 #undef DEBUG_LAST_STEPS
0043 
0044 extern unsigned long switch_to_osf_pal(unsigned long nr,
0045     struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
0046     unsigned long *vptb);
0047 
0048 extern int decompress_kernel(void* destination, void *source,
0049                  size_t ksize, size_t kzsize);
0050 
0051 extern void move_stack(unsigned long new_stack);
0052 
0053 struct hwrpb_struct *hwrpb = INIT_HWRPB;
0054 static struct pcb_struct pcb_va[1];
0055 
0056 /*
0057  * Find a physical address of a virtual object..
0058  *
0059  * This is easy using the virtual page table address.
0060  */
0061 #define VPTB    ((unsigned long *) 0x200000000)
0062 
0063 static inline unsigned long
0064 find_pa(unsigned long address)
0065 {
0066     unsigned long result;
0067 
0068     result = VPTB[address >> 13];
0069     result >>= 32;
0070     result <<= 13;
0071     result |= address & 0x1fff;
0072     return result;
0073 }   
0074 
0075 int
0076 check_range(unsigned long vstart, unsigned long vend,
0077         unsigned long kstart, unsigned long kend)
0078 {
0079     unsigned long vaddr, kaddr;
0080 
0081 #ifdef DEBUG_CHECK_RANGE
0082     srm_printk("check_range: V[0x%lx:0x%lx] K[0x%lx:0x%lx]\n",
0083            vstart, vend, kstart, kend);
0084 #endif
0085     /* do some range checking for detecting an overlap... */
0086     for (vaddr = vstart; vaddr <= vend; vaddr += PAGE_SIZE)
0087     {
0088         kaddr = (find_pa(vaddr) | PAGE_OFFSET);
0089         if (kaddr >= kstart && kaddr <= kend)
0090         {
0091 #ifdef DEBUG_CHECK_RANGE
0092             srm_printk("OVERLAP: vaddr 0x%lx kaddr 0x%lx"
0093                    " [0x%lx:0x%lx]\n",
0094                    vaddr, kaddr, kstart, kend);
0095 #endif
0096             return 1;
0097         }
0098     }
0099     return 0;
0100 }
0101 
0102 /*
0103  * This function moves into OSF/1 pal-code, and has a temporary
0104  * PCB for that. The kernel proper should replace this PCB with
0105  * the real one as soon as possible.
0106  *
0107  * The page table muckery in here depends on the fact that the boot
0108  * code has the L1 page table identity-map itself in the second PTE
0109  * in the L1 page table. Thus the L1-page is virtually addressable
0110  * itself (through three levels) at virtual address 0x200802000.
0111  */
0112 
0113 #define L1  ((unsigned long *) 0x200802000)
0114 
0115 void
0116 pal_init(void)
0117 {
0118     unsigned long i, rev;
0119     struct percpu_struct * percpu;
0120     struct pcb_struct * pcb_pa;
0121 
0122     /* Create the dummy PCB.  */
0123     pcb_va->ksp = 0;
0124     pcb_va->usp = 0;
0125     pcb_va->ptbr = L1[1] >> 32;
0126     pcb_va->asn = 0;
0127     pcb_va->pcc = 0;
0128     pcb_va->unique = 0;
0129     pcb_va->flags = 1;
0130     pcb_va->res1 = 0;
0131     pcb_va->res2 = 0;
0132     pcb_pa = (struct pcb_struct *)find_pa((unsigned long)pcb_va);
0133 
0134     /*
0135      * a0 = 2 (OSF)
0136      * a1 = return address, but we give the asm the vaddr of the PCB
0137      * a2 = physical addr of PCB
0138      * a3 = new virtual page table pointer
0139      * a4 = KSP (but the asm sets it)
0140      */
0141     srm_printk("Switching to OSF PAL-code... ");
0142 
0143     i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
0144     if (i) {
0145         srm_printk("failed, code %ld\n", i);
0146         __halt();
0147     }
0148 
0149     percpu = (struct percpu_struct *)
0150         (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
0151     rev = percpu->pal_revision = percpu->palcode_avail[2];
0152 
0153     srm_printk("OK (rev %lx)\n", rev);
0154 
0155     tbia(); /* do it directly in case we are SMP */
0156 }
0157 
0158 /*
0159  * Start the kernel.
0160  */
0161 static inline void
0162 runkernel(void)
0163 {
0164     __asm__ __volatile__(
0165         "bis %0,%0,$27\n\t"
0166         "jmp ($27)"
0167         : /* no outputs: it doesn't even return */
0168         : "r" (START_ADDR));
0169 }
0170 
0171 /* Must record the SP (it is virtual) on entry, so we can make sure
0172    not to overwrite it during movement or decompression. */
0173 unsigned long SP_on_entry;
0174 
0175 /* Calculate the kernel image address based on the end of the BOOTP
0176    bootstrapper (ie this program).
0177 */
0178 extern char _end;
0179 #define KERNEL_ORIGIN \
0180     ((((unsigned long)&_end) + 511) & ~511)
0181 
0182 /* Round address to next higher page boundary. */
0183 #define NEXT_PAGE(a)    (((a) | (PAGE_SIZE - 1)) + 1)
0184 
0185 #ifdef INITRD_IMAGE_SIZE
0186 # define REAL_INITRD_SIZE INITRD_IMAGE_SIZE
0187 #else
0188 # define REAL_INITRD_SIZE 0
0189 #endif
0190 
0191 /* Defines from include/asm-alpha/system.h
0192 
0193     BOOT_ADDR   Virtual address at which the consoles loads
0194             the BOOTP image.
0195 
0196     KERNEL_START    KSEG address at which the kernel is built to run,
0197             which includes some initial data pages before the
0198             code.
0199 
0200     START_ADDR  KSEG address of the entry point of kernel code.
0201 
0202     ZERO_PGE    KSEG address of page full of zeroes, but 
0203             upon entry to kernel, it can be expected
0204             to hold the parameter list and possible
0205             INTRD information.
0206 
0207    These are used in the local defines below.
0208 */
0209   
0210 
0211 /* Virtual addresses for the BOOTP image. Note that this includes the
0212    bootstrapper code as well as the compressed kernel image, and
0213    possibly the INITRD image.
0214 
0215    Oh, and do NOT forget the STACK, which appears to be placed virtually
0216    beyond the end of the loaded image.
0217 */
0218 #define V_BOOT_IMAGE_START  BOOT_ADDR
0219 #define V_BOOT_IMAGE_END    SP_on_entry
0220 
0221 /* Virtual addresses for just the bootstrapper part of the BOOTP image. */
0222 #define V_BOOTSTRAPPER_START    BOOT_ADDR
0223 #define V_BOOTSTRAPPER_END  KERNEL_ORIGIN
0224 
0225 /* Virtual addresses for just the data part of the BOOTP
0226    image. This may also include the INITRD image, but always
0227    includes the STACK.
0228 */
0229 #define V_DATA_START        KERNEL_ORIGIN
0230 #define V_INITRD_START      (KERNEL_ORIGIN + KERNEL_Z_SIZE)
0231 #define V_INTRD_END     (V_INITRD_START + REAL_INITRD_SIZE)
0232 #define V_DATA_END      V_BOOT_IMAGE_END
0233 
0234 /* KSEG addresses for the uncompressed kernel.
0235 
0236    Note that the end address includes workspace for the decompression.
0237    Note also that the DATA_START address is ZERO_PGE, to which we write
0238    just before jumping to the kernel image at START_ADDR.
0239  */
0240 #define K_KERNEL_DATA_START ZERO_PGE
0241 #define K_KERNEL_IMAGE_START    START_ADDR
0242 #define K_KERNEL_IMAGE_END  (START_ADDR + KERNEL_SIZE)
0243 
0244 /* Define to where we may have to decompress the kernel image, before
0245    we move it to the final position, in case of overlap. This will be
0246    above the final position of the kernel.
0247 
0248    Regardless of overlap, we move the INITRD image to the end of this
0249    copy area, because there needs to be a buffer area after the kernel
0250    for "bootmem" anyway.
0251 */
0252 #define K_COPY_IMAGE_START  NEXT_PAGE(K_KERNEL_IMAGE_END)
0253 /* Reserve one page below INITRD for the new stack. */
0254 #define K_INITRD_START \
0255     NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE)
0256 #define K_COPY_IMAGE_END \
0257     (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE)
0258 #define K_COPY_IMAGE_SIZE \
0259     NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START)
0260 
0261 void
0262 start_kernel(void)
0263 {
0264     int must_move = 0;
0265 
0266     /* Initialize these for the decompression-in-place situation,
0267        which is the smallest amount of work and most likely to
0268        occur when using the normal START_ADDR of the kernel
0269        (currently set to 16MB, to clear all console code.
0270     */
0271     unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START;
0272     unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END;
0273 
0274     unsigned long initrd_image_start = K_INITRD_START;
0275 
0276     /*
0277      * Note that this crufty stuff with static and envval
0278      * and envbuf is because:
0279      *
0280      * 1. Frequently, the stack is short, and we don't want to overrun;
0281      * 2. Frequently the stack is where we are going to copy the kernel to;
0282      * 3. A certain SRM console required the GET_ENV output to stack.
0283      *    ??? A comment in the aboot sources indicates that the GET_ENV
0284      *    destination must be quadword aligned.  Might this explain the
0285      *    behaviour, rather than requiring output to the stack, which
0286      *    seems rather far-fetched.
0287      */
0288     static long nbytes;
0289     static char envval[256] __attribute__((aligned(8)));
0290     register unsigned long asm_sp asm("30");
0291 
0292     SP_on_entry = asm_sp;
0293 
0294     srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n");
0295 
0296     /* Validity check the HWRPB. */
0297     if (INIT_HWRPB->pagesize != 8192) {
0298         srm_printk("Expected 8kB pages, got %ldkB\n",
0299                    INIT_HWRPB->pagesize >> 10);
0300         return;
0301     }
0302     if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
0303         srm_printk("Expected vptb at %p, got %p\n",
0304                VPTB, (void *)INIT_HWRPB->vptb);
0305         return;
0306     }
0307 
0308     /* PALcode (re)initialization. */
0309     pal_init();
0310 
0311     /* Get the parameter list from the console environment variable. */
0312     nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
0313     if (nbytes < 0 || nbytes >= sizeof(envval)) {
0314         nbytes = 0;
0315     }
0316     envval[nbytes] = '\0';
0317 
0318 #ifdef DEBUG_ADDRESSES
0319     srm_printk("START_ADDR 0x%lx\n", START_ADDR);
0320     srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN);
0321     srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE);
0322     srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE);
0323 #endif
0324 
0325     /* Since all the SRM consoles load the BOOTP image at virtual
0326      * 0x20000000, we have to ensure that the physical memory
0327      * pages occupied by that image do NOT overlap the physical
0328      * address range where the kernel wants to be run.  This
0329      * causes real problems when attempting to cdecompress the
0330      * former into the latter... :-(
0331      *
0332      * So, we may have to decompress/move the kernel/INITRD image
0333      * virtual-to-physical someplace else first before moving
0334      * kernel /INITRD to their final resting places... ;-}
0335      *
0336      * Sigh...
0337      */
0338 
0339     /* First, check to see if the range of addresses occupied by
0340        the bootstrapper part of the BOOTP image include any of the
0341        physical pages into which the kernel will be placed for
0342        execution.
0343 
0344        We only need check on the final kernel image range, since we
0345        will put the INITRD someplace that we can be sure is not
0346        in conflict.
0347      */
0348     if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END,
0349             K_KERNEL_DATA_START, K_KERNEL_IMAGE_END))
0350     {
0351         srm_printk("FATAL ERROR: overlap of bootstrapper code\n");
0352         __halt();
0353     }
0354 
0355     /* Next, check to see if the range of addresses occupied by
0356        the compressed kernel/INITRD/stack portion of the BOOTP
0357        image include any of the physical pages into which the
0358        decompressed kernel or the INITRD will be placed for
0359        execution.
0360      */
0361     if (check_range(V_DATA_START, V_DATA_END,
0362             K_KERNEL_IMAGE_START, K_COPY_IMAGE_END))
0363     {
0364 #ifdef DEBUG_ADDRESSES
0365         srm_printk("OVERLAP: cannot decompress in place\n");
0366 #endif
0367         uncompressed_image_start = K_COPY_IMAGE_START;
0368         uncompressed_image_end = K_COPY_IMAGE_END;
0369         must_move = 1;
0370 
0371         /* Finally, check to see if the range of addresses
0372            occupied by the compressed kernel/INITRD part of
0373            the BOOTP image include any of the physical pages
0374            into which that part is to be copied for
0375            decompression.
0376         */
0377         while (check_range(V_DATA_START, V_DATA_END,
0378                    uncompressed_image_start,
0379                    uncompressed_image_end))
0380         {
0381 #if 0
0382             uncompressed_image_start += K_COPY_IMAGE_SIZE;
0383             uncompressed_image_end += K_COPY_IMAGE_SIZE;
0384             initrd_image_start += K_COPY_IMAGE_SIZE;
0385 #else
0386             /* Keep as close as possible to end of BOOTP image. */
0387             uncompressed_image_start += PAGE_SIZE;
0388             uncompressed_image_end += PAGE_SIZE;
0389             initrd_image_start += PAGE_SIZE;
0390 #endif
0391         }
0392     }
0393 
0394     srm_printk("Starting to load the kernel with args '%s'\n", envval);
0395 
0396 #ifdef DEBUG_ADDRESSES
0397     srm_printk("Decompressing the kernel...\n"
0398            "...from 0x%lx to 0x%lx size 0x%x\n",
0399            V_DATA_START,
0400            uncompressed_image_start,
0401            KERNEL_SIZE);
0402 #endif
0403         decompress_kernel((void *)uncompressed_image_start,
0404               (void *)V_DATA_START,
0405               KERNEL_SIZE, KERNEL_Z_SIZE);
0406 
0407     /*
0408      * Now, move things to their final positions, if/as required.
0409      */
0410 
0411 #ifdef INITRD_IMAGE_SIZE
0412 
0413     /* First, we always move the INITRD image, if present. */
0414 #ifdef DEBUG_ADDRESSES
0415     srm_printk("Moving the INITRD image...\n"
0416            " from 0x%lx to 0x%lx size 0x%x\n",
0417            V_INITRD_START,
0418            initrd_image_start,
0419            INITRD_IMAGE_SIZE);
0420 #endif
0421     memcpy((void *)initrd_image_start, (void *)V_INITRD_START,
0422            INITRD_IMAGE_SIZE);
0423 
0424 #endif /* INITRD_IMAGE_SIZE */
0425 
0426     /* Next, we may have to move the uncompressed kernel to the
0427        final destination.
0428      */
0429     if (must_move) {
0430 #ifdef DEBUG_ADDRESSES
0431         srm_printk("Moving the uncompressed kernel...\n"
0432                "...from 0x%lx to 0x%lx size 0x%x\n",
0433                uncompressed_image_start,
0434                K_KERNEL_IMAGE_START,
0435                (unsigned)KERNEL_SIZE);
0436 #endif
0437         /*
0438          * Move the stack to a safe place to ensure it won't be
0439          * overwritten by kernel image.
0440          */
0441         move_stack(initrd_image_start - PAGE_SIZE);
0442 
0443         memcpy((void *)K_KERNEL_IMAGE_START,
0444                (void *)uncompressed_image_start, KERNEL_SIZE);
0445     }
0446     
0447     /* Clear the zero page, then move the argument list in. */
0448 #ifdef DEBUG_LAST_STEPS
0449     srm_printk("Preparing ZERO_PGE...\n");
0450 #endif
0451     memset((char*)ZERO_PGE, 0, PAGE_SIZE);
0452     strcpy((char*)ZERO_PGE, envval);
0453 
0454 #ifdef INITRD_IMAGE_SIZE
0455 
0456 #ifdef DEBUG_LAST_STEPS
0457     srm_printk("Preparing INITRD info...\n");
0458 #endif
0459     /* Finally, set the INITRD paramenters for the kernel. */
0460     ((long *)(ZERO_PGE+256))[0] = initrd_image_start;
0461     ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
0462 
0463 #endif /* INITRD_IMAGE_SIZE */
0464 
0465 #ifdef DEBUG_LAST_STEPS
0466     srm_printk("Doing 'runkernel()'...\n");
0467 #endif
0468     runkernel();
0469 }
0470 
0471  /* dummy function, should never be called. */
0472 void *__kmalloc(size_t size, gfp_t flags)
0473 {
0474     return (void *)NULL;
0475 }