[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 01/20] loader.c: Add support Motrola S-record format.
From: |
Alistair Francis |
Subject: |
Re: [PATCH 01/20] loader.c: Add support Motrola S-record format. |
Date: |
Tue, 27 Oct 2020 14:05:44 -0700 |
On Thu, Aug 27, 2020 at 5:39 AM Yoshinori Sato
<ysato@users.sourceforge.jp> wrote:
>
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
> include/hw/loader.h | 14 +++
> hw/core/loader.c | 208 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 222 insertions(+)
>
> diff --git a/include/hw/loader.h b/include/hw/loader.h
> index a9eeea3952..6f1fb62ded 100644
> --- a/include/hw/loader.h
> +++ b/include/hw/loader.h
> @@ -55,6 +55,20 @@ int load_image_targphys_as(const char *filename,
> */
> int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace
> *as);
>
> +/*
> + * load_targphys_srec_as:
> + * @filename: Path to the .hex file
> + * @entry: Store the entry point given by the .hex file
> + * @as: The AddressSpace to load the .hex file to. The value of
> + * address_space_memory is used if nothing is supplied here.
> + *
> + * Load a fixed .srec file into memory.
> + *
> + * Returns the size of the loaded .hex file on success, -1 otherwise.
> + */
> +int load_targphys_srec_as(const char *filename,
> + hwaddr *entry, AddressSpace *as);
> +
> /** load_image_targphys:
> * Same as load_image_targphys_as(), but doesn't allow the caller to specify
> * an AddressSpace.
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index 8bbb1797a4..6964b04ec7 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -1618,3 +1618,211 @@ int load_targphys_hex_as(const char *filename, hwaddr
> *entry, AddressSpace *as)
> g_free(hex_blob);
> return total_size;
> }
> +
> +typedef enum {
> + SREC_SOH,
> + SREC_TYPE,
> + SREC_LEN,
> + SREC_ADDR,
> + SREC_DATA,
> + SREC_SKIP,
> + SREC_SUM,
> +} srec_state;
> +
> +typedef struct {
> + srec_state state;
> + int nibble;
> + int total_size;
> + uint32_t address;
> + uint32_t topaddr;
> + uint32_t bufremain;
> + int length;
> + int addr_len;
> + int record_type;
> + uint8_t byte;
> + uint8_t data[DATA_FIELD_MAX_LEN];
> + uint8_t *datap;
> + uint8_t *bufptr;
> + uint8_t sum;
> +} SrecLine;
> +
> +static bool parse_srec_line(SrecLine *line, char c)
> +{
> + if (!g_ascii_isxdigit(c)) {
> + return false;
> + }
> + line->byte <<= 4;
> + line->byte |= g_ascii_xdigit_value(c);
> + line->nibble++;
> + if (line->nibble == 2) {
> + line->nibble = 0;
> + line->length--;
> + line->sum += line->byte;
> + switch (line->state) {
> + case SREC_SOH:
> + case SREC_TYPE:
> + /* first 2chars ignore parse */
> + break;
> + case SREC_LEN:
> + line->sum = line->length = line->byte;
> + if (line->addr_len > 0) {
> + line->state = SREC_ADDR;
> + line->address = 0;
> + } else {
> + line->state = SREC_SKIP;
> + }
> + break;
> + case SREC_ADDR:
> + line->address <<= 8;
> + line->address |= line->byte;
> + if (--line->addr_len == 0) {
> + if (line->length > 1) {
> + if (line->record_type != 0) {
> + line->state = SREC_DATA;
> + } else {
> + line->state = SREC_SKIP;
> + }
> + line->datap = line->data;
> + } else {
> + line->state = SREC_SUM;
> + }
> + }
> + break;
> + case SREC_DATA:
> + *line->datap++ = line->byte;
> + /* fail through */
s/fail/fall/g
> + case SREC_SKIP:
> + if (line->length == 1) {
> + line->state = SREC_SUM;
> + }
> + break;
> + case SREC_SUM:
> + if ((line->sum & 0xff) != 0xff) {
> + return false;
> + }
> + }
> + }
> + return true;
> +}
> +
> +#define SRECBUFSIZE 0x40000
> +
> +/* return size or -1 if error */
> +static int parse_srec_blob(const char *filename, hwaddr *addr,
> + uint8_t *hex_blob, size_t hex_blob_size,
> + AddressSpace *as)
> +{
> + SrecLine line;
> + size_t len;
> + int total_len = 0;
> + uint8_t *end = hex_blob + hex_blob_size;
> + rom_transaction_begin();
> + line.state = SREC_SOH;
> + line.bufptr = g_malloc(SRECBUFSIZE);
> + line.bufremain = SRECBUFSIZE;
> + line.topaddr = UINT32_MAX;
> + for (; hex_blob < end; ++hex_blob) {
> + switch (*hex_blob) {
> + case '\r':
> + case '\n':
> + if (line.state == SREC_SUM) {
> + switch (line.record_type) {
What if a file starts with a new line, won't line.record_type be invalid?
Alistair
> + case 1:
> + case 2:
> + case 3:
> + len = line.datap - line.data;
> + if (line.topaddr == UINT32_MAX) {
> + line.topaddr = line.address;
> + }
> + if (line.bufremain < len || line.address < line.topaddr)
> {
> + rom_add_blob_fixed_as(filename, line.bufptr,
> + SRECBUFSIZE - line.bufremain,
> + line.topaddr, as);
> + line.topaddr = line.address;
> + line.bufremain = SRECBUFSIZE;
> + }
> + memcpy(line.bufptr + (line.address - line.topaddr),
> + line.data, len);
> + line.bufremain -= len;
> + total_len += len;
> + break;
> + case 7:
> + case 8:
> + case 9:
> + *addr = line.address;
> + break;
> + }
> + line.state = SREC_SOH;
> + }
> + break;
> + /* start of a new record. */
> + case 'S':
> + if (line.state != SREC_SOH) {
> + total_len = -1;
> + goto out;
> + }
> + line.state = SREC_TYPE;
> + break;
> + /* decoding lines */
> + default:
> + if (line.state == SREC_TYPE) {
> + if (g_ascii_isdigit(*hex_blob)) {
> + line.record_type = g_ascii_digit_value(*hex_blob);
> + switch (line.record_type) {
> + case 1:
> + case 2:
> + case 3:
> + line.addr_len = 1 + line.record_type;
> + break;
> + case 0:
> + case 5:
> + line.addr_len = 2;
> + break;
> + case 7:
> + case 8:
> + case 9:
> + line.addr_len = 11 - line.record_type;
> + break;
> + default:
> + line.addr_len = 0;
> + }
> + }
> + line.state = SREC_LEN;
> + line.nibble = 0;
> + } else {
> + if (!parse_srec_line(&line, *hex_blob)) {
> + total_len = -1;
> + goto out;
> + }
> + }
> + break;
> + }
> + }
> + if (line.bufremain < SRECBUFSIZE) {
> + rom_add_blob_fixed_as(filename, line.bufptr,
> + SRECBUFSIZE - line.bufremain,
> + line.topaddr, as);
> + }
> +out:
> + rom_transaction_end(total_len != -1);
> + g_free(line.bufptr);
> + return total_len;
> +}
> +
> +/* return size or -1 if error */
> +int load_targphys_srec_as(const char *filename, hwaddr *entry, AddressSpace
> *as)
> +{
> + gsize hex_blob_size;
> + gchar *hex_blob;
> + int total_size = 0;
> +
> + if (!g_file_get_contents(filename, &hex_blob, &hex_blob_size, NULL)) {
> + return -1;
> + }
> +
> + total_size = parse_srec_blob(filename, entry, (uint8_t *)hex_blob,
> + hex_blob_size, as);
> +
> + g_free(hex_blob);
> + return total_size;
> +}
> --
> 2.20.1
>
>