1/* 2 * arch/alpha/boot/bootpz.c 3 * 4 * Copyright (C) 1997 Jay Estabrook 5 * 6 * This file is used for creating a compressed BOOTP file for the 7 * Linux/AXP kernel 8 * 9 * based significantly on the arch/alpha/boot/main.c of Linus Torvalds 10 * and the decompression code from MILO. 11 */ 12#include <linux/kernel.h> 13#include <linux/slab.h> 14#include <linux/string.h> 15#include <generated/utsrelease.h> 16#include <linux/mm.h> 17 18#include <asm/system.h> 19#include <asm/console.h> 20#include <asm/hwrpb.h> 21#include <asm/pgtable.h> 22#include <asm/io.h> 23 24#include <stdarg.h> 25 26#include "kzsize.h" 27 28#define MALLOC_AREA_SIZE 0x200000 /* 2MB for now */ 29 30 31/* 32 WARNING NOTE 33 34 It is very possible that turning on additional messages may cause 35 kernel image corruption due to stack usage to do the printing. 36 37*/ 38 39#undef DEBUG_CHECK_RANGE 40#undef DEBUG_ADDRESSES 41#undef DEBUG_LAST_STEPS 42 43extern unsigned long switch_to_osf_pal(unsigned long nr, 44 struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, 45 unsigned long *vptb); 46 47extern int decompress_kernel(void* destination, void *source, 48 size_t ksize, size_t kzsize); 49 50extern void move_stack(unsigned long new_stack); 51 52struct hwrpb_struct *hwrpb = INIT_HWRPB; 53static struct pcb_struct pcb_va[1]; 54 55/* 56 * Find a physical address of a virtual object.. 57 * 58 * This is easy using the virtual page table address. 59 */ 60#define VPTB ((unsigned long *) 0x200000000) 61 62static inline unsigned long 63find_pa(unsigned long address) 64{ 65 unsigned long result; 66 67 result = VPTB[address >> 13]; 68 result >>= 32; 69 result <<= 13; 70 result |= address & 0x1fff; 71 return result; 72} 73 74int 75check_range(unsigned long vstart, unsigned long vend, 76 unsigned long kstart, unsigned long kend) 77{ 78 unsigned long vaddr, kaddr; 79 80#ifdef DEBUG_CHECK_RANGE 81 srm_printk("check_range: V[0x%lx:0x%lx] K[0x%lx:0x%lx]\n", 82 vstart, vend, kstart, kend); 83#endif 84 /* do some range checking for detecting an overlap... */ 85 for (vaddr = vstart; vaddr <= vend; vaddr += PAGE_SIZE) 86 { 87 kaddr = (find_pa(vaddr) | PAGE_OFFSET); 88 if (kaddr >= kstart && kaddr <= kend) 89 { 90#ifdef DEBUG_CHECK_RANGE 91 srm_printk("OVERLAP: vaddr 0x%lx kaddr 0x%lx" 92 " [0x%lx:0x%lx]\n", 93 vaddr, kaddr, kstart, kend); 94#endif 95 return 1; 96 } 97 } 98 return 0; 99} 100 101/* 102 * This function moves into OSF/1 pal-code, and has a temporary 103 * PCB for that. The kernel proper should replace this PCB with 104 * the real one as soon as possible. 105 * 106 * The page table muckery in here depends on the fact that the boot 107 * code has the L1 page table identity-map itself in the second PTE 108 * in the L1 page table. Thus the L1-page is virtually addressable 109 * itself (through three levels) at virtual address 0x200802000. 110 */ 111 112#define L1 ((unsigned long *) 0x200802000) 113 114void 115pal_init(void) 116{ 117 unsigned long i, rev; 118 struct percpu_struct * percpu; 119 struct pcb_struct * pcb_pa; 120 121 /* Create the dummy PCB. */ 122 pcb_va->ksp = 0; 123 pcb_va->usp = 0; 124 pcb_va->ptbr = L1[1] >> 32; 125 pcb_va->asn = 0; 126 pcb_va->pcc = 0; 127 pcb_va->unique = 0; 128 pcb_va->flags = 1; 129 pcb_va->res1 = 0; 130 pcb_va->res2 = 0; 131 pcb_pa = (struct pcb_struct *)find_pa((unsigned long)pcb_va); 132 133 /* 134 * a0 = 2 (OSF) 135 * a1 = return address, but we give the asm the vaddr of the PCB 136 * a2 = physical addr of PCB 137 * a3 = new virtual page table pointer 138 * a4 = KSP (but the asm sets it) 139 */ 140 srm_printk("Switching to OSF PAL-code... "); 141 142 i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); 143 if (i) { 144 srm_printk("failed, code %ld\n", i); 145 __halt(); 146 } 147 148 percpu = (struct percpu_struct *) 149 (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB); 150 rev = percpu->pal_revision = percpu->palcode_avail[2]; 151 152 srm_printk("OK (rev %lx)\n", rev); 153 154 tbia(); /* do it directly in case we are SMP */ 155} 156 157/* 158 * Start the kernel. 159 */ 160static inline void 161runkernel(void) 162{ 163 __asm__ __volatile__( 164 "bis %0,%0,$27\n\t" 165 "jmp ($27)" 166 : /* no outputs: it doesn't even return */ 167 : "r" (START_ADDR)); 168} 169 170/* Must record the SP (it is virtual) on entry, so we can make sure 171 not to overwrite it during movement or decompression. */ 172unsigned long SP_on_entry; 173 174/* Calculate the kernel image address based on the end of the BOOTP 175 bootstrapper (ie this program). 176*/ 177extern char _end; 178#define KERNEL_ORIGIN \ 179 ((((unsigned long)&_end) + 511) & ~511) 180 181/* Round address to next higher page boundary. */ 182#define NEXT_PAGE(a) (((a) | (PAGE_SIZE - 1)) + 1) 183 184#ifdef INITRD_IMAGE_SIZE 185# define REAL_INITRD_SIZE INITRD_IMAGE_SIZE 186#else 187# define REAL_INITRD_SIZE 0 188#endif 189 190/* Defines from include/asm-alpha/system.h 191 192 BOOT_ADDR Virtual address at which the consoles loads 193 the BOOTP image. 194 195 KERNEL_START KSEG address at which the kernel is built to run, 196 which includes some initial data pages before the 197 code. 198 199 START_ADDR KSEG address of the entry point of kernel code. 200 201 ZERO_PGE KSEG address of page full of zeroes, but 202 upon entry to kerne cvan be expected 203 to hold the parameter list and possible 204 INTRD information. 205 206 These are used in the local defines below. 207*/ 208 209 210/* Virtual addresses for the BOOTP image. Note that this includes the 211 bootstrapper code as well as the compressed kernel image, and 212 possibly the INITRD image. 213 214 Oh, and do NOT forget the STACK, which appears to be placed virtually 215 beyond the end of the loaded image. 216*/ 217#define V_BOOT_IMAGE_START BOOT_ADDR 218#define V_BOOT_IMAGE_END SP_on_entry 219 220/* Virtual addresses for just the bootstrapper part of the BOOTP image. */ 221#define V_BOOTSTRAPPER_START BOOT_ADDR 222#define V_BOOTSTRAPPER_END KERNEL_ORIGIN 223 224/* Virtual addresses for just the data part of the BOOTP 225 image. This may also include the INITRD image, but always 226 includes the STACK. 227*/ 228#define V_DATA_START KERNEL_ORIGIN 229#define V_INITRD_START (KERNEL_ORIGIN + KERNEL_Z_SIZE) 230#define V_INTRD_END (V_INITRD_START + REAL_INITRD_SIZE) 231#define V_DATA_END V_BOOT_IMAGE_END 232 233/* KSEG addresses for the uncompressed kernel. 234 235 Note that the end address includes workspace for the decompression. 236 Note also that the DATA_START address is ZERO_PGE, to which we write 237 just before jumping to the kernel image at START_ADDR. 238 */ 239#define K_KERNEL_DATA_START ZERO_PGE 240#define K_KERNEL_IMAGE_START START_ADDR 241#define K_KERNEL_IMAGE_END (START_ADDR + KERNEL_SIZE) 242 243/* Define to where we may have to decompress the kernel image, before 244 we move it to the final position, in case of overlap. This will be 245 above the final position of the kernel. 246 247 Regardless of overlap, we move the INITRD image to the end of this 248 copy area, because there needs to be a buffer area after the kernel 249 for "bootmem" anyway. 250*/ 251#define K_COPY_IMAGE_START NEXT_PAGE(K_KERNEL_IMAGE_END) 252/* Reserve one page below INITRD for the new stack. */ 253#define K_INITRD_START \ 254 NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE) 255#define K_COPY_IMAGE_END \ 256 (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE) 257#define K_COPY_IMAGE_SIZE \ 258 NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START) 259 260void 261start_kernel(void) 262{ 263 int must_move = 0; 264 265 /* Initialize these for the decompression-in-place situation, 266 which is the smallest amount of work and most likely to 267 occur when using the normal START_ADDR of the kernel 268 (currently set to 16MB, to clear all console code. 269 */ 270 unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START; 271 unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END; 272 273 unsigned long initrd_image_start = K_INITRD_START; 274 275 /* 276 * Note that this crufty stuff with static and envval 277 * and envbuf is because: 278 * 279 * 1. Frequently, the stack is short, and we don't want to overrun; 280 * 2. Frequently the stack is where we are going to copy the kernel to; 281 * 3. A certain SRM console required the GET_ENV output to stack. 282 * ??? A comment in the aboot sources indicates that the GET_ENV 283 * destination must be quadword aligned. Might this explain the 284 * behaviour, rather than requiring output to the stack, which 285 * seems rather far-fetched. 286 */ 287 static long nbytes; 288 static char envval[256] __attribute__((aligned(8))); 289 register unsigned long asm_sp asm("30"); 290 291 SP_on_entry = asm_sp; 292 293 srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n"); 294 295 /* Validity check the HWRPB. */ 296 if (INIT_HWRPB->pagesize != 8192) { 297 srm_printk("Expected 8kB pages, got %ldkB\n", 298 INIT_HWRPB->pagesize >> 10); 299 return; 300 } 301 if (INIT_HWRPB->vptb != (unsigned long) VPTB) { 302 srm_printk("Expected vptb at %p, got %p\n", 303 VPTB, (void *)INIT_HWRPB->vptb); 304 return; 305 } 306 307 /* PALcode (re)initialization. */ 308 pal_init(); 309 310 /* Get the parameter list from the console environment variable. */ 311 nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); 312 if (nbytes < 0 || nbytes >= sizeof(envval)) { 313 nbytes = 0; 314 } 315 envval[nbytes] = '\0'; 316 317#ifdef DEBUG_ADDRESSES 318 srm_printk("START_ADDR 0x%lx\n", START_ADDR); 319 srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN); 320 srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE); 321 srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE); 322#endif 323 324 /* Since all the SRM consoles load the BOOTP image at virtual 325 * 0x20000000, we have to ensure that the physical memory 326 * pages occupied by that image do NOT overlap the physical 327 * address range where the kernel wants to be run. This 328 * causes real problems when attempting to cdecompress the 329 * former into the latter... :-( 330 * 331 * So, we may have to decompress/move the kernel/INITRD image 332 * virtual-to-physical someplace else first before moving 333 * kernel /INITRD to their final resting places... ;-} 334 * 335 * Sigh... 336 */ 337 338 /* First, check to see if the range of addresses occupied by 339 the bootstrapper part of the BOOTP image include any of the 340 physical pages into which the kernel will be placed for 341 execution. 342 343 We only need check on the final kernel image range, since we 344 will put the INITRD someplace that we can be sure is not 345 in conflict. 346 */ 347 if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END, 348 K_KERNEL_DATA_START, K_KERNEL_IMAGE_END)) 349 { 350 srm_printk("FATAL ERROR: overlap of bootstrapper code\n"); 351 __halt(); 352 } 353 354 /* Next, check to see if the range of addresses occupied by 355 the compressed kernel/INITRD/stack portion of the BOOTP 356 image include any of the physical pages into which the 357 decompressed kernel or the INITRD will be placed for 358 execution. 359 */ 360 if (check_range(V_DATA_START, V_DATA_END, 361 K_KERNEL_IMAGE_START, K_COPY_IMAGE_END)) 362 { 363#ifdef DEBUG_ADDRESSES 364 srm_printk("OVERLAP: cannot decompress in place\n"); 365#endif 366 uncompressed_image_start = K_COPY_IMAGE_START; 367 uncompressed_image_end = K_COPY_IMAGE_END; 368 must_move = 1; 369 370 /* Finally, check to see if the range of addresses 371 occupied by the compressed kernel/INITRD part of 372 the BOOTP image include any of the physical pages 373 into which that part is to be copied for 374 decompression. 375 */ 376 while (check_range(V_DATA_START, V_DATA_END, 377 uncompressed_image_start, 378 uncompressed_image_end)) 379 { 380 /* Keep as close as possible to end of BOOTP image. */ 381 uncompressed_image_start += PAGE_SIZE; 382 uncompressed_image_end += PAGE_SIZE; 383 initrd_image_start += PAGE_SIZE; 384 } 385 } 386 387 srm_printk("Starting to load the kernel with args '%s'\n", envval); 388 389#ifdef DEBUG_ADDRESSES 390 srm_printk("Decompressing the kernel...\n" 391 "...from 0x%lx to 0x%lx size 0x%x\n", 392 V_DATA_START, 393 uncompressed_image_start, 394 KERNEL_SIZE); 395#endif 396 decompress_kernel((void *)uncompressed_image_start, 397 (void *)V_DATA_START, 398 KERNEL_SIZE, KERNEL_Z_SIZE); 399 400 /* 401 * Now, move things to their final positions, if/as required. 402 */ 403 404#ifdef INITRD_IMAGE_SIZE 405 406 /* First, we always move the INITRD image, if present. */ 407#ifdef DEBUG_ADDRESSES 408 srm_printk("Moving the INITRD image...\n" 409 " from 0x%lx to 0x%lx size 0x%x\n", 410 V_INITRD_START, 411 initrd_image_start, 412 INITRD_IMAGE_SIZE); 413#endif 414 memcpy((void *)initrd_image_start, (void *)V_INITRD_START, 415 INITRD_IMAGE_SIZE); 416 417#endif /* INITRD_IMAGE_SIZE */ 418 419 /* Next, we may have to move the uncompressed kernel to the 420 final destination. 421 */ 422 if (must_move) { 423#ifdef DEBUG_ADDRESSES 424 srm_printk("Moving the uncompressed kernel...\n" 425 "...from 0x%lx to 0x%lx size 0x%x\n", 426 uncompressed_image_start, 427 K_KERNEL_IMAGE_START, 428 (unsigned)KERNEL_SIZE); 429#endif 430 /* 431 * Move the stack to a safe place to ensure it won't be 432 * overwritten by kernel image. 433 */ 434 move_stack(initrd_image_start - PAGE_SIZE); 435 436 memcpy((void *)K_KERNEL_IMAGE_START, 437 (void *)uncompressed_image_start, KERNEL_SIZE); 438 } 439 440 /* Clear the zero page, then move the argument list in. */ 441#ifdef DEBUG_LAST_STEPS 442 srm_printk("Preparing ZERO_PGE...\n"); 443#endif 444 memset((char*)ZERO_PGE, 0, PAGE_SIZE); 445 strcpy((char*)ZERO_PGE, envval); 446 447#ifdef INITRD_IMAGE_SIZE 448 449#ifdef DEBUG_LAST_STEPS 450 srm_printk("Preparing INITRD info...\n"); 451#endif 452 /* Finally, set the INITRD paramenters for the kernel. */ 453 ((long *)(ZERO_PGE+256))[0] = initrd_image_start; 454 ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE; 455 456#endif /* INITRD_IMAGE_SIZE */ 457 458#ifdef DEBUG_LAST_STEPS 459 srm_printk("Doing 'runkernel()'...\n"); 460#endif 461 runkernel(); 462} 463 464 /* dummy function, should never be called. */ 465void *__kmalloc(size_t size, gfp_t flags) 466{ 467 return (void *)NULL; 468} 469