view fluid-mnf/fileio.c @ 320:20feaf83c661

frbl/reconst/convert.c: better match to original object still not perfect though
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 05 Mar 2020 05:01:14 +0000
parents 9cecc930d78f
children b730c7844233
line wrap: on
line source

/******************************************************************************
 * FLUID (Flash Loader Utility Independent of Device)
 *
 * Copyright Texas Instruments, 2001.
 * Mads Meisner-Jensen, mmj@ti.com.
 *
 * File reading/loading
 *
 * $Id: fileio.c 1.24 Mon, 28 Apr 2003 08:49:16 +0200 tsj $
 *
 ******************************************************************************/

#include "fluid.h"
#include "flash.h"
#include "fileio.h"
#include "misc.h"
#include "trace.h"
#include "../target/target.h"
#include "../inc/secure_types.h"   // Secure Calypso Plus

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>


/******************************************************************************
 * Globals
 ******************************************************************************/

// Secure Calypso Plus
extern int bootloader_is_secure_rom;
extern int a_certified_cmd_file_name;

#define HEX_MOTOROLA_LINE_SIZE 32 // number of bytes in each line
#define HEX_MOTOROLA_ADDR_SIZE 32 // number of bits in addresses (16, 24 or 32)


struct {
    char   type;
    char   size;
    uint32 addr;
    uint8  data[128];
    uint8  dummy; // required - don't remove!
} mhex;


int hexfile_read(char *name, char *buf, int buf_size,
                 char *usage_map, int usage_map_chunk_size);
int hexline_motorola_read(char* line);
int hextoint(char *src, int digits);
void hextobytes(uint8 *dst, char *src, int bytes);

int hexblock_write(char *buf, int size, unsigned long addr, int addr_size,
                   char hexfile_type);
int hexline_motorola_write(char *buf, int size,
                           unsigned long addr, int addr_size);
int hexfile_write_open(char *name, char hexfile_type, char *buf, int size);
int hexfile_write_close(char hexfile_type, int addr_size);

/******************************************************************************
 * File Reading
 ******************************************************************************/

// Convert image from one endian type to another. The memory width is
// specified with <width>.
void buffer_endian_convert(unsigned char *buf, int buf_size, int width)
{
    unsigned char tmp1, tmp2;
    int i;

    tr(TrHexWrite, "buffer_endian_convert(*, %d, %d)\n", buf_size, width);

    for (i = 0; i < buf_size; i += width) {
        if (width == 16 || width == 2) {
            tmp1     = buf[i+0];
            buf[i+0] = buf[i+1];
            buf[i+1] = tmp1;
        }
        else if (width == 32 || width == 4) {
            tmp1     = buf[i+0];
            tmp2     = buf[i+1];
            buf[i+0] = buf[i+3];
            buf[i+1] = buf[i+2];
            buf[i+2] = tmp2;
            buf[i+3] = tmp1;
        }
    }
}

int file_read_rc(char *filename)
{
    // TODO: Read the .fluidrc file. It can contain the following
    // directives:
    //
    // path = <path>  /* semi-colon? separated list of directories in which
    //                   to look for m0 files etc. */
    // target = [h]|[c]
    // baudrate = <baudrate>
    // port = <port>
    // more?

    return 0;
}

extern void tr_image_usage_map(void);

int file_read_image(char *image, int image_size,
                    char *usage_map, int usage_map_chunk_size)
{
    int size, size_total = 0, i = 0;
    int time_load;

    flowf(NORMAL, "Reading image file:");

    memset(image,     0xFF, image_size);
    memset(usage_map, 0,    image_size / usage_map_chunk_size);

    if (arg_file_list[0] == NULL)
        main_warning(E_FILE_INPUT);

    time_load = stopwatch_start();

    while (arg_file_list[i] != NULL)
    {
        flowf(NORMAL, " '%s'", arg_file_list[i]);
        if ((size = hexfile_read(arg_file_list[i], image, image_size,
                                 usage_map, usage_map_chunk_size)) < 0) {
            flowf(ALWAYS, " MESSAGE: File '%s' not found\n", arg_file_list[i]);
            main_error(size);
        }

        size_total += size;
        flowf(NORMAL, " (%dkB)", (size + 512) / 1024);

        i++;
        if (arg_file_list[i] != NULL)
            flowf(NORMAL, ",");
    }
    time_load = (stopwatch_stop(time_load) + 50) /100;
    flowf(BLABBER, " (%d.%ds)", time_load / 10, time_load % 10);
    flowf(NORMAL, " ok\n");

    // Now convert image from big endian to little endian format
    buffer_endian_convert(image, image_size, arg_hexfile_memwidth);

    return size_total;
}

