summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/export/linuxboot.h189
-rw-r--r--firmware/linuxboot.c218
3 files changed, 408 insertions, 1 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 4ea922af1b..2e2f13bbe9 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -33,6 +33,7 @@ logf.c
33#endif /* ROCKBOX_HAS_LOGF */ 33#endif /* ROCKBOX_HAS_LOGF */
34#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 34#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
35load_code.c 35load_code.c
36linuxboot.c
36#ifdef RB_PROFILE 37#ifdef RB_PROFILE
37profile.c 38profile.c
38#endif /* RB_PROFILE */ 39#endif /* RB_PROFILE */
@@ -46,7 +47,6 @@ timer.c
46debug.c 47debug.c
47#endif /* PLATFORM_NATIVE */ 48#endif /* PLATFORM_NATIVE */
48panic.c 49panic.c
49
50#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(BOOTFILE) 50#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(BOOTFILE)
51target/hosted/rolo.c 51target/hosted/rolo.c
52#endif 52#endif
diff --git a/firmware/export/linuxboot.h b/firmware/export/linuxboot.h
new file mode 100644
index 0000000000..7dbc213012
--- /dev/null
+++ b/firmware/export/linuxboot.h
@@ -0,0 +1,189 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2022 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __LINUXBOOT_H__
23#define __LINUXBOOT_H__
24
25#include "system.h"
26#include <stddef.h>
27#include <sys/types.h>
28
29/*
30 * From u-boot's include/image.h
31 * SPDX-License-Identifier: GPL-2.0+
32 * (C) Copyright 2008 Semihalf
33 * (C) Copyright 2000-2005
34 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
35 */
36
37#define IH_MAGIC 0x27051956
38#define IH_NMLEN 32
39
40enum
41{
42 IH_ARCH_INVALID,
43 IH_ARCH_ALPHA,
44 IH_ARCH_ARM,
45 IH_ARCH_I386,
46 IH_ARCH_IA64,
47 IH_ARCH_MIPS,
48 IH_ARCH_MIPS64,
49 IH_ARCH_PPC,
50 IH_ARCH_S390,
51 IH_ARCH_SH,
52 IH_ARCH_SPARC,
53 IH_ARCH_SPARC64,
54 IH_ARCH_M68K,
55 /* NOTE: Other archs not relevant and omitted here, can add if needed */
56 IH_ARCH_COUNT,
57};
58
59enum
60{
61 IH_TYPE_INVALID = 0,
62 IN_TYPE_STANDALONE,
63 IH_TYPE_KERNEL,
64 IH_TYPE_RAMDISK,
65 IH_TYPE_MULTI,
66 IH_TYPE_FIRMWARE,
67 IH_TYPE_SCRIPT,
68 IH_TYPE_FILESYSTEM,
69 IH_TYPE_FLATDT,
70 /* NOTE: Other types not relevant and omitted here, can add if needed */
71 IH_TYPE_COUNT,
72};
73
74enum
75{
76 IH_COMP_NONE = 0,
77 IH_COMP_GZIP,
78 IH_COMP_BZIP2,
79 IH_COMP_LZMA,
80 IH_COMP_LZO,
81 IH_COMP_LZ4,
82 IH_COMP_ZSTD,
83 IH_COMP_COUNT,
84};
85
86/* Legacy U-Boot image header as produced by mkimage(1).
87 *
88 * WARNING: all fields are big-endian so you usually do not want to
89 * access them directly, use the accessor functions instead.
90 */
91struct uimage_header
92{
93 uint32_t ih_magic;
94 uint32_t ih_hcrc;
95 uint32_t ih_time;
96 uint32_t ih_size;
97 uint32_t ih_load;
98 uint32_t ih_ep;
99 uint32_t ih_dcrc;
100 uint8_t ih_os;
101 uint8_t ih_arch;
102 uint8_t ih_type;
103 uint8_t ih_comp;
104 uint8_t ih_name[IH_NMLEN];
105};
106
107#define _uimage_get32_f(name) \
108 static inline uint32_t uimage_get_##name(const struct uimage_header* uh) \
109 { return betoh32(uh->ih_##name); }
110_uimage_get32_f(magic)
111_uimage_get32_f(hcrc)
112_uimage_get32_f(time)
113_uimage_get32_f(size)
114_uimage_get32_f(load)
115_uimage_get32_f(ep)
116_uimage_get32_f(dcrc)
117#undef _uimage_get32_f
118
119#define _uimage_set32_f(name) \
120 static inline void uimage_set_##name(struct uimage_header* uh, uint32_t val) \
121 { uh->ih_##name = htobe32(val); }
122_uimage_set32_f(magic)
123_uimage_set32_f(hcrc)
124_uimage_set32_f(time)
125_uimage_set32_f(size)
126_uimage_set32_f(load)
127_uimage_set32_f(ep)
128_uimage_set32_f(dcrc)
129#undef _uimage_set32_f
130
131#define _uimage_get8_f(name) \
132 static inline uint8_t uimage_get_##name(const struct uimage_header* uh) \
133 { return uh->ih_##name; }
134_uimage_get8_f(os)
135_uimage_get8_f(arch)
136_uimage_get8_f(type)
137_uimage_get8_f(comp)
138#undef _uimage_get8_f
139
140#define _uimage_set8_f(name) \
141 static inline void uimage_set_##name(struct uimage_header* uh, uint8_t val) \
142 { uh->ih_##name = val; }
143_uimage_set8_f(os)
144_uimage_set8_f(arch)
145_uimage_set8_f(type)
146_uimage_set8_f(comp)
147#undef _uimage_set8_f
148
149/*
150 * uImage utilities
151 */
152
153/** Reader callback for use with `uimage_load`
154 *
155 * \param buf Buffer to write into
156 * \param size Number of bytes to read
157 * \param ctx State argument
158 * \return Number of bytes actually read, or -1 on error.
159 */
160typedef ssize_t(*uimage_reader)(void* buf, size_t size, void* ctx);
161
162/** Calculate U-Boot style CRC */
163uint32_t uimage_crc(uint32_t crc, const void* data, size_t size);
164
165/** Calculate CRC of a uImage header */
166uint32_t uimage_calc_hcrc(const struct uimage_header* uh);
167
168/** Load and decompress a uImage
169 *
170 * \param uh Returned header struct (will be filled with read data)
171 * \param out_size Returned size of the decompressed data
172 * \param reader Data reader function
173 * \param rctx Context argument for the reader function
174 * \return Buflib handle containing the decompressed data, or negative on error
175 *
176 * This function will read a uImage, verify checksums and decompress the image
177 * data into a non-moveable buflib allocation. The length of the compressed
178 * data will be taken from the uImage header.
179 */
180int uimage_load(struct uimage_header* uh, size_t* out_size,
181 uimage_reader reader, void* rctx);
182
183/** File reader for use with `uimage_load`
184 *
185 * \param ctx File descriptor, casted to `void*`
186 */
187ssize_t uimage_fd_reader(void* buf, size_t size, void* ctx);
188
189#endif /* __LINUXBOOT_H__ */
diff --git a/firmware/linuxboot.c b/firmware/linuxboot.c
new file mode 100644
index 0000000000..5b6ab314b3
--- /dev/null
+++ b/firmware/linuxboot.c
@@ -0,0 +1,218 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2022 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "linuxboot.h"
23#include "system.h"
24#include "core_alloc.h"
25#include "crc32.h"
26#include "inflate.h"
27#include "file.h"
28#include <string.h>
29
30/* compression support options - can be decided per target if needed,
31 * for now default to enabling everything */
32#define HAVE_UIMAGE_COMP_NONE
33#define HAVE_UIMAGE_COMP_GZIP
34
35uint32_t uimage_crc(uint32_t crc, const void* data, size_t size)
36{
37 /* is this endian swapping required...? */
38 return letoh32(crc_32r(data, size, htole32(crc ^ 0xffffffff))) ^ 0xffffffff;
39}
40
41uint32_t uimage_calc_hcrc(const struct uimage_header* uh)
42{
43 struct uimage_header h = *uh;
44 uimage_set_hcrc(&h, 0);
45 return uimage_crc(0, &h, sizeof(h));
46}
47
48static int uimage_check_header(const struct uimage_header* uh)
49{
50 if(uimage_get_magic(uh) != IH_MAGIC)
51 return -1;
52
53 if(uimage_get_hcrc(uh) != uimage_calc_hcrc(uh))
54 return -2;
55
56 return 0;
57}
58
59static int uimage_alloc_state(const struct uimage_header* uh)
60{
61 size_t size;
62
63 switch(uimage_get_comp(uh)) {
64#ifdef HAVE_UIMAGE_COMP_NONE
65 case IH_COMP_NONE:
66 return 0;
67#endif
68
69#ifdef HAVE_UIMAGE_COMP_GZIP
70 case IH_COMP_GZIP:
71 size = inflate_size + inflate_align - 1;
72 return core_alloc_ex("inflate", size, &buflib_ops_locked);
73#endif
74
75 default:
76 return -1;
77 }
78}
79
80#ifdef HAVE_UIMAGE_COMP_GZIP
81struct uimage_inflatectx
82{
83 uimage_reader reader;
84 void* rctx;
85 uint32_t dcrc;
86 size_t remain;
87};
88
89static uint32_t uimage_inflate_reader(void* block, uint32_t block_size, void* ctx)
90{
91 struct uimage_inflatectx* c = ctx;
92 ssize_t len = c->reader(block, block_size, c->rctx);
93 if(len > 0) {
94 len = MIN(c->remain, (size_t)len);
95 c->remain -= len;
96 c->dcrc = uimage_crc(c->dcrc, block, len);
97 }
98
99 return len;
100}
101
102static int uimage_decompress_gzip(const struct uimage_header* uh, int state_h,
103 void* out, size_t* out_size,
104 uimage_reader reader, void* rctx)
105{
106 size_t hbufsz = inflate_size + inflate_align - 1;
107 void* hbuf = core_get_data(state_h);
108 ALIGN_BUFFER(hbuf, hbufsz, inflate_align);
109
110 struct uimage_inflatectx r_ctx;
111 r_ctx.reader = reader;
112 r_ctx.rctx = rctx;
113 r_ctx.dcrc = 0;
114 r_ctx.remain = uimage_get_size(uh);
115
116 struct inflate_bufferctx w_ctx;
117 w_ctx.buf = out;
118 w_ctx.end = out + *out_size;
119
120 int ret = inflate(hbuf, INFLATE_GZIP,
121 uimage_inflate_reader, &r_ctx,
122 inflate_buffer_writer, &w_ctx);
123 if(ret)
124 return ret;
125
126 if(r_ctx.remain > 0)
127 return -1;
128 if(r_ctx.dcrc != uimage_get_dcrc(uh))
129 return -2;
130
131 *out_size = w_ctx.end - w_ctx.buf;
132 return 0;
133}
134#endif /* HAVE_UIMAGE_COMP_GZIP */
135
136static int uimage_decompress(const struct uimage_header* uh, int state_h,
137 void* out, size_t* out_size,
138 uimage_reader reader, void* rctx)
139{
140 size_t in_size = uimage_get_size(uh);
141 ssize_t len;
142
143 switch(uimage_get_comp(uh)) {
144#ifdef HAVE_UIMAGE_COMP_NONE
145 case IH_COMP_NONE:
146 if(*out_size < in_size)
147 return -2;
148
149 len = reader(out, in_size, rctx);
150 if(len < 0 || (size_t)len != in_size)
151 return -3;
152
153 if(uimage_crc(0, out, in_size) != uimage_get_dcrc(uh))
154 return -4;
155
156 *out_size = in_size;
157 break;
158#endif
159
160#ifdef HAVE_UIMAGE_COMP_GZIP
161 case IH_COMP_GZIP:
162 return uimage_decompress_gzip(uh, state_h, out, out_size, reader, rctx);
163#endif
164
165 default:
166 return -1;
167 }
168
169 return 0;
170}
171
172int uimage_load(struct uimage_header* uh, size_t* out_size,
173 uimage_reader reader, void* rctx)
174{
175 if(reader(uh, sizeof(*uh), rctx) != (ssize_t)sizeof(*uh))
176 return -1; /* read error */
177
178 int ret = uimage_check_header(uh);
179 if(ret)
180 return ret;
181
182 int state_h = uimage_alloc_state(uh);
183 if(state_h < 0)
184 return state_h;
185
186 *out_size = 0;
187 int out_h = core_alloc_maximum("uimage", out_size, &buflib_ops_locked);
188 if(out_h <= 0) {
189 ret = -1;
190 goto err;
191 }
192
193 ret = uimage_decompress(uh, state_h, core_get_data(out_h), out_size,
194 reader, rctx);
195 if(ret)
196 goto err;
197
198 core_shrink(out_h, core_get_data(out_h), *out_size);
199 ret = 0;
200
201 err:
202 if(state_h > 0)
203 core_free(state_h);
204 if(out_h > 0) {
205 if(ret == 0)
206 ret = out_h;
207 else
208 core_free(out_h);
209 }
210
211 return ret;
212}
213
214ssize_t uimage_fd_reader(void* buf, size_t size, void* ctx)
215{
216 int fd = (intptr_t)ctx;
217 return read(fd, buf, size);
218}