Beispiel #1
0
HRESULT fis_erase(CYG_ADDRESS flash_addr, unsigned long length)
{
	int stat;
	void *err_addr;

	if (((stat = flash_verify_addr((void *)flash_addr)) ||
			 (stat = flash_verify_addr((void *)(flash_addr+length-1)))))
	{
		_show_invalid_flash_address(flash_addr, stat);
		return NO_ERROR;
	}
	if (flash_addr & (flash_block_size-1))
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Invalid FLASH address: %p\n\r", (void *)flash_addr);
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "   must be 0x%x aligned\n\r", flash_block_size);
		return NO_ERROR;
	}
	// Safety check - make sure the address range is not within the code we're running
	if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1)))
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't erase this region - contains code in use!\n\r");
		return NO_ERROR;
	}
	if ((stat = fis_flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0)
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Error erasing at %p: %s\n\r", err_addr, flash_errmsg(stat));
	}
	return NO_ERROR;
}
Beispiel #2
0
HRESULT fis_write(CYG_ADDRESS mem_addr, uint32 length, CYG_ADDRESS flash_addr)
{
	int stat;
	void *err_addr;
	bool prog_ok;

	SYS_DEBUG(SYSDEBUG_TRACE_FIS, "fis_write(%x, %x, %x)\n\r", mem_addr, length, flash_addr);

	// Round up length to FLASH block size
	if (((stat = flash_verify_addr((void *)flash_addr)) ||
			 (stat = flash_verify_addr((void *)(flash_addr+length-1))))) 
	{
		_show_invalid_flash_address(flash_addr, stat);
		return NO_ERROR;
	}
	if (flash_addr & (flash_block_size-1)) 
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Invalid FLASH address: %p\n\r", (void *)flash_addr);
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "   must be 0x%x aligned\n\r", flash_block_size);
		return NO_ERROR;
	}
	if ((mem_addr < (CYG_ADDRESS)ram_start) ||
			((mem_addr+length) >= (CYG_ADDRESS)ram_end))
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "** WARNING: RAM address: %p may be invalid\n\r", (void *)mem_addr);
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "   valid range is %p-%p\n\r", (void *)ram_start, (void *)ram_end);
	}
	// Safety check - make sure the address range is not within the code we're running
	if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1)))
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't program this region - contains code in use!\n\r");
		return NO_ERROR;
	}
	prog_ok = true;
	if (prog_ok)
	{
		// Erase area to be programmed
		if ((stat = fis_flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0)
		{
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't erase region at %p: %s\n\r", err_addr, flash_errmsg(stat));
			prog_ok = false;
		}
	}
	if (prog_ok)
	{
		// Now program it
		if ((stat = fis_flash_program((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0)
		{
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "fis_write: can't program region at %p: %s\n\r", 
			err_addr, flash_errmsg(stat));

			//sysDebugPrintf("Can't program region at %p: %s\n\r", err_addr, stat);
			// prog_ok = false;
		}
	}
	return NO_ERROR;
}
Beispiel #3
0
static void
fis_unlock(int argc, char *argv[])
{
    char *name;
    int stat;
    unsigned long length;
    CYG_ADDRESS flash_addr;
    bool flash_addr_set = false;
    bool length_set = false;
    void *err_addr;
    struct option_info opts[2];

    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, 
              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, 
              (void *)&length, (bool *)&length_set, "length");
    if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
    {
        fis_usage("invalid arguments");
        return;
    }

    if (name) {
        struct fis_image_desc *img;
        if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
            diag_printf("No image '%s' found\n", name);
            return;
        }

        flash_addr = img->flash_base;
        length = img->size;
    } else  if (!flash_addr_set || !length_set) {
        fis_usage("missing argument");
        return;
    }
    if (flash_addr_set &&
        ((stat = flash_verify_addr((void *)flash_addr)) ||
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
        _show_invalid_flash_address(flash_addr, stat);
        return;
    }

    if ((stat = flash_unlock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
        diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
    }
}
Beispiel #4
0
static void
fis_erase(int argc, char *argv[])
{
    int stat;
    unsigned long length;
    CYG_ADDRESS flash_addr;
    bool flash_addr_set = false;
    bool length_set = false;
    void *err_addr;
    struct option_info opts[2];

    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, 
              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, 
              (void *)&length, (bool *)&length_set, "length");
    if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, ""))
    {
        fis_usage("invalid arguments");
        return;
    }

    if (!flash_addr_set || !length_set) {
        fis_usage("missing argument");
        return;
    }
    if (flash_addr_set &&
        ((stat = flash_verify_addr((void *)flash_addr)) ||
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
        _show_invalid_flash_address(flash_addr, stat);
        return;
    }
    if (flash_addr_set && flash_addr & (flash_block_size-1)) {
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
        return;
    }
    // Safety check - make sure the address range is not within the code we're running
    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
        diag_printf("Can't erase this region - contains code in use!\n");
        return;
    }
    if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
        diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
    }
}
Beispiel #5
0
static int
flash_fis_op2( int op, unsigned int index, struct fis_table_entry *entry)
{
   int res=0;
   CYGARC_HAL_SAVE_GP();
   switch ( op ) {
      case CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION:
         res=CYG_REDBOOT_FIS_VERSION;
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_INIT:
         __flash_init=0;  //force reinitialization
         res=do_flash_init();
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT:
         res=fisdir_size / sizeof(struct fis_image_desc);
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY:
         {
            struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
            CYG_ASSERT(entry!=0, "fis_table_entry == 0 !");
            memcpy(entry->name, img[index].u.name, 16);
            entry->flash_base=img[index].flash_base;
            entry->mem_base=img[index].mem_base;
            entry->size=img[index].size;
            entry->entry_point=img[index].entry_point;
            entry->data_length=img[index].data_length;
            entry->desc_cksum=img[index].desc_cksum;
            entry->file_cksum=img[index].file_cksum;
            res=0;
         }
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE:
         fis_start_update_directory(1);
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE:
         fis_update_directory(1, index);
         break;
      case CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY:
         {
            res=0;
            if (entry->name[0]!=0xff)
            {
               if ((entry->size==0)
                   || ((entry->size % flash_block_size) !=0)
                   || (flash_verify_addr((void*)entry->flash_base)!=0)
                   || (flash_verify_addr((void*)(entry->flash_base+entry->size-1))!=0)
                   || (entry->size < entry->data_length))
                  res=-1;
            }

            if (res==0)
            {
               struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
               memcpy(img[index].u.name, entry->name, 16);
               img[index].flash_base=entry->flash_base;
               img[index].mem_base=entry->mem_base;
               img[index].size=entry->size;
               img[index].entry_point=entry->entry_point;
               img[index].data_length=entry->data_length;
               img[index].desc_cksum=entry->desc_cksum;
               img[index].file_cksum=entry->file_cksum;
            }
         }
         break;
      default:
         break;
   }
   CYGARC_HAL_RESTORE_GP();
   return res;
}
Beispiel #6
0
void 
do_load(int argc, char *argv[])
{
    int res, num_options;
    int i, err;
    bool verbose, raw;
    bool base_addr_set, mode_str_set;
    char *mode_str;
#ifdef CYGPKG_REDBOOT_NETWORKING
    struct sockaddr_in host;
    bool hostname_set, port_set;
    unsigned int port;	// int because it's an OPTION_ARG_TYPE_NUM, 
                        // but will be cast to short
    char *hostname;
#endif
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
    bool flash_addr_set = false;
#endif
    bool decompress = false;
    int chan = -1;
#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
    bool chan_set;
#endif
    unsigned long base = 0;
    unsigned long end = 0;
    char type[4];
    char *filename = 0;
    struct option_info opts[9];
    connection_info_t info;
    getc_io_funcs_t *io = NULL;
    struct load_io_entry *io_tab;
#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
    bool spillover_ok = false;
#endif

#ifdef CYGPKG_REDBOOT_NETWORKING
    memset((char *)&host, 0, sizeof(host));
    host.sin_len = sizeof(host);
    host.sin_family = AF_INET;
    host.sin_addr = my_bootp_info.bp_siaddr;
    host.sin_port = 0;
#endif

    init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, 
              (void *)&verbose, 0, "verbose");
    init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, 
              (void *)&raw, 0, "load raw data");
    init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM, 
              (void *)&base, (bool *)&base_addr_set, "load address");
    init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR, 
              (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)");
    num_options = 4;
