diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2022-03-07 11:53:40 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2022-03-11 10:58:20 -0500 |
commit | 7fa48faeb55fb43b6a4e727d0abd104b267c89a4 (patch) | |
tree | 4f3a735bc72009dc100045c8964d937be1cce7e4 /firmware/common | |
parent | 439b4e8bcad57fac53f4286033f431e7e9df6546 (diff) | |
download | rockbox-7fa48faeb55fb43b6a4e727d0abd104b267c89a4.tar.gz rockbox-7fa48faeb55fb43b6a4e727d0abd104b267c89a4.zip |
multiboot: Refactor duplicated functions to a separate file
The implementation of write_bootdata() and get_redirect_dir() was
copied verbatim in two different places, obviously a bad thing for
maintainability. This moves them to a new file multiboot.c as they
are only used for multiboot.
Change-Id: Id0279216e4dd019f8bf612a81d3835eff010e506
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/multiboot.c | 113 | ||||
-rw-r--r-- | firmware/common/rb-loader.c | 93 |
2 files changed, 116 insertions, 90 deletions
diff --git a/firmware/common/multiboot.c b/firmware/common/multiboot.c new file mode 100644 index 0000000000..dfa6556be3 --- /dev/null +++ b/firmware/common/multiboot.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2017, 2020 by William Wilgus | ||
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 "system.h" | ||
22 | #include "bootdata.h" | ||
23 | #include "crc32.h" | ||
24 | #include "loader_strerror.h" | ||
25 | #include "file.h" | ||
26 | #include <string.h> | ||
27 | #include <stdio.h> | ||
28 | |||
29 | /* Write bootdata into location in FIRMWARE marked by magic header | ||
30 | * Assumes buffer is already loaded with the firmware image | ||
31 | * We just need to find the location and write data into the | ||
32 | * payload region along with the crc for later verification and use. | ||
33 | * Returns payload len on success, | ||
34 | * On error returns EKEY_NOT_FOUND | ||
35 | */ | ||
36 | int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) | ||
37 | { | ||
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); | ||
41 | int payload_len = EKEY_NOT_FOUND; | ||
42 | |||
43 | /* search for boot data header prior to search_len */ | ||
44 | for(int i = 0;i < search_len;i++) | ||
45 | { | ||
46 | fw_boot_data = (struct boot_data_t*) &buf[i]; | ||
47 | if (fw_boot_data->magic[0] != BOOT_DATA_MAGIC0 || | ||
48 | fw_boot_data->magic[1] != BOOT_DATA_MAGIC1) | ||
49 | continue; | ||
50 | |||
51 | memset(&bl_boot_data.payload, 0, BOOT_DATA_PAYLOAD_SIZE); | ||
52 | bl_boot_data.boot_volume = boot_volume; | ||
53 | |||
54 | memset(fw_boot_data->payload, 0, fw_boot_data->length); | ||
55 | /* determine maximum bytes we can write to firmware | ||
56 | BOOT_DATA_PAYLOAD_SIZE is the size the bootloader expects */ | ||
57 | payload_len = MIN(BOOT_DATA_PAYLOAD_SIZE, fw_boot_data->length); | ||
58 | fw_boot_data->length = payload_len; | ||
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 | |||
65 | } | ||
66 | return payload_len; | ||
67 | } | ||
68 | |||
69 | #ifdef HAVE_MULTIBOOT | ||
70 | /* Check in root of this <volume> for rockbox_main.<playername> | ||
71 | * if this file empty or there is a single slash '/' | ||
72 | * buf = '<volume#>/<rootdir>/<firmware(name)>\0' | ||
73 | * If instead '/<*DIRECTORY*>' is supplied | ||
74 | * addpath will be set to this DIRECTORY buf = | ||
75 | * '/<volume#>/addpath/<rootdir>/<firmware(name)>\0' | ||
76 | * On error returns Negative number or 0 | ||
77 | * On success returns bytes from snprintf | ||
78 | * and generated path will be placed in buf | ||
79 | * note: if supplied buffer is too small return will be | ||
80 | * the number of bytes that would have been written | ||
81 | */ | ||
82 | int get_redirect_dir(char* buf, int buffer_size, int volume, | ||
83 | const char* rootdir, const char* firmware) | ||
84 | { | ||
85 | int fd; | ||
86 | int f_offset; | ||
87 | char add_path[MAX_PATH]; | ||
88 | /* Check in root of volume for rockbox_main.<playername> redirect */ | ||
89 | snprintf(add_path, sizeof(add_path), "/<%d>/"BOOT_REDIR, volume); | ||
90 | fd = open(add_path, O_RDONLY); | ||
91 | if (fd < 0) | ||
92 | return EFILE_NOT_FOUND; | ||
93 | |||
94 | /*clear add_path for re-use*/ | ||
95 | memset(add_path, 0, sizeof(add_path)); | ||
96 | f_offset = read(fd, add_path,sizeof(add_path)); | ||
97 | close(fd); | ||
98 | |||
99 | for(int i = f_offset - 1;i > 0; i--) | ||
100 | { | ||
101 | /* strip control chars < SPACE or all if path doesn't start with '/' */ | ||
102 | if (add_path[i] < 0x20 || add_path[0] != '/') | ||
103 | add_path[i] = '\0'; | ||
104 | } | ||
105 | /* if '/add_path' is specified in rockbox_main.<playername> | ||
106 | path is /<vol#>/add_path/rootdir/firmwarename | ||
107 | if add_path is empty or '/' is missing from beginning | ||
108 | path is /<vol#>/rootdir/firmwarename | ||
109 | */ | ||
110 | return snprintf(buf, buffer_size, "/<%d>%s/%s/%s", volume, add_path, | ||
111 | rootdir, firmware); | ||
112 | } | ||
113 | #endif | ||
diff --git a/firmware/common/rb-loader.c b/firmware/common/rb-loader.c index 300ba55401..e3fc90342c 100644 --- a/firmware/common/rb-loader.c +++ b/firmware/common/rb-loader.c | |||
@@ -26,96 +26,9 @@ | |||
26 | #include "loader_strerror.h" | 26 | #include "loader_strerror.h" |
27 | #include "checksum.h" | 27 | #include "checksum.h" |
28 | 28 | ||
29 | #if defined(HAVE_BOOTDATA) | 29 | #if defined(HAVE_BOOTDATA) || defined(HAVE_MULTIBOOT) |
30 | #include "bootdata.h" | 30 | #include "multiboot.h" |
31 | #include "crc32.h" | 31 | #endif |
32 | |||
33 | /* Write bootdata into location in FIRMWARE marked by magic header | ||
34 | * Assumes buffer is already loaded with the firmware image | ||
35 | * We just need to find the location and write data into the | ||
36 | * payload region along with the crc for later verification and use. | ||
37 | * Returns payload len on success, | ||
38 | * On error returns EKEY_NOT_FOUND | ||
39 | */ | ||
40 | int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) | ||
41 | { | ||
42 | struct boot_data_t bl_boot_data; | ||
43 | struct boot_data_t *fw_boot_data = NULL; | ||
44 | int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); | ||
45 | int payload_len = EKEY_NOT_FOUND; | ||
46 | |||
47 | /* search for boot data header prior to search_len */ | ||
48 | for(int i = 0;i < search_len;i++) | ||
49 | { | ||
50 | fw_boot_data = (struct boot_data_t*) &buf[i]; | ||
51 | if (fw_boot_data->magic[0] != BOOT_DATA_MAGIC0 || | ||
52 | fw_boot_data->magic[1] != BOOT_DATA_MAGIC1) | ||
53 | continue; | ||
54 | |||
55 | memset(&bl_boot_data.payload, 0, BOOT_DATA_PAYLOAD_SIZE); | ||
56 | bl_boot_data.boot_volume = boot_volume; | ||
57 | |||
58 | memset(fw_boot_data->payload, 0, fw_boot_data->length); | ||
59 | /* determine maximum bytes we can write to firmware | ||
60 | BOOT_DATA_PAYLOAD_SIZE is the size the bootloader expects */ | ||
61 | payload_len = MIN(BOOT_DATA_PAYLOAD_SIZE, fw_boot_data->length); | ||
62 | fw_boot_data->length = payload_len; | ||
63 | /* copy data to FIRMWARE bootdata struct */ | ||
64 | memcpy(fw_boot_data->payload, &bl_boot_data.payload, payload_len); | ||
65 | /* crc will be used within the firmware to check validity of bootdata */ | ||
66 | fw_boot_data->crc = crc_32(fw_boot_data->payload, payload_len, 0xffffffff); | ||
67 | break; | ||
68 | |||
69 | } | ||
70 | return payload_len; | ||
71 | } | ||
72 | #endif /* HAVE_BOOTDATA */ | ||
73 | |||
74 | #ifdef HAVE_MULTIBOOT /* defined by config.h */ | ||
75 | /* Check in root of this <volume> for rockbox_main.<playername> | ||
76 | * if this file empty or there is a single slash '/' | ||
77 | * buf = '<volume#>/<rootdir>/<firmware(name)>\0' | ||
78 | * If instead '/<*DIRECTORY*>' is supplied | ||
79 | * addpath will be set to this DIRECTORY buf = | ||
80 | * '/<volume#>/addpath/<rootdir>/<firmware(name)>\0' | ||
81 | * On error returns Negative number or 0 | ||
82 | * On success returns bytes from snprintf | ||
83 | * and generated path will be placed in buf | ||
84 | * note: if supplied buffer is too small return will be | ||
85 | * the number of bytes that would have been written | ||
86 | */ | ||
87 | int get_redirect_dir(char* buf, int buffer_size, int volume, | ||
88 | const char* rootdir, const char* firmware) | ||
89 | { | ||
90 | int fd; | ||
91 | int f_offset; | ||
92 | char add_path[MAX_PATH]; | ||
93 | /* Check in root of volume for rockbox_main.<playername> redirect */ | ||
94 | snprintf(add_path, sizeof(add_path), "/<%d>/"BOOT_REDIR, volume); | ||
95 | fd = open(add_path, O_RDONLY); | ||
96 | if (fd < 0) | ||
97 | return EFILE_NOT_FOUND; | ||
98 | |||
99 | /*clear add_path for re-use*/ | ||
100 | memset(add_path, 0, sizeof(add_path)); | ||
101 | f_offset = read(fd, add_path,sizeof(add_path)); | ||
102 | close(fd); | ||
103 | |||
104 | for(int i = f_offset - 1;i > 0; i--) | ||
105 | { | ||
106 | /* strip control chars < SPACE or all if path doesn't start with '/' */ | ||
107 | if (add_path[i] < 0x20 || add_path[0] != '/') | ||
108 | add_path[i] = '\0'; | ||
109 | } | ||
110 | /* if '/add_path' is specified in rockbox_main.<playername> | ||
111 | path is /<vol#>/add_path/rootdir/firmwarename | ||
112 | if add_path is empty or '/' is missing from beginning | ||
113 | path is /<vol#>/rootdir/firmwarename | ||
114 | */ | ||
115 | return snprintf(buf, buffer_size, "/<%d>%s/%s/%s", volume, add_path, | ||
116 | rootdir, firmware); | ||
117 | } | ||
118 | #endif /* HAVE_MULTIBOOT */ | ||
119 | 32 | ||
120 | /* loads a firmware file from supplied filename | 33 | /* loads a firmware file from supplied filename |
121 | * file opened, checks firmware size and checksum | 34 | * file opened, checks firmware size and checksum |