Skip to content

Commit 91647a7

Browse files
pillo79facchinm
authored andcommitted
post-build: rework to use empty area in ELF header or add it in binaries
- identify ELF files, add empty area if header is missing - store sketch flags in empty bytes in ELF identification area
1 parent fc8985d commit 91647a7

File tree

2 files changed

+74
-26
lines changed

2 files changed

+74
-26
lines changed

extra/post_build_tool/main.go

+55-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package main
22

33
import (
4+
"bytes"
5+
"encoding/binary"
46
"flag"
57
"fmt"
68
"os"
@@ -10,6 +12,8 @@ func main() {
1012
var output = flag.String("output", "", "Output to a specific file (default: add .dfu suffix)")
1113
var debug = flag.Bool("debug", false, "Enable debugging mode")
1214
var linked = flag.Bool("prelinked", false, "Provided file has already been linked to Zephyr")
15+
var force = flag.Bool("force", false, "Ignore safety checks and overwrite the header")
16+
var add_header = flag.Bool("add_header", false, "Add space for the header to the file")
1317

1418
flag.Parse()
1519
if flag.NArg() != 1 {
@@ -26,16 +30,57 @@ func main() {
2630
return
2731
}
2832

29-
// Get the length of the file content
30-
length := len(content)
33+
var ELF_HEADER = []byte { 0x7f, 0x45, 0x4c, 0x46 }
34+
var elf_header_found = bytes.Compare(ELF_HEADER, content[0:4]) == 0
35+
if *add_header || (!*force && !elf_header_found) {
36+
fmt.Printf("File does not have an ELF header, adding empty space\n")
3137

32-
// Create the new content with the length in front
33-
len_str := fmt.Sprintf("%d", length)
34-
newContent := append([]byte(len_str), 0, byte(*debug), byte(*linked))
35-
// make newContent 16 bytes
36-
tmp := make([]byte, 16-len(newContent))
37-
newContent = append(newContent, tmp...)
38-
newContent = append(newContent, content...)
38+
var newContent = make([]byte, len(content)+16)
39+
copy(newContent[16:], content)
40+
content = newContent
41+
}
42+
43+
// Create and fill custom header
44+
var header struct {
45+
ver uint8 // @ 0x07
46+
len uint32 // @ 0x08
47+
magic uint16 // @ 0x0c
48+
flags uint8 // @ 0x0e
49+
}
50+
51+
header.ver = 1
52+
header.magic = 0x2341 // Arduino USB VID
53+
header.len = uint32(len(content))
54+
55+
header.flags = 0
56+
if *debug {
57+
header.flags |= 0x01
58+
}
59+
if *linked {
60+
header.flags |= 0x02
61+
}
62+
63+
var bytes = make([]byte, 9)
64+
_, err = binary.Encode(bytes, binary.LittleEndian, header)
65+
if err != nil {
66+
fmt.Printf("Error encoding header: %v\n", err)
67+
return
68+
}
69+
70+
// Bytes 7 to 15 are free to use in current ELF specification. We will
71+
// use them to store the debug and linked flags.
72+
// Check if the target area is empty
73+
if !*force {
74+
for i := 7; i < 16; i++ {
75+
if content[i] != 0 {
76+
fmt.Printf("Target ELF header area is not empty. Use --force to overwrite\n")
77+
return
78+
}
79+
}
80+
}
81+
82+
// Change the header bytes in the content
83+
copy(content[7:16], bytes)
3984

4085
// Create a new filename for the copy
4186
newFilename := *output
@@ -44,13 +89,7 @@ func main() {
4489
}
4590

4691
// Write the new content to the new file
47-
err = os.WriteFile(newFilename, []byte(newContent), 0644)
48-
if err != nil {
49-
fmt.Printf("Error writing to file: %v\n", err)
50-
return
51-
}
52-
// Copy in .bin
53-
err = os.WriteFile(newFilename+".bin", []byte(newContent), 0644)
92+
err = os.WriteFile(newFilename, content, 0644)
5493
if err != nil {
5594
fmt.Printf("Error writing to file: %v\n", err)
5695
return

loader/main.c

+19-10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ LOG_MODULE_REGISTER(app);
2222

2323
#define HEADER_LEN 16
2424

25+
struct sketch_header_v1 {
26+
uint8_t ver; // @ 0x07
27+
uint32_t len; // @ 0x08
28+
uint16_t magic; // @ 0x0c
29+
uint8_t flags; // @ 0x0e
30+
} __attribute__ ((packed));
31+
32+
#define SKETCH_FLAG_DEBUG 0x01
33+
#define SKETCH_FLAG_LINKED 0x02
34+
2535
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
2636
const struct device *const usb_dev = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), cdc_acm, 0));
2737
#endif
@@ -66,17 +76,17 @@ static int loader(const struct shell *sh)
6676
return -ENOENT;
6777
}
6878

69-
char *endptr;
70-
size_t sketch_buf_len = strtoul(header, &endptr, 10);
71-
// make sure number got parsed correctly"
72-
if (header == endptr) {
73-
printk("Failed to parse sketch size\n");
79+
struct sketch_header_v1 *sketch_hdr = (struct sketch_header_v1 *)(header + 7);
80+
if (sketch_hdr->ver != 0x1 || sketch_hdr->magic != 0x2341) {
81+
printk("Invalid sketch header\n");
7482
return -EINVAL;
7583
}
7684

85+
size_t sketch_buf_len = sketch_hdr->len;
86+
7787
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm) && CONFIG_SHELL && CONFIG_USB_DEVICE_STACK
78-
uint8_t debug = endptr[1];
79-
if (debug == 1 && strcmp(k_thread_name_get(k_current_get()), "main") == 0) {
88+
int debug = sketch_hdr->flags & SKETCH_FLAG_DEBUG;
89+
if (debug && strcmp(k_thread_name_get(k_current_get()), "main") == 0) {
8090
// disables default shell on UART
8191
shell_uninit(shell_backend_uart_get_ptr(), NULL);
8292
// enables USB and starts the shell
@@ -92,8 +102,7 @@ static int loader(const struct shell *sh)
92102
}
93103
#endif
94104

95-
uint8_t linked = endptr[2];
96-
if (linked) {
105+
if (sketch_hdr->flags & SKETCH_FLAG_LINKED) {
97106
#ifdef CONFIG_BOARD_ARDUINO_PORTENTA_C33
98107
#if CONFIG_MPU
99108
barrier_dmem_fence_full();
@@ -130,7 +139,7 @@ static int loader(const struct shell *sh)
130139
}
131140
#else
132141
// Assuming the sketch is stored in the same flash device as the loader
133-
uint8_t* sketch_buf = (uint8_t*)(base_addr + HEADER_LEN);
142+
uint8_t* sketch_buf = (uint8_t*)base_addr;
134143
#endif
135144

136145
#ifdef CONFIG_LLEXT

0 commit comments

Comments
 (0)