#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
    init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM, 
              (void *)&chan, (bool *)&chan_set, "I/O channel");
    num_options++;
#endif
#ifdef CYGPKG_REDBOOT_NETWORKING
    init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR, 
              (void *)&hostname, (bool *)&hostname_set, "host name or IP address");
    num_options++;
    init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM, 
              (void *)&port, (bool *)&port_set, "TCP port");
    num_options++;
#endif
#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
    init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, 
              (void *)&decompress, 0, "decompress");
    num_options++;
#endif
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
    init_opts(&opts[num_options], 'f', true, OPTION_ARG_TYPE_NUM,
              (void *)&base, (bool *)&flash_addr_set, "flash address");
    num_options++;
#endif
    CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
    
    if (!scan_opts(argc, argv, 1, opts, num_options, 
                   (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) {
        return;
    }
#ifdef CYGPKG_REDBOOT_NETWORKING
    if (hostname_set) {
        ip_route_t rt;
        if (!_gethostbyname(hostname, (in_addr_t *)&host)) {
            err_printf("Invalid host: %s\n", hostname);
            return;
        }
        /* check that the host can be accessed */
        if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) {
            err_printf("Unable to reach host %s (%s)\n",
                        hostname, inet_ntoa((in_addr_t *)&host));
            return;
        }
    }
    if (port_set) 
	    host.sin_port = port;
#endif
    if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
        err_printf("Invalid I/O channel: %d\n", chan);
        return;
    }
    if (mode_str_set) {
        for (io_tab = __RedBoot_LOAD_TAB__; 
             io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
            if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) {
                io = io_tab->funcs;
                break;
            }
        }
        if (!io) {
            diag_printf("Invalid 'mode': %s.  Valid modes are:", mode_str);
            for (io_tab = __RedBoot_LOAD_TAB__; 
                 io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
                diag_printf(" %s", io_tab->name);
            }
            err_printf("\n");
        }
        if (!io) {
            return;
        }
        verbose &= io_tab->can_verbose;
        if (io_tab->need_filename && !filename) {
            diag_printf("File name required\n");
            err_printf("usage: load %s\n", usage);
            return;
        }
    } else {
        char *which = "";
        io_tab = (struct load_io_entry *)NULL;  // Default
#ifdef CYGPKG_REDBOOT_NETWORKING
#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD        
        which = "TFTP";
        io = &tftp_io;
#elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD)
        which = "HTTP";
        io = &http_io;
#endif
#endif
#if 0 //def CYGPKG_REDBOOT_FILEIO
        // Make file I/O default if mounted
	if (fileio_mounted) {
	    which = "file";
	    io = &fileio_io;
	}
#endif
        if (!io) {
#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
            which = "Xmodem";
            io = &xyzModem_io;
            verbose = false;
#else
            err_printf("No default protocol!\n");
            return;
#endif
        }
        diag_printf("Using default protocol (%s)\n", which);
    }
