16 Commits
Author SHA1 Message Date
Marek Kraus 6306a00de7 Include Windows headers for missing data types 2023-08-01 14:38:55 +02:00
Ben V. Brown c87a4a092c Pragma -> ifndef 2023-08-01 21:36:39 +10:00
Ben V. Brown dbd7ee2257 Adjust DFU to avoid goto 2023-08-01 21:31:07 +10:00
Ben V. Brown 05b62d2fa5 Drop extra erase 2023-08-01 21:08:58 +10:00
Ben V. Brown d25bd65f15 Improve logging 2023-08-01 20:59:36 +10:00
Ben V. Brown ec44c2358b Update dfu_file.c 2023-08-01 18:49:14 +10:00
Ben V. Brown c63883bfa7 FIXUP! flash offset 2023-08-01 18:28:55 +10:00
Ben V. Brown 99a30ae9cc stdlib
Update dfu_file.c
2023-08-01 18:11:44 +10:00
Ben V. Brown 11c31d6eed Rebase address 2023-08-01 17:54:17 +10:00
Ben V. Brown 6724a9c682 Print flash address 2023-08-01 17:54:17 +10:00
Ben V. Brown 342a43b071 Pull in the generic parser
Fixup

.
2023-08-01 17:54:17 +10:00
Ben V. Brown d052d2ebe4 Pull out get file util
Update CMakeLists.txt
2023-08-01 17:45:09 +10:00
Ben V. Brown 9893a49376 Generic bin parser 2023-08-01 17:40:59 +10:00
Ben V. Brown cf00bedeaf Scratching out parsers 2023-08-01 08:26:56 +10:00
Ben V. Brown 013c1d0141 Relocate dfu parsing and link in 2023-08-01 08:18:32 +10:00
Ben V. Brown 98343db387 DFU file work
Just grabbing first one for now

Expose crc

Update CMakeLists.txt

Test DFU file

Split crc function

Fixup

Zero init struct
Dont null the pointer 🤦
correct fread

Adding tests

Create dfu_file.h

Format

Scratching out more parsing

Basic port parser

