xref: /kernel/linux/linux-6.6/arch/alpha/boot/bootpz.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/alpha/boot/bootpz.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1997 Jay Estabrook
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file is used for creating a compressed BOOTP file for the
862306a36Sopenharmony_ci * Linux/AXP kernel
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
1162306a36Sopenharmony_ci * and the decompression code from MILO.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <generated/utsrelease.h>
1762306a36Sopenharmony_ci#include <linux/mm.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/console.h>
2062306a36Sopenharmony_ci#include <asm/hwrpb.h>
2162306a36Sopenharmony_ci#include <asm/io.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/stdarg.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "kzsize.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* FIXME FIXME FIXME */
2862306a36Sopenharmony_ci#define MALLOC_AREA_SIZE 0x200000 /* 2MB for now */
2962306a36Sopenharmony_ci/* FIXME FIXME FIXME */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci  WARNING NOTE
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci  It is very possible that turning on additional messages may cause
3662306a36Sopenharmony_ci  kernel image corruption due to stack usage to do the printing.
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci*/
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#undef DEBUG_CHECK_RANGE
4162306a36Sopenharmony_ci#undef DEBUG_ADDRESSES
4262306a36Sopenharmony_ci#undef DEBUG_LAST_STEPS
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciextern unsigned long switch_to_osf_pal(unsigned long nr,
4562306a36Sopenharmony_ci	struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
4662306a36Sopenharmony_ci	unsigned long *vptb);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciextern int decompress_kernel(void* destination, void *source,
4962306a36Sopenharmony_ci			     size_t ksize, size_t kzsize);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciextern void move_stack(unsigned long new_stack);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct hwrpb_struct *hwrpb = INIT_HWRPB;
5462306a36Sopenharmony_cistatic struct pcb_struct pcb_va[1];
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * Find a physical address of a virtual object..
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * This is easy using the virtual page table address.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ci#define VPTB	((unsigned long *) 0x200000000)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic inline unsigned long
6462306a36Sopenharmony_cifind_pa(unsigned long address)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	unsigned long result;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	result = VPTB[address >> 13];
6962306a36Sopenharmony_ci	result >>= 32;
7062306a36Sopenharmony_ci	result <<= 13;
7162306a36Sopenharmony_ci	result |= address & 0x1fff;
7262306a36Sopenharmony_ci	return result;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint
7662306a36Sopenharmony_cicheck_range(unsigned long vstart, unsigned long vend,
7762306a36Sopenharmony_ci	    unsigned long kstart, unsigned long kend)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	unsigned long vaddr, kaddr;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifdef DEBUG_CHECK_RANGE
8262306a36Sopenharmony_ci	srm_printk("check_range: V[0x%lx:0x%lx] K[0x%lx:0x%lx]\n",
8362306a36Sopenharmony_ci		   vstart, vend, kstart, kend);
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci	/* do some range checking for detecting an overlap... */
8662306a36Sopenharmony_ci	for (vaddr = vstart; vaddr <= vend; vaddr += PAGE_SIZE)
8762306a36Sopenharmony_ci	{
8862306a36Sopenharmony_ci		kaddr = (find_pa(vaddr) | PAGE_OFFSET);
8962306a36Sopenharmony_ci		if (kaddr >= kstart && kaddr <= kend)
9062306a36Sopenharmony_ci		{
9162306a36Sopenharmony_ci#ifdef DEBUG_CHECK_RANGE
9262306a36Sopenharmony_ci			srm_printk("OVERLAP: vaddr 0x%lx kaddr 0x%lx"
9362306a36Sopenharmony_ci				   " [0x%lx:0x%lx]\n",
9462306a36Sopenharmony_ci				   vaddr, kaddr, kstart, kend);
9562306a36Sopenharmony_ci#endif
9662306a36Sopenharmony_ci			return 1;
9762306a36Sopenharmony_ci		}
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	return 0;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/*
10362306a36Sopenharmony_ci * This function moves into OSF/1 pal-code, and has a temporary
10462306a36Sopenharmony_ci * PCB for that. The kernel proper should replace this PCB with
10562306a36Sopenharmony_ci * the real one as soon as possible.
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * The page table muckery in here depends on the fact that the boot
10862306a36Sopenharmony_ci * code has the L1 page table identity-map itself in the second PTE
10962306a36Sopenharmony_ci * in the L1 page table. Thus the L1-page is virtually addressable
11062306a36Sopenharmony_ci * itself (through three levels) at virtual address 0x200802000.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define L1	((unsigned long *) 0x200802000)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civoid
11662306a36Sopenharmony_cipal_init(void)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	unsigned long i, rev;
11962306a36Sopenharmony_ci	struct percpu_struct * percpu;
12062306a36Sopenharmony_ci	struct pcb_struct * pcb_pa;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Create the dummy PCB.  */
12362306a36Sopenharmony_ci	pcb_va->ksp = 0;
12462306a36Sopenharmony_ci	pcb_va->usp = 0;
12562306a36Sopenharmony_ci	pcb_va->ptbr = L1[1] >> 32;
12662306a36Sopenharmony_ci	pcb_va->asn = 0;
12762306a36Sopenharmony_ci	pcb_va->pcc = 0;
12862306a36Sopenharmony_ci	pcb_va->unique = 0;
12962306a36Sopenharmony_ci	pcb_va->flags = 1;
13062306a36Sopenharmony_ci	pcb_va->res1 = 0;
13162306a36Sopenharmony_ci	pcb_va->res2 = 0;
13262306a36Sopenharmony_ci	pcb_pa = (struct pcb_struct *)find_pa((unsigned long)pcb_va);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/*
13562306a36Sopenharmony_ci	 * a0 = 2 (OSF)
13662306a36Sopenharmony_ci	 * a1 = return address, but we give the asm the vaddr of the PCB
13762306a36Sopenharmony_ci	 * a2 = physical addr of PCB
13862306a36Sopenharmony_ci	 * a3 = new virtual page table pointer
13962306a36Sopenharmony_ci	 * a4 = KSP (but the asm sets it)
14062306a36Sopenharmony_ci	 */
14162306a36Sopenharmony_ci	srm_printk("Switching to OSF PAL-code... ");
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
14462306a36Sopenharmony_ci	if (i) {
14562306a36Sopenharmony_ci		srm_printk("failed, code %ld\n", i);
14662306a36Sopenharmony_ci		__halt();
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	percpu = (struct percpu_struct *)
15062306a36Sopenharmony_ci		(INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
15162306a36Sopenharmony_ci	rev = percpu->pal_revision = percpu->palcode_avail[2];
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	srm_printk("OK (rev %lx)\n", rev);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	tbia(); /* do it directly in case we are SMP */
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * Start the kernel.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic inline void
16262306a36Sopenharmony_cirunkernel(void)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	__asm__ __volatile__(
16562306a36Sopenharmony_ci		"bis %0,%0,$27\n\t"
16662306a36Sopenharmony_ci		"jmp ($27)"
16762306a36Sopenharmony_ci		: /* no outputs: it doesn't even return */
16862306a36Sopenharmony_ci		: "r" (START_ADDR));
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/* Must record the SP (it is virtual) on entry, so we can make sure
17262306a36Sopenharmony_ci   not to overwrite it during movement or decompression. */
17362306a36Sopenharmony_ciunsigned long SP_on_entry;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/* Calculate the kernel image address based on the end of the BOOTP
17662306a36Sopenharmony_ci   bootstrapper (ie this program).
17762306a36Sopenharmony_ci*/
17862306a36Sopenharmony_ciextern char _end;
17962306a36Sopenharmony_ci#define KERNEL_ORIGIN \
18062306a36Sopenharmony_ci	((((unsigned long)&_end) + 511) & ~511)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* Round address to next higher page boundary. */
18362306a36Sopenharmony_ci#define NEXT_PAGE(a)	(((a) | (PAGE_SIZE - 1)) + 1)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE
18662306a36Sopenharmony_ci# define REAL_INITRD_SIZE INITRD_IMAGE_SIZE
18762306a36Sopenharmony_ci#else
18862306a36Sopenharmony_ci# define REAL_INITRD_SIZE 0
18962306a36Sopenharmony_ci#endif
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* Defines from include/asm-alpha/system.h
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	BOOT_ADDR	Virtual address at which the consoles loads
19462306a36Sopenharmony_ci			the BOOTP image.
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	KERNEL_START    KSEG address at which the kernel is built to run,
19762306a36Sopenharmony_ci			which includes some initial data pages before the
19862306a36Sopenharmony_ci			code.
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	START_ADDR	KSEG address of the entry point of kernel code.
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ZERO_PGE	KSEG address of page full of zeroes, but
20362306a36Sopenharmony_ci			upon entry to kernel, it can be expected
20462306a36Sopenharmony_ci			to hold the parameter list and possible
20562306a36Sopenharmony_ci			INTRD information.
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci   These are used in the local defines below.
20862306a36Sopenharmony_ci*/
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/* Virtual addresses for the BOOTP image. Note that this includes the
21262306a36Sopenharmony_ci   bootstrapper code as well as the compressed kernel image, and
21362306a36Sopenharmony_ci   possibly the INITRD image.
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci   Oh, and do NOT forget the STACK, which appears to be placed virtually
21662306a36Sopenharmony_ci   beyond the end of the loaded image.
21762306a36Sopenharmony_ci*/
21862306a36Sopenharmony_ci#define V_BOOT_IMAGE_START	BOOT_ADDR
21962306a36Sopenharmony_ci#define V_BOOT_IMAGE_END	SP_on_entry
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/* Virtual addresses for just the bootstrapper part of the BOOTP image. */
22262306a36Sopenharmony_ci#define V_BOOTSTRAPPER_START	BOOT_ADDR
22362306a36Sopenharmony_ci#define V_BOOTSTRAPPER_END	KERNEL_ORIGIN
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Virtual addresses for just the data part of the BOOTP
22662306a36Sopenharmony_ci   image. This may also include the INITRD image, but always
22762306a36Sopenharmony_ci   includes the STACK.
22862306a36Sopenharmony_ci*/
22962306a36Sopenharmony_ci#define V_DATA_START		KERNEL_ORIGIN
23062306a36Sopenharmony_ci#define V_INITRD_START		(KERNEL_ORIGIN + KERNEL_Z_SIZE)
23162306a36Sopenharmony_ci#define V_INTRD_END		(V_INITRD_START + REAL_INITRD_SIZE)
23262306a36Sopenharmony_ci#define V_DATA_END	 	V_BOOT_IMAGE_END
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/* KSEG addresses for the uncompressed kernel.
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci   Note that the end address includes workspace for the decompression.
23762306a36Sopenharmony_ci   Note also that the DATA_START address is ZERO_PGE, to which we write
23862306a36Sopenharmony_ci   just before jumping to the kernel image at START_ADDR.
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_ci#define K_KERNEL_DATA_START	ZERO_PGE
24162306a36Sopenharmony_ci#define K_KERNEL_IMAGE_START	START_ADDR
24262306a36Sopenharmony_ci#define K_KERNEL_IMAGE_END	(START_ADDR + KERNEL_SIZE)
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/* Define to where we may have to decompress the kernel image, before
24562306a36Sopenharmony_ci   we move it to the final position, in case of overlap. This will be
24662306a36Sopenharmony_ci   above the final position of the kernel.
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci   Regardless of overlap, we move the INITRD image to the end of this
24962306a36Sopenharmony_ci   copy area, because there needs to be a buffer area after the kernel
25062306a36Sopenharmony_ci   for "bootmem" anyway.
25162306a36Sopenharmony_ci*/
25262306a36Sopenharmony_ci#define K_COPY_IMAGE_START	NEXT_PAGE(K_KERNEL_IMAGE_END)
25362306a36Sopenharmony_ci/* Reserve one page below INITRD for the new stack. */
25462306a36Sopenharmony_ci#define K_INITRD_START \
25562306a36Sopenharmony_ci    NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE)
25662306a36Sopenharmony_ci#define K_COPY_IMAGE_END \
25762306a36Sopenharmony_ci    (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE)
25862306a36Sopenharmony_ci#define K_COPY_IMAGE_SIZE \
25962306a36Sopenharmony_ci    NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START)
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_civoid
26262306a36Sopenharmony_cistart_kernel(void)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	int must_move = 0;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* Initialize these for the decompression-in-place situation,
26762306a36Sopenharmony_ci	   which is the smallest amount of work and most likely to
26862306a36Sopenharmony_ci	   occur when using the normal START_ADDR of the kernel
26962306a36Sopenharmony_ci	   (currently set to 16MB, to clear all console code.
27062306a36Sopenharmony_ci	*/
27162306a36Sopenharmony_ci	unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START;
27262306a36Sopenharmony_ci	unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	unsigned long initrd_image_start = K_INITRD_START;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/*
27762306a36Sopenharmony_ci	 * Note that this crufty stuff with static and envval
27862306a36Sopenharmony_ci	 * and envbuf is because:
27962306a36Sopenharmony_ci	 *
28062306a36Sopenharmony_ci	 * 1. Frequently, the stack is short, and we don't want to overrun;
28162306a36Sopenharmony_ci	 * 2. Frequently the stack is where we are going to copy the kernel to;
28262306a36Sopenharmony_ci	 * 3. A certain SRM console required the GET_ENV output to stack.
28362306a36Sopenharmony_ci	 *    ??? A comment in the aboot sources indicates that the GET_ENV
28462306a36Sopenharmony_ci	 *    destination must be quadword aligned.  Might this explain the
28562306a36Sopenharmony_ci	 *    behaviour, rather than requiring output to the stack, which
28662306a36Sopenharmony_ci	 *    seems rather far-fetched.
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	static long nbytes;
28962306a36Sopenharmony_ci	static char envval[256] __attribute__((aligned(8)));
29062306a36Sopenharmony_ci	register unsigned long asm_sp asm("30");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	SP_on_entry = asm_sp;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n");
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* Validity check the HWRPB. */
29762306a36Sopenharmony_ci	if (INIT_HWRPB->pagesize != 8192) {
29862306a36Sopenharmony_ci		srm_printk("Expected 8kB pages, got %ldkB\n",
29962306a36Sopenharmony_ci		           INIT_HWRPB->pagesize >> 10);
30062306a36Sopenharmony_ci		return;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci	if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
30362306a36Sopenharmony_ci		srm_printk("Expected vptb at %p, got %p\n",
30462306a36Sopenharmony_ci			   VPTB, (void *)INIT_HWRPB->vptb);
30562306a36Sopenharmony_ci		return;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* PALcode (re)initialization. */
30962306a36Sopenharmony_ci	pal_init();
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Get the parameter list from the console environment variable. */
31262306a36Sopenharmony_ci	nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
31362306a36Sopenharmony_ci	if (nbytes < 0 || nbytes >= sizeof(envval)) {
31462306a36Sopenharmony_ci		nbytes = 0;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	envval[nbytes] = '\0';
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci#ifdef DEBUG_ADDRESSES
31962306a36Sopenharmony_ci	srm_printk("START_ADDR 0x%lx\n", START_ADDR);
32062306a36Sopenharmony_ci	srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN);
32162306a36Sopenharmony_ci	srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE);
32262306a36Sopenharmony_ci	srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE);
32362306a36Sopenharmony_ci#endif
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Since all the SRM consoles load the BOOTP image at virtual
32662306a36Sopenharmony_ci	 * 0x20000000, we have to ensure that the physical memory
32762306a36Sopenharmony_ci	 * pages occupied by that image do NOT overlap the physical
32862306a36Sopenharmony_ci	 * address range where the kernel wants to be run.  This
32962306a36Sopenharmony_ci	 * causes real problems when attempting to cdecompress the
33062306a36Sopenharmony_ci	 * former into the latter... :-(
33162306a36Sopenharmony_ci	 *
33262306a36Sopenharmony_ci	 * So, we may have to decompress/move the kernel/INITRD image
33362306a36Sopenharmony_ci	 * virtual-to-physical someplace else first before moving
33462306a36Sopenharmony_ci	 * kernel /INITRD to their final resting places... ;-}
33562306a36Sopenharmony_ci	 *
33662306a36Sopenharmony_ci	 * Sigh...
33762306a36Sopenharmony_ci	 */
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* First, check to see if the range of addresses occupied by
34062306a36Sopenharmony_ci	   the bootstrapper part of the BOOTP image include any of the
34162306a36Sopenharmony_ci	   physical pages into which the kernel will be placed for
34262306a36Sopenharmony_ci	   execution.
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	   We only need check on the final kernel image range, since we
34562306a36Sopenharmony_ci	   will put the INITRD someplace that we can be sure is not
34662306a36Sopenharmony_ci	   in conflict.
34762306a36Sopenharmony_ci	 */
34862306a36Sopenharmony_ci	if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END,
34962306a36Sopenharmony_ci			K_KERNEL_DATA_START, K_KERNEL_IMAGE_END))
35062306a36Sopenharmony_ci	{
35162306a36Sopenharmony_ci		srm_printk("FATAL ERROR: overlap of bootstrapper code\n");
35262306a36Sopenharmony_ci		__halt();
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Next, check to see if the range of addresses occupied by
35662306a36Sopenharmony_ci	   the compressed kernel/INITRD/stack portion of the BOOTP
35762306a36Sopenharmony_ci	   image include any of the physical pages into which the
35862306a36Sopenharmony_ci	   decompressed kernel or the INITRD will be placed for
35962306a36Sopenharmony_ci	   execution.
36062306a36Sopenharmony_ci	 */
36162306a36Sopenharmony_ci	if (check_range(V_DATA_START, V_DATA_END,
36262306a36Sopenharmony_ci			K_KERNEL_IMAGE_START, K_COPY_IMAGE_END))
36362306a36Sopenharmony_ci	{
36462306a36Sopenharmony_ci#ifdef DEBUG_ADDRESSES
36562306a36Sopenharmony_ci		srm_printk("OVERLAP: cannot decompress in place\n");
36662306a36Sopenharmony_ci#endif
36762306a36Sopenharmony_ci		uncompressed_image_start = K_COPY_IMAGE_START;
36862306a36Sopenharmony_ci		uncompressed_image_end = K_COPY_IMAGE_END;
36962306a36Sopenharmony_ci		must_move = 1;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		/* Finally, check to see if the range of addresses
37262306a36Sopenharmony_ci		   occupied by the compressed kernel/INITRD part of
37362306a36Sopenharmony_ci		   the BOOTP image include any of the physical pages
37462306a36Sopenharmony_ci		   into which that part is to be copied for
37562306a36Sopenharmony_ci		   decompression.
37662306a36Sopenharmony_ci		*/
37762306a36Sopenharmony_ci		while (check_range(V_DATA_START, V_DATA_END,
37862306a36Sopenharmony_ci				   uncompressed_image_start,
37962306a36Sopenharmony_ci				   uncompressed_image_end))
38062306a36Sopenharmony_ci		{
38162306a36Sopenharmony_ci#if 0
38262306a36Sopenharmony_ci			uncompressed_image_start += K_COPY_IMAGE_SIZE;
38362306a36Sopenharmony_ci			uncompressed_image_end += K_COPY_IMAGE_SIZE;
38462306a36Sopenharmony_ci			initrd_image_start += K_COPY_IMAGE_SIZE;
38562306a36Sopenharmony_ci#else
38662306a36Sopenharmony_ci			/* Keep as close as possible to end of BOOTP image. */
38762306a36Sopenharmony_ci			uncompressed_image_start += PAGE_SIZE;
38862306a36Sopenharmony_ci			uncompressed_image_end += PAGE_SIZE;
38962306a36Sopenharmony_ci			initrd_image_start += PAGE_SIZE;
39062306a36Sopenharmony_ci#endif
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	srm_printk("Starting to load the kernel with args '%s'\n", envval);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci#ifdef DEBUG_ADDRESSES
39762306a36Sopenharmony_ci	srm_printk("Decompressing the kernel...\n"
39862306a36Sopenharmony_ci		   "...from 0x%lx to 0x%lx size 0x%x\n",
39962306a36Sopenharmony_ci		   V_DATA_START,
40062306a36Sopenharmony_ci		   uncompressed_image_start,
40162306a36Sopenharmony_ci		   KERNEL_SIZE);
40262306a36Sopenharmony_ci#endif
40362306a36Sopenharmony_ci        decompress_kernel((void *)uncompressed_image_start,
40462306a36Sopenharmony_ci			  (void *)V_DATA_START,
40562306a36Sopenharmony_ci			  KERNEL_SIZE, KERNEL_Z_SIZE);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/*
40862306a36Sopenharmony_ci	 * Now, move things to their final positions, if/as required.
40962306a36Sopenharmony_ci	 */
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* First, we always move the INITRD image, if present. */
41462306a36Sopenharmony_ci#ifdef DEBUG_ADDRESSES
41562306a36Sopenharmony_ci	srm_printk("Moving the INITRD image...\n"
41662306a36Sopenharmony_ci		   " from 0x%lx to 0x%lx size 0x%x\n",
41762306a36Sopenharmony_ci		   V_INITRD_START,
41862306a36Sopenharmony_ci		   initrd_image_start,
41962306a36Sopenharmony_ci		   INITRD_IMAGE_SIZE);
42062306a36Sopenharmony_ci#endif
42162306a36Sopenharmony_ci	memcpy((void *)initrd_image_start, (void *)V_INITRD_START,
42262306a36Sopenharmony_ci	       INITRD_IMAGE_SIZE);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci#endif /* INITRD_IMAGE_SIZE */
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Next, we may have to move the uncompressed kernel to the
42762306a36Sopenharmony_ci	   final destination.
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci	if (must_move) {
43062306a36Sopenharmony_ci#ifdef DEBUG_ADDRESSES
43162306a36Sopenharmony_ci		srm_printk("Moving the uncompressed kernel...\n"
43262306a36Sopenharmony_ci			   "...from 0x%lx to 0x%lx size 0x%x\n",
43362306a36Sopenharmony_ci			   uncompressed_image_start,
43462306a36Sopenharmony_ci			   K_KERNEL_IMAGE_START,
43562306a36Sopenharmony_ci			   (unsigned)KERNEL_SIZE);
43662306a36Sopenharmony_ci#endif
43762306a36Sopenharmony_ci		/*
43862306a36Sopenharmony_ci		 * Move the stack to a safe place to ensure it won't be
43962306a36Sopenharmony_ci		 * overwritten by kernel image.
44062306a36Sopenharmony_ci		 */
44162306a36Sopenharmony_ci		move_stack(initrd_image_start - PAGE_SIZE);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		memcpy((void *)K_KERNEL_IMAGE_START,
44462306a36Sopenharmony_ci		       (void *)uncompressed_image_start, KERNEL_SIZE);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* Clear the zero page, then move the argument list in. */
44862306a36Sopenharmony_ci#ifdef DEBUG_LAST_STEPS
44962306a36Sopenharmony_ci	srm_printk("Preparing ZERO_PGE...\n");
45062306a36Sopenharmony_ci#endif
45162306a36Sopenharmony_ci	memset((char*)ZERO_PGE, 0, PAGE_SIZE);
45262306a36Sopenharmony_ci	strcpy((char*)ZERO_PGE, envval);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci#ifdef DEBUG_LAST_STEPS
45762306a36Sopenharmony_ci	srm_printk("Preparing INITRD info...\n");
45862306a36Sopenharmony_ci#endif
45962306a36Sopenharmony_ci	/* Finally, set the INITRD paramenters for the kernel. */
46062306a36Sopenharmony_ci	((long *)(ZERO_PGE+256))[0] = initrd_image_start;
46162306a36Sopenharmony_ci	((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci#endif /* INITRD_IMAGE_SIZE */
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci#ifdef DEBUG_LAST_STEPS
46662306a36Sopenharmony_ci	srm_printk("Doing 'runkernel()'...\n");
46762306a36Sopenharmony_ci#endif
46862306a36Sopenharmony_ci	runkernel();
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci /* dummy function, should never be called. */
47262306a36Sopenharmony_civoid *__kmalloc(size_t size, gfp_t flags)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	return (void *)NULL;
47562306a36Sopenharmony_ci}
476