#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
#ifdef  CYGBLD_REDBOOT_LOAD_INTO_FLASH
    if (flash_addr_set && flash_verify_addr((unsigned char *)base)) {
        if (!verify_action("Specified address (%p) is not believed to be in FLASH", (void*)base))
          return;
        spillover_ok = true;
    }
#endif
    if (base_addr_set && !valid_address((unsigned char *)base)) {
        if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
            return;
        spillover_ok = true;
    }
#endif
    if (raw && !(base_addr_set 
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
                || flash_addr_set
#endif
        )) {
        err_printf("Raw load requires a memory address\n");
        return;
    }
    info.filename = filename;
    info.chan = chan;
    info.mode = io_tab ? io_tab->mode : 0;
#ifdef CYGPKG_REDBOOT_NETWORKING
    info.server = &host;
#endif
    res = redboot_getc_init(&info, io, verbose, decompress);
    if (res < 0) {
        return;
    }
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
    flash_load_start();
#endif
    // Stream open, process the data
    if (raw) {
        unsigned char *mp = (unsigned char *)base;
        err = 0;
        while ((res = redboot_getc()) >= 0) {
#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
            if (flash_addr_set && flash_verify_addr(mp) && !spillover_ok) {
                // Only if there is no need to stop the download
                // before printing output can we ask confirmation
                // questions.
                redboot_getc_terminate(true);
                err_printf("*** Abort! RAW data spills over limit of FLASH at %p\n",(void*)mp);
                err = -1;
                break;
            }
#endif
            if (base_addr_set && !valid_address(mp) && !spillover_ok) {
                // Only if there is no need to stop the download
                // before printing output can we ask confirmation
                // questions.
                redboot_getc_terminate(true);
                err_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
                err = -1;
                break;
            }
#endif
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
            if (flash_addr_set) {
              flash_load_write(mp, res);
              mp++;
              res++;
            } else
#endif
            *mp++ = res;
        }
        end = (unsigned long) mp;

        // Save load base/top
        load_address = base;
        load_address_end = end;
        entry_address = base;           // best guess

        redboot_getc_terminate(false);
        if (0 == err)
            diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", 
                        (void *)base, (void *)(end - 1), (void*)base);
    } else {
        // Read initial header - to determine file [image] type
        for (i = 0;  i < sizeof(type);  i++) {
            if ((res = redboot_getc()) < 0) {
                err = getc_info.err;
                break;
            } 
            type[i] = res;
        }
        if (res >= 0) {
            redboot_getc_rewind();  // Restore header to stream
            // Treat data as some sort of executable image
            if (strncmp(&type[1], "ELF", 3) == 0) {
                end = load_elf_image(redboot_getc, base);
            } else if ((type[0] == 'S') &&
                       ((type[1] >= '0') && (type[1] <= '9'))) {
		end = load_srec_image(redboot_getc, base);
            } else {
                redboot_getc_terminate(true);
                err_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
            }
        }
    }
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
    flash_load_finish();
