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