diff options
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/bootdata.c | 74 | ||||
-rw-r--r-- | firmware/common/multiboot.c | 55 | ||||
-rw-r--r-- | firmware/common/rb-loader.c | 2 |
3 files changed, 109 insertions, 22 deletions
diff --git a/firmware/common/bootdata.c b/firmware/common/bootdata.c new file mode 100644 index 0000000000..fa74c5fe91 --- /dev/null +++ b/firmware/common/bootdata.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2022 by Aidan MacDonald | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "bootdata.h" | ||
22 | #include "crc32.h" | ||
23 | #include <stddef.h> | ||
24 | |||
25 | #ifdef BOOTLOADER | ||
26 | # error "not to be included in bootloader builds" | ||
27 | #endif | ||
28 | |||
29 | bool boot_data_valid; | ||
30 | |||
31 | static bool verify_boot_data_v0(void) INIT_ATTR; | ||
32 | static bool verify_boot_data_v0(void) | ||
33 | { | ||
34 | /* validate protocol version */ | ||
35 | if (boot_data.version != 0) | ||
36 | return false; | ||
37 | |||
38 | /* validate length */ | ||
39 | if (boot_data.length != 4) | ||
40 | return false; | ||
41 | |||
42 | return true; | ||
43 | } | ||
44 | |||
45 | struct verify_bd_entry | ||
46 | { | ||
47 | int version; | ||
48 | bool (*verify) (void); | ||
49 | }; | ||
50 | |||
51 | static const struct verify_bd_entry verify_bd[] INITDATA_ATTR = { | ||
52 | { 0, verify_boot_data_v0 }, | ||
53 | }; | ||
54 | |||
55 | void verify_boot_data(void) | ||
56 | { | ||
57 | /* verify payload with checksum - all protocol versions */ | ||
58 | uint32_t crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff); | ||
59 | if (crc != boot_data.crc) | ||
60 | return; | ||
61 | |||
62 | /* apply verification specific to the protocol version */ | ||
63 | for (size_t i = 0; i < ARRAYLEN(verify_bd); ++i) | ||
64 | { | ||
65 | const struct verify_bd_entry *e = &verify_bd[i]; | ||
66 | if (e->version == boot_data.version) | ||
67 | { | ||
68 | if (e->verify()) | ||
69 | boot_data_valid = true; | ||
70 | |||
71 | return; | ||
72 | } | ||
73 | } | ||
74 | } | ||
diff --git a/firmware/common/multiboot.c b/firmware/common/multiboot.c index c2cedc102d..c292aa1c30 100644 --- a/firmware/common/multiboot.c +++ b/firmware/common/multiboot.c | |||
@@ -26,44 +26,57 @@ | |||
26 | #include <string.h> | 26 | #include <string.h> |
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | 28 | ||
29 | static void write_bootdata_v0(struct boot_data_t *data, unsigned int boot_volume) | ||
30 | { | ||
31 | memset(data->payload, data->length, 0); | ||
32 | |||
33 | data->boot_volume = boot_volume; | ||
34 | data->version = 0; | ||
35 | } | ||
36 | |||
29 | /* Write bootdata into location in FIRMWARE marked by magic header | 37 | /* Write bootdata into location in FIRMWARE marked by magic header |
30 | * Assumes buffer is already loaded with the firmware image | 38 | * Assumes buffer is already loaded with the firmware image |
31 | * We just need to find the location and write data into the | 39 | * We just need to find the location and write data into the |
32 | * payload region along with the crc for later verification and use. | 40 | * payload region along with the crc for later verification and use. |
33 | * Returns payload len on success, | 41 | * Returns payload len on success, |
34 | * On error returns EKEY_NOT_FOUND | 42 | * On error returns false |
35 | */ | 43 | */ |
36 | int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) | 44 | bool write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) |
37 | { | 45 | { |
38 | struct boot_data_t bl_boot_data; | ||
39 | struct boot_data_t *fw_boot_data = NULL; | ||
40 | int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); | 46 | int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); |
41 | int payload_len = EKEY_NOT_FOUND; | ||
42 | 47 | ||
43 | /* search for boot data header prior to search_len */ | 48 | /* search for boot data header prior to search_len */ |
44 | for(int i = 0; i < search_len; i++) | 49 | for(int i = 0; i < search_len; i++) |
45 | { | 50 | { |
46 | fw_boot_data = (struct boot_data_t*) &buf[i]; | 51 | struct boot_data_t *data = (struct boot_data_t *)&buf[i]; |
47 | if (fw_boot_data->magic[0] != BOOT_DATA_MAGIC0 || | 52 | if (data->magic[0] != BOOT_DATA_MAGIC0 || |
48 | fw_boot_data->magic[1] != BOOT_DATA_MAGIC1) | 53 | data->magic[1] != BOOT_DATA_MAGIC1) |
49 | continue; | 54 | continue; |
50 | 55 | ||
51 | memset(&bl_boot_data.payload, 0, BOOT_DATA_PAYLOAD_SIZE); | 56 | /* Ignore it if the length extends past the end of the buffer. */ |
52 | bl_boot_data.boot_volume = boot_volume; | 57 | int data_len = offsetof(struct boot_data_t, payload) + data->length; |
58 | if (i + data_len > len) | ||
59 | continue; | ||
60 | |||
61 | /* Determine the maximum supported boot protocol version. | ||
62 | * Version 0 firmware may use 0 or 0xff, all other versions | ||
63 | * declare the highest supported version in the version byte. */ | ||
64 | int proto_version = 0; | ||
65 | if (data->version < 0xff) | ||
66 | proto_version = MIN(BOOT_DATA_VERSION, data->version); | ||
53 | 67 | ||
54 | memset(fw_boot_data->payload, 0, fw_boot_data->length); | 68 | /* Write boot data according to the selected protocol */ |
55 | /* determine maximum bytes we can write to firmware | 69 | if (proto_version == 0) |
56 | BOOT_DATA_PAYLOAD_SIZE is the size the bootloader expects */ | 70 | write_bootdata_v0(data, boot_volume); |
57 | payload_len = MIN(BOOT_DATA_PAYLOAD_SIZE, fw_boot_data->length); | 71 | else |
58 | fw_boot_data->length = payload_len; | 72 | break; |
59 | /* copy data to FIRMWARE bootdata struct */ | ||
60 | memcpy(fw_boot_data->payload, &bl_boot_data.payload, payload_len); | ||
61 | /* crc will be used within the firmware to check validity of bootdata */ | ||
62 | fw_boot_data->crc = crc_32(fw_boot_data->payload, payload_len, 0xffffffff); | ||
63 | break; | ||
64 | 73 | ||
74 | /* Calculate payload CRC, used by all protocol versions. */ | ||
75 | data->crc = crc_32(data->payload, data->length, 0xffffffff); | ||
76 | return true; | ||
65 | } | 77 | } |
66 | return payload_len; | 78 | |
79 | return false; | ||
67 | } | 80 | } |
68 | 81 | ||
69 | #ifdef HAVE_MULTIBOOT | 82 | #ifdef HAVE_MULTIBOOT |
diff --git a/firmware/common/rb-loader.c b/firmware/common/rb-loader.c index 0256f21884..61d8b1ddd2 100644 --- a/firmware/common/rb-loader.c +++ b/firmware/common/rb-loader.c | |||
@@ -112,7 +112,7 @@ int load_firmware(unsigned char* buf, const char* firmware, int buffer_size) | |||
112 | { | 112 | { |
113 | ret = load_firmware_filename(buf, filename, buffer_size); | 113 | ret = load_firmware_filename(buf, filename, buffer_size); |
114 | /* if firmware has no boot_data don't load from external drive */ | 114 | /* if firmware has no boot_data don't load from external drive */ |
115 | if (write_bootdata(buf, ret, i) <= 0) | 115 | if (!write_bootdata(buf, ret, i)) |
116 | ret = EKEY_NOT_FOUND; | 116 | ret = EKEY_NOT_FOUND; |
117 | } | 117 | } |
118 | /* if ret is valid breaks from loop to continue loading */ | 118 | /* if ret is valid breaks from loop to continue loading */ |