#endif

    redboot_getc_close();  // Clean up
    return;
}
Beispiel #7
0
//
// 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.
//
static unsigned long
load_srec_image(getc_t getc, unsigned long base)
{
    int  c;
    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) {
        // Start of line
        if (c != 'S') {
            redboot_getc_terminate(true);
            err_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) {
            redboot_getc_terminate(true);
            err_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;
                } 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 (!(valid_address(addr)
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
                  || (flash_verify_addr(addr) == FLASH_ERR_OK)
#endif
                  )) {
	      // Only if there is no need to stop the download before printing
	      // output can we ask confirmation questions.
                redboot_getc_terminate(true);
		err_printf("*** Abort! Attempt to load S-record to address: %p, which is not valid\n",(void*)addr);
                return 0;
            }
#endif
            count -= ((type-'1'+2)+1);
            offset += count;
            while (count-- > 0) {
                val = _hex2(getc, 1, &sum);
                if (valid_address(addr)) {
                  *addr++ = val;
                }
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
                else {
                  flash_load_write(addr, val);
                  addr++;
                }
#endif
            }
            cksum = _hex2(getc, 1, 0);
            offset += 1;
            sum = sum & 0xFF;
            cksum = (~cksum & 0xFF);
            if (cksum != sum) {
                redboot_getc_terminate(true);
                err_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);
            // Save load base/top, entry address
            if (base) {
                load_address = base;
                load_address_end = base + (highest_address - lowest_address);
                entry_address = (unsigned long)(base + (addr - lowest_address));
            } else {
                load_address = lowest_address;
                load_address_end = highest_address;
                entry_address = (unsigned long)addr;
            }
            redboot_getc_terminate(false);
            if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
            diag_printf("Entry point: %p, address range: %p-%p\n", 
                   (void*)entry_address, (void *)load_address, (void *)load_address_end);

            return load_address_end;
        default:
            redboot_getc_terminate(true);
            err_printf("Invalid S-record at offset 0x%lx, type: %x\n", 
                   (unsigned long)offset, type);
            return 0;
        }
        while ((c = (*getc)()) != '\n') offset++;
    }
    return 0;
}
Beispiel #8
0
//
// 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)) {
        err_printf("Can't read ELF header\n");
        redboot_getc_terminate(true);
        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) {
        err_printf("Only absolute ELF images supported\n");
        redboot_getc_terminate(true);
        return 0;
    }
    if (ehdr.e_phnum > MAX_PHDR) {
        err_printf("Too many program headers\n");
        redboot_getc_terminate(true);
        return 0;
    }
    while (offset < ehdr.e_phoff) {
        if ((*getc)() < 0) {
            err_printf(SHORT_DATA);
            redboot_getc_terminate(true);
            return 0;
        }
        offset++;
    }
    for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
        if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) {
            err_printf("Can't read ELF program header\n");
            redboot_getc_terminate(true);
            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++) {
#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS     
            if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) {
                addr_offset = phdr[phx].p_vaddr;
#else
            if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) {
                addr_offset = phdr[phx].p_paddr;
#endif
            }
        }
        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
#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
            addr = (unsigned char *)phdr[phx].p_vaddr;
#else     
            addr = (unsigned char *)phdr[phx].p_paddr;
#endif
            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) {
                    err_printf("Can't load ELF file - program headers out of order\n");
                    redboot_getc_terminate(true);
                    return 0;
                }
                addr += offset - phdr[phx].p_offset;
            } else {
                while (offset < phdr[phx].p_offset) {
                    if ((*getc)() < 0) {
                        err_printf(SHORT_DATA);
                        redboot_getc_terminate(true);
                        return 0;
                    }
                    offset++;
                }
            }

            // Copy data into memory
            while (len-- > 0) {
#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
                if (!(valid_address(addr) 
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
                    || (flash_verify_addr(addr) == FLASH_ERR_OK)
#endif
                    )) {
                    redboot_getc_terminate(true);
                    err_printf("*** Abort! Attempt to load ELF data to address: %p which is not valid\n", (void*)addr);
                    return 0;
                }
#endif
                if ((ch = (*getc)()) < 0) {
                    err_printf(SHORT_DATA);
                    redboot_getc_terminate(true);
                    return 0;
                }
                if (valid_address(addr)) {
                  *addr++ = ch;
                }
#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
                else {
                  flash_load_write(addr, ch);
                  addr++;
                }
#endif
                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;
        load_address_end = base + (highest_address - lowest_address);
        entry_address = base + (ehdr.e_entry - lowest_address);
    } else {
        load_address = lowest_address;
        load_address_end = highest_address;
        entry_address = ehdr.e_entry;
    }

    // nak everything to stop the transfer, since redboot
    // usually doesn't read all the way to the end of the
    // elf files.
    redboot_getc_terminate(true);
    if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
    diag_printf("Entry point: %p, address range: %p-%p\n", 
                (void*)entry_address, (void *)load_address, (void *)load_address_end);
    return 1;
#else // CYGSEM_REDBOOT_ELF
    err_printf("Loading ELF images not supported\n");
    return 0;
