📄 gzip.c
字号:
/* * Copyright (C) 2001-2003 Hewlett-Packard Co. * Contributed by Stephane Eranian <eranian@hpl.hp.com> * * Copyright (C) 2001 Silicon Graphics, Inc. * Contributed by Brent Casavant <bcasavan@sgi.com> * * This file is part of the ELILO, the EFI Linux boot loader. * * ELILO is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * ELILO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ELILO; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Please check out the elilo.txt for complete documentation on how * to use this program. */#include <efi.h>#include <efilib.h>#include "elf.h"#include "elilo.h"#include "gzip.h"#include "private.h"#include "setjmp.h"#define memzero(s, n) Memset((VOID *)(s), 0, (n))#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))/* size of output buffer */#define WSIZE 0x8000 /* Window size must be at least 32k, */ /* and a power of two *//* size of input buffer */#define INBUFSIZE 0x8000/* * gzip declarations */#define OF(args) args#define FUNC_STATIC statictypedef unsigned char uch;typedef unsigned short ush;typedef unsigned long ulg;typedef struct segment { unsigned long addr; /* start address */ unsigned long offset; /* file offset */ unsigned long size; /* file size */ unsigned long bss_sz; /* BSS size */ UINT8 flags; /* indicates whether to load or not */} segment_t;#define CHUNK_FL_VALID 0x1#define CHUNK_FL_LOAD 0x2#define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD#define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD#define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)#define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID#define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0#define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)/* * static parameters to gzip helper functions * we cannot use paramters because API was not * designed that way */static segment_t *chunks; /* holds the list of segments */static segment_t *cur_chunk;static UINTN nchunks;static UINTN chunk; /* current segment */static UINTN input_fd;static VOID *kernel_entry, *kernel_base, *kernel_end;static uch *inbuf; /* input buffer (compressed data) */static uch *window; /* output buffer (uncompressed data) */static unsigned long file_offset; /* position in the file */static unsigned insize = 0; /* valid bytes in inbuf */static unsigned inptr = 0; /* index of next byte to be processed in inbuf */static unsigned outcnt = 0; /* bytes in output buffer *//* gzip flag byte */#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */#define ORIG_NAME 0x08 /* bit 3 set: original file name present */#define COMMENT 0x10 /* bit 4 set: file comment present */#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */#define RESERVED 0xC0 /* bit 6,7: reserved */#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())/* Diagnostic functions */#ifdef INFLATE_DEBUG# define Assert(cond,msg) {if(!(cond)) error(msg);}int stderr;# define Trace(x) Print(L"line %d:\n", __LINE__);# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}#else# define Assert(cond,msg)# define Trace(x)# define Tracev(x)# define Tracevv(x)# define Tracec(c,x)# define Tracecv(c,x)#endifstatic int fill_inbuf(void);static void flush_window(void);static void error(char *m);static long bytes_out;static void error(char *m);static jmp_buf jbuf;static int error_return;static UINTN elf_is_big_endian; /* true if ELF file is big endian */static void *gzip_malloc(int size){ return (void *)alloc(size, 0);}static voidgzip_free(void *where){ return free(where);}#include "inflate.c"/* * Fill the input buffer and return the first byte in it. This is called * only when the buffer is empty and at least one byte is really needed. */intfill_inbuf(void){ INTN expected, nread; EFI_STATUS status; expected = nread = INBUFSIZE; status = fops_read(input_fd, inbuf, &nread); if (EFI_ERROR(status)) { error("elilo: Read failed"); } DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected)); insize = nread; inptr = 1; return inbuf[0];}/* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) *//* * Run a set of bytes through the crc shift register. If s is a NULL * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. * * Input: * S pointer to bytes to pump through. * N number of bytes in S[]. */unsigned longupdcrc(unsigned char *s, unsigned n){ register unsigned long c; /* crc is defined in inflate.c */ if (!s) { c = 0xffffffffL; } else { c = crc; while (n--) { c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } } crc = c; return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */}/* * Clear input and output buffers */voidclear_bufs(void){ outcnt = 0; inptr = 0; chunk = 0; cur_chunk = NULL; file_offset = 0;}static inline UINT64 bswap64(UINT64 v){ if(elf_is_big_endian) v = __ia64_swab64(v); return v;}static inline UINT32bswap32(UINT32 v){ if(elf_is_big_endian) v = __ia64_swab32(v); return v;}static inline UINT16bswap16(UINT16 v){ if(elf_is_big_endian) v = __ia64_swab16(v); return v;}static INTNis_valid_header(Elf64_Ehdr *ehdr){ UINT16 type, machine; if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) { type = __ia64_swab16(ehdr->e_type); machine = __ia64_swab16(ehdr->e_machine); } else { type = ehdr->e_type; machine = ehdr->e_machine; } VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n", ehdr->e_ident[EI_CLASS], type, ehdr->e_ident[EI_DATA], machine)); return ehdr->e_ident[EI_MAG0] == 0x7f && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F' && ehdr->e_ident[EI_CLASS] == ELFCLASS64 && type == ET_EXEC /* must be executable */ && machine == EM_IA_64 ? 0 : -1;}/* * will invalidate loadble segments which overlap with others */ voidcheck_overlap(int i){ int j; unsigned long iend = chunks[i].addr + chunks[i].size; for(j=0; j < nchunks; j++) { if (j ==i) continue; if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) { DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j)); CHUNK_INVALIDATE(i); /* nullyify segment */ break; } }}voidanalyze_chunks(void){ INTN i; for(i=0; i < nchunks; i++) { if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i); }}/* * The decompression code calls this function after decompressing the * first block of the object file. The first block must contain all * the relevant header information. */intfirst_block (const char *buf, long blocksize){ Elf64_Ehdr *elf; Elf64_Phdr *phdrs; UINTN total_size, pages; UINTN low_addr, max_addr; UINTN load_offset = 0; UINTN offs = 0; UINT16 phnum; UINTN paddr, memsz; INTN i; elf = (Elf64_Ehdr *)buf; if (is_valid_header(elf) == -1) return -1; /* determine file endianess */ elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -