|
@@ -242,3 +242,172 @@ extern char _end;
|
|
#define K_KERNEL_IMAGE_END (START_ADDR + KERNEL_SIZE)
|
|
#define K_KERNEL_IMAGE_END (START_ADDR + KERNEL_SIZE)
|
|
|
|
|
|
/* Define to where we may have to decompress the kernel image, before
|
|
/* Define to where we may have to decompress the kernel image, before
|
|
|
|
+ we move it to the final position, in case of overlap. This will be
|
|
|
|
+ above the final position of the kernel.
|
|
|
|
+
|
|
|
|
+ Regardless of overlap, we move the INITRD image to the end of this
|
|
|
|
+ copy area, because there needs to be a buffer area after the kernel
|
|
|
|
+ for "bootmem" anyway.
|
|
|
|
+*/
|
|
|
|
+#define K_COPY_IMAGE_START NEXT_PAGE(K_KERNEL_IMAGE_END)
|
|
|
|
+/* Reserve one page below INITRD for the new stack. */
|
|
|
|
+#define K_INITRD_START \
|
|
|
|
+ NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE)
|
|
|
|
+#define K_COPY_IMAGE_END \
|
|
|
|
+ (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE)
|
|
|
|
+#define K_COPY_IMAGE_SIZE \
|
|
|
|
+ NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START)
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+start_kernel(void)
|
|
|
|
+{
|
|
|
|
+ int must_move = 0;
|
|
|
|
+
|
|
|
|
+ /* Initialize these for the decompression-in-place situation,
|
|
|
|
+ which is the smallest amount of work and most likely to
|
|
|
|
+ occur when using the normal START_ADDR of the kernel
|
|
|
|
+ (currently set to 16MB, to clear all console code.
|
|
|
|
+ */
|
|
|
|
+ unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START;
|
|
|
|
+ unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END;
|
|
|
|
+
|
|
|
|
+ unsigned long initrd_image_start = K_INITRD_START;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Note that this crufty stuff with static and envval
|
|
|
|
+ * and envbuf is because:
|
|
|
|
+ *
|
|
|
|
+ * 1. Frequently, the stack is short, and we don't want to overrun;
|
|
|
|
+ * 2. Frequently the stack is where we are going to copy the kernel to;
|
|
|
|
+ * 3. A certain SRM console required the GET_ENV output to stack.
|
|
|
|
+ * ??? A comment in the aboot sources indicates that the GET_ENV
|
|
|
|
+ * destination must be quadword aligned. Might this explain the
|
|
|
|
+ * behaviour, rather than requiring output to the stack, which
|
|
|
|
+ * seems rather far-fetched.
|
|
|
|
+ */
|
|
|
|
+ static long nbytes;
|
|
|
|
+ static char envval[256] __attribute__((aligned(8)));
|
|
|
|
+ register unsigned long asm_sp asm("30");
|
|
|
|
+
|
|
|
|
+ SP_on_entry = asm_sp;
|
|
|
|
+
|
|
|
|
+ srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n");
|
|
|
|
+
|
|
|
|
+ /* Validity check the HWRPB. */
|
|
|
|
+ if (INIT_HWRPB->pagesize != 8192) {
|
|
|
|
+ srm_printk("Expected 8kB pages, got %ldkB\n",
|
|
|
|
+ INIT_HWRPB->pagesize >> 10);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
|
|
|
|
+ srm_printk("Expected vptb at %p, got %p\n",
|
|
|
|
+ VPTB, (void *)INIT_HWRPB->vptb);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* PALcode (re)initialization. */
|
|
|
|
+ pal_init();
|
|
|
|
+
|
|
|
|
+ /* Get the parameter list from the console environment variable. */
|
|
|
|
+ nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
|
|
|
|
+ if (nbytes < 0 || nbytes >= sizeof(envval)) {
|
|
|
|
+ nbytes = 0;
|
|
|
|
+ }
|
|
|
|
+ envval[nbytes] = '\0';
|
|
|
|
+
|
|
|
|
+#ifdef DEBUG_ADDRESSES
|
|
|
|
+ srm_printk("START_ADDR 0x%lx\n", START_ADDR);
|
|
|
|
+ srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN);
|
|
|
|
+ srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE);
|
|
|
|
+ srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ /* Since all the SRM consoles load the BOOTP image at virtual
|
|
|
|
+ * 0x20000000, we have to ensure that the physical memory
|
|
|
|
+ * pages occupied by that image do NOT overlap the physical
|
|
|
|
+ * address range where the kernel wants to be run. This
|
|
|
|
+ * causes real problems when attempting to cdecompress the
|
|
|
|
+ * former into the latter... :-(
|
|
|
|
+ *
|
|
|
|
+ * So, we may have to decompress/move the kernel/INITRD image
|
|
|
|
+ * virtual-to-physical someplace else first before moving
|
|
|
|
+ * kernel /INITRD to their final resting places... ;-}
|
|
|
|
+ *
|
|
|
|
+ * Sigh...
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ /* First, check to see if the range of addresses occupied by
|
|
|
|
+ the bootstrapper part of the BOOTP image include any of the
|
|
|
|
+ physical pages into which the kernel will be placed for
|
|
|
|
+ execution.
|
|
|
|
+
|
|
|
|
+ We only need check on the final kernel image range, since we
|
|
|
|
+ will put the INITRD someplace that we can be sure is not
|
|
|
|
+ in conflict.
|
|
|
|
+ */
|
|
|
|
+ if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END,
|
|
|
|
+ K_KERNEL_DATA_START, K_KERNEL_IMAGE_END))
|
|
|
|
+ {
|
|
|
|
+ srm_printk("FATAL ERROR: overlap of bootstrapper code\n");
|
|
|
|
+ __halt();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Next, check to see if the range of addresses occupied by
|
|
|
|
+ the compressed kernel/INITRD/stack portion of the BOOTP
|
|
|
|
+ image include any of the physical pages into which the
|
|
|
|
+ decompressed kernel or the INITRD will be placed for
|
|
|
|
+ execution.
|
|
|
|
+ */
|
|
|
|
+ if (check_range(V_DATA_START, V_DATA_END,
|
|
|
|
+ K_KERNEL_IMAGE_START, K_COPY_IMAGE_END))
|
|
|
|
+ {
|
|
|
|
+#ifdef DEBUG_ADDRESSES
|
|
|
|
+ srm_printk("OVERLAP: cannot decompress in place\n");
|
|
|
|
+#endif
|
|
|
|
+ uncompressed_image_start = K_COPY_IMAGE_START;
|
|
|
|
+ uncompressed_image_end = K_COPY_IMAGE_END;
|
|
|
|
+ must_move = 1;
|
|
|
|
+
|
|
|
|
+ /* Finally, check to see if the range of addresses
|
|
|
|
+ occupied by the compressed kernel/INITRD part of
|
|
|
|
+ the BOOTP image include any of the physical pages
|
|
|
|
+ into which that part is to be copied for
|
|
|
|
+ decompression.
|
|
|
|
+ */
|
|
|
|
+ while (check_range(V_DATA_START, V_DATA_END,
|
|
|
|
+ uncompressed_image_start,
|
|
|
|
+ uncompressed_image_end))
|
|
|
|
+ {
|
|
|
|
+#if 0
|
|
|
|
+ uncompressed_image_start += K_COPY_IMAGE_SIZE;
|
|
|
|
+ uncompressed_image_end += K_COPY_IMAGE_SIZE;
|
|
|
|
+ initrd_image_start += K_COPY_IMAGE_SIZE;
|
|
|
|
+#else
|
|
|
|
+ /* Keep as close as possible to end of BOOTP image. */
|
|
|
|
+ uncompressed_image_start += PAGE_SIZE;
|
|
|
|
+ uncompressed_image_end += PAGE_SIZE;
|
|
|
|
+ initrd_image_start += PAGE_SIZE;
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ srm_printk("Starting to load the kernel with args '%s'\n", envval);
|
|
|
|
+
|
|
|
|
+#ifdef DEBUG_ADDRESSES
|
|
|
|
+ srm_printk("Decompressing the kernel...\n"
|
|
|
|
+ "...from 0x%lx to 0x%lx size 0x%x\n",
|
|
|
|
+ V_DATA_START,
|
|
|
|
+ uncompressed_image_start,
|
|
|
|
+ KERNEL_SIZE);
|
|
|
|
+#endif
|
|
|
|
+ decompress_kernel((void *)uncompressed_image_start,
|
|
|
|
+ (void *)V_DATA_START,
|
|
|
|
+ KERNEL_SIZE, KERNEL_Z_SIZE);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Now, move things to their final positions, if/as required.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#ifdef INITRD_IMAGE_SIZE
|
|
|
|
+
|
|
|
|
+ /* First, we always move the INITRD image, if present. */
|