int file_read_cmd(char *image, int image_size, char *filename)
{
    //char filename[20] = "cmd.m0";

    memset(image, 0, image_size);

    flowf(BLABBER, "Reading cmd file '%s': ", filename);
    if ((image_size = hexfile_read(filename, image, image_size, 0, 0)) < 0) {
        flowf(ALWAYS, "MESSAGE: File '%s' not found\n", filename);
        main_error(image_size);
    }
    flowf(BLABBER, "(%dB) ok\n", image_size);

    return image_size;
}

int file_read_method(char *image, int image_size, struct device_s *device)
{
    char filename[20];

    strncpy(filename,
            algorithm_name_lookup_by_id(device->algorithm_id),
            20 - sizeof(".m0"));
    strcat(filename, ".m0");

    memset(image, 0, image_size);

    flowf(BLABBER, "Reading method file '%s': ", filename);
    if ((image_size = hexfile_read(filename, image, image_size, 0, 0)) < 0) {
        flowf(ALWAYS, "MESSAGE: File '%s' not found\n", filename);
        main_error(image_size);
    }
    flowf(BLABBER, "(%dB) ok\n", image_size);

    return image_size;
}


/******************************************************************************
 * Hex File Read Functions
 ******************************************************************************/

// Read an input file in Motorola (or Intel) hex format. On success, return
// the number of raw data bytes read.
int hexfile_read(char *filename, char *buf, int buf_size,
                 char *usage_map, int usage_map_chunk_size)
{
    FILE* stream;
    char line[100];
    uint32 addr;
    int type, mysize = 0;

    // First look for file in current directory. Then look for it in the
    // directory where the fluid executable was found.
    flowf(DEBUG, "(looking for '%s') ", filename);

    if ((stream = fopen(filename, "rt")) == NULL)
    {
        char buf[256];

        flowf(DEBUG, "(oops) ");

        if (pathname_make(buf, sizeof(buf), argv_0, filename) < 0)
            return E_BUFFER;

        flowf(DEBUG, "(looking for '%s') ", buf);

        if ((stream = fopen(buf, "rt")) == NULL)
            return E_FILE_OPEN;
    }
    flowf(DEBUG, "(ok) ");

    // TODO?: Read the first character of the file and determine the file
    // type this way (Motorola format, Intel format or .out format)
    type = 'S';

    while (fgets(line, 100, stream) != NULL) {
        switch (type) {
        case 'S':
            if (hexline_motorola_read(line)) {
                mysize += (int) mhex.size;

                // Secure Calypso Plus
                if (bootloader_is_secure_rom &&
                   strcmp(filename, (char *)&a_certified_cmd_file_name) == 0 &&
                    mhex.addr >= CMD_SECURE_CALP_OFFSET) {
                    // The flash programmer is linked to 0x08020000 in internal
                    // SRAM.
                    addr = mhex.addr - CMD_SECURE_CALP_OFFSET;
                }
                else if (mhex.addr >= CALP_OFFSET)
                    // Assume linked to Calypso Plus (0x04000000 Flash Base)
                    addr = mhex.addr - CALP_OFFSET;
                else
                    addr = mhex.addr;

                if (addr > (uint32) buf_size) {
                    fprintf(stderr, "Address too big: 0x%08X\n", (int) addr);
                    return E_FILE_BUF_SMALL;
                }
                memcpy(&buf[addr], &mhex.data[0], mhex.size);
                // Update the image usage map
                if (usage_map != NULL) {
                    usage_map[(addr) / usage_map_chunk_size] = 'x';
                    usage_map[(addr + mhex.size - 1) / usage_map_chunk_size] = 'x';
                }
            }
            break;
        case '?':
            // Intel format
            break;
        case 'O':
            // .out format
            break;
        default:
            return E_FILE_FORMAT;
        }
    }
    fclose(stream);

    return mysize;
}

