From bbb0d352a35fee2d22bb2eb9ffbfd5bb62280127 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Fri, 2 Dec 2022 11:21:35 +0100 Subject: [PATCH] simavr is now able to load multiple overlapping flash sections --- simavr/sim/sim_elf.c | 164 +++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 76 deletions(-) diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 371b9db..246af57 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -279,7 +279,7 @@ elf_copy_segment(int fd, Elf32_Phdr *php, uint8_t **dest) if (*dest == NULL) *dest = malloc(php->p_filesz); - if (!*dest) + if (*dest == NULL) return -1; lseek(fd, php->p_offset, SEEK_SET); @@ -291,8 +291,6 @@ elf_copy_segment(int fd, Elf32_Phdr *php, uint8_t **dest) rv, php->p_filesz, php->p_vaddr, php->p_offset); return -1; } - AVR_LOG(NULL, LOG_DEBUG, "Loaded %d bytes at 0x%04x\n", - php->p_filesz, php->p_vaddr); return 0; } @@ -304,10 +302,15 @@ elf_handle_segment(int fd, Elf32_Phdr *php, uint8_t **dest, const char *name) "Unexpected extra %s data: %d bytes at %x.\n", name, php->p_filesz, php->p_vaddr); return -1; - } else { - elf_copy_segment(fd, php, dest); - return 0; + } else if (elf_copy_segment(fd, php, dest)) { + AVR_LOG(NULL, LOG_ERROR, + "copy segment fails (%d bytes at %x)!\n", + name, php->p_filesz, php->p_vaddr); + return -1; } + AVR_LOG(NULL, LOG_DEBUG, " Loaded %d (0x%0x) bytes (section offset 0x%04x)\n", + php->p_filesz, php->p_filesz, php->p_vaddr); + return 0; } /* The structure *firmware must be pre-initialised to zero, then optionally @@ -363,6 +366,8 @@ elf_read_firmware( return -1; } + int isTextSectionLoaded = 0; + uint32_t offset = 0; for (i = 0; i < (int)ph_count; ++i, ++php) { #if 0 printf("Header %d type %d addr %x/%x size %d/%d flags %x\n", @@ -371,62 +376,90 @@ elf_read_firmware( #endif if (php->p_type != PT_LOAD || php->p_filesz == 0) continue; - if (php->p_vaddr < 0x800000) { - /* Explicit flash section. Load it. */ + + if (php->p_vaddr < 0x810000) { // .text or .data section if (firmware->flash == NULL) { + avr_t *avr = avr_make_mcu_by_name(firmware->mmcu); firmware->flashbase = 0; - firmware->flashsize = php->p_vaddr + php->p_filesz; - firmware->flash = malloc(firmware->flashsize); - memset(firmware->flash, 0xff, firmware->flashsize); - uint8_t *where = firmware->flash + php->p_vaddr; - elf_copy_segment(fd, php, &where); - - } else { - long gapSize = php->p_vaddr - firmware->flashsize; - if (gapSize < 0) { - AVR_LOG(NULL, LOG_ERROR, - "Overlapping flash sections!\n"); + firmware->flashsize = avr->flashend + 1; + if (firmware->flashsize <= 0) { + AVR_LOG(NULL, LOG_ERROR, "cannot initialize flash, unknown size!\n"); return -1; - } else if (gapSize > 0) { - firmware->flash = realloc(firmware->flash,php->p_vaddr ); - uint8_t *where = firmware->flash + firmware->flashsize; - memset(where, 0xff, gapSize); - firmware->flashsize = php->p_vaddr; } - firmware->flash = realloc(firmware->flash, - firmware->flashsize + php->p_filesz); - if (!firmware->flash) + firmware->flash = (uint8_t *)malloc(firmware->flashsize); + if (firmware->flash == NULL) { + AVR_LOG(NULL, LOG_ERROR, "malloc flash memory fails!\n"); return -1; - uint8_t *where = firmware->flash + firmware->flashsize; - elf_copy_segment(fd, php, &where); - firmware->flashsize += php->p_filesz; + } + memset(firmware->flash, 0xff, firmware->flashsize); + AVR_LOG(NULL, LOG_DEBUG, "flash initialization with 0xff (%d bytes)\n", firmware->flashsize); } - } else if (php->p_vaddr < 0x810000) { - /* Data space. If there are initialised variables, treat - * them as extra initialised flash. The C startup function - * understands that and will copy them to RAM. - */ - - if (firmware->flash != NULL) { - uint8_t *where; - - firmware->flash = realloc(firmware->flash, - firmware->flashsize + php->p_filesz); - if (!firmware->flash) - return -1; - where = firmware->flash + firmware->flashsize; - elf_copy_segment(fd, php, &where); - AVR_LOG(NULL, LOG_DEBUG, ".data section %d bytes copied to flash at 0x%04x\n", php->p_filesz, firmware->flashsize); - firmware->flashsize += php->p_filesz; - } else { - /* If this ever happens, add a second pass. */ - + if (php->p_vaddr < 0x800000) { + /* Explicit flash section. Load it. */ + isTextSectionLoaded = 1; + offset = php->p_vaddr; + } else if (isTextSectionLoaded ) { + /* Data space. If there are initialised variables, treat + * them as extra initialised flash. The C startup function + * understands that and will copy them to RAM. + */ + isTextSectionLoaded = 0; + } else if (!isTextSectionLoaded) { AVR_LOG(NULL, LOG_ERROR, - "Initialialised data but no flash (%d bytes at %x)!\n", - php->p_filesz, php->p_vaddr); + "Initialialised data but no flash (%d bytes at %x in file \"%s\")!\n", + php->p_filesz, php->p_vaddr, file); return -1; } + uint8_t *section = NULL; + if (elf_copy_segment(fd, php, §ion) || section == NULL) { + AVR_LOG(NULL, LOG_ERROR, + "cannot read section (%d bytes at %x in file \"%s\")!\n", + php->p_filesz, php->p_vaddr, file); + if (section != NULL) { + free(section); + section = NULL; + } + return -1; + } else { + AVR_LOG(NULL, LOG_DEBUG, " Loading %d (0x%0x) bytes (section offset 0x%04x) to flash address 0x%04x\n", + php->p_filesz, php->p_filesz, php->p_vaddr, offset); + } + + uint32_t overlapping_start = UINT32_MAX; + uint32_t overlapping_end = 0; + int overlapping_error = 0; + for (uint32_t addr = offset; addr < (offset + php->p_filesz); addr++) { + if (addr >= firmware->flashsize) { + AVR_LOG(NULL, LOG_ERROR, + "section out of flash address range (%d bytes at %x in file \"%s\")!\n", + php->p_filesz, php->p_vaddr, file); + return -1; + } + if (firmware->flash[addr] != 0xff) { + overlapping_start = addr < overlapping_start ? addr : overlapping_start; + overlapping_end = addr > overlapping_end ? addr : overlapping_end; + if (firmware->flash[addr] != section[addr - offset]) { + overlapping_error = 1; + } + } + firmware->flash[addr] = section[addr - offset]; + } + offset += php->p_filesz; + if (overlapping_start <= overlapping_end) { + if (overlapping_error) { + AVR_LOG(NULL, LOG_OUTPUT, + "WARNING: overlapping section with different content (0x%04x..0x%04x)!\n", + overlapping_start, overlapping_end); + } else { + AVR_LOG(NULL, LOG_OUTPUT, + "overlapping section with same content (0x%04x..0x%04x)!\n", + overlapping_start, overlapping_end); + } + } + free(section); + section = NULL; + } else if (php->p_vaddr < 0x820000) { /* EEPROM. */ @@ -446,27 +479,6 @@ elf_read_firmware( } } - avr_t *avr = avr_make_mcu_by_name(firmware->mmcu); - if (avr != NULL) { - if (firmware->flash == NULL) { - AVR_LOG(NULL, LOG_ERROR, - "no flash!\n", - php->p_filesz, php->p_vaddr); - return -1; - } else { - long gapSize = avr->flashend + 1 - firmware->flashsize; - if (gapSize < 0) { - AVR_LOG(NULL, LOG_ERROR, - "flash size 0x%04x too large for selected mmcu device %s!\n", firmware->flashsize, firmware->mmcu); - return -1; - } else if (gapSize > 0) { - firmware->flash = realloc(firmware->flash, firmware->flashsize + gapSize); - uint8_t *where = firmware->flash + firmware->flashsize; - memset(where, 0xff, gapSize); - firmware->flashsize += gapSize; - } - } - } /* Scan the section table for .mmcu magic and symbols. */ while ((scn = elf_nextscn(elf, scn)) != NULL) { @@ -539,9 +551,9 @@ elf_read_firmware( } #endif // ELF_SYMBOLS } - if (firmware->flash != NULL) { - AVR_LOG(NULL, LOG_DEBUG, "end of flash initialization (size=0x%04x)\n", firmware->flashsize); - } + // if (firmware->flash != NULL) { + // AVR_LOG(NULL, LOG_DEBUG, "end of flash initialization (size=0x%04x)\n", firmware->flashsize); + // } elf_end(elf); close(fd); return 0; -- 2.39.5