18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/alpha/boot/bootpz.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1997 Jay Estabrook 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is used for creating a compressed BOOTP file for the 88c2ecf20Sopenharmony_ci * Linux/AXP kernel 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * based significantly on the arch/alpha/boot/main.c of Linus Torvalds 118c2ecf20Sopenharmony_ci * and the decompression code from MILO. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 178c2ecf20Sopenharmony_ci#include <linux/mm.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/console.h> 208c2ecf20Sopenharmony_ci#include <asm/hwrpb.h> 218c2ecf20Sopenharmony_ci#include <asm/io.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <stdarg.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "kzsize.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* FIXME FIXME FIXME */ 288c2ecf20Sopenharmony_ci#define MALLOC_AREA_SIZE 0x200000 /* 2MB for now */ 298c2ecf20Sopenharmony_ci/* FIXME FIXME FIXME */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci WARNING NOTE 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci It is very possible that turning on additional messages may cause 368c2ecf20Sopenharmony_ci kernel image corruption due to stack usage to do the printing. 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci*/ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#undef DEBUG_CHECK_RANGE 418c2ecf20Sopenharmony_ci#undef DEBUG_ADDRESSES 428c2ecf20Sopenharmony_ci#undef DEBUG_LAST_STEPS 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciextern unsigned long switch_to_osf_pal(unsigned long nr, 458c2ecf20Sopenharmony_ci struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, 468c2ecf20Sopenharmony_ci unsigned long *vptb); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciextern int decompress_kernel(void* destination, void *source, 498c2ecf20Sopenharmony_ci size_t ksize, size_t kzsize); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciextern void move_stack(unsigned long new_stack); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct hwrpb_struct *hwrpb = INIT_HWRPB; 548c2ecf20Sopenharmony_cistatic struct pcb_struct pcb_va[1]; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * Find a physical address of a virtual object.. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * This is easy using the virtual page table address. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci#define VPTB ((unsigned long *) 0x200000000) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline unsigned long 648c2ecf20Sopenharmony_cifind_pa(unsigned long address) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci unsigned long result; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci result = VPTB[address >> 13]; 698c2ecf20Sopenharmony_ci result >>= 32; 708c2ecf20Sopenharmony_ci result <<= 13; 718c2ecf20Sopenharmony_ci result |= address & 0x1fff; 728c2ecf20Sopenharmony_ci return result; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint 768c2ecf20Sopenharmony_cicheck_range(unsigned long vstart, unsigned long vend, 778c2ecf20Sopenharmony_ci unsigned long kstart, unsigned long kend) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned long vaddr, kaddr; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#ifdef DEBUG_CHECK_RANGE 828c2ecf20Sopenharmony_ci srm_printk("check_range: V[0x%lx:0x%lx] K[0x%lx:0x%lx]\n", 838c2ecf20Sopenharmony_ci vstart, vend, kstart, kend); 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci /* do some range checking for detecting an overlap... */ 868c2ecf20Sopenharmony_ci for (vaddr = vstart; vaddr <= vend; vaddr += PAGE_SIZE) 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci kaddr = (find_pa(vaddr) | PAGE_OFFSET); 898c2ecf20Sopenharmony_ci if (kaddr >= kstart && kaddr <= kend) 908c2ecf20Sopenharmony_ci { 918c2ecf20Sopenharmony_ci#ifdef DEBUG_CHECK_RANGE 928c2ecf20Sopenharmony_ci srm_printk("OVERLAP: vaddr 0x%lx kaddr 0x%lx" 938c2ecf20Sopenharmony_ci " [0x%lx:0x%lx]\n", 948c2ecf20Sopenharmony_ci vaddr, kaddr, kstart, kend); 958c2ecf20Sopenharmony_ci#endif 968c2ecf20Sopenharmony_ci return 1; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * This function moves into OSF/1 pal-code, and has a temporary 1048c2ecf20Sopenharmony_ci * PCB for that. The kernel proper should replace this PCB with 1058c2ecf20Sopenharmony_ci * the real one as soon as possible. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * The page table muckery in here depends on the fact that the boot 1088c2ecf20Sopenharmony_ci * code has the L1 page table identity-map itself in the second PTE 1098c2ecf20Sopenharmony_ci * in the L1 page table. Thus the L1-page is virtually addressable 1108c2ecf20Sopenharmony_ci * itself (through three levels) at virtual address 0x200802000. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define L1 ((unsigned long *) 0x200802000) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid 1168c2ecf20Sopenharmony_cipal_init(void) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci unsigned long i, rev; 1198c2ecf20Sopenharmony_ci struct percpu_struct * percpu; 1208c2ecf20Sopenharmony_ci struct pcb_struct * pcb_pa; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Create the dummy PCB. */ 1238c2ecf20Sopenharmony_ci pcb_va->ksp = 0; 1248c2ecf20Sopenharmony_ci pcb_va->usp = 0; 1258c2ecf20Sopenharmony_ci pcb_va->ptbr = L1[1] >> 32; 1268c2ecf20Sopenharmony_ci pcb_va->asn = 0; 1278c2ecf20Sopenharmony_ci pcb_va->pcc = 0; 1288c2ecf20Sopenharmony_ci pcb_va->unique = 0; 1298c2ecf20Sopenharmony_ci pcb_va->flags = 1; 1308c2ecf20Sopenharmony_ci pcb_va->res1 = 0; 1318c2ecf20Sopenharmony_ci pcb_va->res2 = 0; 1328c2ecf20Sopenharmony_ci pcb_pa = (struct pcb_struct *)find_pa((unsigned long)pcb_va); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * a0 = 2 (OSF) 1368c2ecf20Sopenharmony_ci * a1 = return address, but we give the asm the vaddr of the PCB 1378c2ecf20Sopenharmony_ci * a2 = physical addr of PCB 1388c2ecf20Sopenharmony_ci * a3 = new virtual page table pointer 1398c2ecf20Sopenharmony_ci * a4 = KSP (but the asm sets it) 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci srm_printk("Switching to OSF PAL-code... "); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); 1448c2ecf20Sopenharmony_ci if (i) { 1458c2ecf20Sopenharmony_ci srm_printk("failed, code %ld\n", i); 1468c2ecf20Sopenharmony_ci __halt(); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci percpu = (struct percpu_struct *) 1508c2ecf20Sopenharmony_ci (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB); 1518c2ecf20Sopenharmony_ci rev = percpu->pal_revision = percpu->palcode_avail[2]; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci srm_printk("OK (rev %lx)\n", rev); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci tbia(); /* do it directly in case we are SMP */ 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* 1598c2ecf20Sopenharmony_ci * Start the kernel. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistatic inline void 1628c2ecf20Sopenharmony_cirunkernel(void) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci __asm__ __volatile__( 1658c2ecf20Sopenharmony_ci "bis %0,%0,$27\n\t" 1668c2ecf20Sopenharmony_ci "jmp ($27)" 1678c2ecf20Sopenharmony_ci : /* no outputs: it doesn't even return */ 1688c2ecf20Sopenharmony_ci : "r" (START_ADDR)); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Must record the SP (it is virtual) on entry, so we can make sure 1728c2ecf20Sopenharmony_ci not to overwrite it during movement or decompression. */ 1738c2ecf20Sopenharmony_ciunsigned long SP_on_entry; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* Calculate the kernel image address based on the end of the BOOTP 1768c2ecf20Sopenharmony_ci bootstrapper (ie this program). 1778c2ecf20Sopenharmony_ci*/ 1788c2ecf20Sopenharmony_ciextern char _end; 1798c2ecf20Sopenharmony_ci#define KERNEL_ORIGIN \ 1808c2ecf20Sopenharmony_ci ((((unsigned long)&_end) + 511) & ~511) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Round address to next higher page boundary. */ 1838c2ecf20Sopenharmony_ci#define NEXT_PAGE(a) (((a) | (PAGE_SIZE - 1)) + 1) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE 1868c2ecf20Sopenharmony_ci# define REAL_INITRD_SIZE INITRD_IMAGE_SIZE 1878c2ecf20Sopenharmony_ci#else 1888c2ecf20Sopenharmony_ci# define REAL_INITRD_SIZE 0 1898c2ecf20Sopenharmony_ci#endif 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* Defines from include/asm-alpha/system.h 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci BOOT_ADDR Virtual address at which the consoles loads 1948c2ecf20Sopenharmony_ci the BOOTP image. 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci KERNEL_START KSEG address at which the kernel is built to run, 1978c2ecf20Sopenharmony_ci which includes some initial data pages before the 1988c2ecf20Sopenharmony_ci code. 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci START_ADDR KSEG address of the entry point of kernel code. 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ZERO_PGE KSEG address of page full of zeroes, but 2038c2ecf20Sopenharmony_ci upon entry to kerne cvan be expected 2048c2ecf20Sopenharmony_ci to hold the parameter list and possible 2058c2ecf20Sopenharmony_ci INTRD information. 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci These are used in the local defines below. 2088c2ecf20Sopenharmony_ci*/ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* Virtual addresses for the BOOTP image. Note that this includes the 2128c2ecf20Sopenharmony_ci bootstrapper code as well as the compressed kernel image, and 2138c2ecf20Sopenharmony_ci possibly the INITRD image. 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci Oh, and do NOT forget the STACK, which appears to be placed virtually 2168c2ecf20Sopenharmony_ci beyond the end of the loaded image. 2178c2ecf20Sopenharmony_ci*/ 2188c2ecf20Sopenharmony_ci#define V_BOOT_IMAGE_START BOOT_ADDR 2198c2ecf20Sopenharmony_ci#define V_BOOT_IMAGE_END SP_on_entry 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* Virtual addresses for just the bootstrapper part of the BOOTP image. */ 2228c2ecf20Sopenharmony_ci#define V_BOOTSTRAPPER_START BOOT_ADDR 2238c2ecf20Sopenharmony_ci#define V_BOOTSTRAPPER_END KERNEL_ORIGIN 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* Virtual addresses for just the data part of the BOOTP 2268c2ecf20Sopenharmony_ci image. This may also include the INITRD image, but always 2278c2ecf20Sopenharmony_ci includes the STACK. 2288c2ecf20Sopenharmony_ci*/ 2298c2ecf20Sopenharmony_ci#define V_DATA_START KERNEL_ORIGIN 2308c2ecf20Sopenharmony_ci#define V_INITRD_START (KERNEL_ORIGIN + KERNEL_Z_SIZE) 2318c2ecf20Sopenharmony_ci#define V_INTRD_END (V_INITRD_START + REAL_INITRD_SIZE) 2328c2ecf20Sopenharmony_ci#define V_DATA_END V_BOOT_IMAGE_END 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* KSEG addresses for the uncompressed kernel. 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci Note that the end address includes workspace for the decompression. 2378c2ecf20Sopenharmony_ci Note also that the DATA_START address is ZERO_PGE, to which we write 2388c2ecf20Sopenharmony_ci just before jumping to the kernel image at START_ADDR. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci#define K_KERNEL_DATA_START ZERO_PGE 2418c2ecf20Sopenharmony_ci#define K_KERNEL_IMAGE_START START_ADDR 2428c2ecf20Sopenharmony_ci#define K_KERNEL_IMAGE_END (START_ADDR + KERNEL_SIZE) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* Define to where we may have to decompress the kernel image, before 2458c2ecf20Sopenharmony_ci we move it to the final position, in case of overlap. This will be 2468c2ecf20Sopenharmony_ci above the final position of the kernel. 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci Regardless of overlap, we move the INITRD image to the end of this 2498c2ecf20Sopenharmony_ci copy area, because there needs to be a buffer area after the kernel 2508c2ecf20Sopenharmony_ci for "bootmem" anyway. 2518c2ecf20Sopenharmony_ci*/ 2528c2ecf20Sopenharmony_ci#define K_COPY_IMAGE_START NEXT_PAGE(K_KERNEL_IMAGE_END) 2538c2ecf20Sopenharmony_ci/* Reserve one page below INITRD for the new stack. */ 2548c2ecf20Sopenharmony_ci#define K_INITRD_START \ 2558c2ecf20Sopenharmony_ci NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE) 2568c2ecf20Sopenharmony_ci#define K_COPY_IMAGE_END \ 2578c2ecf20Sopenharmony_ci (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE) 2588c2ecf20Sopenharmony_ci#define K_COPY_IMAGE_SIZE \ 2598c2ecf20Sopenharmony_ci NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_civoid 2628c2ecf20Sopenharmony_cistart_kernel(void) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int must_move = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Initialize these for the decompression-in-place situation, 2678c2ecf20Sopenharmony_ci which is the smallest amount of work and most likely to 2688c2ecf20Sopenharmony_ci occur when using the normal START_ADDR of the kernel 2698c2ecf20Sopenharmony_ci (currently set to 16MB, to clear all console code. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START; 2728c2ecf20Sopenharmony_ci unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci unsigned long initrd_image_start = K_INITRD_START; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * Note that this crufty stuff with static and envval 2788c2ecf20Sopenharmony_ci * and envbuf is because: 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * 1. Frequently, the stack is short, and we don't want to overrun; 2818c2ecf20Sopenharmony_ci * 2. Frequently the stack is where we are going to copy the kernel to; 2828c2ecf20Sopenharmony_ci * 3. A certain SRM console required the GET_ENV output to stack. 2838c2ecf20Sopenharmony_ci * ??? A comment in the aboot sources indicates that the GET_ENV 2848c2ecf20Sopenharmony_ci * destination must be quadword aligned. Might this explain the 2858c2ecf20Sopenharmony_ci * behaviour, rather than requiring output to the stack, which 2868c2ecf20Sopenharmony_ci * seems rather far-fetched. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci static long nbytes; 2898c2ecf20Sopenharmony_ci static char envval[256] __attribute__((aligned(8))); 2908c2ecf20Sopenharmony_ci register unsigned long asm_sp asm("30"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci SP_on_entry = asm_sp; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Validity check the HWRPB. */ 2978c2ecf20Sopenharmony_ci if (INIT_HWRPB->pagesize != 8192) { 2988c2ecf20Sopenharmony_ci srm_printk("Expected 8kB pages, got %ldkB\n", 2998c2ecf20Sopenharmony_ci INIT_HWRPB->pagesize >> 10); 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci if (INIT_HWRPB->vptb != (unsigned long) VPTB) { 3038c2ecf20Sopenharmony_ci srm_printk("Expected vptb at %p, got %p\n", 3048c2ecf20Sopenharmony_ci VPTB, (void *)INIT_HWRPB->vptb); 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* PALcode (re)initialization. */ 3098c2ecf20Sopenharmony_ci pal_init(); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Get the parameter list from the console environment variable. */ 3128c2ecf20Sopenharmony_ci nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); 3138c2ecf20Sopenharmony_ci if (nbytes < 0 || nbytes >= sizeof(envval)) { 3148c2ecf20Sopenharmony_ci nbytes = 0; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci envval[nbytes] = '\0'; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#ifdef DEBUG_ADDRESSES 3198c2ecf20Sopenharmony_ci srm_printk("START_ADDR 0x%lx\n", START_ADDR); 3208c2ecf20Sopenharmony_ci srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN); 3218c2ecf20Sopenharmony_ci srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE); 3228c2ecf20Sopenharmony_ci srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE); 3238c2ecf20Sopenharmony_ci#endif 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Since all the SRM consoles load the BOOTP image at virtual 3268c2ecf20Sopenharmony_ci * 0x20000000, we have to ensure that the physical memory 3278c2ecf20Sopenharmony_ci * pages occupied by that image do NOT overlap the physical 3288c2ecf20Sopenharmony_ci * address range where the kernel wants to be run. This 3298c2ecf20Sopenharmony_ci * causes real problems when attempting to cdecompress the 3308c2ecf20Sopenharmony_ci * former into the latter... :-( 3318c2ecf20Sopenharmony_ci * 3328c2ecf20Sopenharmony_ci * So, we may have to decompress/move the kernel/INITRD image 3338c2ecf20Sopenharmony_ci * virtual-to-physical someplace else first before moving 3348c2ecf20Sopenharmony_ci * kernel /INITRD to their final resting places... ;-} 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * Sigh... 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* First, check to see if the range of addresses occupied by 3408c2ecf20Sopenharmony_ci the bootstrapper part of the BOOTP image include any of the 3418c2ecf20Sopenharmony_ci physical pages into which the kernel will be placed for 3428c2ecf20Sopenharmony_ci execution. 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci We only need check on the final kernel image range, since we 3458c2ecf20Sopenharmony_ci will put the INITRD someplace that we can be sure is not 3468c2ecf20Sopenharmony_ci in conflict. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END, 3498c2ecf20Sopenharmony_ci K_KERNEL_DATA_START, K_KERNEL_IMAGE_END)) 3508c2ecf20Sopenharmony_ci { 3518c2ecf20Sopenharmony_ci srm_printk("FATAL ERROR: overlap of bootstrapper code\n"); 3528c2ecf20Sopenharmony_ci __halt(); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Next, check to see if the range of addresses occupied by 3568c2ecf20Sopenharmony_ci the compressed kernel/INITRD/stack portion of the BOOTP 3578c2ecf20Sopenharmony_ci image include any of the physical pages into which the 3588c2ecf20Sopenharmony_ci decompressed kernel or the INITRD will be placed for 3598c2ecf20Sopenharmony_ci execution. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (check_range(V_DATA_START, V_DATA_END, 3628c2ecf20Sopenharmony_ci K_KERNEL_IMAGE_START, K_COPY_IMAGE_END)) 3638c2ecf20Sopenharmony_ci { 3648c2ecf20Sopenharmony_ci#ifdef DEBUG_ADDRESSES 3658c2ecf20Sopenharmony_ci srm_printk("OVERLAP: cannot decompress in place\n"); 3668c2ecf20Sopenharmony_ci#endif 3678c2ecf20Sopenharmony_ci uncompressed_image_start = K_COPY_IMAGE_START; 3688c2ecf20Sopenharmony_ci uncompressed_image_end = K_COPY_IMAGE_END; 3698c2ecf20Sopenharmony_ci must_move = 1; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Finally, check to see if the range of addresses 3728c2ecf20Sopenharmony_ci occupied by the compressed kernel/INITRD part of 3738c2ecf20Sopenharmony_ci the BOOTP image include any of the physical pages 3748c2ecf20Sopenharmony_ci into which that part is to be copied for 3758c2ecf20Sopenharmony_ci decompression. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci while (check_range(V_DATA_START, V_DATA_END, 3788c2ecf20Sopenharmony_ci uncompressed_image_start, 3798c2ecf20Sopenharmony_ci uncompressed_image_end)) 3808c2ecf20Sopenharmony_ci { 3818c2ecf20Sopenharmony_ci#if 0 3828c2ecf20Sopenharmony_ci uncompressed_image_start += K_COPY_IMAGE_SIZE; 3838c2ecf20Sopenharmony_ci uncompressed_image_end += K_COPY_IMAGE_SIZE; 3848c2ecf20Sopenharmony_ci initrd_image_start += K_COPY_IMAGE_SIZE; 3858c2ecf20Sopenharmony_ci#else 3868c2ecf20Sopenharmony_ci /* Keep as close as possible to end of BOOTP image. */ 3878c2ecf20Sopenharmony_ci uncompressed_image_start += PAGE_SIZE; 3888c2ecf20Sopenharmony_ci uncompressed_image_end += PAGE_SIZE; 3898c2ecf20Sopenharmony_ci initrd_image_start += PAGE_SIZE; 3908c2ecf20Sopenharmony_ci#endif 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci srm_printk("Starting to load the kernel with args '%s'\n", envval); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci#ifdef DEBUG_ADDRESSES 3978c2ecf20Sopenharmony_ci srm_printk("Decompressing the kernel...\n" 3988c2ecf20Sopenharmony_ci "...from 0x%lx to 0x%lx size 0x%x\n", 3998c2ecf20Sopenharmony_ci V_DATA_START, 4008c2ecf20Sopenharmony_ci uncompressed_image_start, 4018c2ecf20Sopenharmony_ci KERNEL_SIZE); 4028c2ecf20Sopenharmony_ci#endif 4038c2ecf20Sopenharmony_ci decompress_kernel((void *)uncompressed_image_start, 4048c2ecf20Sopenharmony_ci (void *)V_DATA_START, 4058c2ecf20Sopenharmony_ci KERNEL_SIZE, KERNEL_Z_SIZE); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * Now, move things to their final positions, if/as required. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* First, we always move the INITRD image, if present. */ 4148c2ecf20Sopenharmony_ci#ifdef DEBUG_ADDRESSES 4158c2ecf20Sopenharmony_ci srm_printk("Moving the INITRD image...\n" 4168c2ecf20Sopenharmony_ci " from 0x%lx to 0x%lx size 0x%x\n", 4178c2ecf20Sopenharmony_ci V_INITRD_START, 4188c2ecf20Sopenharmony_ci initrd_image_start, 4198c2ecf20Sopenharmony_ci INITRD_IMAGE_SIZE); 4208c2ecf20Sopenharmony_ci#endif 4218c2ecf20Sopenharmony_ci memcpy((void *)initrd_image_start, (void *)V_INITRD_START, 4228c2ecf20Sopenharmony_ci INITRD_IMAGE_SIZE); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci#endif /* INITRD_IMAGE_SIZE */ 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Next, we may have to move the uncompressed kernel to the 4278c2ecf20Sopenharmony_ci final destination. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (must_move) { 4308c2ecf20Sopenharmony_ci#ifdef DEBUG_ADDRESSES 4318c2ecf20Sopenharmony_ci srm_printk("Moving the uncompressed kernel...\n" 4328c2ecf20Sopenharmony_ci "...from 0x%lx to 0x%lx size 0x%x\n", 4338c2ecf20Sopenharmony_ci uncompressed_image_start, 4348c2ecf20Sopenharmony_ci K_KERNEL_IMAGE_START, 4358c2ecf20Sopenharmony_ci (unsigned)KERNEL_SIZE); 4368c2ecf20Sopenharmony_ci#endif 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Move the stack to a safe place to ensure it won't be 4398c2ecf20Sopenharmony_ci * overwritten by kernel image. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci move_stack(initrd_image_start - PAGE_SIZE); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci memcpy((void *)K_KERNEL_IMAGE_START, 4448c2ecf20Sopenharmony_ci (void *)uncompressed_image_start, KERNEL_SIZE); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Clear the zero page, then move the argument list in. */ 4488c2ecf20Sopenharmony_ci#ifdef DEBUG_LAST_STEPS 4498c2ecf20Sopenharmony_ci srm_printk("Preparing ZERO_PGE...\n"); 4508c2ecf20Sopenharmony_ci#endif 4518c2ecf20Sopenharmony_ci memset((char*)ZERO_PGE, 0, PAGE_SIZE); 4528c2ecf20Sopenharmony_ci strcpy((char*)ZERO_PGE, envval); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci#ifdef INITRD_IMAGE_SIZE 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci#ifdef DEBUG_LAST_STEPS 4578c2ecf20Sopenharmony_ci srm_printk("Preparing INITRD info...\n"); 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci /* Finally, set the INITRD paramenters for the kernel. */ 4608c2ecf20Sopenharmony_ci ((long *)(ZERO_PGE+256))[0] = initrd_image_start; 4618c2ecf20Sopenharmony_ci ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#endif /* INITRD_IMAGE_SIZE */ 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#ifdef DEBUG_LAST_STEPS 4668c2ecf20Sopenharmony_ci srm_printk("Doing 'runkernel()'...\n"); 4678c2ecf20Sopenharmony_ci#endif 4688c2ecf20Sopenharmony_ci runkernel(); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* dummy function, should never be called. */ 4728c2ecf20Sopenharmony_civoid *__kmalloc(size_t size, gfp_t flags) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci return (void *)NULL; 4758c2ecf20Sopenharmony_ci} 476