2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * Copyright (C) 2001 Silicon Graphics, Inc.
6 * Contributed by Brent Casavant <bcasavan@sgi.com>
8 * This file is part of the ELILO, the EFI Linux boot loader.
10 * ELILO is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * ELILO is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with ELILO; see the file COPYING. If not, write to the Free
22 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 * Please check out the elilo.txt for complete documentation on how
26 * to use this program.
40 #define LD_NAME L"gzip_ia64"
42 #define memzero(s, n) Memset((VOID *)(s), 0, (n))
43 #define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))
45 /* size of output buffer */
46 #define WSIZE 0x8000 /* Window size must be at least 32k, */
47 /* and a power of two */
48 /* size of input buffer */
49 #define INBUFSIZE 0x8000
56 #define FUNC_STATIC static
58 typedef unsigned char uch;
59 typedef unsigned short ush;
60 typedef unsigned long ulg;
63 typedef struct segment {
64 unsigned long addr; /* start address */
65 unsigned long offset; /* file offset */
66 unsigned long size; /* file size */
67 unsigned long bss_sz; /* BSS size */
68 UINT8 flags; /* indicates whether to load or not */
71 #define CHUNK_FL_VALID 0x1
72 #define CHUNK_FL_LOAD 0x2
73 #define CHUNK_FL_X 0x4
75 #define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD
76 #define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD
77 #define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)
79 #define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID
80 #define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0
81 #define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)
84 * static parameters to gzip helper functions
85 * we cannot use paramters because API was not
88 static segment_t *chunks; /* holds the list of segments */
89 static segment_t *cur_chunk;
91 static UINTN chunk; /* current segment */
92 static UINTN input_fd;
93 static VOID *kernel_entry, *kernel_base, *kernel_end;
95 static uch *inbuf; /* input buffer (compressed data) */
96 static uch *window; /* output buffer (uncompressed data) */
97 static unsigned long file_offset; /* position in the file */
99 static unsigned insize = 0; /* valid bytes in inbuf */
100 static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
101 static unsigned outcnt = 0; /* bytes in output buffer */
104 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
105 #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
106 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
107 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
108 #define COMMENT 0x10 /* bit 4 set: file comment present */
109 #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
110 #define RESERVED 0xC0 /* bit 6,7: reserved */
112 #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
114 /* Diagnostic functions */
116 # define Assert(cond,msg) {if(!(cond)) error(msg);}
118 # define Trace(x) Print(L"line %d:\n", __LINE__);
119 # define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
120 # define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}
121 # define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}
122 # define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}
124 # define Assert(cond,msg)
129 # define Tracecv(c,x)
132 static int fill_inbuf(void);
133 static void flush_window(void);
134 static void error(char *m);
135 static long bytes_out;
137 static void error(char *m);
140 static int error_return;
141 static UINTN elf_is_big_endian; /* true if ELF file is big endian */
144 gzip_malloc(int size)
146 return (void *)alloc(size, 0);
150 gzip_free(void *where)
158 * Fill the input buffer and return the first byte in it. This is called
159 * only when the buffer is empty and at least one byte is really needed.
164 UINTN expected, nread;
167 expected = nread = INBUFSIZE;
169 status = fops_read(input_fd, inbuf, &nread);
170 if (EFI_ERROR(status)) {
171 error("elilo: Read failed");
174 DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
183 /* ===========================================================================
184 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
185 * (Used for the decompressed data only.)
189 * Run a set of bytes through the crc shift register. If s is a NULL
190 * pointer, then initialize the crc shift register contents instead.
191 * Return the current crc in either case.
194 * S pointer to bytes to pump through.
195 * N number of bytes in S[].
198 updcrc(unsigned char *s, unsigned n)
200 register unsigned long c;
201 /* crc is defined in inflate.c */
208 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
212 return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */
217 * Clear input and output buffers
233 if(elf_is_big_endian) v = __ia64_swab64(v);
240 if(elf_is_big_endian) v = __ia64_swab32(v);
247 if(elf_is_big_endian) v = __ia64_swab16(v);
252 is_valid_header(Elf64_Ehdr *ehdr)
254 UINT16 type, machine;
256 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
257 type = __ia64_swab16(ehdr->e_type);
258 machine = __ia64_swab16(ehdr->e_machine);
261 machine = ehdr->e_machine;
263 VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n",
264 ehdr->e_ident[EI_CLASS],
266 ehdr->e_ident[EI_DATA],
269 return ehdr->e_ident[EI_MAG0] == 0x7f
270 && ehdr->e_ident[EI_MAG1] == 'E'
271 && ehdr->e_ident[EI_MAG2] == 'L'
272 && ehdr->e_ident[EI_MAG3] == 'F'
273 && ehdr->e_ident[EI_CLASS] == ELFCLASS64
274 && type == ET_EXEC /* must be executable */
275 && machine == EM_IA_64 ? 0 : -1;
279 * will invalidate loadble segments which overlap with others
285 unsigned long iend = chunks[i].addr + chunks[i].size;
287 for(j=0; j < nchunks; j++) {
289 if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) {
290 DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j));
291 CHUNK_INVALIDATE(i); /* nullyify segment */
302 for(i=0; i < nchunks; i++) {
303 if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i);
309 * The decompression code calls this function after decompressing the
310 * first block of the object file. The first block must contain all
311 * the relevant header information.
314 first_block (const unsigned char *buf, long blocksize)
318 UINTN total_size, pages;
319 UINTN low_addr, max_addr;
320 UINTN load_offset = 0;
326 elf = (Elf64_Ehdr *)buf;
328 if (is_valid_header(elf) == -1) return -1;
330 /* determine file endianess */
331 elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
334 offs = bswap64(elf->e_phoff);
335 phnum = bswap16(elf->e_phnum);
338 Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
339 Print(L"Entry point 0x%lx\n", bswap64(elf->e_entry));
340 Print(L"%d program headers\n", phnum);
341 Print(L"%d segment headers\n", bswap16(elf->e_shnum));
345 /* XXX: need to check on this */
346 if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
347 ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
351 kernel_entry = (void *)bswap64(elf->e_entry);
353 if (((UINTN)kernel_entry >> 61) != 0) {
354 ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kernel_entry));
357 phdrs = (Elf64_Phdr *) (buf + offs);
363 * allocate chunk table
364 * Convention: a segment that does not need loading will
365 * have chunk[].addr = 0.
367 chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
368 if (chunks == NULL) {
369 ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
374 * find lowest and higest virtual addresses
375 * don't assume FULLY sorted !
377 for (i = 0; i < phnum; ++i) {
380 * record chunk no matter what because no load may happen
381 * anywhere in archive, not just as the last segment
383 paddr = bswap64(phdrs[i].p_paddr);
384 memsz = bswap64(phdrs[i].p_memsz),
386 chunks[i].addr = paddr;
387 chunks[i].offset = bswap64(phdrs[i].p_offset);
388 chunks[i].size = bswap64(phdrs[i].p_filesz);
389 chunks[i].bss_sz = bswap64(phdrs[i].p_memsz) - bswap64(phdrs[i].p_filesz);
393 if (bswap32(phdrs[i].p_type) != PT_LOAD) {
394 CHUNK_NO_LOAD(i); /* mark no load chunk */
395 DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
399 if (bswap32(phdrs[i].p_flags) & PF_X)
400 chunks[i].flags |= CHUNK_FL_X;
402 CHUNK_CAN_LOAD(i); /* mark no load chunk */
405 Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld memsz=%ld bss_sz=%ld\n",
409 chunks[i].addr+bswap64(phdrs[i].p_filesz),
415 if (paddr < low_addr) low_addr = paddr;
417 if (paddr + memsz > max_addr) max_addr = paddr + memsz;
420 if (low_addr & (EFI_PAGE_SIZE - 1)) {
421 ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
427 DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n",
429 phnum, kernel_entry, low_addr, max_addr));
431 total_size = (UINTN)max_addr - (UINTN)low_addr;
432 pages = EFI_SIZE_TO_PAGES(total_size);
435 * Record end of kernel for initrd
437 kernel_base = (void *)low_addr;
438 kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
440 /* allocate memory for the kernel */
441 if (alloc_kmem((void *)low_addr, pages) == -1) {
444 VERB_PRT(1, Print(L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
446 if (ia64_can_relocate() == 0) {
447 ERR_PRT((L"relocation is disabled, cannot load kernel"));
452 * could not allocate at requested spot, try to find a
453 * suitable location to relocate the kernel
455 * The maximum sized Itanium TLB translation entry is 256 MB.
456 * If we relocate the kernel by this amount we know for sure
457 * that alignment constraints will be satisified, regardless
458 * of the kernel used.
460 VERB_PRT(1, Print(L"Attempting to relocate kernel.\n"));
462 if (find_kernel_memory((VOID*) low_addr, (VOID*) max_addr, 256*MB, &new_addr) == -1) {
463 ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
466 /* unsigned arithmetic */
467 load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
469 VERB_PRT(1, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
472 * correct various addresses for non-zero load_offset
474 kernel_base = (void *) ((UINTN) kernel_base + load_offset);
475 kernel_end = (void *) ((UINTN) kernel_end + load_offset);
476 kernel_entry = (void*) ((UINTN) kernel_entry + load_offset);
478 for (i = 0; i < phnum; ++i) {
479 chunks[i].addr += load_offset;
480 phdrs[i].p_paddr = (Elf64_Addr) ((UINT64) phdrs[i].p_paddr + load_offset);
484 * try one last time to get memory for the kernel
486 if (alloc_kmem((void *)low_addr+load_offset, pages) == -1) {
487 ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr+load_offset));
488 ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
494 if (chunks) free(chunks);
499 * Determine which chunk in the Elf file will be coming out of the expand
509 for(i=0; i < nchunks; i++) {
511 if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
513 if (file_offset > chunks[i].offset) continue;
515 if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
522 * Write the output window window[0..outcnt-1] holding uncompressed
523 * data and update crc.
528 static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
529 static UINTN heli_count;
531 unsigned char *src, *dst;
536 DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
539 Print(L"%c\b",helicopter[heli_count++%4]);
541 updcrc(window, outcnt);
544 * first time, we extract the headers
547 if (first_block(window, outcnt) < 0) error("invalid exec header");
554 /* check if user wants to abort */
555 if (check_abort() == EFI_SUCCESS) goto load_abort;
558 if (cp == NULL || file_offset + outcnt <= cp->offset) {
559 file_offset += outcnt;
563 // Does this window begin before the current chunk?
564 if (file_offset < cp->offset) {
565 unsigned long skip = cp->offset - file_offset;
571 dst = (unsigned char *)cp->addr + (file_offset - cp->offset);
573 cnt = cp->offset + cp->size - file_offset;
575 if (cnt > outcnt) cnt = outcnt;
577 Memcpy(dst, src, cnt);
578 if (cp->flags & CHUNK_FL_X)
579 flush_dcache (dst, cnt);
585 /* See if we are at the end of this chunk */
586 if (file_offset == cp->offset + cp->size) {
588 dst = (unsigned char *)cp->addr + cp->size;
589 Memset(dst, 0, cp->bss_sz);
592 /* handle remaining bytes */
593 if (outcnt) goto tail;
598 error_return = ELILO_LOAD_ABORTED;
605 ERR_PRT((L"%s : %a", LD_NAME, x));
606 /* will eventually exit with error from gunzip() */
611 decompress_kernel(VOID)
617 Print(L"Uncompressing Linux... ");
619 if (ret == 0) Print(L"done\n");
620 return ret == 0 ? 0 : -1;
624 gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
628 error_return = ELILO_LOAD_ERROR;
630 window = (void *)alloc(WSIZE, 0);
631 if (window == NULL) {
632 ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
636 inbuf = (void *)alloc(INBUFSIZE, 0);
638 ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
646 if (setjmp(jbuf) == 1) goto error;
649 ret = decompress_kernel();
652 if (window) free(window);
653 if (inbuf) free(inbuf);
656 kd->kentry = kernel_entry;
657 kd->kend = kernel_end;
658 kd->kstart = kernel_base;
659 error_return = ELILO_LOAD_SUCCESS;