diff options
Diffstat (limited to 'include/hw')
-rw-r--r-- | include/hw/arm/armv7m.h | 2 | ||||
-rw-r--r-- | include/hw/elf_ops.h | 72 | ||||
-rw-r--r-- | include/hw/intc/armv7m_nvic.h (renamed from include/hw/arm/armv7m_nvic.h) | 0 | ||||
-rw-r--r-- | include/hw/watchdog/wdt_aspeed.h | 2 |
4 files changed, 68 insertions, 8 deletions
diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h index a9b3f2ab35..10eb058027 100644 --- a/include/hw/arm/armv7m.h +++ b/include/hw/arm/armv7m.h @@ -11,7 +11,7 @@ #define HW_ARM_ARMV7M_H #include "hw/sysbus.h" -#include "hw/arm/armv7m_nvic.h" +#include "hw/intc/armv7m_nvic.h" #define TYPE_BITBAND "ARM,bitband-memory" #define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index a172a6068a..d192e7e2a3 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -362,6 +362,54 @@ static int glue(load_elf, SZ)(const char *name, int fd, goto fail; } } + + /* The ELF spec is somewhat vague about the purpose of the + * physical address field. One common use in the embedded world + * is that physical address field specifies the load address + * and the virtual address field specifies the execution address. + * Segments are packed into ROM or flash, and the relocation + * and zero-initialization of data is done at runtime. This + * means that the memsz header represents the runtime size of the + * segment, but the filesz represents the loadtime size. If + * we try to honour the memsz value for an ELF file like this + * we will end up with overlapping segments (which the + * loader.c code will later reject). + * We support ELF files using this scheme by by checking whether + * paddr + memsz for this segment would overlap with any other + * segment. If so, then we assume it's using this scheme and + * truncate the loaded segment to the filesz size. + * If the segment considered as being memsz size doesn't overlap + * then we use memsz for the segment length, to handle ELF files + * which assume that the loader will do the zero-initialization. + */ + if (mem_size > file_size) { + /* If this segment's zero-init portion overlaps another + * segment's data or zero-init portion, then truncate this one. + * Invalid ELF files where the segments overlap even when + * only file_size bytes are loaded will be rejected by + * the ROM overlap check in loader.c, so we don't try to + * explicitly detect those here. + */ + int j; + elf_word zero_start = ph->p_paddr + file_size; + elf_word zero_end = ph->p_paddr + mem_size; + + for (j = 0; j < ehdr.e_phnum; j++) { + struct elf_phdr *jph = &phdr[j]; + + if (i != j && jph->p_type == PT_LOAD) { + elf_word other_start = jph->p_paddr; + elf_word other_end = jph->p_paddr + jph->p_memsz; + + if (!(other_start >= zero_end || + zero_start >= other_end)) { + mem_size = file_size; + break; + } + } + } + } + /* address_offset is hack for kernel images that are linked at the wrong physical address. */ if (translate_fn) { @@ -403,14 +451,24 @@ static int glue(load_elf, SZ)(const char *name, int fd, *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; } - if (load_rom) { - snprintf(label, sizeof(label), "phdr #%d: %s", i, name); - - /* rom_add_elf_program() seize the ownership of 'data' */ - rom_add_elf_program(label, data, file_size, mem_size, addr, as); - } else { - cpu_physical_memory_write(addr, data, file_size); + if (mem_size == 0) { + /* Some ELF files really do have segments of zero size; + * just ignore them rather than trying to create empty + * ROM blobs, because the zero-length blob can falsely + * trigger the overlapping-ROM-blobs check. + */ g_free(data); + } else { + if (load_rom) { + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); + + /* rom_add_elf_program() seize the ownership of 'data' */ + rom_add_elf_program(label, data, file_size, mem_size, + addr, as); + } else { + cpu_physical_memory_write(addr, data, file_size); + g_free(data); + } } total_size += mem_size; diff --git a/include/hw/arm/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h index 1d145fb75f..1d145fb75f 100644 --- a/include/hw/arm/armv7m_nvic.h +++ b/include/hw/intc/armv7m_nvic.h diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index 080c223122..7de3e5c224 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -27,6 +27,8 @@ typedef struct AspeedWDTState { uint32_t regs[ASPEED_WDT_REGS_MAX]; uint32_t pclk_freq; + uint32_t silicon_rev; + uint32_t ext_pulse_width_mask; } AspeedWDTState; #endif /* ASPEED_WDT_H */ |