Compare commits

...

7 Commits

Author SHA1 Message Date
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
10 changed files with 349 additions and 309 deletions

View File

@ -9,6 +9,7 @@
#include "../cmd.h" #include "../cmd.h"
#include "../common.h" #include "../common.h"
#include "../util.h" #include "../util.h"
#include "parse_file.h"
#define REG_EXTENDED 1 #define REG_EXTENDED 1
#define REG_ICASE (REG_EXTENDED << 1) #define REG_ICASE (REG_EXTENDED << 1)
@ -177,61 +178,63 @@ blisp_return_t blisp_flash_firmware() {
// TODO: Error handling // TODO: Error handling
goto exit1; 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);
// Open the file to be flashed; to determine the size of the section of flash // If we are injecting a bootloader section, make it, erase flash, and flash
// to erase // it. Then when we do firmware later on; it will be located afterwards
int64_t firmware_file_size = 0; // the header filles up to a flash erase boundry so this stack should be safe
const uint32_t firmware_base_address_offset = // __should__
0x2000; // Firmware files start 0x2000 offset into flash to skip the boot
// header
int64_t firmware_file_start_address = 0;
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));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n");
goto exit2;
}
// Now burn the header
printf("Flashing boot header...\n");
FILE* firmware_file = fopen(binary_to_write->filename[0], "rb"); ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header,
if (firmware_file == NULL) { sizeof(struct bfl_boot_header));
fprintf(stderr, "Failed to open firmware file \"%s\".\n", if (ret != BLISP_OK) {
binary_to_write->filename[0]); fprintf(stderr, "Failed to write boot header.\n");
goto exit1; goto exit2;
}
// Move the firmware to-be-flashed beyond the boot header area
parsed_file.payload_address += 0x2000;
} }
fseek(firmware_file, 0, SEEK_END); // Now that optional boot header is done, we clear out the flash for the new
firmware_file_size = ftell(firmware_file); // firmware; and flash it in.
rewind(firmware_file);
// Create a default boot header section in ram to be written out printf("Erasing flash for firmware, this might take a while...\n");
struct bfl_boot_header boot_header; ret = blisp_device_flash_erase(
fill_up_boot_header(&boot_header); &device, parsed_file.payload_address,
parsed_file.payload_address + parsed_file.payload_length + 1);
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) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n"); fprintf(stderr,
goto exit2; "Failed to erase flash. Tried to erase from 0x%08X to 0x%08X\n",
} parsed_file.payload_address,
ret = parsed_file.payload_address + parsed_file.payload_length + 1);
blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n");
goto exit2; goto exit2;
} }
printf("Flashing boot header...\n"); printf("Flashing the firmware @ 0x%08X...\n", parsed_file.payload_address);
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header,
sizeof(struct bfl_boot_header));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to write boot header.\n");
goto exit2;
}
printf("Flashing the firmware...\n");
struct blisp_easy_transport data_transport = 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) { if (ret < BLISP_OK) {
fprintf(stderr, "Failed to write app to flash.\n"); fprintf(stderr, "Failed to write app to flash.\n");
goto exit2; goto exit2;
@ -254,8 +257,8 @@ blisp_return_t blisp_flash_firmware() {
printf("Flash complete!\n"); printf("Flash complete!\n");
exit2: exit2:
if (firmware_file != NULL) if (parsed_file.payload != NULL)
fclose(firmware_file); free(parsed_file.payload);
exit1: exit1:
blisp_device_close(&device); blisp_device_close(&device);
} }

View File

@ -13,6 +13,7 @@ add_library(file_parsers
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_file.c" "${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_crc.c" "${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_crc.c"
"${CMAKE_CURRENT_SOURCE_DIR}/parse_file.c" "${CMAKE_CURRENT_SOURCE_DIR}/parse_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/get_file_contents.c"
) )
target_include_directories(file_parsers PUBLIC target_include_directories(file_parsers PUBLIC

View File

@ -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;
}

View File

@ -5,7 +5,6 @@
#ifndef BLISP_BIN_FILE_H #ifndef BLISP_BIN_FILE_H
#define BLISP_BIN_FILE_H #define BLISP_BIN_FILE_H
#include <malloc.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>

View File

@ -2,47 +2,50 @@
// Created by ralim on 25/09/22. // Created by ralim on 25/09/22.
// //
#include "dfu_file.h" #include "dfu_file.h"
#include <stdlib.h>
#define DFU_SUFFIX_LENGTH 16 #define DFU_SUFFIX_LENGTH 16
#define LMDFU_PREFIX_LENGTH 8 #define LMDFU_PREFIX_LENGTH 8
#define LPCDFU_PREFIX_LENGTH 16 #define LPCDFU_PREFIX_LENGTH 16
struct dfu_file { struct dfu_file {
/* File name */ /* File name */
const char* name; const char* name;
/* Pointer to file loaded into memory */ /* Pointer to file loaded into memory */
const uint8_t* firmware; const uint8_t* firmware;
/* Different sizes */ /* Different sizes */
struct { struct {
off_t total; off_t total;
off_t firmware; off_t firmware;
int prefix; int prefix;
int suffix; int suffix;
} size; } size;
/* From prefix fields */ /* From prefix fields */
uint32_t lmdfu_address; uint32_t lmdfu_address;
/* From prefix fields */ /* From prefix fields */
uint32_t prefix_type; uint32_t prefix_type;
/* From DFU suffix fields */ /* From DFU suffix fields */
uint32_t dwCRC; uint32_t dwCRC;
uint16_t bcdDFU; uint16_t bcdDFU;
uint16_t idVendor; uint16_t idVendor;
uint16_t idProduct; uint16_t idProduct;
uint16_t bcdDevice; uint16_t bcdDevice;
}; };
enum prefix_type { enum prefix_type {
ZERO_PREFIX, ZERO_PREFIX,
DFUSE_PREFIX, DFUSE_PREFIX,
LMDFU_PREFIX, LMDFU_PREFIX,
LPCDFU_UNENCRYPTED_PREFIX LPCDFU_UNENCRYPTED_PREFIX
}; };
struct dfu_file parse_dfu_suffix(const uint8_t* file_contents, struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
size_t file_contents_length); size_t file_contents_length);
ssize_t parse_target(const uint8_t* data, uint8_t* out_ealt, ssize_t parse_target(const uint8_t* data,
uint8_t** out_data, size_t* out_data_size, uint8_t* out_ealt,
uint8_t** out_data,
size_t* out_data_size,
size_t* out_data_address); size_t* out_data_address);
ssize_t get_file_contents(const char* file_path_on_disk, ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents); uint8_t** file_contents);
@ -64,259 +67,209 @@ ssize_t get_file_contents(const char* file_path_on_disk,
* free(payload); * free(payload);
*/ */
int int dfu_file_parse(const char* file_path_on_disk,
dfu_file_parse(const char* file_path_on_disk, uint8_t** payload, uint8_t** payload,
size_t* payload_length, size_t* payload_address) { size_t* payload_length,
uint8_t* dfu_file_contents = NULL; size_t* payload_address) {
ssize_t file_size uint8_t* dfu_file_contents = NULL;
= get_file_contents(file_path_on_disk, &dfu_file_contents); ssize_t file_size = get_file_contents(file_path_on_disk, &dfu_file_contents);
if (file_size <= 0 || dfu_file_contents == NULL) { if (file_size <= 0 || dfu_file_contents == NULL) {
return -1; return -1;
}
// Parse DFU data
struct dfu_file dfu_info = parse_dfu_suffix(dfu_file_contents, file_size);
// 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;
} }
// Parse DFU data if (ealt == 0 && blob_size > 0) {
struct dfu_file dfu_info = parse_dfu_suffix(dfu_file_contents, file_size); // Firmware slot, lets prep this and return
// Check if its for a BL* chip *payload = calloc(blob_size, 1);
// if (dfu_info.idVendor != 0x28E9) { *payload_length = blob_size;
// free(dfu_file_contents); *payload_address = blob_address;
// return -1; memcpy(*payload, blob, blob_size);
// } free(dfu_file_contents);
// Okay we have done validation, walk firmware and extract the blob and the return 1;
// 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;
} }
data_consumed += res;
}
return 0; return 0;
} }
// Read next target, output data+size+alt. Returns bytes consumed // Read next target, output data+size+alt. Returns bytes consumed
ssize_t ssize_t parse_target(const uint8_t* data,
parse_target(const uint8_t* data, uint8_t* out_ealt, uint8_t** out_data, uint8_t* out_ealt,
size_t* out_data_size, size_t* out_data_address) { uint8_t** out_data,
if (data == NULL || out_ealt == NULL || out_data == NULL size_t* out_data_size,
|| out_data_size == NULL) { size_t* out_data_address) {
return -99; if (data == NULL || out_ealt == NULL || out_data == NULL ||
} out_data_size == NULL) {
if (data[0] != 'T' || data[1] != 'a') { return -99;
return -1; }
} if (data[0] != 'T' || data[1] != 'a') {
return -1;
}
*out_ealt = data[6]; *out_ealt = data[6];
uint8_t* tdata = data + 6 + 1 + 4 + 255; uint8_t* tdata = (uint8_t*)data + 6 + 1 + 4 + 255;
uint32_t len_tdata = *((uint32_t*)tdata); 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; tdata += 4;
uint32_t num_images = *((uint32_t*)tdata); uint32_t len = *((uint32_t*)tdata);
tdata += 4; tdata += 4;
ssize_t blob_length = 6 + 1 + 4 + 255 + 8 + len_tdata; *out_data = tdata;
// Now read all the image blobs from this target *out_data_size = len;
for (int i = 0; i < num_images; i++) { *out_data_address = address;
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; return blob_length;
// tdata+=len;
}
return blob_length;
} }
static int static int probe_prefix(struct dfu_file* file) {
probe_prefix(struct dfu_file* file) { const uint8_t* prefix = file->firmware;
const uint8_t* prefix = file->firmware; file->size.prefix = 0;
file->size.prefix = 0; if (file->size.total < LMDFU_PREFIX_LENGTH)
if (file->size.total < LMDFU_PREFIX_LENGTH) return 1;
return 1; if (prefix[0] == 'D' && prefix[1] == 'f' && prefix[2] == 'u' &&
if (prefix[0] == 'D' && prefix[1] == 'f' && prefix[2] == 'u' prefix[3] == 'S' && prefix[4] == 'e') {
&& prefix[3] == 'S' && prefix[4] == 'e') { // DfuSe header
// DfuSe header // https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/dfuse-pack.py#l110
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/dfuse-pack.py#l110
file->size.prefix = 11; file->size.prefix = 11;
file->prefix_type = DFUSE_PREFIX; file->prefix_type = DFUSE_PREFIX;
uint8_t numTargets = prefix[10]; uint8_t numTargets = prefix[10];
printf("Number DFU Targets: %d\n", numTargets); printf("Number DFU Targets: %d\n", numTargets);
} }
if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) {
uint32_t payload_length = (prefix[7] << 24) | (prefix[6] << 16) uint32_t payload_length =
| (prefix[5] << 8) | prefix[4]; (prefix[7] << 24) | (prefix[6] << 16) | (prefix[5] << 8) | prefix[4];
uint32_t expected_payload_length = (uint32_t)file->size.total uint32_t expected_payload_length =
- LMDFU_PREFIX_LENGTH (uint32_t)file->size.total - LMDFU_PREFIX_LENGTH - file->size.suffix;
- file->size.suffix; if (payload_length != expected_payload_length)
if (payload_length != expected_payload_length) return 1;
return 1; file->prefix_type = LMDFU_PREFIX;
file->prefix_type = LMDFU_PREFIX; file->size.prefix = LMDFU_PREFIX_LENGTH;
file->size.prefix = LMDFU_PREFIX_LENGTH; file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]);
file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); } else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f) == 0x3f)) {
} else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f) == 0x3f)) { file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX;
file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX; file->size.prefix = LPCDFU_PREFIX_LENGTH;
file->size.prefix = LPCDFU_PREFIX_LENGTH; }
}
if (file->size.prefix + file->size.suffix > file->size.total) if (file->size.prefix + file->size.suffix > file->size.total)
return 1; return 1;
return 0; return 0;
} }
struct dfu_file struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
parse_dfu_suffix(const uint8_t* file_contents, const size_t file_contents_length) {
const size_t file_contents_length) { // This is nearly 1:1 based on
// This is nearly 1:1 based on // https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/dfu_file.c#l368
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/dfu_file.c#l368 struct dfu_file output;
struct dfu_file output; memset(&output, 0, sizeof(output));
memset(&output, 0, sizeof(output)); output.firmware = file_contents;
output.firmware = file_contents; output.size.total = (off_t)file_contents_length;
output.size.total = (off_t)file_contents_length; /* Check for possible DFU file suffix by trying to parse one */
/* Check for possible DFU file suffix by trying to parse one */
uint32_t crc = 0xffffffff; uint32_t crc = 0xffffffff;
const uint8_t* dfu_suffix; const uint8_t* dfu_suffix;
int missing_suffix = 0; int missing_suffix = 0;
const char* reason; const char* reason;
if (file_contents_length < DFU_SUFFIX_LENGTH) { if (file_contents_length < DFU_SUFFIX_LENGTH) {
reason = "File too short for DFU suffix"; reason = "File too short for DFU suffix";
missing_suffix = 1; missing_suffix = 1;
goto checked; goto checked;
} }
dfu_suffix = file_contents + file_contents_length - DFU_SUFFIX_LENGTH; dfu_suffix = file_contents + file_contents_length - DFU_SUFFIX_LENGTH;
if (dfu_suffix[10] != 'D' || dfu_suffix[9] != 'F' if (dfu_suffix[10] != 'D' || dfu_suffix[9] != 'F' || dfu_suffix[8] != 'U') {
|| dfu_suffix[8] != 'U') { reason = "Invalid DFU suffix signature";
reason = "Invalid DFU suffix signature"; missing_suffix = 1;
missing_suffix = 1; goto checked;
goto checked; }
} // Calculate contents CRC32
// Calculate contents CRC32 for (int i = 0; i < file_contents_length - 4; i++) {
for (int i = 0; i < file_contents_length - 4; i++) { crc = crc32_byte(crc, file_contents[i]);
crc = crc32_byte(crc, file_contents[i]); }
}
output.dwCRC = (dfu_suffix[15] << 24) + (dfu_suffix[14] << 16) output.dwCRC = (dfu_suffix[15] << 24) + (dfu_suffix[14] << 16) +
+ (dfu_suffix[13] << 8) + dfu_suffix[12]; (dfu_suffix[13] << 8) + dfu_suffix[12];
if (output.dwCRC != crc) { if (output.dwCRC != crc) {
reason = "DFU suffix CRC does not match"; reason = "DFU suffix CRC does not match";
missing_suffix = 1; missing_suffix = 1;
goto checked; goto checked;
} }
/* At this point we believe we have a DFU suffix /* At this point we believe we have a DFU suffix
so we require further checks to succeed */ so we require further checks to succeed */
output.bcdDFU = (dfu_suffix[7] << 8) + dfu_suffix[6]; output.bcdDFU = (dfu_suffix[7] << 8) + dfu_suffix[6];
output.size.suffix = dfu_suffix[11]; output.size.suffix = dfu_suffix[11];
if (output.size.suffix < DFU_SUFFIX_LENGTH) { if (output.size.suffix < DFU_SUFFIX_LENGTH) {
fprintf(stderr, "Unsupported DFU suffix length %d", fprintf(stderr, "Unsupported DFU suffix length %d", output.size.suffix);
output.size.suffix); }
}
if (output.size.suffix > file_contents_length) { if (output.size.suffix > file_contents_length) {
fprintf(stderr, "Invalid DFU suffix length %d", output.size.suffix); fprintf(stderr, "Invalid DFU suffix length %d", output.size.suffix);
} }
output.idVendor = (dfu_suffix[5] << 8) + dfu_suffix[4]; output.idVendor = (dfu_suffix[5] << 8) + dfu_suffix[4];
output.idProduct = (dfu_suffix[3] << 8) + dfu_suffix[2]; output.idProduct = (dfu_suffix[3] << 8) + dfu_suffix[2];
output.bcdDevice = (dfu_suffix[1] << 8) + dfu_suffix[0]; output.bcdDevice = (dfu_suffix[1] << 8) + dfu_suffix[0];
checked: checked:
const int res = probe_prefix(&output); int res = probe_prefix(&output);
if (output.size.prefix) { if (output.size.prefix) {
const uint8_t* data = file_contents; const uint8_t* data = file_contents;
if (output.prefix_type == DFUSE_PREFIX) { if (output.prefix_type == DFUSE_PREFIX) {
} else if (output.prefix_type == LMDFU_PREFIX) { } else if (output.prefix_type == LMDFU_PREFIX) {
printf("Possible TI Stellaris DFU prefix with " printf(
"the following properties\n" "Possible TI Stellaris DFU prefix with "
"Address: 0x%08x\n" "the following properties\n"
"Payload length: %d\n", "Address: 0x%08x\n"
output.lmdfu_address, "Payload length: %d\n",
data[4] | (data[5] << 8) | (data[6] << 16) output.lmdfu_address,
| (data[7] << 24)); data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24));
} else if (output.prefix_type == LPCDFU_UNENCRYPTED_PREFIX) { } else if (output.prefix_type == LPCDFU_UNENCRYPTED_PREFIX) {
printf("Possible unencrypted NXP LPC DFU prefix with " printf(
"the following properties\n" "Possible unencrypted NXP LPC DFU prefix with "
"Payload length: %d kiByte\n", "the following properties\n"
data[2] >> 1 | (data[3] << 7)); "Payload length: %d kiByte\n",
} else { data[2] >> 1 | (data[3] << 7));
fprintf(stderr, "Unknown DFU prefix type"); } else {
} fprintf(stderr, "Unknown DFU prefix type");
output.firmware
= output.firmware + output.size.prefix; // shift past prefix
} }
output.size.firmware output.firmware =
= output.size.total - (output.size.suffix + output.size.prefix); output.firmware + output.size.prefix; // shift past prefix
return output; }
output.size.firmware =
output.size.total - (output.size.suffix + output.size.prefix);
return output;
} }
// 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",
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;
}