#endif // CYGSEM_REDBOOT_ELF
}
Beispiel #9
0
static void
fis_create(int argc, char *argv[])
{
    int i, stat;
    unsigned long length, img_size;
    CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
    char *name;
    bool mem_addr_set = false;
    bool exec_addr_set = false;
    bool entry_addr_set = false;
    bool flash_addr_set = false;
    bool length_set = false;
    bool img_size_set = false;
    bool no_copy = false;
    void *err_addr;
    struct fis_image_desc *img = NULL;
    bool defaults_assumed;
    struct option_info opts[7];
    bool prog_ok = true;

    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
              (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
    init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM, 
              (void *)&exec_addr, (bool *)&exec_addr_set, "ram base address");
    init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM, 
              (void *)&entry_addr, (bool *)&entry_addr_set, "entry point address");
    init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM, 
              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, 
              (void *)&length, (bool *)&length_set, "image length [in FLASH]");
    init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM, 
              (void *)&img_size, (bool *)&img_size_set, "image size [actual data]");
    init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG, 
              (void *)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory");
    if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name"))
    {
        fis_usage("invalid arguments");
        return;
    }

    fis_read_directory();
    defaults_assumed = false;
    if (name) {
        // Search existing files to acquire defaults for params not specified:
        img = fis_lookup(name, NULL);
        if (img) {
            // Found it, so get image size from there
            if (!length_set) {
                length_set = true;
                length = img->size;
                defaults_assumed = true;
            }
        }
    }
    if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
	(load_address_end) < (CYG_ADDRESS)ram_end) {
	mem_addr = load_address;
	mem_addr_set = true;
        defaults_assumed = true;
        // Get entry address from loader, unless overridden
        if (!entry_addr_set)
            entry_addr = entry_address;
	if (!length_set) {
	    length = load_address_end - load_address;
	    length_set = true;
	} else if (defaults_assumed && !img_size_set) {
	    /* We got length from the FIS table, so the size of the
	       actual loaded image becomes img_size */
	    img_size = load_address_end - load_address;
	    img_size_set = true;
	}
    }
    // Get the remaining fall-back values from the fis
    if (img) {
        if (!exec_addr_set) {
            // Preserve "normal" behaviour
            exec_addr_set = true;
            exec_addr = flash_addr_set ? flash_addr : mem_addr;
        }
        if (!flash_addr_set) {
            flash_addr_set = true;
            flash_addr = img->flash_base;
            defaults_assumed = true;
        }
    }

    if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
        !length_set || !name) {
        fis_usage("required parameter missing");
        return;
    }
    if (!img_size_set) {
        img_size = length;
    }
    // 'length' is size of FLASH image, 'img_size' is actual data size
    // Round up length to FLASH block size
#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
    length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
    if (length < img_size) {
        diag_printf("Invalid FLASH image size/length combination\n");
        return;
    }
#endif
    if (flash_addr_set &&
        ((stat = flash_verify_addr((void *)flash_addr)) ||
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
        _show_invalid_flash_address(flash_addr, stat);
        return;
    }
    if (flash_addr_set && ((flash_addr & (flash_block_size-1)) != 0)) {
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
        return;
    }
    if (strlen(name) >= sizeof(img->name)) {
        diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name));
        return;
    }
    if (!no_copy) {
        if ((mem_addr < (CYG_ADDRESS)ram_start) ||
            ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
            diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
            diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
        }
        if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
            diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
            return;
        }
    }
    // First, see if the image by this name has agreable properties
    if (img) {
        if (flash_addr_set && (img->flash_base != flash_addr)) {
            diag_printf("Image found, but flash address (%p)\n"
                        "             is incorrect (present image location %p)\n",
                        flash_addr, img->flash_base);
            
            return;
        }
        if (img->size != length) {
            diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
                        "             is incorrect (present image size 0x%lx)\n",
                        img_size, length, img->size);
            return;
        }
        if (!verify_action("An image named '%s' exists", name)) {
            return;
        } else {                
            if (defaults_assumed) {
                if (no_copy &&
                    !verify_action("* CAUTION * about to program '%s'\n            at %p..%p from %p", 
                                   name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
                                   (void *)mem_addr)) {
                    return;  // The guy gave up
                }
            }
        }
    } else {
#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
        // Make sure that any FLASH address specified directly is truly free
        if (flash_addr_set && !no_copy) {
            struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
            int idx, num_chunks;
            bool is_free = false;

            num_chunks = find_free(chunks);
            for (idx = 0;  idx < num_chunks;  idx++) {
                if ((flash_addr >= chunks[idx].start) && 
                    ((flash_addr+length-1) <= chunks[idx].end)) {
                    is_free = true;
                }
            }
            if (!is_free) {
                diag_printf("Invalid FLASH address - not free!\n");
                return;
            }
        }
#endif
        // If not image by that name, try and find an empty slot
        img = (struct fis_image_desc *)fis_work_block;
        for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
            if (img->name[0] == (unsigned char)0xFF) {
                break;
            }
        }
    }
    if (!no_copy) {
        // Safety check - make sure the address range is not within the code we're running
        if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
            diag_printf("Can't program this region - contains code in use!\n");
            return;
        }
        if (prog_ok) {
            // Erase area to be programmed
            if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
                diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
                prog_ok = false;
            }
        }
        if (prog_ok) {
            // Now program it
            if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, (void **)&err_addr)) != 0) {
                diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
                prog_ok = false;
            }
        }
    }
    if (prog_ok) {
        // Update directory
        memset(img, 0, sizeof(*img));
        strcpy(img->name, name);
        img->flash_base = flash_addr;
        img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr);
        img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
        img->size = length;
        img->data_length = img_size;
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
        if (!no_copy) {
            img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
        } else {
            // No way to compute this, sorry
            img->file_cksum = 0;
        }
