mirror of https://github.com/wolfSSL/wolfBoot.git
Fixes for encrypt/decrypt with unaligned address. Fix issue with byte count result on Mac. Cleanups for uart-flash-server.
parent
4ee867b2dd
commit
da6d364f1e
|
@ -98,7 +98,8 @@ struct wolfBoot_image {
|
|||
* With ARMORED setup, the flag is redundant, and the information is wrapped in
|
||||
* between canary variables, to mitigate attacks based on memory corruptions.
|
||||
*/
|
||||
static void __attribute__((noinline)) wolfBoot_image_confirm_signature_ok(struct wolfBoot_image *img)
|
||||
static void __attribute__((noinline)) wolfBoot_image_confirm_signature_ok(
|
||||
struct wolfBoot_image *img)
|
||||
{
|
||||
img->canary_FEED4567 = 0xFEED4567UL;
|
||||
img->signature_ok = 1UL;
|
||||
|
@ -502,7 +503,9 @@ struct wolfBoot_image {
|
|||
uint8_t sha_ok : 1;
|
||||
};
|
||||
|
||||
static void wolfBoot_image_confirm_signature_ok(struct wolfBoot_image *img)
|
||||
/* do not warn if this is not used */
|
||||
static void __attribute__ ((unused)) wolfBoot_image_confirm_signature_ok(
|
||||
struct wolfBoot_image *img)
|
||||
{
|
||||
img->signature_ok = 1;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,13 @@
|
|||
#define NVM_CACHE_SIZE WOLFBOOT_SECTOR_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_TOOL
|
||||
/* Building for a local utility tool */
|
||||
#undef EXT_FLASH
|
||||
#undef EXT_ENCRYPTED
|
||||
#undef WOLFBOOT_FIXED_PARTITIONS
|
||||
#endif
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
static uint32_t ext_cache;
|
||||
#endif
|
||||
|
@ -123,10 +130,10 @@ static const uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL;
|
|||
static uint8_t NVM_CACHE[NVM_CACHE_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
int RAMFUNCTION hal_trailer_write(uint32_t addr, uint8_t val) {
|
||||
uint32_t addr_align = addr & (~(NVM_CACHE_SIZE - 1));
|
||||
size_t addr_align = (size_t)(addr & (~(NVM_CACHE_SIZE - 1)));
|
||||
uint32_t addr_off = addr & (NVM_CACHE_SIZE - 1);
|
||||
int ret = 0;
|
||||
XMEMCPY(NVM_CACHE, (void *)addr_align, NVM_CACHE_SIZE);
|
||||
XMEMCPY(NVM_CACHE, (void*)addr_align, NVM_CACHE_SIZE);
|
||||
ret = hal_flash_erase(addr_align, NVM_CACHE_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
@ -147,9 +154,9 @@ int RAMFUNCTION hal_trailer_write(uint32_t addr, uint8_t val) {
|
|||
int RAMFUNCTION hal_set_partition_magic(uint32_t addr)
|
||||
{
|
||||
uint32_t off = addr % NVM_CACHE_SIZE;
|
||||
uint32_t base = addr - off;
|
||||
size_t base = (size_t)addr - off;
|
||||
int ret;
|
||||
XMEMCPY(NVM_CACHE, (void *)base, NVM_CACHE_SIZE);
|
||||
XMEMCPY(NVM_CACHE, (void*)base, NVM_CACHE_SIZE);
|
||||
ret = hal_flash_erase(base, WOLFBOOT_SECTOR_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
@ -164,8 +171,7 @@ int RAMFUNCTION hal_set_partition_magic(uint32_t addr)
|
|||
(void*)&wolfboot_magic_trail, sizeof(uint32_t));
|
||||
#endif
|
||||
|
||||
#if defined EXT_FLASH
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
|
||||
static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at)
|
||||
{
|
||||
|
@ -232,14 +238,20 @@ static void RAMFUNCTION set_partition_magic(uint8_t part)
|
|||
#elif !defined(WOLFBOOT_FIXED_PARTITIONS)
|
||||
static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at)
|
||||
{
|
||||
(void)part;
|
||||
(void)at;
|
||||
return 0;
|
||||
}
|
||||
static void RAMFUNCTION set_trailer_at(uint8_t part, uint32_t at, uint8_t val)
|
||||
{
|
||||
(void)part;
|
||||
(void)at;
|
||||
(void)val;
|
||||
return;
|
||||
}
|
||||
static void RAMFUNCTION set_partition_magic(uint8_t part)
|
||||
{
|
||||
(void)part;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -809,7 +821,6 @@ int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
|
|||
int RAMFUNCTION wolfBoot_erase_encrypt_key(void)
|
||||
{
|
||||
uint8_t ff[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE];
|
||||
int i;
|
||||
uint8_t *mem = (uint8_t *)ENCRYPT_TMP_SECRET_OFFSET +
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
XMEMSET(ff, 0xFF, ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE);
|
||||
|
@ -935,11 +946,11 @@ static uint8_t RAMFUNCTION part_address(uintptr_t a)
|
|||
int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len)
|
||||
{
|
||||
uint8_t block[ENCRYPT_BLOCK_SIZE];
|
||||
uint8_t part;
|
||||
int sz = len;
|
||||
uint32_t row_address = address, row_offset;
|
||||
int i;
|
||||
uint8_t enc_block[ENCRYPT_BLOCK_SIZE];
|
||||
uint32_t row_address = address, row_offset;
|
||||
int sz = len, i, step;
|
||||
uint8_t part;
|
||||
|
||||
row_offset = address & (ENCRYPT_BLOCK_SIZE - 1);
|
||||
if (row_offset != 0) {
|
||||
row_address = address & ~(ENCRYPT_BLOCK_SIZE - 1);
|
||||
|
@ -948,11 +959,12 @@ int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data,
|
|||
if (sz < ENCRYPT_BLOCK_SIZE) {
|
||||
sz = ENCRYPT_BLOCK_SIZE;
|
||||
}
|
||||
if (!encrypt_initialized)
|
||||
if (!encrypt_initialized) {
|
||||
if (crypto_init() < 0)
|
||||
return -1;
|
||||
}
|
||||
part = part_address(address);
|
||||
switch(part) {
|
||||
switch (part) {
|
||||
case PART_UPDATE:
|
||||
/* do not encrypt flag sector */
|
||||
if (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS >=
|
||||
|
@ -966,34 +978,40 @@ int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data,
|
|||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* encrypt blocks */
|
||||
if (sz > len) {
|
||||
int step = ENCRYPT_BLOCK_SIZE - row_offset;
|
||||
step = ENCRYPT_BLOCK_SIZE - row_offset;
|
||||
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
XMEMCPY(block + row_offset, data, step);
|
||||
crypto_encrypt(enc_block, block, ENCRYPT_BLOCK_SIZE);
|
||||
ext_flash_write(row_address, enc_block, ENCRYPT_BLOCK_SIZE);
|
||||
address += step;
|
||||
data += step;
|
||||
sz -= step;
|
||||
sz = len - step;
|
||||
}
|
||||
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
|
||||
|
||||
/* encrypt remainder */
|
||||
step = sz & ~(ENCRYPT_BLOCK_SIZE - 1);
|
||||
for (i = 0; i < step / ENCRYPT_BLOCK_SIZE; i++) {
|
||||
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
|
||||
crypto_encrypt(ENCRYPT_CACHE + (ENCRYPT_BLOCK_SIZE * i), block,
|
||||
ENCRYPT_BLOCK_SIZE);
|
||||
}
|
||||
return ext_flash_write(address, ENCRYPT_CACHE, len);
|
||||
|
||||
return ext_flash_write(address, ENCRYPT_CACHE, step);
|
||||
}
|
||||
|
||||
int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
|
||||
{
|
||||
uint32_t iv_counter = 0;
|
||||
uint8_t block[ENCRYPT_BLOCK_SIZE];
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE];
|
||||
uint32_t row_address = address, row_offset, iv_counter = 0;
|
||||
int sz = len, i, step;
|
||||
uint8_t part;
|
||||
int sz = len;
|
||||
uint32_t row_address = address, row_offset;
|
||||
int i;
|
||||
|
||||
row_offset = address & (ENCRYPT_BLOCK_SIZE - 1);
|
||||
if (row_offset != 0) {
|
||||
|
@ -1003,11 +1021,12 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
|
|||
if (sz < ENCRYPT_BLOCK_SIZE) {
|
||||
sz = ENCRYPT_BLOCK_SIZE;
|
||||
}
|
||||
if (!encrypt_initialized)
|
||||
if (!encrypt_initialized) {
|
||||
if (crypto_init() < 0)
|
||||
return -1;
|
||||
}
|
||||
part = part_address(row_address);
|
||||
switch(part) {
|
||||
switch (part) {
|
||||
case PART_UPDATE:
|
||||
iv_counter = (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS) /
|
||||
ENCRYPT_BLOCK_SIZE;
|
||||
|
@ -1025,27 +1044,42 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
|
|||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* decrypt blocks */
|
||||
if (sz > len) {
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE];
|
||||
int step = ENCRYPT_BLOCK_SIZE - row_offset;
|
||||
step = ENCRYPT_BLOCK_SIZE - row_offset;
|
||||
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
crypto_decrypt(dec_block, block, ENCRYPT_BLOCK_SIZE);
|
||||
XMEMCPY(data, dec_block + row_offset, step);
|
||||
address += step;
|
||||
data += step;
|
||||
sz -= step;
|
||||
sz = len - step;
|
||||
iv_counter++;
|
||||
}
|
||||
if (ext_flash_read(address, data, sz) != sz)
|
||||
|
||||
/* decrypt remainder */
|
||||
step = sz & ~(ENCRYPT_BLOCK_SIZE - 1);
|
||||
if (ext_flash_read(address, data, step) != step)
|
||||
return -1;
|
||||
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
|
||||
for (i = 0; i < step / ENCRYPT_BLOCK_SIZE; i++) {
|
||||
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
|
||||
crypto_decrypt(data + (ENCRYPT_BLOCK_SIZE * i), block,
|
||||
ENCRYPT_BLOCK_SIZE);
|
||||
iv_counter++;
|
||||
}
|
||||
sz -= step;
|
||||
if (sz > 0) {
|
||||
if (ext_flash_read(address + step, block, ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
crypto_decrypt(dec_block, block, ENCRYPT_BLOCK_SIZE);
|
||||
XMEMCPY(data + step, dec_block, sz);
|
||||
iv_counter++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -90,7 +90,7 @@ test-delta-update-ext: distclean factory.bin test-app/image.bin tools/uart-flash
|
|||
@sleep $(TIMEOUT)
|
||||
@killall ufserver
|
||||
@st-flash read boot_full.bin 0x0800C000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v7_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v7_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v7_signed.bin || (echo "TEST FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
@ -104,7 +104,7 @@ test-delta-update-ext: distclean factory.bin test-app/image.bin tools/uart-flash
|
|||
@killall ufserver
|
||||
@st-flash reset
|
||||
@st-flash read boot_full.bin 0x0800C000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v1_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v1_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v1_signed.bin || (echo "TEST INVERSE FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
@ -136,7 +136,7 @@ test-delta-enc-update-ext: distclean factory.bin test-app/image.bin tools/uart-f
|
|||
@sleep $(TIMEOUT)
|
||||
@st-flash reset
|
||||
@st-flash read boot_full.bin 0x0800C000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v7_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v7_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v7_signed.bin || (echo "TEST FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
@ -153,7 +153,7 @@ test-delta-enc-update-ext: distclean factory.bin test-app/image.bin tools/uart-f
|
|||
@killall ufserver
|
||||
@st-flash reset
|
||||
@st-flash read boot_full.bin 0x0800C000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v1_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v1_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v1_signed.bin || (echo "TEST INVERSE FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
|
|
@ -38,7 +38,7 @@ test-enc-update: factory.bin test-app/image.bin tools/uart-flash-server/ufserver
|
|||
@sleep 3
|
||||
@killall ufserver
|
||||
@st-flash read boot_full.bin 0x08010000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin || (echo "TEST FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
@ -61,7 +61,7 @@ test-enc-aes128-update: factory.bin test-app/image.bin tools/uart-flash-server/u
|
|||
@sleep 3
|
||||
@killall ufserver
|
||||
@st-flash read boot_full.bin 0x08010000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin || (echo "TEST FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
@ -84,7 +84,7 @@ test-enc-aes256-update: factory.bin test-app/image.bin tools/uart-flash-server/u
|
|||
@sleep 3
|
||||
@killall ufserver
|
||||
@st-flash read boot_full.bin 0x08010000 0x8000
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | cut -d" " -f 1`; \
|
||||
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | awk '{$$1=$$1};1' | cut -d" " -f 1`; \
|
||||
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
|
||||
@diff boot.bin test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin || (echo "TEST FAILED" && exit 1)
|
||||
@rm boot.bin boot_full.bin
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
-include ../../.config
|
||||
-include ../../tools/config.mk
|
||||
-include ../../options.mk
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
CFLAGS=-Wall -DWOLFSSL_DEBUG -DTFM_TIMING_RESISTANT -DWOLFBOOT_SIGN_ECC256 -DWOLFBOOT_HASH_SHA256 -g -ggdb -I../../include -I../../hal -Wextra
|
||||
CFLAGS+=-DBUILD_TOOL -Wall -g -ggdb -I../../include -I../../hal -Wextra
|
||||
Q?=@
|
||||
ifeq ($(V),1)
|
||||
Q=
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Run on HOST machine to export an emulated external, non-volatile memory.
|
||||
*
|
||||
* Copyright (C) 2021 wolfSSL Inc.
|
||||
* Copyright (C) 2022 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
|
@ -67,7 +67,8 @@ const char msgWriteSwap[] = "Writing SWAP blocks ";
|
|||
const char msgEraseUpdate[] = "Erase update blocks ";
|
||||
const char msgEraseSwap[] = "Erase swap blocks ";
|
||||
|
||||
extern uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr);
|
||||
extern uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type,
|
||||
uint8_t **ptr);
|
||||
|
||||
const char blinker[]="-\\|/";
|
||||
static int valid_update = 1;
|
||||
|
@ -190,8 +191,7 @@ uint8_t *mmap_firmware(const char *fname)
|
|||
return (void *)-1;
|
||||
}
|
||||
fd = open(fname, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return (void *)-1;
|
||||
}
|
||||
|
@ -211,7 +211,9 @@ uint8_t *mmap_firmware(const char *fname)
|
|||
write(fd, &pad, 1);
|
||||
}
|
||||
if (strncmp((char *)&signature_word, "WOLF", 4) != 0) {
|
||||
fprintf(stderr, "Warning: the binary file provided does not appear to contain a valid firmware partition file. (If the update is encrypted, this is OK)\n");
|
||||
fprintf(stderr, "Warning: the binary file provided does not appear to "
|
||||
"contain a valid firmware partition file. "
|
||||
"(If the update is encrypted, this is OK)\n");
|
||||
valid_update = 0;
|
||||
} else {
|
||||
int i;
|
||||
|
@ -221,7 +223,8 @@ uint8_t *mmap_firmware(const char *fname)
|
|||
for (i = 0; i < SWAP_SIZE; i++)
|
||||
write(fd, update_flags, 5);
|
||||
}
|
||||
base_fw = mmap(NULL, FIRMWARE_PARTITION_SIZE + SWAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
base_fw = mmap(NULL, FIRMWARE_PARTITION_SIZE + SWAP_SIZE,
|
||||
(PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
|
||||
if (base_fw == (void *)(-1)) {
|
||||
perror("mmap");
|
||||
return (void *)-1;
|
||||
|
@ -357,7 +360,8 @@ static void serve_update(uint8_t *base, const char *uart_dev)
|
|||
uint8_t buf[8];
|
||||
int ud = open_uart(uart_dev);
|
||||
if (ud < 0) {
|
||||
fprintf(stderr, "Cannot open serial port %s: %s.\n", uart_dev, strerror(errno));
|
||||
fprintf(stderr, "Cannot open serial port %s: %s.\n",
|
||||
uart_dev, strerror(errno));
|
||||
exit(3);
|
||||
}
|
||||
while (1) {
|
||||
|
@ -369,7 +373,9 @@ static void serve_update(uint8_t *base, const char *uart_dev)
|
|||
if (ret == 0)
|
||||
continue;
|
||||
|
||||
if ((buf[0] != CMD_HDR_WOLF) && (buf[0] != CMD_HDR_VER) && (buf[0] != CMD_APP_VER)) {
|
||||
if ((buf[0] != CMD_HDR_WOLF) &&
|
||||
(buf[0] != CMD_HDR_VER) &&
|
||||
(buf[0] != CMD_APP_VER)) {
|
||||
printf("bad hdr: %02x\n", buf[0]);
|
||||
continue;
|
||||
}
|
||||
|
@ -441,7 +447,9 @@ static void serve_update(uint8_t *base, const char *uart_dev)
|
|||
|
||||
void usage(char *pname)
|
||||
{
|
||||
printf("Usage: %s binary_file serial_port\nExample:\n%s firmware_v3_signed.bin /dev/ttyUSB0\n", pname, pname);
|
||||
printf("Usage: %s binary_file serial_port\nExample:\n"
|
||||
"%s firmware_v3_signed.bin /dev/ttyUSB0\n",
|
||||
pname, pname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue