/* * File: option_bytes.c * * Read and write option bytes and option control registers */ #include #include #include #include #include "option_bytes.h" #include "common_flash.h" #include "flash_loader.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" /** * Read option control register F0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR); return stlink_read_debug32(sl, FLASH_OBR, option_byte); } /** * Write option bytes F0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { int32_t ret = 0; if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) { WLOG("Only full write of option bytes area is supported\n"); return -1; } clear_flash_error(sl); WLOG("Erasing option bytes\n"); /* erase option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE)); ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE)); if (ret) { return ret; } wait_flash_busy(sl); ret = check_flash_error(sl); if (ret) { return ret; } WLOG("Writing option bytes to %#10x\n", addr); /* Set the Option PG bit to enable programming */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE)); /* Use flash loader for write OP * because flash memory writable by half word */ flash_loader_t fl; ret = stlink_flash_loader_init(sl, &fl); if (ret) { return ret; } ret = stlink_flash_loader_run(sl, &fl, addr, base, len); if (ret) { return ret; } /* Reload option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH)); return check_flash_error(sl); } /** * Write option control register F0 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; uint16_t opt_val[8]; uint32_t protection, optiondata; uint16_t user_options, user_data, rdp; uint32_t option_offset, user_data_offset; ILOG("Asked to write option control register %#10x to %#010x.\n", option_cr, FLASH_OBR); /* Clear errors */ clear_flash_error(sl); /* Retrieve current values */ ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata); if (ret) { return ret; } ret = stlink_read_debug32(sl, FLASH_WRPR, &protection); if (ret) { return ret; } /* Translate OBR value to flash store structure * F0: RM0091, Option byte description, pp. 75-78 * F1: PM0075, Option byte description, pp. 19-22 * F3: RM0316, Option byte description, pp. 85-87 */ switch(sl->chip_id) { case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ case 0x438: /* STM32F303x6/8 and STM32F328 */ case 0x446: /* STM32F303xD/E and STM32F398xE */ case 0x439: /* STM32F302x6/8 */ case 0x440: /* STM32F05x */ case 0x444: /* STM32F03x */ case 0x445: /* STM32F04x */ case 0x448: /* STM32F07x */ case 0x442: /* STM32F09x */ option_offset = 6; user_data_offset = 16; rdp = 0x55AA; break; default: option_offset = 0; user_data_offset = 10; rdp = 0x5AA5; break; } user_options = (option_cr >> option_offset >> 2) & 0xFFFF; user_data = (option_cr >> user_data_offset) & 0xFFFF; #define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00)) opt_val[0] = (option_cr & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp; opt_val[1] = VAL_WITH_COMPLEMENT(user_options); opt_val[2] = VAL_WITH_COMPLEMENT(user_data); opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8); opt_val[4] = VAL_WITH_COMPLEMENT(protection); opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8); opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16); opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24); #undef VAL_WITH_COMPLEMENT /* Write bytes and check errors */ ret = stlink_write_option_bytes_f0(sl, STM32_F0_OPTION_BYTES_BASE, (uint8_t*)opt_val, sizeof(opt_val)); if (ret) return ret; ret = check_flash_error(sl); if (!ret) { ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_OBR); } return ret; } /** * Read option control register F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte); } /** * Read option bytes F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f2(sl, option_byte); } /** * Read option control register F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte); } /** * Read option bytes F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f4(sl, option_byte); } /** * Write option bytes F4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); // write option byte, ensuring we dont lock opt, and set strt bit stlink_write_debug32(sl, FLASH_F4_OPTCR, (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) | (1 << FLASH_F4_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); // option bytes are reloaded at reset only, no obl. */ return (ret); } /** * Read option bytes F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ // Since multiple bytes can be read, we read and print32_t all, but one here // and then return the last one just like other devices. int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) { int32_t err = -1; for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) { err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte); if (err == -1) { return err; } else { printf("%08x\n", *option_byte); } } return stlink_read_debug32( sl, sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t), option_byte); } /** * Write option bytes F7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), addr); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr); if (addr == 0) { addr = FLASH_F7_OPTCR; ILOG("No address provided, using %#10x\n", addr); } if (addr == FLASH_F7_OPTCR) { /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); } else if (addr == FLASH_F7_OPTCR1) { // Read FLASH_F7_OPTCR uint32_t oldvalue; stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue); /* write option byte */ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte); // Write FLASH_F7_OPTCR lock and start address stlink_write_debug32(sl, FLASH_F7_OPTCR, (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); } else { WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr); stlink_write_debug32(sl, addr, option_byte); } wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, addr); /* option bytes are reloaded at reset only, no obl. */ return ret; } /** * Read option control register F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR); return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte); } /** * Write option control register F7 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, FLASH_F7_OPTCR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_cr & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_F7_OPTCR); return ret; } /** * Read option control register1 F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register 1 byte from %#10x\n", FLASH_F7_OPTCR1); return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte); } /** * Write option control register1 F7 * @param sl * @param option_cr1 * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#010x to %#010x.\n", option_cr1, FLASH_F7_OPTCR1); /* write option byte, ensuring we dont lock opt, and set strt bit */ uint32_t current_control_register_value; stlink_read_debug32(sl, FLASH_F7_OPTCR, ¤t_control_register_value); /* write option byte */ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_cr1); stlink_write_debug32( sl, FLASH_F7_OPTCR, (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr1, FLASH_F7_OPTCR1); return ret; } /** * Read option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option byte boot address\n"); return stlink_read_option_control_register1_f7(sl, option_byte); } /** * Write option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) { ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add); return stlink_write_option_control_register1_f7(sl, option_byte_boot_add); } /** * Read option control register Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_Gx_OPTR, option_byte); } /** * Read option bytes Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_gx(sl, option_byte); } /** * Write option bytes Gx * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, FLASH_Gx_OPTR, data); // Set Options Start bit stlink_read_debug32(sl, FLASH_Gx_CR, &val); val |= (1 << FLASH_Gx_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_Gx_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, FLASH_Gx_CR, &val); val |= (1 << FLASH_Gx_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_Gx_CR, val); return (ret); } /** * Write option bytes H7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; uint32_t data; // Wait until previous flash option has completed wait_flash_busy(sl); // Clear previous error stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); while (len != 0) { switch (addr) { case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1 case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1 case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1 case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG /* Write to FLASH_xxx_PRG registers */ write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); /* Skip if the value in the CUR register is identical */ stlink_read_debug32(sl, addr - 4, &val); if (val == data) { break; } /* Write new option byte values and start modification */ stlink_write_debug32(sl, addr, data); stlink_read_debug32(sl, FLASH_H7_OPTCR, &val); val |= (1 << FLASH_H7_OPTCR_OPTSTART); stlink_write_debug32(sl, FLASH_H7_OPTCR, val); /* Wait for the option bytes modification to complete */ do { stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val); } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0); /* Check for errors */ if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) { stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); return -1; } break; default: /* Skip non-programmable registers */ break; } len -= 4; addr += 4; base += 4; } return 0; } /** * Write option bytes L0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t flash_base = get_stm32l0_flash_base(sl); uint32_t val; uint32_t data; int32_t ret = 0; // Clear errors clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if ((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Reload options stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val); val |= (1 << FLASH_L0_OBL_LAUNCH); stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val); return (ret); } /** * Write option bytes L4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); // write options bytes uint32_t data; write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes 0x%04x\n", data); stlink_write_debug32(sl, FLASH_L4_OPTR, data); // set options start bit stlink_read_debug32(sl, FLASH_L4_CR, &val); val |= (1 << FLASH_L4_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_L4_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // apply options bytes immediate stlink_read_debug32(sl, FLASH_L4_CR, &val); val |= (1 << FLASH_L4_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_L4_CR, val); return (ret); } /** * Write option bytes WB * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if ((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Set Options Start bit stlink_read_debug32(sl, FLASH_WB_CR, &val); val |= (1 << FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, FLASH_WB_CR, &val); val |= (1 << FLASH_WB_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_WB_CR, val); return (ret); } /** * Read option control register WB * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_WB_OPTR); return stlink_read_debug32(sl, FLASH_WB_OPTR, option_byte); } /** * Write option control register WB * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, FLASH_WB_OPTR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_WB_OPTR, option_cr); wait_flash_busy(sl); // Set Options Start bit uint32_t val = (1 << FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_WB_OPTR); return ret; } /** * Read option bytes generic * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); return stlink_read_debug32(sl, sl->option_base, option_byte); } /** * Write option bytes * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { int32_t ret = -1; if (sl->option_base == 0) { ELOG("Option bytes writing is currently not supported for connected chip\n"); return (-1); } if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) { ELOG("Option bytes start address out of Option bytes range\n"); return (-1); } if (addr + len > sl->option_base + sl->option_size) { ELOG("Option bytes data too long\n"); return (-1); } wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return (-1); } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return (-1); } switch (sl->flash_type) { case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_bytes_f0(sl, addr, base, len); break; case STM32_FLASH_TYPE_F2_F4: ret = stlink_write_option_bytes_f4(sl, addr, base, len); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_f7(sl, addr, base, len); break; case STM32_FLASH_TYPE_L0_L1: ret = stlink_write_option_bytes_l0(sl, addr, base, len); break; case STM32_FLASH_TYPE_L4: ret = stlink_write_option_bytes_l4(sl, addr, base, len); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: ret = stlink_write_option_bytes_gx(sl, addr, base, len); break; case STM32_FLASH_TYPE_H7: ret = stlink_write_option_bytes_h7(sl, addr, base, len); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_bytes_wb(sl, addr, base, len); break; default: ELOG("Option bytes writing is currently not implemented for connected chip\n"); break; } if (ret) { ELOG("Flash option write failed!\n"); } else { ILOG("Wrote %d option bytes to %#010x!\n", len, addr); } /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Write the given binary file with option bytes * @param sl * @param path readable file path, should be binary image * @param addr of the memory mapped option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr) { /* Write the file in flash at addr */ int32_t err; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if (map_file(&mf, path) == -1) { ELOG("map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len); stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); } /** * Read option control register 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: return stlink_read_option_control_register_f0(sl, option_byte); case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register_f7(sl, option_byte); case STM32_FLASH_TYPE_WB_WL: return stlink_read_option_control_register_wb(sl, option_byte); default: return -1; } } /** * Write option control register 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_control_register_f0(sl, option_cr); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register_f7(sl, option_cr); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_control_register_wb(sl, option_cr); break; default: ELOG("Option control register writing is currently not implemented for connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register %#010x!\n", option_cr); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Read option control register1 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register1_f7(sl, option_byte); default: return -1; // return stlink_read_option_control_register1_generic(sl, option_byte); } } /** * Write option control register1 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register1_f7(sl, option_cr1); break; default: ELOG("Option control register 1 writing is currently not implemented for " "connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register 1 %#010x!\n", option_cr1); lock_flash_option(sl); lock_flash(sl); return (ret); } /** * Read option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return (-1); } switch (sl->chip_id) { case STM32_CHIPID_F2: return stlink_read_option_bytes_f2(sl, option_byte); case STM32_CHIPID_F4: case STM32_CHIPID_F446: return stlink_read_option_bytes_f4(sl, option_byte); case STM32_CHIPID_F76xxx: return stlink_read_option_bytes_f7(sl, option_byte); case STM32_CHIPID_G0_CAT1: case STM32_CHIPID_G0_CAT2: case STM32_CHIPID_G4_CAT2: case STM32_CHIPID_G4_CAT3: case STM32_CHIPID_G4_CAT4: return stlink_read_option_bytes_gx(sl, option_byte); default: return stlink_read_option_bytes_generic(sl, option_byte); } } /** * Write option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) { WLOG("About to write option byte %#10x to %#10x.\n", option_byte, sl->option_base); return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, 4); } /** * Read option bytes boot address 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes boot address read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_bytes_boot_add_f7(sl, option_byte); default: return -1; // return stlink_read_option_bytes_boot_add_generic(sl, option_byte); } } /** * Write option bytes boot address 32 * @param sl * @param option_bytes_boot_add * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add); break; default: ELOG("Option bytes boot address writing is currently not implemented for connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; }