#endif
        fis_update_directory();
    }
}
Beispiel #10
0
static void
fis_write(int argc, char *argv[])
{
    int stat;
    unsigned long length;
    CYG_ADDRESS mem_addr, flash_addr;
    bool mem_addr_set = false;
    bool flash_addr_set = false;
    bool length_set = false;
    void *err_addr;
    struct option_info opts[3];
    bool prog_ok;

    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
              (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
    init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM, 
              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
    init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM, 
              (void *)&length, (bool *)&length_set, "image length [in FLASH]");
    if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
    {
        fis_usage("invalid arguments");
        return;
    }

    if (!mem_addr_set || !flash_addr_set || !length_set) {
        fis_usage("required parameter missing");
        return;
    }

    // Round up length to FLASH block size
#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
    length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
#endif
    if (flash_addr_set &&
        ((stat = flash_verify_addr((void *)flash_addr)) ||
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
        _show_invalid_flash_address(flash_addr, stat);
        return;
    }
    if (flash_addr_set && flash_addr & (flash_block_size-1)) {
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
        return;
    }
    if ((mem_addr < (CYG_ADDRESS)ram_start) ||
        ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
        diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
        diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
    }
    // Safety check - make sure the address range is not within the code we're running
    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
        diag_printf("Can't program this region - contains code in use!\n");
        return;
    }
    if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p", 
                       (void *)flash_addr, (void *)(flash_addr+length-1),
                       (void *)mem_addr)) {
        return;  // The guy gave up
    }
    prog_ok = true;
    if (prog_ok) {
        // Erase area to be programmed
        if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
            diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
            prog_ok = false;
        }
    }
    if (prog_ok) {
        // Now program it
        if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) {
            diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
            prog_ok = false;
        }
    }
}
Beispiel #11
0
HRESULT fis_create_progress(CYG_ADDRESS mem_addr, uint32 length, 
		   CYG_ADDRESS exec_addr, CYG_ADDRESS entry_addr,
		   char *name, BOOL bDeleteIfNeeded, FIS_PROGRESS_FUNC progressFunc)
{
	int stat, i;
	unsigned long img_size;
	CYG_ADDRESS flash_addr;
	void *err_addr;
	struct fis_image_desc *img = NULL;
	BOOL bFlashAddrGood = FALSE;
	BOOL bDelOldImage = FALSE;
	FIS_PROGRESS_STRUCT progress;

	memset (&progress,0,sizeof(progress));
	memcpy(fis_work_block, fis_addr, fisdir_size);

	img_size = length;

	// 'length' is size of FLASH image, 'img_size' is actual data size
	// Round up length to FLASH block size
	length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
	if (length < img_size) 
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r");
		return E_FIS_ILLEGAL_IMAGE;
	}

	if (!name)
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r");
		return E_FIS_ILLEGAL_IMAGE;
	}
	if (strlen(name) >= sizeof(img->name))
	{
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r");
		return E_FIS_ILLEGAL_IMAGE;
	}

	// Search existing files to acquire defaults for params not specified:
	img = fis_lookup(name, NULL);

	// If we have an image we need to check if it is any good
	if (img) 
	{
		if (length != img->size)
		{
			//in this case we either return an error or delete the old image
			if (!bDeleteIfNeeded) 
			{	
				SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Image already exist with different size\n\r");
				return E_FIS_ILLEGAL_IMAGE;
			}
			//We need to remember to delete the image
			bDelOldImage = TRUE;
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Delete old image\n\r");
		}
		else
		{
			bFlashAddrGood = TRUE;
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Reuse old image\n\r");
		}
	}
	else
	{
		//need to find a new free image
		img = (struct fis_image_desc *)fis_work_block;
		for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++)
		{
			if (img->name[0] == (unsigned char)0xFF) break;
		}
		if (img->name[0] != (unsigned char)0xFF)
		{
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "No more directory entries\n\r");
			return E_FIS_NO_SPACE;
		}
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Using new image\n\r");
	}
	//we definitely have an img pointer which is valid
	//Let's figure out the work we need to do for the progress info
	if (progressFunc) 
	{
		progress.func = progressFunc;
		progress.procur = 0;
		progress.promax = fis_flash_program_progressinfo(img_size);
		if (bDelOldImage || bFlashAddrGood) progress.promax += fis_flash_erase_progressinfo (img->size);
		if (!bFlashAddrGood) progress.promax += fis_flash_erase_progressinfo (length);
		progress.promax += 10; //to update the directory 		
		progressFunc(progress.promax, progress.procur);
	}

	if (bDelOldImage || bFlashAddrGood)
	{
	  if ((stat = fis_flash_erase_progress((void *)img->flash_base, img->size, &err_addr, &progress )) != 0)
		{	
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash Erase failed\n\r");
			return E_FIS_FLASH_OP_FAILED;
		}
	}
	if (!bFlashAddrGood)
	{
		//we need to find space
		if (!fis_find_free(&flash_addr, length))
		{	
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "No free space in flash\n\r");
			return E_FIS_NO_SPACE;
		}
	} 
	else
	{
		flash_addr = img->flash_base;
	}
	//at this point we have erased old stuff if needed and we are ready to program

	if (((stat = flash_verify_addr((void *)flash_addr)) ||
			 (stat = flash_verify_addr((void *)(flash_addr+img_size-1)))))
	{
		//this should not happen, it is an internal error
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error, illegal flash address\n\r");
		return E_FIS_FLASH_OP_FAILED;
	}
	if (flash_addr & (flash_block_size-1))
	{
		//this should not happen, it is an internal error
		SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error, illegal flash address\n\r");
		return E_FIS_FLASH_OP_FAILED;
	}

	// We need to erase the new are we found but it is likely clean so we will not progress it
	// as it will only be a blank check
	if (!bFlashAddrGood)
	{
	  if ((stat = fis_flash_erase_progress((void *)img->flash_base, img->size, &err_addr, &progress)) != 0)
		{	
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash erase failed\n\r");
			return E_FIS_FLASH_OP_FAILED;
		}		
	}

	if (mem_addr!=0xffffffff) //ML:Create image without programming if addr=0xffffffff
	{
		// Now program it
		if ((stat = fis_flash_program_progress((void *)flash_addr, (void *)mem_addr, img_size, &err_addr,&progress)) != 0)
		{
			SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash program failed\n\r");
			return E_FIS_FLASH_OP_FAILED;
		}
	}
	// Update directory
	memset(img, 0, sizeof(*img));
	strcpy(img->name, name);
	img->flash_base = flash_addr;
	img->mem_base = exec_addr;
	img->entry_point = entry_addr;  // Hope it's been set
	img->size = length;
	img->data_length = img_size;
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
	img->file_cksum = cyg_crc32((unsigned char *)flash_addr, img_size);
#endif
	fis_update_directory();
	if (progressFunc) progressFunc(progress.promax, progress.promax);
	return NO_ERROR;
}