Scratching fread wrapper
2023-08-01 07:44:40 +10:00
19 changed files with 702 additions and 43 deletions
+7 -1
View File
@@ -1,10 +1,11 @@
cmake_minimum_required(VERSION 3.22)
project(blisp C)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 23)
option(BLISP_BUILD_CLI "Build CLI Tool" OFF)
option(BLISP_USE_SYSTEM_LIBRARIES "Use system-installed libraries" "${CMAKE_USE_SYSTEM_LIBRARIES}")
option(COMPILE_TESTS "Compile the tests" OFF)
add_library(libblisp_obj OBJECT
lib/blisp.c
@@ -94,3 +95,8 @@ install(TARGETS libblisp libblisp_static DESTINATION lib)
if(BLISP_BUILD_CLI)
add_subdirectory(tools/blisp)
endif()
if(COMPILE_TESTS)
add_subdirectory(tools/blisp/src/cmd/dfu/tests)
endif(COMPILE_TESTS)
+7 -4
View File
@@ -354,13 +354,16 @@ int32_t blisp_easy_flash_write(struct blisp_device* device,
if (buffer_size > buffer_max_size) {
buffer_size = buffer_max_size;
}
blisp_easy_transport_read(data_transport, buffer,
buffer_size); // TODO: Error Handling
ret = blisp_easy_transport_read(data_transport, buffer, buffer_size);
if (ret < BLISP_OK) {
fprintf(stderr, "Failed to read firmware chunk! (ret:%d)\n ", ret);
return ret;
}
ret = blisp_device_flash_write(device, flash_location + sent_data, buffer,
buffer_size);
if (ret < BLISP_OK) {
// TODO: Error logigng: fprintf(stderr, "Failed to write firmware! (ret:
// %d)\n", ret);
fprintf(stderr, "Failed to write firmware! (ret:%d)\n ", ret);
return ret;
}
sent_data += buffer_size;
+4 -1
View File
@@ -4,6 +4,9 @@ set(ARGTABLE3_ENABLE_EXAMPLES OFF CACHE BOOL "Enable examples")
add_executable(blisp src/main.c src/cmd/write.c src/util.c src/common.c src/cmd/iot.c)
add_subdirectory(src/file_parsers)
if(BLISP_USE_SYSTEM_LIBRARIES)
find_package(Argtable3 REQUIRED)
else()
@@ -18,7 +21,7 @@ target_include_directories(blisp PRIVATE
target_link_libraries(blisp PRIVATE
argtable3
libblisp_static)
libblisp_static file_parsers)
if (WIN32)
target_link_libraries(blisp PRIVATE Setupapi.lib)
+44 -27
View File
@@ -9,6 +9,7 @@
#include "../cmd.h"
#include "../common.h"
#include "../util.h"
#include "parse_file.h"
#define REG_EXTENDED 1
#define REG_ICASE (REG_EXTENDED << 1)
@@ -177,35 +178,29 @@ blisp_return_t blisp_flash_firmware() {
// TODO: Error handling
goto exit1;
}
parsed_firmware_file_t parsed_file;
memset(&parsed_file, 0, sizeof(parsed_file));
int parsed_result =
parse_firmware_file(binary_to_write->filename[0], &parsed_file);
FILE* firmware_file = fopen(binary_to_write->filename[0], "rb");
if (firmware_file == NULL) {
fprintf(stderr, "Failed to open firmware file \"%s\".\n",
binary_to_write->filename[0]);
goto exit1;
}
fseek(firmware_file, 0, SEEK_END);
int64_t firmware_file_size = ftell(firmware_file);
rewind(firmware_file);
// If we are injecting a bootloader section, make it, erase flash, and flash
// it. Then when we do firmware later on; it will be located afterwards
// the header filles up to a flash erase boundry so this stack should be safe
// __should__
if (parsed_file.needs_boot_struct) {
// Create a default boot header section in ram to be written out
struct bfl_boot_header boot_header;
fill_up_boot_header(&boot_header);
printf("Erasing flash to flash boot header\n");
ret = blisp_device_flash_erase(&device, 0x0000,
sizeof(struct bfl_boot_header));
const uint32_t firmware_base_address = 0x2000;
printf("Erasing flash, this might take a while...\n");
ret =
blisp_device_flash_erase(&device, firmware_base_address,
firmware_base_address + firmware_file_size + 1);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n");
goto exit2;
}
ret =
blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n");
goto exit2;
}
// Now burn the header
printf("Flashing boot header...\n");
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header,
@@ -214,13 +209,35 @@ blisp_return_t blisp_flash_firmware() {
fprintf(stderr, "Failed to write boot header.\n");
goto exit2;
}
printf("Flashing the firmware...\n");
// Move the firmware to-be-flashed beyond the boot header area
parsed_file.payload_address += 0x2000;
}
// Now that optional boot header is done, we clear out the flash for the new
// firmware; and flash it in.
printf("Erasing flash for firmware, this might take a while...\n");
ret = blisp_device_flash_erase(
&device, parsed_file.payload_address,
parsed_file.payload_address + parsed_file.payload_length);
if (ret != BLISP_OK) {
fprintf(stderr,
"Failed to erase flash. Tried to erase from 0x%08X to 0x%08X\n",
parsed_file.payload_address,
parsed_file.payload_address + parsed_file.payload_length + 1);
goto exit2;
}
printf("Flashing the firmware %d bytes @ 0x%08X...\n",
parsed_file.payload_length, parsed_file.payload_address);
struct blisp_easy_transport data_transport =
blisp_easy_transport_new_from_file(firmware_file);
blisp_easy_transport_new_from_memory(parsed_file.payload,
parsed_file.payload_length);
ret = blisp_easy_flash_write(
&device, &data_transport, parsed_file.payload_address,
parsed_file.payload_length, blisp_common_progress_callback);
ret = blisp_easy_flash_write(&device, &data_transport, firmware_base_address,
firmware_file_size,
blisp_common_progress_callback);
if (ret < BLISP_OK) {
fprintf(stderr, "Failed to write app to flash.\n");
goto exit2;
@@ -243,8 +260,8 @@ blisp_return_t blisp_flash_firmware() {
printf("Flash complete!\n");
exit2:
if (firmware_file != NULL)
fclose(firmware_file);
if (parsed_file.payload != NULL)
free(parsed_file.payload);
exit1:
blisp_device_close(&device);
}
@@ -0,0 +1,24 @@
list(APPEND ADD_INCLUDE
"${CMAKE_CURRENT_SOURCE_DIR}/bin"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu"
"${CMAKE_CURRENT_SOURCE_DIR}"
)
file(GLOB_RECURSE sources
)
list(APPEND ADD_SRCS ${sources})
add_library(file_parsers
"${CMAKE_CURRENT_SOURCE_DIR}/bin/bin_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_crc.c"
"${CMAKE_CURRENT_SOURCE_DIR}/parse_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/get_file_contents.c"
)
target_include_directories(file_parsers PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/bin
${CMAKE_CURRENT_SOURCE_DIR}/dfu
${CMAKE_CURRENT_SOURCE_DIR}
)
@@ -0,0 +1,15 @@
#include <stdio.h>
#include "parse_file.h"
int bin_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address) {
// Bin files a dumb so we cant do any fancy logic
*payload_address = 0; // We cant know otherwise
ssize_t len = get_file_contents(file_path_on_disk, payload);
if (len > 0) {
*payload_length = len;
}
return len;
}
@@ -0,0 +1,24 @@
//
// Created by ralim on 01/08/23.
//
#ifndef BLISP_BIN_FILE_H
#define BLISP_BIN_FILE_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
int bin_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address);
#ifdef __cplusplus
};
#endif
#endif // BLISP_BIN_FILE_H
@@ -0,0 +1,53 @@
//
// Created by ralim on 26/09/22.
//
#include "dfu_file.h"
static const unsigned long crc32_table[]
= { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
uint32_t
crc32_byte(uint32_t accum, uint8_t delta) {
return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8);
}
+293
View File
@@ -0,0 +1,293 @@
//
// Created by ralim on 25/09/22.
//
#include "dfu_file.h"
#include <stdlib.h>
#include "parse_file.h"
#if defined(_MSC_VER)
#include <sys\types.h>
#endif
#define DFU_SUFFIX_LENGTH 16
#define LMDFU_PREFIX_LENGTH 8
#define LPCDFU_PREFIX_LENGTH 16
struct dfu_file {
/* File name */
const char* name;
/* Pointer to file loaded into memory */
const uint8_t* firmware;
/* Different sizes */
struct {
off_t total;
off_t firmware;
int prefix;
int suffix;
} size;
/* From prefix fields */
uint32_t lmdfu_address;
/* From prefix fields */
uint32_t prefix_type;
/* From DFU suffix fields */
uint32_t dwCRC;
uint16_t bcdDFU;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
};
enum prefix_type {
ZERO_PREFIX,
DFUSE_PREFIX,
LMDFU_PREFIX,
LPCDFU_UNENCRYPTED_PREFIX
};
struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
size_t file_contents_length);
ssize_t parse_target(const uint8_t* data,
uint8_t* out_ealt,
uint8_t** out_data,
size_t* out_data_size,
size_t* out_data_address);
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents);
/* Parse a .dfu file and extract its payload and metadata
* Returns 0 if file parsed correctly, negative on error
* Inputs:
* - File path to read from
*
* Outputs:
* - File payload contents
* - File payload start address
*
* Usage:
* uint8_t* payload=NULL;
* size_t payload_length=0;
* int res = dfu_file_path("test.dfu",&payload,&payload_length);
* ...
* free(payload);
*/
int dfu_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address) {
uint8_t* dfu_file_contents = NULL;
ssize_t file_size = get_file_contents(file_path_on_disk, &dfu_file_contents);
if (file_size < 0) {
return file_size;
}
if (file_size == 0 || dfu_file_contents == NULL) {
return PARSED_ERROR_CANT_OPEN_FILE;
}
// Parse DFU data
struct dfu_file dfu_info = parse_dfu_suffix(dfu_file_contents, file_size);
if (dfu_info.size.firmware == 0) {
return PARSED_ERROR_BAD_DFU;
}
// Check if its for a BL* chip
// if (dfu_info.idVendor != 0x28E9) {
// free(dfu_file_contents);
// return -1;
// }
// Okay we have done validation, walk firmware and extract the blob and the
// offset
size_t data_consumed = 0;
while (data_consumed < dfu_info.size.firmware) {
uint8_t ealt = 0;
uint8_t* blob = NULL;
size_t blob_size = 0;
size_t blob_address = 0;
ssize_t res = parse_target(dfu_info.firmware + data_consumed, &ealt, &blob,
&blob_size, &blob_address);
if (res < 0) {
break;
}
if (ealt == 0 && blob_size > 0) {
// Firmware slot, lets prep this and return
*payload = calloc(blob_size, 1);
*payload_length = blob_size;
*payload_address = blob_address;
memcpy(*payload, blob, blob_size);
free(dfu_file_contents);
return 1;
}
data_consumed += res;
}
return 0;
}
// Read next target, output data+size+alt. Returns bytes consumed
ssize_t parse_target(const uint8_t* data,
uint8_t* out_ealt,
uint8_t** out_data,
size_t* out_data_size,
size_t* out_data_address) {
if (data == NULL || out_ealt == NULL || out_data == NULL ||
out_data_size == NULL) {
return -99;
}
if (data[0] != 'T' || data[1] != 'a') {
return -1;
}
*out_ealt = data[6];
uint8_t* tdata = (uint8_t*)data + 6 + 1 + 4 + 255;
uint32_t len_tdata = *((uint32_t*)tdata);
tdata += 4;
uint32_t num_images = *((uint32_t*)tdata);
tdata += 4;
ssize_t blob_length = 6 + 1 + 4 + 255 + 8 + len_tdata;
// Now read all the image blobs from this target
for (int i = 0; i < num_images; i++) {
uint32_t address = *((uint32_t*)tdata);
tdata += 4;
uint32_t len = *((uint32_t*)tdata);
tdata += 4;
*out_data = tdata;
*out_data_size = len;
*out_data_address = address;
return blob_length;
// tdata+=len;
}
return blob_length;
}
static int probe_prefix(struct dfu_file* file) {
const uint8_t* prefix = file->firmware;
file->size.prefix = 0;
if (file->size.total < LMDFU_PREFIX_LENGTH)
return 1;
if (prefix[0] == 'D' && prefix[1] == 'f' && prefix[2] == 'u' &&
prefix[3] == 'S' && prefix[4] == 'e') {
// DfuSe header
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/dfuse-pack.py#l110
file->size.prefix = 11;
file->prefix_type = DFUSE_PREFIX;
uint8_t numTargets = prefix[10];
printf("Number DFU Targets: %d\n", numTargets);
}
if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) {
uint32_t payload_length =
(prefix[7] << 24) | (prefix[6] << 16) | (prefix[5] << 8) | prefix[4];
uint32_t expected_payload_length =
(uint32_t)file->size.total - LMDFU_PREFIX_LENGTH - file->size.suffix;
if (payload_length != expected_payload_length)
return 1;
file->prefix_type = LMDFU_PREFIX;
file->size.prefix = LMDFU_PREFIX_LENGTH;
file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]);
} else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f) == 0x3f)) {
file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX;
file->size.prefix = LPCDFU_PREFIX_LENGTH;
}
if (file->size.prefix + file->size.suffix > file->size.total)
return 1;
return 0;
}
struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
const size_t file_contents_length) {
// This is nearly 1:1 based on
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/dfu_file.c#l368
struct dfu_file output;
memset(&output, 0, sizeof(output));
output.firmware = file_contents;
output.size.total = (off_t)file_contents_length;
/* Check for possible DFU file suffix by trying to parse one */
uint32_t crc = 0xffffffff;
const uint8_t* dfu_suffix;
int missing_suffix = 0;
const char* reason;
if (file_contents_length < DFU_SUFFIX_LENGTH) {
reason = "File too short for DFU suffix";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
dfu_suffix = file_contents + file_contents_length - DFU_SUFFIX_LENGTH;
if (dfu_suffix[10] != 'D' || dfu_suffix[9] != 'F' || dfu_suffix[8] != 'U') {
reason = "Invalid DFU suffix signature";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
// Calculate contents CRC32
for (int i = 0; i < file_contents_length - 4; i++) {
crc = crc32_byte(crc, file_contents[i]);
}
output.dwCRC = (dfu_suffix[15] << 24) + (dfu_suffix[14] << 16) +
(dfu_suffix[13] << 8) + dfu_suffix[12];
if (output.dwCRC != crc) {
reason = "DFU suffix CRC does not match";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
/* At this point we believe we have a DFU suffix
so we require further checks to succeed */
output.bcdDFU = (dfu_suffix[7] << 8) + dfu_suffix[6];
output.size.suffix = dfu_suffix[11];
if (output.size.suffix < DFU_SUFFIX_LENGTH) {
fprintf(stderr, "Unsupported DFU suffix length %d", output.size.suffix);
output.size.firmware = 0;
return output;
}
if (output.size.suffix > file_contents_length) {
fprintf(stderr, "Invalid DFU suffix length %d", output.size.suffix);
output.size.firmware = 0;
return output;
}
output.idVendor = (dfu_suffix[5] << 8) + dfu_suffix[4];
output.idProduct = (dfu_suffix[3] << 8) + dfu_suffix[2];
output.bcdDevice = (dfu_suffix[1] << 8) + dfu_suffix[0];
const int res = probe_prefix(&output);
if (output.size.prefix) {
const uint8_t* data = file_contents;
if (output.prefix_type == DFUSE_PREFIX) {
} else if (output.prefix_type == LMDFU_PREFIX) {
printf(
"Possible TI Stellaris DFU prefix with "
"the following properties\n"
"Address: 0x%08x\n"
"Payload length: %d\n",
output.lmdfu_address,
data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24));
} else if (output.prefix_type == LPCDFU_UNENCRYPTED_PREFIX) {
printf(
"Possible unencrypted NXP LPC DFU prefix with "
"the following properties\n"
"Payload length: %d kiByte\n",
data[2] >> 1 | (data[3] << 7));
} else {
fprintf(stderr, "Unknown DFU prefix type");
}
output.firmware =
output.firmware + output.size.prefix; // shift past prefix
}
output.size.firmware =
output.size.total - (output.size.suffix + output.size.prefix);
return output;
}
@@ -0,0 +1,27 @@
//
// Created by ralim on 26/09/22.
//
#ifndef BLISP_DFU_FILE_H
#define BLISP_DFU_FILE_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
// Parse the dfu file and returns 0 if ok, or -ve on error parsing
int dfu_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address);
// Internal
uint32_t crc32_byte(uint32_t accum, uint8_t delta);
#ifdef __cplusplus
};
#endif
#endif // BLISP_DFU_FILE_H
@@ -0,0 +1,31 @@
enable_language(CXX)
enable_testing()
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
)
FetchContent_MakeAvailable(googletest)
add_library(GTest::GTest INTERFACE IMPORTED)
target_link_libraries(GTest::GTest INTERFACE gtest_main)
add_executable(dfu_file_test test_dfu_file.cpp ../dfu_file.c ../dfu_crc.c)
target_link_libraries(dfu_file_test
PRIVATE
GTest::GTest
)
include_directories(dfu_file_test PRIVATE ../)
add_test(dfu_file_test_gtests dfu_file_test)
configure_file(Config.h.in ${CMAKE_BINARY_DIR}/Config.h)
include_directories(${CMAKE_BINARY_DIR})
set(TEST_APP_NAME dfu_file_tests)
#add_custom_command(TARGET ${TEST_APP_NAME} COMMAND ./${TEST_APP_NAME} POST_BUILD)
@@ -0,0 +1,10 @@
//
// Created by ralim on 26/09/22.
//
#ifndef BLISP_CONFIG_H_IN_H
#define BLISP_CONFIG_H_IN_H
#define SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
#endif // BLISP_CONFIG_H_IN_H
Binary file not shown.
@@ -0,0 +1,17 @@
//
// Created by ralim on 26/09/22.
//
#include "Config.h"
#include "dfu_file.h"
#include <gtest/gtest.h>
TEST(DFU_FILE_PARSER, ParseTestFile) {
uint8_t* payload = nullptr;
size_t payload_size = 0;
size_t payload_address = 0;
int res = dfu_file_parse(SOURCE_DIR "/test.dfu", &payload, &payload_size,
&payload_address);
ASSERT_EQ(res, 1);
ASSERT_EQ(payload_size, 1337);
ASSERT_EQ(payload_address, 0x11223344);
}
@@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#include "parse_file.h"
// Returns file size _or_ negative on error
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents) {
size_t read_count;
size_t file_size = 0;
size_t read_total = 0;
FILE* f;
if (file_contents == NULL) {
return -99;
}
f = fopen(file_path_on_disk, "rb");
if (f <= 0) {
fprintf(stderr, "Could not open file %s for reading\n", file_path_on_disk);
return -1;
}
fseek(f, 0, SEEK_END);
file_size = ftell(f);
fseek(f, 0, SEEK_SET);
*file_contents = calloc(file_size, sizeof(uint8_t));
while (read_total < file_size) {
size_t to_read = file_size - read_total;
/* read() limit on Linux, slightly below MAX_INT on Windows */
if (to_read > 0x7ffff000)
to_read = 0x7ffff000;
read_count = fread((*file_contents) + read_total, 1, to_read, f);
if (read_count == 0)
break;
// If error and not end of file, break
if (read_count == -1 && !feof(f))
break;
read_total += read_count;
}
if (read_total != file_size) {
fprintf(stderr, "Could only read %lld of %lld bytes from %s",
(long long)read_total, (long long)file_size, file_path_on_disk);
return -1;
}
fclose(f);
return (ssize_t)file_size;
}
+43
View File
@@ -0,0 +1,43 @@
#include "parse_file.h"
#include <string.h>
#include "bin_file.h"
#include "dfu_file.h"
const char* get_filename_ext(const char* filename) {
const char* dot = strrchr(filename, '.');
if (!dot || dot == filename)
return "";
return dot + 1;
}
#define FLASH_MAP_ADDR 0x23000000
int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results) {
// Switchcase on the extension of the file
const char* ext = get_filename_ext(file_path_on_disk);
int res = PARSED_ERROR_INVALID_FILETYPE;
if (strncmp(ext, "dfu", 3) == 0 || strncmp(ext, "DFU", 3) == 0) {
printf("Input file identified as a .dfu file\n");
// Handle as a .dfu file
res = dfu_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
} else if (strncmp(ext, "bin", 3) == 0 || strncmp(ext, "BIN", 3) == 0) {
printf("Input file identified as a .bin file\n");
// Raw binary file
res = bin_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
}
// If we wanted to support hex files, here would be where
// Normalise address, some builds will base the firmware at flash start but
// for the flasher we use 0 base (i.e. offsets into flash)
if (parsed_results->payload_address >= FLASH_MAP_ADDR) {
parsed_results->payload_address -= FLASH_MAP_ADDR;
}
// If the firmware starts at "0" we need to pre-pend a boot sector later on
parsed_results->needs_boot_struct = parsed_results->payload_address == 0;
return res;
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef PARSE_FILE_H_
#define PARSE_FILE_H_
#include <stdio.h>
#include <stdlib.h>
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#include "parsed_firmware_file.h"
#define PARSED_ERROR_INVALID_FILETYPE -0x1000
#define PARSED_ERROR_CANT_OPEN_FILE -0x1001
#define PARSED_ERROR_TOO_BIG -0x1001 /* Input expands to be too big */
#define PARSED_ERROR_BAD_DFU -0x1002 /* DFU file provided but not valid */
// This attempts to parse the given file, and returns the parsed version of that
// file. This will handle any repacking required to create one contigious file
// Eg if the input file has holes,they will be 0x00 filled
// And headers etc are parsed to determine start position
int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results);
// Internal util
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents);
#endif // PARSE_FILE_H_
@@ -0,0 +1,17 @@
#ifndef PARSED_FIRMWARE_H_
#define PARSED_FIRMWARE_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
// Parsed firmware file is a generic struct that we parse from a user input
// firmware file This is used so that we can (relatively) seamlessly handle
// .bin, .hex and .def files
typedef struct {
bool needs_boot_struct; // If true, boot struct should be generated
uint8_t* payload; // The main firmware payload
size_t payload_length; // Size of the payload
size_t payload_address; // Start address of the payload
} parsed_firmware_file_t;
#endif // PARSED_FIRMWARE_H_
+1 -1
View File
@@ -45,7 +45,7 @@ int8_t args_parse_exec(int argc, char** argv) {
print_help();
return BLISP_OK;
} else if (version->count) {
printf("blisp v0.0.3\n");
printf("blisp v0.0.4\n");
printf("Copyright (C) 2023 Marek Kraus and PINE64 Community\n");
return BLISP_OK;
}