// Read and decode one line of a Motorola hex file.
// Original design and code by Delta Technologies, 2001.
int hexline_motorola_read(char* line)
{
    mhex.type = (uint8) line[1] - '0';
    mhex.size = hextoint(&line[2], 2);

    tr(TrHexRead, "S%d%02X", mhex.type, mhex.size);

    switch (mhex.type) {
    case 0:
        // First record in file - no action required
        mhex.size = 0;
        break;
    case 1:
        // Data record 16-bit address: S1nnAAAAxxxxxxxxxxxxxxxCC
        mhex.size -= 3;
        mhex.addr = hextoint(&line[4], 4);
        tr(TrCont|TrHexRead, "%04X", mhex.addr);
        hextobytes(&mhex.data[0], &line[8], mhex.size);
        break;
    case 2:
        // Data record 24-bit address: S2nnAAAAAAxxxxxxxxxxxxxxxCC
        mhex.size -= 4;
        mhex.addr = hextoint(&line[4], 6);
        tr(TrCont|TrHexRead, "%06X", mhex.addr);
        hextobytes(&mhex.data[0], &line[10], mhex.size);
        break;
    case 3:
        // Data record 32-bit address: S3nnAAAAAAAAxxxxxxxxxxxxxxxCC
        mhex.size -= 5;
        mhex.addr = hextoint(&line[4], 8);
        tr(TrCont|TrHexRead, "%08X", mhex.addr);
        hextobytes(&mhex.data[0], &line[12], mhex.size);
        break;
    case 7:
        // End of file record 32-bit address
        mhex.size = 0;
        break;
    case 8:
        // End of file record 24-bit address
        mhex.size = 0;
        break;
    case 9:
        // End of file record 16-bit address
        mhex.size = 0;
        break;
    default:
        fprintf(stderr, "WARNING: Illegal hex line: %s\n", line);
        main_error(E_FILE_FORMAT);
    }
    tr(TrCont|TrHexRead, "\n");

    return mhex.size;
}

int hextoint(char *src, int digits)
{
    int number = 0;
    char ch;

    while (digits-- && *src) {
        ch = *src++;
        if (ch >= '0' && ch <= '9')
            ch = ch - '0';
        else if (ch >= 'A' && ch <= 'F')
            ch = ch - 'A' + 10;
        else if (ch >= 'a' && ch <= 'f')
            ch = ch - 'a' + 10;
        else
            break;
        number = (number << 4) + ch;
    }
    return number;
}

void hextobytes(uint8 *dst, char *src, int bytes)
{
    while (bytes-- && *src) {
        *dst++ =
            (src[0] - (src[0] <= '9' ? '0' : 'A' - 10)) * 16 +
            (src[1] - (src[1] <= '9' ? '0' : 'A' - 10));
        src += 2;
        tr(TrCont|TrHexRead, "%02X", dst[-1]);
    }
}


/******************************************************************************
 * File Writing
 ******************************************************************************/

static FILE* ostream;

int file_write_image(char *image, int image_size,
                     struct image_part_s *image_list)
{
    int size, size_total = 0;
    struct image_part_s *image_list_start = image_list;

    if (arg_show_hexdump == 0 && arg_file_list[0] == NULL)
        main_fatal(E_FILE_OUTPUT);

    if (arg_file_list[1] != NULL)
        main_fatal(E_ARG_MULTI);

    if (arg_file_list[0] != NULL)
    {
        flowf(NORMAL, "Writing flash image file: '%s' ", arg_file_list[0]);

        if ((size = hexfile_write_open(arg_file_list[0], arg_hexfile_type,
                                       image, image_size)) < 0)
            main_error(size);

        while (image_list->size != 0)
        {
            // Note that we wrap/mirror memory each 'image_size' bytes
            if ((size =
                 hexblock_write(&image[image_list->addr & (image_size - 1)],
                                image_list->size,
                                image_list->addr, 32,
                                arg_hexfile_type)) < 0)
                main_error(E_FILE_BUF_SMALL);

            size_total += size;
            flowf(NORMAL, "(%dkB) ", (size + 512) / 1024);
            image_list++;
        }
        if (hexfile_write_close(arg_hexfile_type, 32) < 0)
            main_error(E_FILE_CLOSE);

        flowf(NORMAL, " ok\n");
    }

    if (arg_show_hexdump) {
        image_list = image_list_start;
        while (image_list->size != 0)
        {
            hexdump(&image[image_list->addr & (image_size - 1)],
                    image_list->size,
                    image_list->addr, 1);
            putchar('\n');
            image_list++;
        }
    }

    return size_total;
}

int file_write_die_id(unsigned char *die_id, char *filename) {
    int i;

    if (arg_hexfile_type == 'b') {
        // Binary write
        if ((ostream = fopen(filename, "wb")) == NULL)
            return E_FILE_OPEN;

        if (fwrite(die_id, C_WORD32LGB * C_DIE_ID_SIZE, 1, ostream) < 0)
            return E_FILE_WRITE;
    }
    else {
        // Text write
        if ((ostream = fopen(filename, "wt")) == NULL)
            return E_FILE_OPEN;

        for (i = 0 ; i < (C_WORD32LGB * C_DIE_ID_SIZE) ; i++)
            fprintf(ostream, "0x%2.2x ", die_id[i]);
    }

    fclose(ostream);

    return 0;
}

/******************************************************************************
 * Hex File Write Functions
 ******************************************************************************/

int hexblock_write(char *buf, int size, unsigned long addr, int addr_size,
                   char hexfile_type)
{
    int size_start = size;
    int line_size;

    tr(TrHexWrite, "hexblock_write(*, %d, 0x%x, %d, '%c')\n",
       size, addr, addr_size, hexfile_type);

    while (size > 0) {
        switch (hexfile_type) {
        case 'b':
            line_size = fwrite(buf, 1, size, ostream);
            if (line_size < size_start)
                return E_FILE_WRITE;
            break;
        case 'm':
        case 'S':
            line_size = (size > HEX_MOTOROLA_LINE_SIZE ?
                         HEX_MOTOROLA_LINE_SIZE : size);
            hexline_motorola_write(buf, line_size, addr, addr_size);
            break;
        case '?':
            // Intel format
            break;
        default:
            main_fatal(E_FILE_FORMAT);
        }
        buf  += line_size;
        size -= line_size;
        addr += line_size;
    }

    return size_start;
}

int hexfile_write_open(char *name, char hexfile_type, char *buf, int size)
{
    if ((ostream = fopen(name, "wt")) == NULL)
        return E_FILE_OPEN;

    // Write file header
    switch (hexfile_type) {
    case 'b':
        // Binary format --- close file, then reopen it for binary writing
        if (fclose(ostream) == EOF)
            return E_FILE_OPEN;
        if ((ostream = fopen(name, "wb")) == NULL)
            return E_FILE_OPEN;
        flowf(VERBOSE, "(binary) ");
        break;
    case 'm':
    case 'S':
        // Motorola hex files are always in big endian format.
        flowf(VERBOSE, "(motorola) ");
        buffer_endian_convert(buf, size, arg_hexfile_memwidth);
        fprintf(ostream,"S0030000FC\n");
        break;
    case '?':
        flowf(VERBOSE, "(intel) ");
        // Intel format
        break;
    default:
        return E_FILE_FORMAT;
    }

    return 0;
}

int hexfile_write_close(char hexfile_type, int addr_size)
{
    switch (hexfile_type) {
    case 'b':
        // Binary format --- do nothing
        break;
    case 'm':
    case 'S':
        switch (addr_size) {
        case 16: fprintf(ostream, "S9030000FC\n"); break;
        case 24: fprintf(ostream, "S804000000FB\n"); break;
        case 32: fprintf(ostream, "S70500000000FA\n"); break;
        }
        break;
    case '?':
        // Intel format
        break;
    default:
        return E_FILE_FORMAT;
    }

    fclose(ostream);

    return 0;
}

int hexline_motorola_write(char *buf, int size,
                           unsigned long addr, int addr_size)
{
    uint8 cksum;
    int	i;

    tr(TrHexWrite, "hexline_motorola_write(*, %d, 0x%x, %d)\n",
       size, addr, addr_size);

    if (addr_size == 0) {
        if ((addr + (unsigned long)(size - 1)) < 0x10000L)
            addr_size = 16;
        else if ((addr + (unsigned long)(size - 1)) < 0x1000000L)
            addr_size = 24;
        else
            addr_size = 32;
    }
    switch (addr_size) {
    case 16:
        fprintf(ostream, "S1%02X%04lX", size + 3, addr);
        cksum = size + 3;
        break;
    case 24:
        fprintf(ostream, "S2%02X%06lX", size + 4, addr);
        cksum = size + 4;
        break;
    case 32:
        fprintf(ostream, "S3%02X%08lX", size + 5, addr);
        cksum = size + 5;
        break;
    }
    cksum +=
        (uint8) ((addr >> 24) & 0xFF) +
        (uint8) ((addr >> 16) & 0xFF) +
        (uint8) ((addr >>  8) & 0xFF) +
        (uint8) ((addr >>  0) & 0xFF);
    
    for (i = 0; i < size; i++) {
        fprintf(ostream,"%02X", buf[i] & 0xFF);
        cksum += buf[i];
    }
    cksum = ~cksum;
    fprintf(ostream,"%02X\n", cksum);

    return 0;
}