summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-12-22 20:31:06 +0000
committerAidan MacDonald <amachronic@protonmail.com>2024-03-31 16:57:19 +0100
commitdc9d354ed22b4c6230c6bfe885e8a3d2519b1285 (patch)
treeae7e82354a3599bf3bb24cc25b341ba94d235375
parent6ffd42548bf10cda13a01555ff4fa56d4213cdf2 (diff)
downloadrockbox-dc9d354ed22b4c6230c6bfe885e8a3d2519b1285.tar.gz
rockbox-dc9d354ed22b4c6230c6bfe885e8a3d2519b1285.zip
multiboot: Add v1 boot protocol
v1 passes the drive and partition number of the boot volume instead of using the volume number. The volume number isn't reliable because the same filesystem might get a different volume number once the firmware is loaded, which will cause the firmware to use the wrong root volume and fail to locate the correct .rockbox directory. Using drive and partition numbers avoids this issue because drive numbering is fixed and determined by the target. Change-Id: I7e68b892d9424a1f686197a6122e139b438e5f7e
-rw-r--r--apps/debug_menu.c11
-rw-r--r--firmware/common/bootdata.c15
-rw-r--r--firmware/common/multiboot.c15
-rw-r--r--firmware/export/bootdata.h6
-rw-r--r--firmware/include/dircache_redirect.h43
-rw-r--r--firmware/rolo.c21
6 files changed, 99 insertions, 12 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 5e2451e41b..36927dd890 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2546,7 +2546,16 @@ static bool dbg_boot_data(void)
2546 { 2546 {
2547 simplelist_addline("Boot data valid"); 2547 simplelist_addline("Boot data valid");
2548 simplelist_addline("Version: %d", (int)boot_data.version); 2548 simplelist_addline("Version: %d", (int)boot_data.version);
2549 simplelist_addline("Boot volume: %d", (int)boot_data.boot_volume); 2549
2550 if (boot_data.version == 0)
2551 {
2552 simplelist_addline("Boot volume: %d", (int)boot_data._boot_volume);
2553 }
2554 else if (boot_data.version == 1)
2555 {
2556 simplelist_addline("Boot drive: %d", (int)boot_data.boot_drive);
2557 simplelist_addline("Boot partition: %d", (int)boot_data.boot_partition);
2558 }
2550 } 2559 }
2551 2560
2552 simplelist_addline("Bootdata RAW:"); 2561 simplelist_addline("Bootdata RAW:");
diff --git a/firmware/common/bootdata.c b/firmware/common/bootdata.c
index fa74c5fe91..224a48d0c1 100644
--- a/firmware/common/bootdata.c
+++ b/firmware/common/bootdata.c
@@ -42,6 +42,20 @@ static bool verify_boot_data_v0(void)
42 return true; 42 return true;
43} 43}
44 44
45static bool verify_boot_data_v1(void) INIT_ATTR;
46static bool verify_boot_data_v1(void)
47{
48 /* validate protocol version */
49 if (boot_data.version != 1)
50 return false;
51
52 /* validate length */
53 if (boot_data.length != 4)
54 return false;
55
56 return true;
57}
58
45struct verify_bd_entry 59struct verify_bd_entry
46{ 60{
47 int version; 61 int version;
@@ -50,6 +64,7 @@ struct verify_bd_entry
50 64
51static const struct verify_bd_entry verify_bd[] INITDATA_ATTR = { 65static const struct verify_bd_entry verify_bd[] INITDATA_ATTR = {
52 { 0, verify_boot_data_v0 }, 66 { 0, verify_boot_data_v0 },
67 { 1, verify_boot_data_v1 },
53}; 68};
54 69
55void verify_boot_data(void) 70void verify_boot_data(void)
diff --git a/firmware/common/multiboot.c b/firmware/common/multiboot.c
index c292aa1c30..8d6573d2dd 100644
--- a/firmware/common/multiboot.c
+++ b/firmware/common/multiboot.c
@@ -23,6 +23,7 @@
23#include "crc32.h" 23#include "crc32.h"
24#include "loader_strerror.h" 24#include "loader_strerror.h"
25#include "file.h" 25#include "file.h"
26#include "disk.h"
26#include <string.h> 27#include <string.h>
27#include <stdio.h> 28#include <stdio.h>
28 29
@@ -30,10 +31,20 @@ static void write_bootdata_v0(struct boot_data_t *data, unsigned int boot_volume
30{ 31{
31 memset(data->payload, data->length, 0); 32 memset(data->payload, data->length, 0);
32 33
33 data->boot_volume = boot_volume; 34 data->_boot_volume = boot_volume;
34 data->version = 0; 35 data->version = 0;
35} 36}
36 37
38static void write_bootdata_v1(struct boot_data_t *data, unsigned int boot_volume)
39{
40 memset(data->payload, data->length, 0);
41
42 data->_boot_volume = 0xff;
43 data->version = 1;
44 data->boot_drive = volume_drive(boot_volume);
45 data->boot_partition = volume_partition(boot_volume);
46}
47
37/* Write bootdata into location in FIRMWARE marked by magic header 48/* Write bootdata into location in FIRMWARE marked by magic header
38 * Assumes buffer is already loaded with the firmware image 49 * Assumes buffer is already loaded with the firmware image
39 * We just need to find the location and write data into the 50 * We just need to find the location and write data into the
@@ -68,6 +79,8 @@ bool write_bootdata(unsigned char* buf, int len, unsigned int boot_volume)
68 /* Write boot data according to the selected protocol */ 79 /* Write boot data according to the selected protocol */
69 if (proto_version == 0) 80 if (proto_version == 0)
70 write_bootdata_v0(data, boot_volume); 81 write_bootdata_v0(data, boot_volume);
82 else if (proto_version == 1)
83 write_bootdata_v1(data, boot_volume);
71 else 84 else
72 break; 85 break;
73 86
diff --git a/firmware/export/bootdata.h b/firmware/export/bootdata.h
index 319f442511..2a6f96d22e 100644
--- a/firmware/export/bootdata.h
+++ b/firmware/export/bootdata.h
@@ -37,7 +37,7 @@
37 37
38#define BOOT_DATA_MAGIC0 ('r' | 'b' << 8 | 'm' << 16 | 'a' << 24) 38#define BOOT_DATA_MAGIC0 ('r' | 'b' << 8 | 'm' << 16 | 'a' << 24)
39#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 40#define BOOT_DATA_VERSION 1
41 41
42/* maximum size of payload */ 42/* maximum size of payload */
43#define BOOT_DATA_PAYLOAD_SIZE 4 43#define BOOT_DATA_PAYLOAD_SIZE 4
@@ -59,8 +59,10 @@ struct boot_data_t
59 { 59 {
60 struct 60 struct
61 { 61 {
62 uint8_t boot_volume; 62 uint8_t _boot_volume; /* IGNORED */
63 uint8_t version; 63 uint8_t version;
64 uint8_t boot_drive;
65 uint8_t boot_partition;
64 }; 66 };
65 uint8_t payload[BOOT_DATA_PAYLOAD_SIZE]; 67 uint8_t payload[BOOT_DATA_PAYLOAD_SIZE];
66 }; 68 };
diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h
index d4d72978c0..32e441c5b3 100644
--- a/firmware/include/dircache_redirect.h
+++ b/firmware/include/dircache_redirect.h
@@ -136,6 +136,41 @@ static inline void fileop_onsync_internal(struct filestr_base *stream)
136#endif 136#endif
137} 137}
138 138
139#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
140static inline bool multiboot_is_boot_volume(int volume)
141{
142 if (boot_data.version == 0)
143 {
144 /*
145 * Version 0 bootloaders just pass the volume number, but that's
146 * dynamically assigned and sometimes differs by the time we get
147 * into the firmware. So we can't rely on the volume passed by
148 * the bootloader.
149 */
150#if CONFIG_CPU == X1000
151 /* The affected X1000 players only have one drive to begin with */
152 return volume_drive(volume) == 0;
153#else
154 /* FIXME: Anything else that can get here is a Sansa. */
155 return volume_drive(volume) == boot_data.boot_volume ||
156 volume == boot_data.boot_volume;
157#endif
158 }
159
160 if (boot_data.version == 1)
161 {
162 /*
163 * Since version 1 the bootloader passes drive and partition
164 * number which unambiguously identifies the boot volume.
165 */
166 return volume_drive(volume) == boot_data.boot_drive &&
167 volume_partition(volume) == boot_data.boot_partition;
168 }
169
170 return false;
171}
172#endif
173
139static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) 174static inline void volume_onmount_internal(IF_MV_NONVOID(int volume))
140{ 175{
141#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER) 176#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
@@ -148,13 +183,7 @@ static inline void volume_onmount_internal(IF_MV_NONVOID(int volume))
148 /* we need to mount the drive before we can access it */ 183 /* we need to mount the drive before we can access it */
149 root_mount_path(path, 0); /* root could be different folder don't hide */ 184 root_mount_path(path, 0); /* root could be different folder don't hide */
150 185
151/*BUGFIX bootloader is less selective about which drives it will mount -- revisit */ 186 if (multiboot_is_boot_volume(IF_MV_VOL(volume)))
152#if defined(HAVE_MULTIDRIVE) && (NUM_VOLUMES_PER_DRIVE == 1)
153 if (volume_drive(volume) == boot_data.boot_volume
154 || volume == boot_data.boot_volume)
155#else
156 if (volume == boot_data.boot_volume) /* boot volume contained in uint8_t payload */
157#endif
158 { 187 {
159 int rtlen = get_redirect_dir(rtpath, sizeof(rtpath), volume, "", ""); 188 int rtlen = get_redirect_dir(rtpath, sizeof(rtpath), volume, "", "");
160 while (rtlen > 0 && rtpath[--rtlen] == PATH_SEPCH) 189 while (rtlen > 0 && rtpath[--rtlen] == PATH_SEPCH)
diff --git a/firmware/rolo.c b/firmware/rolo.c
index 1b37b6f771..f9b0cc9e61 100644
--- a/firmware/rolo.c
+++ b/firmware/rolo.c
@@ -253,7 +253,26 @@ int rolo_load(const char* filename)
253 /* write the bootdata as if rolo were the bootloader 253 /* write the bootdata as if rolo were the bootloader
254 * FIXME: this won't work for root redirect... */ 254 * FIXME: this won't work for root redirect... */
255 if (!strcmp(filename, BOOTDIR "/" BOOTFILE) && boot_data_valid) 255 if (!strcmp(filename, BOOTDIR "/" BOOTFILE) && boot_data_valid)
256 write_bootdata(filebuf, filebuf_size, boot_data.boot_volume); /* rb-loader.c */ 256 {
257 int volume = 0;
258
259 if (boot_data.version == 0)
260 volume = boot_data._boot_volume;
261 else if (boot_data.version == 1)
262 {
263 for (int i = 0; i < NUM_VOLUMES; ++i)
264 {
265 if (volume_drive(i) == boot_data.boot_drive &&
266 volume_partition(i) == boot_data.boot_partition)
267 {
268 volume = i;
269 break;
270 }
271 }
272 }
273
274 write_bootdata(filebuf, filebuf_size, volume);
275 }
257#endif 276#endif
258 277
259 if (err <= 0) 278 if (err <= 0)