📄 load.c
字号:
//==========================================================================//// load.c//// RedBoot file/image loader////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2002, 2003, 2004 Gary Thomas//// eCos 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.//// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): gthomas// Contributors: gthomas, tsmith// Date: 2000-07-14// Purpose: // Description: // // This code is part of RedBoot (tm).////####DESCRIPTIONEND####////==========================================================================#include <redboot.h>#include <elf.h>#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM#include <xyzModem.h>#endif#ifdef CYGPKG_REDBOOT_DISK#include <fs/disk.h>#endif#ifdef CYGPKG_REDBOOT_FILEIO#include <fs/fileio.h>#endif#ifdef CYGPKG_REDBOOT_NETWORKING#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD#include <net/tftp_support.h>#endif#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD#include <net/http.h>#endif#endif#include <cyg/infra/cyg_ass.h> // assertion macrosstatic char usage[] = "[-r] [-v] "#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB "[-d] "#endif#ifdef CYGPKG_REDBOOT_NETWORKING "[-h <host>] [-p <TCP port>]"#endif "[-m <varies>] "#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 "[-c <channel_number>] "#endif "\n [-b <base_address>] <file_name>";// Exported CLI functionRedBoot_cmd("load", "Load a file", usage, do_load );//// Stream I/O support//// Table describing the various I/O methodsCYG_HAL_TABLE_BEGIN( __RedBoot_LOAD_TAB__, RedBoot_load );CYG_HAL_TABLE_END( __RedBoot_LOAD_TAB_END__, RedBoot_load );extern struct load_io_entry __RedBoot_LOAD_TAB__[], __RedBoot_LOAD_TAB_END__;// Buffers, data used by redboot_getc#define BUF_SIZE 256struct { getc_io_funcs_t *io; int (*fun)(char *, int len, int *err); unsigned char buf[BUF_SIZE]; unsigned char *bufp; int avail, len, err; int verbose, decompress, tick;#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB int (*raw_fun)(char *, int len, int *err); _pipe_t load_pipe; unsigned char _buffer[CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER];#endif} getc_info;typedef int (*getc_t)(void);//// Read the next data byte from the stream.// Returns:// >= 0 - actual data// -1 - error or EOF, status in getc_info.err//static int redboot_getc(void){ static char spin[] = "|/-\\|-"; if (getc_info.avail < 0) { return -1; } if (getc_info.avail == 0) { if (getc_info.verbose) { diag_printf("%c\b", spin[getc_info.tick++]); if (getc_info.tick >= sizeof(spin)) { getc_info.tick = 0; } } if (getc_info.len < BUF_SIZE) { // No more data available if (getc_info.verbose) diag_printf("\n"); return -1; } getc_info.bufp = getc_info.buf; getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err); if ((getc_info.avail = getc_info.len) <= 0) { if (getc_info.len < 0) { diag_printf("I/O error: %s\n", (getc_info.io->error)(getc_info.err)); } if (getc_info.verbose) diag_printf("\n"); return -1; } } getc_info.avail--; return *getc_info.bufp++;}#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB//// Called to fetch a new chunk of data and decompress it//static int _decompress_stream(char *buf, int len, int *err){ _pipe_t* p = &getc_info.load_pipe; int res, total; total = 0; while (len > 0) { if (p->in_avail == 0) { p->in_buf = &getc_info._buffer[0]; res = (*getc_info.raw_fun)(p->in_buf, CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER, &getc_info.err); if ((p->in_avail = res) <= 0) { // No more data return total; } } p->out_buf = buf; p->out_size = 0; p->out_max = len; res = (*_dc_inflate)(p); if (res != 0) { *err = res; return total; } len -= p->out_size; buf += p->out_size; total += p->out_size; } return total;}#endifstatic intredboot_getc_init(connection_info_t *info, getc_io_funcs_t *funcs, int verbose, int decompress){ int res; res = (funcs->open)(info, &getc_info.err); if (res < 0) { diag_printf("Can't load '%s': %s\n", info->filename, (funcs->error)(getc_info.err)); return res; } getc_info.io = funcs; getc_info.fun = funcs->read; getc_info.avail = 0; getc_info.len = BUF_SIZE; getc_info.verbose = verbose; getc_info.decompress = decompress; getc_info.tick = 0;#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB if (decompress) { _pipe_t* p = &getc_info.load_pipe; p->out_buf = &getc_info.buf[0]; p->out_size = 0; p->in_avail = 0; getc_info.raw_fun = getc_info.fun; getc_info.fun = _decompress_stream; getc_info.err = (*_dc_init)(p); if (0 != getc_info.err && p->msg) { diag_printf("open decompression error: %s\n", p->msg); } }#endif return 0;}static voidredboot_getc_rewind(void){ getc_info.bufp = getc_info.buf; getc_info.avail = getc_info.len;}static voidredboot_getc_terminate(bool abort){ if (getc_info.io->terminate) { (getc_info.io->terminate)(abort, redboot_getc); }}static voidredboot_getc_close(void){ (getc_info.io->close)(&getc_info.err);#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB if (getc_info.decompress) { _pipe_t* p = &getc_info.load_pipe; int err = getc_info.err; if (0 != err && p->msg) { diag_printf("decompression error: %s\n", p->msg); } err = (*_dc_close)(p, getc_info.err); }#endif}#ifdef CYGSEM_REDBOOT_ELF//// Support function - used to read bytes into a buffer// Returns the number of bytes read (stops short on errors)//static int_read(int (*getc)(void), unsigned char *buf, int len){ int total = 0; int ch; while (len-- > 0) { ch = (*getc)(); if (ch < 0) { // EOF or error break; } *buf++ = ch; total++; } return total;}#endif//// Load an ELF [binary] image //static unsigned longload_elf_image(getc_t getc, unsigned long base){#ifdef CYGSEM_REDBOOT_ELF Elf32_Ehdr ehdr;#define MAX_PHDR 8 Elf32_Phdr phdr[MAX_PHDR]; unsigned long offset = 0; int phx, len, ch; unsigned char *addr; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; unsigned char *SHORT_DATA = "Short data reading ELF file\n"; // Read the header if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { diag_printf("Can't read ELF header\n"); return 0; } offset += sizeof(ehdr); #if 0 // DEBUG diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);#endif if (ehdr.e_type != ET_EXEC) { diag_printf("Only absolute ELF images supported\n"); return 0; } if (ehdr.e_phnum > MAX_PHDR) { diag_printf("Too many program headers\n"); return 0; } while (offset < ehdr.e_phoff) { if ((*getc)() < 0) { diag_printf(SHORT_DATA); return 0; } offset++; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { diag_printf("Can't read ELF program header\n"); return 0; }#if 0 // DEBUG diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags);#endif offset += sizeof(phdr[0]); } if (base) { // Set address offset based on lowest address in file. addr_offset = 0xFFFFFFFF; for (phx = 0; phx < ehdr.e_phnum; phx++) { if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) { addr_offset = phdr[phx].p_paddr; } } addr_offset = (unsigned long)base - addr_offset; } else { addr_offset = 0; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (phdr[phx].p_type == PT_LOAD) { // Loadable segment addr = (unsigned char *)phdr[phx].p_paddr; len = phdr[phx].p_filesz; if ((unsigned long)addr < lowest_address) { lowest_address = (unsigned long)addr; } addr += addr_offset; if (offset > phdr[phx].p_offset) { if ((phdr[phx].p_offset + len) < offset) { diag_printf("Can't load ELF file - program headers out of order\n"); return 0; } addr += offset - phdr[phx].p_offset; } else { while (offset < phdr[phx].p_offset) { if ((*getc)() < 0) { diag_printf(SHORT_DATA); return 0; } offset++; } } // Copy data into memory while (len-- > 0) {#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address(addr)) { redboot_getc_terminate(true); diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr); return 0; }#endif if ((ch = (*getc)()) < 0) { diag_printf(SHORT_DATA); return 0; } *addr++ = ch; offset++; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } } } // Save load base/top and entry if (base) { load_address = base;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -