📄 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 macros
static 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 function
RedBoot_cmd("load",
"Load a file",
usage,
do_load
);
//
// Stream I/O support
//
// Table describing the various I/O methods
CYG_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 256
struct {
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;
}
#endif
static int
redboot_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 void
redboot_getc_rewind(void)
{
getc_info.bufp = getc_info.buf;
getc_info.avail = getc_info.len;
}
static void
redboot_getc_terminate(bool abort)
{
if (getc_info.io->terminate) {
(getc_info.io->terminate)(abort, redboot_getc);
}
}
static void
redboot_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 long
load_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 + -