View File

@ -5,7 +5,6 @@
#ifndef BLISP_DFU_FILE_H #ifndef BLISP_DFU_FILE_H
#define BLISP_DFU_FILE_H #define BLISP_DFU_FILE_H
#include <malloc.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>

View File

@ -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;
}

View File

@ -1,5 +1,6 @@
#include "parse_file.h" #include "parse_file.h"
#include <string.h> #include <string.h>
#include "bin_file.h"
#include "dfu_file.h" #include "dfu_file.h"
const char* get_filename_ext(const char* filename) { const char* get_filename_ext(const char* filename) {
@ -8,22 +9,35 @@ const char* get_filename_ext(const char* filename) {
return ""; return "";
return dot + 1; return dot + 1;
} }
#define FLASH_MAP_ADDR 0x23000000
int parse_firmware_file(const char* file_path_on_disk, int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results) { parsed_firmware_file_t* parsed_results) {
// Switchcase on the extension of the file // Switchcase on the extension of the file
const char* ext = get_filename_ext(file_path_on_disk); 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) { if (strncmp(ext, "dfu", 3) == 0 || strncmp(ext, "DFU", 3) == 0) {
printf("Input file identified as a .dfu file\r\n"); printf("Input file identified as a .dfu file\n");
// Handle as a .dfu file // Handle as a .dfu file
return dfu_file_parse("test.dfu", &parsed_results->payload, res = dfu_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length, &parsed_results->payload_length,
&parsed_results->payload_address); &parsed_results->payload_address);
} else if (strncmp(ext, "bin", 3) == 0 || strncmp(ext, "BIN", 3) == 0) { } else if (strncmp(ext, "bin", 3) == 0 || strncmp(ext, "BIN", 3) == 0) {
printf("Input file identified as a .bin file\r\n"); printf("Input file identified as a .bin file\n");
// Raw binary file // Raw binary file
res = bin_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
} }
// TODO: Hex files? // If we wanted to support hex files, here would be where
return PARSED_ERROR_INVALID_FILETYPE;
// 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;
} }

View File

@ -1,7 +1,10 @@
#pragma once #pragma once
#include <stdio.h>
#include <stdlib.h>
#include "parsed_firmware_file.h" #include "parsed_firmware_file.h"
#define PARSED_ERROR_INVALID_FILETYPE -0x1000 #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_TOO_BIG -0x1001 /* Input expands to be too big */
#define PARSED_ERROR_BAD_DFU -0x1002 /* DFU file provided but not valid */ #define PARSED_ERROR_BAD_DFU -0x1002 /* DFU file provided but not valid */
@ -12,3 +15,7 @@
int parse_firmware_file(const char* file_path_on_disk, int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results); parsed_firmware_file_t* parsed_results);
// Internal util
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents);

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>