From 363536ecacf9fffe0ad669b314bba4f798d423e8 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Mon, 17 Jun 2024 18:05:45 +0800 Subject: [PATCH 01/11] 0.4.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d8ac303e..91061c83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "esptool-js", - "version": "0.4.1", + "version": "0.4.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "esptool-js", - "version": "0.4.1", + "version": "0.4.2", "license": "Apache-2.0", "dependencies": { "atob-lite": "^2.0.0", diff --git a/package.json b/package.json index 732f9b31..22af0f8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esptool-js", - "version": "0.4.1", + "version": "0.4.2", "type": "module", "module": "lib/index.js", "main": "lib/index.js", From d48fe9ccd1e682e45ffcac5cc8c1e57c7aaf41fa Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Tue, 18 Jun 2024 19:54:15 +0800 Subject: [PATCH 02/11] rm type module package json --- package.json | 3 +-- rollup.config.js => rollup.config.mjs | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename rollup.config.js => rollup.config.mjs (100%) diff --git a/package.json b/package.json index 22af0f8f..a4237a77 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "esptool-js", "version": "0.4.2", - "type": "module", "module": "lib/index.js", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -12,7 +11,7 @@ ], "scripts": { "build": "npm run clean && tsc && rollup --config", - "clean": "rimraf lib bundle.js .parcel-cache", + "clean": "rimraf lib bundle.js .parcel-cache esptool-js-*.tgz", "format": "prettier --write \"src/**/*.ts\"", "genDocs": "rimraf docs && typedoc", "lint": "eslint . --ext .ts", diff --git a/rollup.config.js b/rollup.config.mjs similarity index 100% rename from rollup.config.js rename to rollup.config.mjs From d071e7d04187770a4fcacf68cc5b90fa1e7c493a Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Tue, 18 Jun 2024 19:57:30 +0800 Subject: [PATCH 03/11] 0.4.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91061c83..03f2b6e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "esptool-js", - "version": "0.4.2", + "version": "0.4.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "esptool-js", - "version": "0.4.2", + "version": "0.4.3", "license": "Apache-2.0", "dependencies": { "atob-lite": "^2.0.0", diff --git a/package.json b/package.json index a4237a77..1857de9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esptool-js", - "version": "0.4.2", + "version": "0.4.3", "module": "lib/index.js", "main": "lib/index.js", "types": "lib/index.d.ts", From 71a6a298700abeadb8807991e54db0685bfa46d5 Mon Sep 17 00:00:00 2001 From: "Brian A. Ignacio" Date: Thu, 18 Jul 2024 16:49:51 +0800 Subject: [PATCH 04/11] add esp32 p4 stub and target code (#147) * add esp32 p4 stub and target code * update esp32p4 magic value * add all listed esp32 p4 magic values --- src/esploader.ts | 7 + src/targets/esp32p4.ts | 222 ++++++++++++++++++ .../stub_flasher/stub_flasher_32p4.json | 8 + 3 files changed, 237 insertions(+) create mode 100644 src/targets/esp32p4.ts create mode 100644 src/targets/stub_flasher/stub_flasher_32p4.json diff --git a/src/esploader.ts b/src/esploader.ts index e47b1900..fb70ecd5 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -155,6 +155,12 @@ async function magic2Chip(magic: number): Promise { const { ESP8266ROM } = await import("./targets/esp8266.js"); return new ESP8266ROM(); } + case 0x0: + case 0x0addbad0: + case 0x7039ad9: { + const { ESP32P4ROM } = await import("./targets/esp32p4.js"); + return new ESP32P4ROM(); + } default: return null; } @@ -672,6 +678,7 @@ export class ESPLoader { if (!detecting) { const chipMagicValue = (await this.readReg(0x40001000)) >>> 0; this.debug("Chip Magic " + chipMagicValue.toString(16)); + this.info("Chip Magic " + chipMagicValue.toString(16)); const chip = await magic2Chip(chipMagicValue); if (this.chip === null) { throw new ESPError(`Unexpected CHIP magic value ${chipMagicValue}. Failed to autodetect chip type.`); diff --git a/src/targets/esp32p4.ts b/src/targets/esp32p4.ts new file mode 100644 index 00000000..49044720 --- /dev/null +++ b/src/targets/esp32p4.ts @@ -0,0 +1,222 @@ +import { ESPLoader } from "../esploader.js"; +import { ESP32ROM } from "./esp32.js"; +import ESP32P4_STUB from "./stub_flasher/stub_flasher_32p4.json"; + +export class ESP32P4ROM extends ESP32ROM { + public CHIP_NAME = "ESP32-P4"; + public IMAGE_CHIP_ID = 18; + + public IROM_MAP_START = 0x40000000; + public IROM_MAP_END = 0x4c000000; + public DROM_MAP_START = 0x40000000; + public DROM_MAP_END = 0x4c000000; + + public BOOTLOADER_FLASH_OFFSET = 0x2000; // First 2 sectors are reserved for FE purposes + + public CHIP_DETECT_MAGIC_VALUE = [0x0, 0x0addbad0]; + + public UART_DATE_REG_ADDR = 0x500ca000 + 0x8c; + + public EFUSE_BASE = 0x5012d000; + public EFUSE_BLOCK1_ADDR = this.EFUSE_BASE + 0x044; + public MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; + + public SPI_REG_BASE = 0x5008d000; // SPIMEM1 + public SPI_USR_OFFS = 0x18; + public SPI_USR1_OFFS = 0x1c; + public SPI_USR2_OFFS = 0x20; + public SPI_MOSI_DLEN_OFFS = 0x24; + public SPI_MISO_DLEN_OFFS = 0x28; + public SPI_W0_OFFS = 0x58; + + public EFUSE_RD_REG_BASE = this.EFUSE_BASE + 0x030; // BLOCK0 read base address + + public EFUSE_PURPOSE_KEY0_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY0_SHIFT = 24; + public EFUSE_PURPOSE_KEY1_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY1_SHIFT = 28; + public EFUSE_PURPOSE_KEY2_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY2_SHIFT = 0; + public EFUSE_PURPOSE_KEY3_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY3_SHIFT = 4; + public EFUSE_PURPOSE_KEY4_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY4_SHIFT = 8; + public EFUSE_PURPOSE_KEY5_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY5_SHIFT = 12; + + public EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = this.EFUSE_RD_REG_BASE; + public EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20; + + public EFUSE_SPI_BOOT_CRYPT_CNT_REG = this.EFUSE_BASE + 0x034; + public EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18; + + public EFUSE_SECURE_BOOT_EN_REG = this.EFUSE_BASE + 0x038; + public EFUSE_SECURE_BOOT_EN_MASK = 1 << 20; + + public PURPOSE_VAL_XTS_AES256_KEY_1 = 2; + public PURPOSE_VAL_XTS_AES256_KEY_2 = 3; + public PURPOSE_VAL_XTS_AES128_KEY = 4; + + public SUPPORTS_ENCRYPTED_FLASH = true; + + public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + + public MEMORY_MAP = [ + [0x00000000, 0x00010000, "PADDING"], + [0x40000000, 0x4c000000, "DROM"], + [0x4ff00000, 0x4ffa0000, "DRAM"], + [0x4ff00000, 0x4ffa0000, "BYTE_ACCESSIBLE"], + [0x4fc00000, 0x4fc20000, "DROM_MASK"], + [0x4fc00000, 0x4fc20000, "IROM_MASK"], + [0x40000000, 0x4c000000, "IROM"], + [0x4ff00000, 0x4ffa0000, "IRAM"], + [0x50108000, 0x50110000, "RTC_IRAM"], + [0x50108000, 0x50110000, "RTC_DRAM"], + [0x600fe000, 0x60100000, "MEM_INTERNAL2"], + ]; + + public UF2_FAMILY_ID = 0x3d308e94; + + public EFUSE_MAX_KEY = 5; + public KEY_PURPOSES = { + 0: "USER/EMPTY", + 1: "ECDSA_KEY", + 2: "XTS_AES_256_KEY_1", + 3: "XTS_AES_256_KEY_2", + 4: "XTS_AES_128_KEY", + 5: "HMAC_DOWN_ALL", + 6: "HMAC_DOWN_JTAG", + 7: "HMAC_DOWN_DIGITAL_SIGNATURE", + 8: "HMAC_UP", + 9: "SECURE_BOOT_DIGEST0", + 10: "SECURE_BOOT_DIGEST1", + 11: "SECURE_BOOT_DIGEST2", + 12: "KM_INIT_KEY", + }; + + public TEXT_START = ESP32P4_STUB.text_start; + public ENTRY = ESP32P4_STUB.entry; + public DATA_START = ESP32P4_STUB.data_start; + public ROM_DATA = ESP32P4_STUB.data; + public ROM_TEXT = ESP32P4_STUB.text; + + public async getPkgVersion(loader: ESPLoader): Promise { + const numWord = 2; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; + const registerValue = await loader.readReg(addr); + return (registerValue >> 27) & 0x07; + } + + public async getMinorChipVersion(loader: ESPLoader): Promise { + const numWord = 2; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; + const registerValue = await loader.readReg(addr); + return (registerValue >> 0) & 0x0f; + } + + public async getMajorChipVersion(loader: ESPLoader): Promise { + const numWord = 2; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; + const registerValue = await loader.readReg(addr); + return (registerValue >> 4) & 0x03; + } + + public async getChipDescription(loader: ESPLoader): Promise { + const pkgVersion = await this.getPkgVersion(loader); + const chipName = pkgVersion === 0 ? "ESP32-P4" : "unknown ESP32-P4"; + const majorRev = await this.getMajorChipVersion(loader); + const minorRev = await this.getMinorChipVersion(loader); + return `${chipName} (revision v${majorRev}.${minorRev})`; + } + + public async getChipFeatures(loader: ESPLoader): Promise { + return ["High-Performance MCU"]; + } + + public async getCrystalFreq(loader: ESPLoader): Promise { + return 40; // ESP32P4 XTAL is fixed to 40MHz + } + + public async getFlashVoltage(loader: ESPLoader) { + return; + } + + public async overrideVddsdio(loader: ESPLoader) { + loader.debug("VDD_SDIO overrides are not supported for ESP32-P4"); + } + + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + + return ( + this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5]) + ); + } + + public async getFlashCryptConfig(loader: ESPLoader) { + return; // doesn't exist on ESP32-P4 + } + + public async getSecureBootEnabled(laoder: ESPLoader) { + const registerValue = await laoder.readReg(this.EFUSE_SECURE_BOOT_EN_REG); + return registerValue & this.EFUSE_SECURE_BOOT_EN_MASK; + } + + public async getKeyBlockPurpose(loader: ESPLoader, keyBlock: number) { + if (keyBlock < 0 || keyBlock > this.EFUSE_MAX_KEY) { + loader.debug(`Valid key block numbers must be in range 0-${this.EFUSE_MAX_KEY}`); + return; + } + + const regShiftDictionary = [ + [this.EFUSE_PURPOSE_KEY0_REG, this.EFUSE_PURPOSE_KEY0_SHIFT], + [this.EFUSE_PURPOSE_KEY1_REG, this.EFUSE_PURPOSE_KEY1_SHIFT], + [this.EFUSE_PURPOSE_KEY2_REG, this.EFUSE_PURPOSE_KEY2_SHIFT], + [this.EFUSE_PURPOSE_KEY3_REG, this.EFUSE_PURPOSE_KEY3_SHIFT], + [this.EFUSE_PURPOSE_KEY4_REG, this.EFUSE_PURPOSE_KEY4_SHIFT], + [this.EFUSE_PURPOSE_KEY5_REG, this.EFUSE_PURPOSE_KEY5_SHIFT], + ]; + const [reg, shift] = regShiftDictionary[keyBlock]; + + const registerValue = await loader.readReg(reg); + return (registerValue >> shift) & 0xf; + } + + public async isFlashEncryptionKeyValid(loader: ESPLoader) { + const purposes = []; + for (let i = 0; i <= this.EFUSE_MAX_KEY; i++) { + const purpose = await this.getKeyBlockPurpose(loader, i); + purposes.push(purpose); + } + const isXtsAes128Key = purposes.find((p) => p === this.PURPOSE_VAL_XTS_AES128_KEY); + if (typeof isXtsAes128Key !== undefined) { + return true; + } + const isXtsAes256Key1 = purposes.find((p) => p === this.PURPOSE_VAL_XTS_AES256_KEY_1); + const isXtsAes256Key2 = purposes.find((p) => p === this.PURPOSE_VAL_XTS_AES256_KEY_2); + if (typeof isXtsAes256Key1 !== undefined && typeof isXtsAes256Key2 !== undefined) { + return true; + } + return false; + } +} diff --git a/src/targets/stub_flasher/stub_flasher_32p4.json b/src/targets/stub_flasher/stub_flasher_32p4.json new file mode 100644 index 00000000..01fbe00a --- /dev/null +++ b/src/targets/stub_flasher/stub_flasher_32p4.json @@ -0,0 +1,8 @@ +{ + "entry": 1341195918, + "text": "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", + "text_start": 1341194240, + "data": "EAD1TwYK8U9WCvFPrgrxT4QL8U/wC/FPngvxT9QI8U9AC/FPgAvxT8IK8U+ECPFP9grxT4QI8U/gCfFPJgrxT1YK8U+uCvFP8gnxTzgJ8U9oCfFP7gnxT0AO8U9WCvFPCA3xTwAO8U/EB/FPJA7xT8QH8U/EB/FPxAfxT8QH8U/EB/FPxAfxT8QH8U/EB/FPpAzxT8QH8U8mDfFPAA7xTw==", + "data_start": 1341533100, + "bss_start": 1341456384 +} \ No newline at end of file From 5782eb0565cf6a1a38ac266554d4267e509ce5c8 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Thu, 18 Jul 2024 17:27:30 +0800 Subject: [PATCH 05/11] 0.4.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03f2b6e4..2e53b8d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "esptool-js", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "esptool-js", - "version": "0.4.3", + "version": "0.4.4", "license": "Apache-2.0", "dependencies": { "atob-lite": "^2.0.0", diff --git a/package.json b/package.json index 1857de9b..5d5f8943 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esptool-js", - "version": "0.4.3", + "version": "0.4.4", "module": "lib/index.js", "main": "lib/index.js", "types": "lib/index.d.ts", From 34b93b4644326e9f3e3fed7051596448f0b8ab91 Mon Sep 17 00:00:00 2001 From: "Brian A. Ignacio" Date: Thu, 18 Jul 2024 21:56:43 +0800 Subject: [PATCH 06/11] rm info chip magic, fix bundle atob ref (#148) --- rollup.config.mjs | 2 +- src/esploader.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rollup.config.mjs b/rollup.config.mjs index 793897e2..48abcdc2 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -17,7 +17,7 @@ const config = { inlineDynamicImports: true }, plugins: [ - resolve({ preferBuiltins: false}), + resolve({ preferBuiltins: false, mainFields: ["browser"]}), commonjs(), babel({ exclude: 'node_modules/**', babelHelpers: "runtime", skipPreflightCheck: true }), json({ namedExports: false, preferConst: true }), diff --git a/src/esploader.ts b/src/esploader.ts index fb70ecd5..54a9399a 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -678,7 +678,6 @@ export class ESPLoader { if (!detecting) { const chipMagicValue = (await this.readReg(0x40001000)) >>> 0; this.debug("Chip Magic " + chipMagicValue.toString(16)); - this.info("Chip Magic " + chipMagicValue.toString(16)); const chip = await magic2Chip(chipMagicValue); if (this.chip === null) { throw new ESPError(`Unexpected CHIP magic value ${chipMagicValue}. Failed to autodetect chip type.`); From 1e721b05e59a251e9d160c6dab4c63021269a35d Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Thu, 18 Jul 2024 21:58:23 +0800 Subject: [PATCH 07/11] 0.4.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e53b8d6..030ef43e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "esptool-js", - "version": "0.4.4", + "version": "0.4.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "esptool-js", - "version": "0.4.4", + "version": "0.4.5", "license": "Apache-2.0", "dependencies": { "atob-lite": "^2.0.0", diff --git a/package.json b/package.json index 5d5f8943..dfc9b82d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esptool-js", - "version": "0.4.4", + "version": "0.4.5", "module": "lib/index.js", "main": "lib/index.js", "types": "lib/index.d.ts", From 1a0c7b56bc9b42d752b6a38aad40ea34c5aff28f Mon Sep 17 00:00:00 2001 From: rakosnicekcz Date: Thu, 11 Apr 2024 16:23:35 +0200 Subject: [PATCH 08/11] Added non compressed writes --- src/esploader.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/esploader.ts b/src/esploader.ts index 54a9399a..467a2fa3 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -1422,7 +1422,7 @@ export class ESPLoader { Math.floor((100 * (seq + 1)) / blocks) + "%)", ); - const block = this.bstrToUi8(image.slice(0, this.FLASH_WRITE_SIZE)); + let block = this.bstrToUi8(image.slice(0, this.FLASH_WRITE_SIZE)); if (options.compress) { const lenUncompressedPrevious = totalLenUncompressed; @@ -1442,7 +1442,10 @@ export class ESPLoader { timeout = blockTimeout; } } else { - throw new ESPError("Yet to handle Non Compressed writes"); + const padding = new Uint8Array(this.FLASH_WRITE_SIZE - block.length).fill(0xff); + block = this._appendArray(block, padding); + + await this.flashBlock(block, seq, timeout); } bytesSent += block.length; image = image.slice(this.FLASH_WRITE_SIZE, image.length); From 766541e58bde754fdf4a13f1598823b4817ba513 Mon Sep 17 00:00:00 2001 From: rakosnicekcz Date: Fri, 12 Apr 2024 16:45:06 +0200 Subject: [PATCH 09/11] Added flash encryption --- examples/typescript/src/index.ts | 1 + src/esploader.ts | 64 +++++++++++++++++++++++++++++--- src/targets/esp32.ts | 2 + src/targets/esp32c3.ts | 3 ++ src/targets/esp32c6.ts | 3 ++ src/targets/esp32h2.ts | 3 ++ src/targets/esp32s2.ts | 3 ++ src/targets/esp32s3.ts | 3 ++ src/targets/esp8266.ts | 1 + src/targets/rom.ts | 1 + 10 files changed, 79 insertions(+), 5 deletions(-) diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 7df3008f..96320db5 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -346,6 +346,7 @@ programButton.onclick = async () => { flashSize: "keep", eraseAll: false, compress: true, + encrpyt: false, reportProgress: (fileIndex, written, total) => { progressBars[fileIndex].value = (written / total) * 100; }, diff --git a/src/esploader.ts b/src/esploader.ts index 467a2fa3..0d169203 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -48,6 +48,12 @@ export interface FlashOptions { */ compress: boolean; + /** + * Flag indicating whether to apply flash encryption when writing data. + * @type {boolean} + */ + encrpyt: boolean; + /** * A function to report the progress of the flashing operation (optional). * @type {(fileIndex: number, written: number, total: number) => void} @@ -213,6 +219,9 @@ export class ESPLoader { ESP_READ_FLASH = 0xd2; ESP_RUN_USER_CODE = 0xd3; + // Flash encryption encrypted data command + ESP_FLASH_ENCRYPT_DATA = 0xd4; + ESP_IMAGE_MAGIC = 0xe9; ESP_CHECKSUM_MAGIC = 0xef; @@ -455,6 +464,19 @@ export class ESPLoader { } } + /** + * Pads a given string to a specified alignment by appending a specified character. + * @param {string} data - String to be padded. + * @param {number} alignment - Alignment boundary. + * @param {string} padCharacter - The character to use for padding. Defaults to "\xff" if not specified. + * @returns {string} Return the padded string. + */ + padTo(data: string, alignment: number, padCharacter = "\xff"): string { + const pad_mod = data.length % alignment; + if (pad_mod !== 0) data += padCharacter.repeat(alignment).substring(alignment - pad_mod); + return data; + } + /** * Use the device serial port read function with given timeout to create a valid packet. * @param {number} op Operation number @@ -902,6 +924,29 @@ export class ESPLoader { await this.checkCommand("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); } + /** + * Write encrypted block to flash, retry if fail + * @param {Uint8Array} data Unsigned 8-bit array data. + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + async flashEncryptBlock(data: Uint8Array, seq: number, timeout: number) { + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, data); + + const checksum = this.checksum(data); + + await this.checkCommand( + "write encrypted to target Flash after seq " + seq, + this.ESP_FLASH_ENCRYPT_DATA, + pkt, + checksum, + timeout, + ); + } + /** * Write block to flash, send compressed, retry if fail * @param {Uint8Array} data Unsigned int 8-bit array data to write @@ -1373,9 +1418,15 @@ export class ESPLoader { let image: string, address: number; for (let i = 0; i < options.fileArray.length; i++) { this.debug("Data Length " + options.fileArray[i].data.length); + + if (options.compress && options.encrpyt) { + this.info("WARNING: compress and encrypt options are mutually exclusive"); + this.info("Will flash uncompressed"); + options.compress = false; + } + image = options.fileArray[i].data; - const reminder = options.fileArray[i].data.length % 4; - if (reminder > 0) image += "\xff\xff\xff\xff".substring(4 - reminder); + image = this.padTo(image, options.encrpyt ? this.chip.FLASH_ENCRYPTED_WRITE_ALIGN : 4); address = options.fileArray[i].address; this.debug("Image Length " + image.length); if (image.length === 0) { @@ -1444,8 +1495,11 @@ export class ESPLoader { } else { const padding = new Uint8Array(this.FLASH_WRITE_SIZE - block.length).fill(0xff); block = this._appendArray(block, padding); - - await this.flashBlock(block, seq, timeout); + if (options.encrpyt) { + await this.flashEncryptBlock(block, seq, timeout); + } else { + await this.flashBlock(block, seq, timeout); + } } bytesSent += block.length; image = image.slice(this.FLASH_WRITE_SIZE, image.length); @@ -1470,7 +1524,7 @@ export class ESPLoader { " seconds.", ); } - if (calcmd5) { + if (calcmd5 && !options.encrpyt) { const res = await this.flashMd5sum(address, uncsize); if (new String(res).valueOf() != new String(calcmd5).valueOf()) { this.info("File md5: " + calcmd5); diff --git a/src/targets/esp32.ts b/src/targets/esp32.ts index 6ef67f3c..d14963d3 100644 --- a/src/targets/esp32.ts +++ b/src/targets/esp32.ts @@ -23,6 +23,8 @@ export class ESP32ROM extends ROM { public FLASH_WRITE_SIZE = 0x400; public BOOTLOADER_FLASH_OFFSET = 0x1000; + public FLASH_ENCRYPTED_WRITE_ALIGN = 32; + public SPI_REG_BASE = 0x3ff42000; public SPI_USR_OFFS = 0x1c; public SPI_USR1_OFFS = 0x20; diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index af65a081..8b9c1203 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -22,6 +22,9 @@ export class ESP32C3ROM extends ROM { "16MB": 0x40, }; + public SUPPORTS_ENCRYPTED_FLASH = true; + public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + public SPI_REG_BASE = 0x60002000; public SPI_USR_OFFS = 0x18; public SPI_USR1_OFFS = 0x1c; diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index 6d82e3bd..0b203419 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -22,6 +22,9 @@ export class ESP32C6ROM extends ROM { "16MB": 0x40, }; + public SUPPORTS_ENCRYPTED_FLASH = true; + public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + public SPI_REG_BASE = 0x60002000; public SPI_USR_OFFS = 0x18; public SPI_USR1_OFFS = 0x1c; diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index 4d2ccfaf..6a65cf30 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -14,6 +14,9 @@ export class ESP32H2ROM extends ROM { public FLASH_WRITE_SIZE = 0x400; public BOOTLOADER_FLASH_OFFSET = 0x0; + // NOT IMPLEMENTED, SETTING EMPTY VALUE + public FLASH_ENCRYPTED_WRITE_ALIGN = 0; + public FLASH_SIZES = { "1MB": 0x00, "2MB": 0x10, diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index f23387a3..a3c3e6c0 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -22,6 +22,9 @@ export class ESP32S2ROM extends ROM { "16MB": 0x40, }; + public SUPPORTS_ENCRYPTED_FLASH = true; + public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + public SPI_REG_BASE = 0x3f402000; public SPI_USR_OFFS = 0x18; public SPI_USR1_OFFS = 0x1c; diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 583a3f87..ae6e99af 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -22,6 +22,9 @@ export class ESP32S3ROM extends ROM { "16MB": 0x40, }; + public SUPPORTS_ENCRYPTED_FLASH = true; + public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + public SPI_REG_BASE = 0x60002000; public SPI_USR_OFFS = 0x18; public SPI_USR1_OFFS = 0x1c; diff --git a/src/targets/esp8266.ts b/src/targets/esp8266.ts index 96ba8df5..d8689897 100644 --- a/src/targets/esp8266.ts +++ b/src/targets/esp8266.ts @@ -15,6 +15,7 @@ export class ESP8266ROM extends ROM { // NOT IMPLEMENTED, SETTING EMPTY VALUE public BOOTLOADER_FLASH_OFFSET = 0; public UART_DATE_REG_ADDR = 0; + public FLASH_ENCRYPTED_WRITE_ALIGN = 0; public FLASH_SIZES = { "512KB": 0x00, diff --git a/src/targets/rom.ts b/src/targets/rom.ts index 02146ded..d4981dc7 100644 --- a/src/targets/rom.ts +++ b/src/targets/rom.ts @@ -100,4 +100,5 @@ export abstract class ROM { abstract UART_DATE_REG_ADDR: number; // not in esp8266 abstract TEXT_START: number; // abstract XTAL_CLK_DIVIDER: number; //esp32 + abstract FLASH_ENCRYPTED_WRITE_ALIGN: number; } From 73bd5451a1cccf2b2af0c61c6e840f2b5caa5078 Mon Sep 17 00:00:00 2001 From: urbanek Date: Tue, 13 Aug 2024 09:38:53 +0200 Subject: [PATCH 10/11] fix: typo --- examples/typescript/src/index.ts | 4 ++-- src/esploader.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 96320db5..829de487 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -346,12 +346,12 @@ programButton.onclick = async () => { flashSize: "keep", eraseAll: false, compress: true, - encrpyt: false, + encrypt: false, reportProgress: (fileIndex, written, total) => { progressBars[fileIndex].value = (written / total) * 100; }, calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image)), - } as FlashOptions; + } as unknown as FlashOptions; await esploader.writeFlash(flashOptions); } catch (e) { console.error(e); diff --git a/src/esploader.ts b/src/esploader.ts index 0d169203..4ed5a606 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -52,7 +52,7 @@ export interface FlashOptions { * Flag indicating whether to apply flash encryption when writing data. * @type {boolean} */ - encrpyt: boolean; + encrypt: boolean; /** * A function to report the progress of the flashing operation (optional). @@ -1419,14 +1419,14 @@ export class ESPLoader { for (let i = 0; i < options.fileArray.length; i++) { this.debug("Data Length " + options.fileArray[i].data.length); - if (options.compress && options.encrpyt) { + if (options.compress && options.encrypt) { this.info("WARNING: compress and encrypt options are mutually exclusive"); this.info("Will flash uncompressed"); options.compress = false; } image = options.fileArray[i].data; - image = this.padTo(image, options.encrpyt ? this.chip.FLASH_ENCRYPTED_WRITE_ALIGN : 4); + image = this.padTo(image, options.encrypt ? this.chip.FLASH_ENCRYPTED_WRITE_ALIGN : 4); address = options.fileArray[i].address; this.debug("Image Length " + image.length); if (image.length === 0) { @@ -1495,7 +1495,7 @@ export class ESPLoader { } else { const padding = new Uint8Array(this.FLASH_WRITE_SIZE - block.length).fill(0xff); block = this._appendArray(block, padding); - if (options.encrpyt) { + if (options.encrypt) { await this.flashEncryptBlock(block, seq, timeout); } else { await this.flashBlock(block, seq, timeout); @@ -1524,7 +1524,7 @@ export class ESPLoader { " seconds.", ); } - if (calcmd5 && !options.encrpyt) { + if (calcmd5 && !options.encrypt) { const res = await this.flashMd5sum(address, uncsize); if (new String(res).valueOf() != new String(calcmd5).valueOf()) { this.info("File md5: " + calcmd5); From 117b12aa7f8678bf7547c65579fe527dfce4da16 Mon Sep 17 00:00:00 2001 From: fredo Date: Fri, 12 Apr 2024 18:52:13 +0200 Subject: [PATCH 11/11] feature: added example frontend for the user to interact with the compression and encrypted flashing. --- examples/typescript/src/index.html | 6 ++++++ examples/typescript/src/index.ts | 24 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/typescript/src/index.html b/examples/typescript/src/index.html index 82d40802..382a5007 100644 --- a/examples/typescript/src/index.html +++ b/examples/typescript/src/index.html @@ -63,6 +63,12 @@

Program

+

+ + +
+ +
diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 829de487..6389348a 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -306,9 +306,29 @@ function validateProgramInputs() { return "success"; } +document.addEventListener('DOMContentLoaded', (event) => { + const compressCheckbox = document.getElementById('compressCheckbox') as HTMLInputElement; + const encryptCheckbox = document.getElementById('encryptCheckbox') as HTMLInputElement; + + encryptCheckbox.addEventListener('change', () => { + if (encryptCheckbox.checked) { + compressCheckbox.checked = false; + compressCheckbox.disabled = true; + } else { + compressCheckbox.checked = true; + compressCheckbox.disabled = false; + } + }); +}); + programButton.onclick = async () => { const alertMsg = document.getElementById("alertmsg"); const err = validateProgramInputs(); + const compressCheckbox = document.getElementById('compressCheckbox') as HTMLInputElement; + const encryptCheckbox = document.getElementById('encryptCheckbox') as HTMLInputElement; + + console.log("compressCheckbox", compressCheckbox.checked); + console.log("encryptCheckbox", encryptCheckbox.checked); if (err != "success") { alertMsg.innerHTML = "" + err + ""; @@ -345,8 +365,8 @@ programButton.onclick = async () => { fileArray: fileArray, flashSize: "keep", eraseAll: false, - compress: true, - encrypt: false, + compress: compressCheckbox.checked, + encrypt: encryptCheckbox.checked, reportProgress: (fileIndex, written, total) => { progressBars[fileIndex].value = (written / total) * 100; },