From 4d2d5f6d061af0ce244ae54496a434f15f59733f Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sun, 4 Dec 2022 15:19:28 +0100 Subject: [PATCH] simavr now oarsing fuse values (boot reset) --- simavr/cores/sim_core_declare.h | 5 +- simavr/cores/sim_mega16.c | 72 +++++++++++++++++++++++++++- simavr/cores/sim_mega324.c | 85 ++++++++++++++++++++++++++++++++- simavr/cores/sim_mega328.c | 77 ++++++++++++++++++++++++++++- simavr/sim/sim_avr.c | 7 +-- simavr/sim/sim_avr.h | 52 ++++++++++++++++++++ simavr/sim/sim_elf.c | 71 ++++++++++++++++++++------- 7 files changed, 345 insertions(+), 24 deletions(-) diff --git a/simavr/cores/sim_core_declare.h b/simavr/cores/sim_core_declare.h index 7e76771..eeae701 100644 --- a/simavr/cores/sim_core_declare.h +++ b/simavr/cores/sim_core_declare.h @@ -83,6 +83,7 @@ .ioend = RAMSTART - 1, \ .ramend = RAMEND, \ .flashend = FLASHEND, \ + .spm_pagesize = SPM_PAGESIZE, \ .e2end = E2END, \ .vector_size = _vector_size, \ .fuse = _FUSE_HELPER, \ @@ -93,7 +94,9 @@ .extrf = AVR_IO_REGBIT(MCU_STATUS_REG, EXTRF),\ .borf = AVR_IO_REGBIT(MCU_STATUS_REG, BORF),\ .wdrf = AVR_IO_REGBIT(MCU_STATUS_REG, WDRF)\ - } + }, \ + .fuse_value = DEFAULT_avr_fuse_value, \ + .lock_value = DEFAULT_avr_lock_value #else // Disable signature when using an old avr toolchain #define DEFAULT_CORE(_vector_size) \ diff --git a/simavr/cores/sim_mega16.c b/simavr/cores/sim_mega16.c index aa3563d..3c0fbb0 100644 --- a/simavr/cores/sim_mega16.c +++ b/simavr/cores/sim_mega16.c @@ -22,6 +22,7 @@ // atmega32 has different name for Watchdog Turn-off Enable register #define WDCE WDTOE #include "sim_avr.h" +#include #define SIM_VECTOR_SIZE 4 #define SIM_MMCU "atmega16" @@ -54,9 +55,78 @@ // instantiate the new core #include "sim_megax.h" +static void init_fuse_lock(struct avr_t * avr) +{ + avr->fuse_value.lfuse = avr->fuse[0]; + avr->fuse_value.hfuse = avr->fuse[1]; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t lfuse = avr->fuse_value.lfuse; + avr->fuse_value.cksel = + (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) | + (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0); + avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0); + avr->fuse_value.boden_disabled = (lfuse & ~FUSE_BODEN) != 0; + avr->fuse_value.bodlevel = (lfuse & ~FUSE_BODLEVEL) != 0; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t hfuse = avr->fuse_value.hfuse; + avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0; + avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0); + avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0; + avr->fuse_value.ckopt_disabled = (hfuse & ~FUSE_CKOPT) != 0; + avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0; + avr->fuse_value.jtagen_disabled = (hfuse & ~FUSE_JTAGEN) != 0; + avr->fuse_value.ocden_disabled = (hfuse & ~FUSE_OCDEN) != 0; + + memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t)); + uint8_t lock = avr->lockbits; + avr->lock_value.lock = lock; + switch (lock & 0x03) { + case 0: avr->lock_value.mode3_dis_prg_ver = 1; break; + case 1: break; + case 2: avr->lock_value.mode2_dis_prg = 1; break; + case 3: avr->lock_value.mode1_nolock = 1; break; + } + switch ((lock >> 2)& 0x03) { + case 0: avr->lock_value.app_mode4_nolpm = 1; break; + case 1: avr->lock_value.app_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.app_mode2_nospm = 1; break; + case 3: avr->lock_value.app_mode1_nolock = 1; break; + } + switch ((lock >> 4)& 0x03) { + case 0: avr->lock_value.boot_mode4_nolpm = 1; break; + case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.boot_mode2_nospm = 1; break; + case 3: avr->lock_value.boot_mode1_nolock = 1; break; + } + + if (FLASHEND == 0x3fff) { + switch (avr->fuse_value.bootsz) { + case 0: avr->fuse_value.bootloader_pages = 16; break; + case 1: avr->fuse_value.bootloader_pages = 8; break; + case 2: avr->fuse_value.bootloader_pages = 4; break; + case 3: avr->fuse_value.bootloader_pages = 2; break; + } + uint32_t appEnd = avr->flashend - avr->fuse_value.bootloader_pages * avr->spm_pagesize; + AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend); + if (!avr->fuse_value.bootrst_disabled) { + avr->reset_pc = appEnd + 1; + avr->pc = avr->reset_pc; + AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc); + } + + } else { + AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n"); + } +} + static avr_t * make() { - return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr->init_fuse_lock = init_fuse_lock; + avr->init_fuse_lock(avr); + return avr; } avr_kind_t mega16 = { diff --git a/simavr/cores/sim_mega324.c b/simavr/cores/sim_mega324.c index 0697b76..15001e6 100644 --- a/simavr/cores/sim_mega324.c +++ b/simavr/cores/sim_mega324.c @@ -20,6 +20,7 @@ */ #include "sim_avr.h" +#include #define SIM_MMCU "atmega324" #define SIM_CORENAME mcu_mega324 @@ -37,12 +38,93 @@ #define EFUSE_DEFAULT (0xFF) #endif +// #define HFUSE_DEFAULT 0 + // instantiate the new core #include "sim_megax4.h" +#define _BVX(v) (1 << v) +#define BIT6 (unsigned char)~_BVX(6) +#define BIT7 (unsigned char)~_BVX(7) +#define VALUE_DEFAULT (BIT6 & BIT7) + +static void init_fuse_lock(struct avr_t * avr) +{ + avr->fuse_value.lfuse = avr->fuse[0]; + avr->fuse_value.hfuse = avr->fuse[1]; + avr->fuse_value.efuse = avr->fuse[2]; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t lfuse = avr->fuse_value.lfuse; + avr->fuse_value.cksel = + (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) | + (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0); + avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0); + avr->fuse_value.ckout_disabled = (lfuse & ~FUSE_CKOUT) != 0; + avr->fuse_value.ckdiv8_disabled = (lfuse & ~FUSE_CKDIV8) != 0; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t hfuse = avr->fuse_value.hfuse; + avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0; + avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0); + avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0; + avr->fuse_value.wdton_disabled = (hfuse & ~FUSE_WDTON) != 0; + avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0; + avr->fuse_value.jtagen_disabled = (hfuse & ~FUSE_JTAGEN) != 0; + avr->fuse_value.ocden_disabled = (hfuse & ~FUSE_OCDEN) != 0; + + uint8_t efuse = avr->fuse_value.efuse; + avr->fuse_value.bodlevel = (((efuse & ~FUSE_BODLEVEL2) != 0) << 2) | + (((efuse & ~FUSE_BODLEVEL1) != 0) << 1) | (((efuse & ~FUSE_BODLEVEL0) != 0) << 0); + + memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t)); + uint8_t lock = avr->lockbits; + avr->lock_value.lock = lock; + switch (lock & 0x03) { + case 0: avr->lock_value.mode3_dis_prg_ver = 1; break; + case 1: break; + case 2: avr->lock_value.mode2_dis_prg = 1; break; + case 3: avr->lock_value.mode1_nolock = 1; break; + } + switch ((lock >> 2)& 0x03) { + case 0: avr->lock_value.app_mode4_nolpm = 1; break; + case 1: avr->lock_value.app_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.app_mode2_nospm = 1; break; + case 3: avr->lock_value.app_mode1_nolock = 1; break; + } + switch ((lock >> 4)& 0x03) { + case 0: avr->lock_value.boot_mode4_nolpm = 1; break; + case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.boot_mode2_nospm = 1; break; + case 3: avr->lock_value.boot_mode1_nolock = 1; break; + } + + if (FLASHEND == 0x7fff) { + switch (avr->fuse_value.bootsz) { + case 0: avr->fuse_value.bootloader_pages = 32; break; + case 1: avr->fuse_value.bootloader_pages = 16; break; + case 2: avr->fuse_value.bootloader_pages = 8; break; + case 3: avr->fuse_value.bootloader_pages = 4; break; + } + uint32_t appEnd = avr->flashend - avr->fuse_value.bootloader_pages * avr->spm_pagesize; + AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend); + if (!avr->fuse_value.bootrst_disabled) { + avr->reset_pc = appEnd + 1; + avr->pc = avr->reset_pc; + AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc); + } + + } else { + AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n"); + } +} + static avr_t * make() { - return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr->init_fuse_lock = init_fuse_lock; + avr->init_fuse_lock(avr); + return avr; } avr_kind_t mega324 = { @@ -50,3 +132,4 @@ avr_kind_t mega324 = { .make = make }; + diff --git a/simavr/cores/sim_mega328.c b/simavr/cores/sim_mega328.c index 3466939..ae7e891 100644 --- a/simavr/cores/sim_mega328.c +++ b/simavr/cores/sim_mega328.c @@ -20,6 +20,7 @@ */ #include "sim_avr.h" +#include #define SIM_VECTOR_SIZE 4 #define SIM_MMCU "atmega328" @@ -31,9 +32,83 @@ // instantiate the new core #include "sim_megax8.h" +static void init_fuse_lock(struct avr_t * avr) +{ + avr->fuse_value.lfuse = avr->fuse[0]; + avr->fuse_value.hfuse = avr->fuse[1]; + avr->fuse_value.efuse = avr->fuse[2]; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t lfuse = avr->fuse_value.lfuse; + avr->fuse_value.cksel = + (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) | + (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0); + avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0); + avr->fuse_value.ckout_disabled = (lfuse & ~FUSE_CKOUT) != 0; + avr->fuse_value.ckdiv8_disabled = (lfuse & ~FUSE_CKDIV8) != 0; + + // 0= programmed (function active), 1=not programmed (function not active) + uint8_t hfuse = avr->fuse_value.hfuse; + avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0; + avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0); + avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0; + avr->fuse_value.wdton_disabled = (hfuse & ~FUSE_WDTON) != 0; + avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0; + avr->fuse_value.dwen_disabled = (hfuse & ~FUSE_DWEN) != 0; + avr->fuse_value.rstdisbl_disabled = (hfuse & ~FUSE_RSTDISBL) != 0; + + uint8_t efuse = avr->fuse_value.efuse; + avr->fuse_value.bodlevel = (((efuse & ~FUSE_BODLEVEL2) != 0) << 2) | + (((efuse & ~FUSE_BODLEVEL1) != 0) << 1) | (((efuse & ~FUSE_BODLEVEL0) != 0) << 0); + + memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t)); + uint8_t lock = avr->lockbits; + avr->lock_value.lock = lock; + switch (lock & 0x03) { + case 0: avr->lock_value.mode3_dis_prg_ver = 1; break; + case 1: break; + case 2: avr->lock_value.mode2_dis_prg = 1; break; + case 3: avr->lock_value.mode1_nolock = 1; break; + } + switch ((lock >> 2)& 0x03) { + case 0: avr->lock_value.app_mode4_nolpm = 1; break; + case 1: avr->lock_value.app_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.app_mode2_nospm = 1; break; + case 3: avr->lock_value.app_mode1_nolock = 1; break; + } + switch ((lock >> 4)& 0x03) { + case 0: avr->lock_value.boot_mode4_nolpm = 1; break; + case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break; + case 2: avr->lock_value.boot_mode2_nospm = 1; break; + case 3: avr->lock_value.boot_mode1_nolock = 1; break; + } + + if (FLASHEND == 0x7fff) { + switch (avr->fuse_value.bootsz) { + case 0: avr->fuse_value.bootloader_pages = 32; break; + case 1: avr->fuse_value.bootloader_pages = 16; break; + case 2: avr->fuse_value.bootloader_pages = 8; break; + case 3: avr->fuse_value.bootloader_pages = 4; break; + } + uint32_t appEnd = avr->flashend - avr->fuse_value.bootloader_pages * avr->spm_pagesize; + AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend); + if (!avr->fuse_value.bootrst_disabled) { + avr->reset_pc = appEnd + 1; + avr->pc = avr->reset_pc; + AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc); + } + + } else { + AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n"); + } +} + static avr_t * make() { - return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t)); + avr->init_fuse_lock = init_fuse_lock; + avr->init_fuse_lock(avr); + return avr; } avr_kind_t mega328 = { diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 24cb244..4b01ed0 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -123,7 +123,7 @@ avr_init( avr->sleep = avr_callback_sleep_raw; // number of address bytes to push/pull on/off the stack avr->address_size = avr->eind ? 3 : 2; - avr->log = 1; + avr->log = LOG_WARNING; avr_reset(avr); avr_regbit_set(avr, avr->reset_flags.porf); // by default set to power-on reset return 0; @@ -160,8 +160,9 @@ void avr_reset( avr_t * avr) { - AVR_LOG(avr, LOG_TRACE, "%s reset\n", avr->mmcu); - + if (avr->cycle > 0) { + AVR_LOG(avr, LOG_OUTPUT, "%s reset (PC set to 0x%04x)\n", avr->mmcu, avr->reset_pc); + } avr->state = cpu_Running; for(int i = 0x20; i <= avr->ioend; i++) avr->data[i] = 0; diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index e9a97cd..1ba9786 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -43,6 +43,51 @@ extern "C" { typedef uint32_t avr_flashaddr_t; +// fuse values are initialized with -1 and set by device specific init_fuse_lock() +// Attention: fuse unprogrammed -> bit=1 (function disabled) +// fuse programmed -> bit=0 (function enabled) +#define DEFAULT_avr_fuse_value { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } +typedef struct avr_fuse_value_t { + int lfuse; // LFUSE + int hfuse; // HFUSE + int efuse; // EFUSE + int cksel; // FUSE_CKSEL3, FUSE_CKSEL2, FUSE_CKSEL1, FUSE_CKSEL0 + int sut; // FUSE_SUT1, FUSE_SUT0 + int ckout_disabled; // FUSE_CKOUT + int ckdiv8_disabled; // FUSE_CKDIV8 + int bootrst_disabled; // FUSE_BOOTRST + int bootsz; // FUSE_BOOTSZ1, FUSE_BOOTSZ0 + int bootloader_pages; // bootloader size in number of flash pages + int eesave_disabled; // FUSE_EESAVE + int wdton_disabled; // FUSE_WDTON + int ckopt_disabled; // FUSE_CKOPT + int spien_disabled; // FUSE_SPIEN + int jtagen_disabled; // FUSE_JTAGEN + int ocden_disabled; // FUSE_OCDEN + int dwen_disabled; // FUSE FUSE_DWEN + int rstdisbl_disabled; // FUSE_RSTDISBL + int boden_disabled; // FUSE BODEN + int bodlevel; // FUSE_BODLEVEL2, FUSE_BODLEVEL1, FUSE_BODLEVEL0 +} avr_fuse_value_t; + +// lock values are initialized with -1 and set by device specific init_fuse_lock() +#define DEFAULT_avr_lock_value { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } +typedef struct avr_lock_value_t { + int lock; // LOCK value + int mode1_nolock; // Mode 1: No memory lock features enabled + int mode2_dis_prg; // Mode 2: Further programming disabled + int mode3_dis_prg_ver; // Mode 3: Further programming and verification disabled + int app_mode1_nolock; // Application Mode 1, no lock on SPM and LPM + int app_mode2_nospm; // Application Mode 2, SPM prohibited + int app_mode3_nospmlpm; // Application Mode 3, SPM and LPM prohibited + int app_mode4_nolpm; // Application Mode 4, LPM prohibited + int boot_mode1_nolock; // Bootloader Mode 1, no lock on SPM and LPM + int boot_mode2_nospm; // Bootloader Mode 2, SPM prohibited + int boot_mode3_nospmlpm; // Bootloader Mode 3, SPM and LPM prohibited + int boot_mode4_nolpm; // Bootloader Mode 4, LPM prohibited +} avr_lock_value_t; + + struct avr_t; typedef uint8_t (*avr_io_read_t)( struct avr_t * avr, @@ -164,6 +209,7 @@ typedef struct avr_t { uint16_t ioend; uint16_t ramend; uint32_t flashend; + uint16_t spm_pagesize; uint32_t e2end; uint8_t vector_size; uint8_t signature[3]; @@ -348,6 +394,12 @@ typedef struct avr_t { uint32_t size; uint32_t len; } io_console_buffer; + + // fuse and lock bits (function called in avr_load_firmware()) + void (*init_fuse_lock)(struct avr_t * avr); + struct avr_fuse_value_t fuse_value; + struct avr_lock_value_t lock_value; + } avr_t; diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 246af57..04b9180 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -86,8 +86,15 @@ avr_load_firmware( }; avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d); } - if (firmware->fuse) + if (firmware->fuse) { memcpy(avr->fuse, firmware->fuse, firmware->fusesize); + AVR_LOG(avr, LOG_DEBUG, "fuses available, checking bootloader settings\n"); + if (avr->init_fuse_lock) { + avr->init_fuse_lock(avr); + } else { + AVR_LOG(avr, LOG_WARNING, "WARNING: fuse and lock values ignored (no init_fuse_lock() found)\n"); + } + } if (firmware->lockbits) avr->lockbits = firmware->lockbits[0]; // load the default pull up/down values for ports @@ -308,8 +315,6 @@ elf_handle_segment(int fd, Elf32_Phdr *php, uint8_t **dest, const char *name) 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; } @@ -380,19 +385,25 @@ elf_read_firmware( if (php->p_vaddr < 0x810000) { // .text or .data section if (firmware->flash == NULL) { avr_t *avr = avr_make_mcu_by_name(firmware->mmcu); + if (avr == NULL) { + AVR_LOG(NULL, LOG_ERROR, " ERROR: cannot initialize flash, unknown mmcu name %s!\n", firmware->mmcu); + return -1; + } firmware->flashbase = 0; firmware->flashsize = avr->flashend + 1; + free(avr); + avr = NULL; if (firmware->flashsize <= 0) { - AVR_LOG(NULL, LOG_ERROR, "cannot initialize flash, unknown size!\n"); + AVR_LOG(NULL, LOG_ERROR, " ERROR: cannot initialize flash, unknown size!\n"); return -1; } firmware->flash = (uint8_t *)malloc(firmware->flashsize); if (firmware->flash == NULL) { - AVR_LOG(NULL, LOG_ERROR, "malloc flash memory fails!\n"); + AVR_LOG(NULL, LOG_ERROR, " ERROR: malloc flash memory fails!\n"); return -1; } memset(firmware->flash, 0xff, firmware->flashsize); - AVR_LOG(NULL, LOG_DEBUG, "flash initialization with 0xff (%d bytes)\n", firmware->flashsize); + AVR_LOG(NULL, LOG_DEBUG, " Flash (%d bytes = %dKiB) initialized with 0xff\n", firmware->flashsize, firmware->flashsize / 1024); } if (php->p_vaddr < 0x800000) { @@ -407,14 +418,14 @@ elf_read_firmware( isTextSectionLoaded = 0; } else if (!isTextSectionLoaded) { AVR_LOG(NULL, LOG_ERROR, - "Initialialised data but no flash (%d bytes at %x in file \"%s\")!\n", + " ERROR: .data without .text (%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", + " ERROR: cannot read section (%d bytes at %x in file \"%s\")!\n", php->p_filesz, php->p_vaddr, file); if (section != NULL) { free(section); @@ -422,8 +433,8 @@ elf_read_firmware( } 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); + AVR_LOG(NULL, LOG_OUTPUT, " Loading section %s (%d=0x%0x bytes at 0x%04x) to flash 0x%04x\n", + isTextSectionLoaded ? ".text" : ".data", php->p_filesz, php->p_filesz, php->p_vaddr, offset); } uint32_t overlapping_start = UINT32_MAX; @@ -432,7 +443,7 @@ elf_read_firmware( 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", + " ERROR: section out of flash address range (%d bytes at %x in file \"%s\")!\n", php->p_filesz, php->p_vaddr, file); return -1; } @@ -449,11 +460,11 @@ elf_read_firmware( if (overlapping_start <= overlapping_end) { if (overlapping_error) { AVR_LOG(NULL, LOG_OUTPUT, - "WARNING: overlapping section with different content (0x%04x..0x%04x)!\n", + " 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 section with same content (0x%04x..0x%04x)!\n", overlapping_start, overlapping_end); } } @@ -463,19 +474,45 @@ elf_read_firmware( } else if (php->p_vaddr < 0x820000) { /* EEPROM. */ - if (elf_handle_segment(fd, php, &firmware->eeprom, "EEPROM")) + if (elf_handle_segment(fd, php, &firmware->eeprom, "EEPROM")) { + AVR_LOG(NULL, LOG_WARNING, + " WARNING: Loading section .eeprom (%d bytes at 0x%04x) fails!\n", + php->p_filesz, php->p_vaddr); continue; + } firmware->eesize = php->p_filesz; + AVR_LOG(NULL, LOG_OUTPUT, + " Loading eeprom data from section .eeprom (%d bytes at 0x%04x)\n", + php->p_filesz, php->p_vaddr); + } else if (php->p_vaddr < 0x830000) { /* Fuses. */ - if (elf_handle_segment(fd, php, &firmware->fuse, "Fuses")) + if (elf_handle_segment(fd, php, &firmware->fuse, "Fuses")) { + AVR_LOG(NULL, LOG_WARNING, + "WARNING: Loading section .fuse (%d bytes at 0x%04x) fails!\n", + php->p_filesz, php->p_vaddr); continue; + } firmware->fusesize = php->p_filesz; + char lfuse[16], hfuse[16], efuse[16]; + snprintf(lfuse, firmware->fusesize >= 1 ? sizeof(lfuse) : 1, " LFUSE=0x%02x", firmware->fusesize >= 1 ? firmware->fuse[0] : 0); + snprintf(hfuse, firmware->fusesize >= 2 ? sizeof(lfuse) : 1, " HFUSE=0x%02x", firmware->fusesize >= 2 ? firmware->fuse[1] : 0); + snprintf(efuse, firmware->fusesize >= 3 ? sizeof(lfuse) : 1, " EFUSE=0x%02x", firmware->fusesize >= 3 ? firmware->fuse[2] : 0); + AVR_LOG(NULL, LOG_OUTPUT, " Loading%s%s%s from section .fuse (%d bytes at 0x%04x)\n", + lfuse, hfuse, efuse, php->p_filesz, php->p_vaddr); + } else if (php->p_vaddr < 0x840000) { /* Lock bits. */ - - elf_handle_segment(fd, php, &firmware->lockbits, "Lock bits"); + if (elf_handle_segment(fd, php, &firmware->lockbits, "Lock bits")) { + AVR_LOG(NULL, LOG_WARNING, + " WARNING: Loading section .lock (%d bytes at 0x%04x) fails!\n", + php->p_filesz, php->p_vaddr); + continue; + } + AVR_LOG(NULL, LOG_OUTPUT, + " Loading LOCK=0x%02x from section .lock (%d bytes at 0x%04x)\n", + *firmware->lockbits, php->p_filesz, php->p_vaddr); } } -- 2.39.5