diff options
Diffstat (limited to 'firmware/common/multiboot.c')
-rw-r--r-- | firmware/common/multiboot.c | 113 |
1 files changed, 113 insertions, 0 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 | ||