📄 load.c
字号:
//==========================================================================
//
// load.c
//
// RedBoot file/image loader
//
//==========================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <redboot.h>
#include <xyzModem.h>
#ifdef CYGPKG_REDBOOT_DISK
#include <fs/disk.h>
#endif
// Buffer used by redboot_getc
getc_info_t getc_info;
static char usage[] = "[-r] [-v] "
#ifdef CYGPKG_COMPRESS_ZLIB
"[-d] "
#endif
"[-h <host>] [-m {TFTP | xyzMODEM"
#ifdef CYGPKG_REDBOOT_DISK
" | disk"
#endif
"}]\n [-b <base_address>] <file_name>";
// Exported CLI function
RedBoot_cmd("load",
"Load a file",
usage,
do_load
);
static unsigned long
load_elf_image(int (*getc)(void))
{
printf("ELF images not supported\n");
return 0;
}
//
// Scan a string of hex bytes and update the checksum
//
static long
_hex2(int (*getc)(void), int len, long *sum)
{
int val, byte;
char c1, c2;
val = 0;
while (len-- > 0) {
c1 = (*getc)();
c2 = (*getc)();
if (_is_hex(c1) && _is_hex(c2)) {
val <<= 8;
byte = (_from_hex(c1)<<4) | _from_hex(c2);
val |= byte;
if (sum) {
*sum += byte;
}
} else {
return (-1);
}
}
return (val);
}
//
// Process a set of S-records, loading the contents into memory.
// Note: if a "base" value is provided, the data will be relocated
// relative to that location. Of course, this can only work for
// the first section of the data, so if there are non-contiguous
// pieces of data, they will end up relocated in the same fashion.
// Because of this, "base" probably only makes sense for a set of
// data which has only one section, e.g. a ROM image.
//
#define MAX_LINE 80
static unsigned long
load_srec_image(int (*getc)(void), unsigned long base)
{
char line[MAX_LINE];
char *lp;
int c, len;
long offset = 0, count, sum, val, cksum;
unsigned char *addr, *base_addr;
char type;
bool first_addr = true;
unsigned long addr_offset = 0;
unsigned long highest_address = 0;
unsigned long lowest_address = 0xFFFFFFFF;
while ((c = (*getc)()) > 0) {
lp = line; len = 0;
// Start of line
if (c != 'S') {
printf("Invalid S-record at offset %p, input: %c\n",
(void *)offset, c);
return 0;
}
type = (*getc)();
offset += 2;
sum = 0;
if ((count = _hex2(getc, 1, &sum)) < 0) {
printf("Bad S-record count at offset %p\n", (void *)offset);
return 0;
}
offset += 1;
switch (type) {
case '0':
break;
case '1':
case '2':
case '3':
base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
offset += (type-'1'+2);
if (first_addr) {
if (base) {
addr_offset = (unsigned long)base - (unsigned long)addr;
printf("Address offset = %p\n", (void *)addr_offset);
} else {
addr_offset = 0;
}
first_addr = false;
}
addr += addr_offset;
if ((unsigned long)(addr-addr_offset) < lowest_address) {
lowest_address = (unsigned long)(addr - addr_offset);
}
#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
if ((addr < user_ram_start) || (addr > user_ram_end)) {
if (!verify_action("Attempt to load S-record data to address: %p\n"
"RedBoot does not believe this is in RAM", (void*)addr))
return 0;
}
#endif
count -= ((type-'1'+2)+1);
offset += count;
while (count-- > 0) {
val = _hex2(getc, 1, &sum);
*addr++ = val;
}
cksum = _hex2(getc, 1, 0);
offset += 1;
sum = sum & 0xFF;
cksum = (~cksum & 0xFF);
if (cksum != sum) {
printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n",
(unsigned long)base_addr, sum, cksum);
return 0;
}
if ((unsigned long)(addr-addr_offset) > highest_address) {
highest_address = (unsigned long)(addr - addr_offset);
}
break;
case '7':
case '8':
case '9':
addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
offset += ('9'-type+2);
entry_address = (unsigned long *)addr;
printf("Entry point: %p, address range: %p-%p\n",
(void*)entry_address, (void *)lowest_address, (void *)highest_address);
while ((c = (*getc)()) > 0) ; // Swallow rest of data
return highest_address;
default:
printf("Invalid S-record at offset 0x%lx, type: %x\n",
(unsigned long)offset, type);
return 0;
}
while ((c = (*getc)()) != '\n') offset++;
}
return 0;
}
int
redboot_getc(void)
{
static char spin[] = "|/-\\|-";
if (getc_info.avail < 0) {
return -1;
}
if (getc_info.avail == 0) {
if (getc_info.verbose) {
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) 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.verbose) printf("\n");
return -1;
}
}
getc_info.avail--;
return *getc_info.bufp++;
}
void
redboot_getc_init(int (*fun)(char *, int, int *), int verbose)
{
getc_info.avail = 0;
getc_info.len = BUF_SIZE;
getc_info.fun = fun;
getc_info.verbose = verbose;
getc_info.tick = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -