diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/SOURCES | 3 | ||||
-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 | ||||
-rw-r--r-- | firmware/export/bootdata.h | 10 | ||||
-rw-r--r-- | firmware/export/multiboot.h | 2 | ||||
-rw-r--r-- | firmware/include/dircache_redirect.h | 6 | ||||
-rw-r--r-- | firmware/rolo.c | 9 | ||||
-rw-r--r-- | firmware/target/arm/pp/mi4-loader.c | 2 |
9 files changed, 128 insertions, 35 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index f6d35fb5ea..87cadfd55f 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -57,6 +57,9 @@ target/hosted/rolo.c | |||
57 | 57 | ||
58 | #if defined(HAVE_BOOTDATA) || defined(HAVE_MULTIBOOT) | 58 | #if defined(HAVE_BOOTDATA) || defined(HAVE_MULTIBOOT) |
59 | common/multiboot.c | 59 | common/multiboot.c |
60 | #ifndef BOOTLOADER | ||
61 | common/bootdata.c | ||
62 | #endif | ||
60 | #endif | 63 | #endif |
61 | 64 | ||
62 | #ifdef HAVE_SDL | 65 | #ifdef HAVE_SDL |
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 */ |
diff --git a/firmware/export/bootdata.h b/firmware/export/bootdata.h index 322d50c20d..319f442511 100644 --- a/firmware/export/bootdata.h +++ b/firmware/export/bootdata.h | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #ifndef __ASSEMBLER__ | 23 | #ifndef __ASSEMBLER__ |
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include "system.h" | ||
25 | #endif | 26 | #endif |
26 | 27 | ||
27 | /* /!\ This file can be included in assembly files /!\ */ | 28 | /* /!\ This file can be included in assembly files /!\ */ |
@@ -36,6 +37,7 @@ | |||
36 | 37 | ||
37 | #define BOOT_DATA_MAGIC0 ('r' | 'b' << 8 | 'm' << 16 | 'a' << 24) | 38 | #define BOOT_DATA_MAGIC0 ('r' | 'b' << 8 | 'm' << 16 | 'a' << 24) |
38 | #define BOOT_DATA_MAGIC1 ('g' | 'i' << 8 | 'c' << 16 | '!' << 24) | 39 | #define BOOT_DATA_MAGIC1 ('g' | 'i' << 8 | 'c' << 16 | '!' << 24) |
40 | #define BOOT_DATA_VERSION 0 | ||
39 | 41 | ||
40 | /* maximum size of payload */ | 42 | /* maximum size of payload */ |
41 | #define BOOT_DATA_PAYLOAD_SIZE 4 | 43 | #define BOOT_DATA_PAYLOAD_SIZE 4 |
@@ -58,6 +60,7 @@ struct boot_data_t | |||
58 | struct | 60 | struct |
59 | { | 61 | { |
60 | uint8_t boot_volume; | 62 | uint8_t boot_volume; |
63 | uint8_t version; | ||
61 | }; | 64 | }; |
62 | uint8_t payload[BOOT_DATA_PAYLOAD_SIZE]; | 65 | uint8_t payload[BOOT_DATA_PAYLOAD_SIZE]; |
63 | }; | 66 | }; |
@@ -65,6 +68,9 @@ struct boot_data_t | |||
65 | 68 | ||
66 | #if !defined(BOOTLOADER) | 69 | #if !defined(BOOTLOADER) |
67 | extern struct boot_data_t boot_data; | 70 | extern struct boot_data_t boot_data; |
71 | extern bool boot_data_valid; | ||
72 | |||
73 | void verify_boot_data(void) INIT_ATTR; | ||
68 | #endif | 74 | #endif |
69 | #else /* __ASSEMBLER__ */ | 75 | #else /* __ASSEMBLER__ */ |
70 | 76 | ||
@@ -76,7 +82,9 @@ boot_data: | |||
76 | .word BOOT_DATA_MAGIC0 | 82 | .word BOOT_DATA_MAGIC0 |
77 | .word BOOT_DATA_MAGIC1 | 83 | .word BOOT_DATA_MAGIC1 |
78 | .word BOOT_DATA_PAYLOAD_SIZE | 84 | .word BOOT_DATA_PAYLOAD_SIZE |
79 | .space BOOT_DATA_PAYLOAD_SIZE, 0xff /* payload, initialised with value 0xff */ | 85 | .byte 0xff /* boot volume */ |
86 | .byte BOOT_DATA_VERSION /* maximum supported boot protocol version */ | ||
87 | .space (BOOT_DATA_PAYLOAD_SIZE - 2), 0xff /* remainder of payload */ | ||
80 | .endm | 88 | .endm |
81 | 89 | ||
82 | #endif | 90 | #endif |
diff --git a/firmware/export/multiboot.h b/firmware/export/multiboot.h index 0132b8531f..4174e71d61 100644 --- a/firmware/export/multiboot.h +++ b/firmware/export/multiboot.h | |||
@@ -21,7 +21,7 @@ | |||
21 | #ifndef __MULTIBOOT_H__ | 21 | #ifndef __MULTIBOOT_H__ |
22 | #define __MULTIBOOT_H__ | 22 | #define __MULTIBOOT_H__ |
23 | 23 | ||
24 | extern int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume); | 24 | extern bool write_bootdata(unsigned char* buf, int len, unsigned int boot_volume); |
25 | #ifdef HAVE_MULTIBOOT | 25 | #ifdef HAVE_MULTIBOOT |
26 | extern int get_redirect_dir(char* buf, int buffer_size, int volume, | 26 | extern int get_redirect_dir(char* buf, int buffer_size, int volume, |
27 | const char* rootdir, const char* firmware); | 27 | const char* rootdir, const char* firmware); |
diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h index f51ce70690..d4d72978c0 100644 --- a/firmware/include/dircache_redirect.h +++ b/firmware/include/dircache_redirect.h | |||
@@ -29,7 +29,6 @@ | |||
29 | #include "rb-loader.h" | 29 | #include "rb-loader.h" |
30 | #include "multiboot.h" | 30 | #include "multiboot.h" |
31 | #include "bootdata.h" | 31 | #include "bootdata.h" |
32 | #include "crc32.h" | ||
33 | #endif | 32 | #endif |
34 | 33 | ||
35 | #ifndef RB_ROOT_VOL_HIDDEN | 34 | #ifndef RB_ROOT_VOL_HIDDEN |
@@ -144,8 +143,7 @@ static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) | |||
144 | char rtpath[MAX_PATH / 2]; | 143 | char rtpath[MAX_PATH / 2]; |
145 | make_volume_root(volume, path); | 144 | make_volume_root(volume, path); |
146 | 145 | ||
147 | unsigned int crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff); | 146 | if (boot_data_valid) |
148 | if (crc > 0 && crc == boot_data.crc) | ||
149 | { | 147 | { |
150 | /* we need to mount the drive before we can access it */ | 148 | /* we need to mount the drive before we can access it */ |
151 | root_mount_path(path, 0); /* root could be different folder don't hide */ | 149 | root_mount_path(path, 0); /* root could be different folder don't hide */ |
@@ -174,7 +172,7 @@ static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) | |||
174 | root_mount_path(rtpath, NSITEM_CONTENTS); | 172 | root_mount_path(rtpath, NSITEM_CONTENTS); |
175 | } | 173 | } |
176 | 174 | ||
177 | } /*CRC OK*/ | 175 | } |
178 | else | 176 | else |
179 | { | 177 | { |
180 | standard_redirect: | 178 | standard_redirect: |
diff --git a/firmware/rolo.c b/firmware/rolo.c index a3e6d5c2b9..1b37b6f771 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c | |||
@@ -250,12 +250,9 @@ int rolo_load(const char* filename) | |||
250 | 250 | ||
251 | err = LOAD_FIRMWARE(filebuf, filename, filebuf_size); | 251 | err = LOAD_FIRMWARE(filebuf, filename, filebuf_size); |
252 | #if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) | 252 | #if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) |
253 | /* write the bootdata as if rolo were the bootloader */ | 253 | /* write the bootdata as if rolo were the bootloader |
254 | unsigned int crc = 0; | 254 | * FIXME: this won't work for root redirect... */ |
255 | if (strcmp(filename, BOOTDIR "/" BOOTFILE) == 0) | 255 | if (!strcmp(filename, BOOTDIR "/" BOOTFILE) && boot_data_valid) |
256 | crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff); | ||
257 | |||
258 | if(crc > 0 && crc == boot_data.crc) | ||
259 | write_bootdata(filebuf, filebuf_size, boot_data.boot_volume); /* rb-loader.c */ | 256 | write_bootdata(filebuf, filebuf_size, boot_data.boot_volume); /* rb-loader.c */ |
260 | #endif | 257 | #endif |
261 | 258 | ||
diff --git a/firmware/target/arm/pp/mi4-loader.c b/firmware/target/arm/pp/mi4-loader.c index f609e3ff7a..14bb5e6f47 100644 --- a/firmware/target/arm/pp/mi4-loader.c +++ b/firmware/target/arm/pp/mi4-loader.c | |||
@@ -256,7 +256,7 @@ int load_mi4(unsigned char* buf, const char* firmware, unsigned int buffer_size) | |||
256 | { | 256 | { |
257 | ret = load_mi4_filename(buf, filename, buffer_size); | 257 | ret = load_mi4_filename(buf, filename, buffer_size); |
258 | /* if firmware has no boot_data don't load from external drive */ | 258 | /* if firmware has no boot_data don't load from external drive */ |
259 | if (write_bootdata(buf, ret, i) <= 0) | 259 | if (!write_bootdata(buf, ret, i)) |
260 | ret = EKEY_NOT_FOUND; | 260 | ret = EKEY_NOT_FOUND; |
261 | } | 261 | } |
262 | /* if ret is valid breaks from loop to continue loading */ | 262 | /* if ret is valid breaks from loop to continue loading */ |