2 * Flattened Image Tree loader.
4 * Copyright (c) 2016 Imagination Technologies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qapi/error.h"
22 #include "qemu/units.h"
23 #include "exec/memory.h"
24 #include "hw/loader.h"
25 #include "hw/loader-fit.h"
26 #include "qemu/cutils.h"
27 #include "qemu/error-report.h"
28 #include "sysemu/device_tree.h"
29 #include "sysemu/sysemu.h"
34 #define FIT_LOADER_MAX_PATH (128)
36 static const void *fit_load_image_alloc(const void *itb
, const char *name
,
37 int *poff
, size_t *psz
, Error
**errp
)
42 char path
[FIT_LOADER_MAX_PATH
];
46 snprintf(path
, sizeof(path
), "/images/%s", name
);
48 off
= fdt_path_offset(itb
, path
);
50 error_setg(errp
, "can't find node %s", path
);
57 data
= fdt_getprop(itb
, off
, "data", &sz
);
59 error_setg(errp
, "can't get %s/data", path
);
63 comp
= fdt_getprop(itb
, off
, "compression", NULL
);
64 if (!comp
|| !strcmp(comp
, "none")) {
68 uncomp_data
= g_malloc(sz
);
69 memmove(uncomp_data
, data
, sz
);
73 if (!strcmp(comp
, "gzip")) {
74 uncomp_len
= UBOOT_MAX_GUNZIP_BYTES
;
75 uncomp_data
= g_malloc(uncomp_len
);
77 uncomp_len
= gunzip(uncomp_data
, uncomp_len
, (void *) data
, sz
);
79 error_setg(errp
, "unable to decompress %s image", name
);
84 data
= g_realloc(uncomp_data
, uncomp_len
);
91 error_setg(errp
, "unknown compression '%s'", comp
);
95 static int fit_image_addr(const void *itb
, int img
, const char *name
,
96 hwaddr
*addr
, Error
**errp
)
101 prop
= fdt_getprop(itb
, img
, name
, &len
);
103 error_setg(errp
, "can't find %s address", name
);
109 *addr
= fdt32_to_cpu(*(fdt32_t
*)prop
);
112 *addr
= fdt64_to_cpu(*(fdt64_t
*)prop
);
115 error_setg(errp
, "invalid %s address length %d", name
, len
);
120 static int fit_load_kernel(const struct fit_loader
*ldr
, const void *itb
,
121 int cfg
, void *opaque
, hwaddr
*pend
,
126 const void *load_data
;
127 hwaddr load_addr
, entry_addr
;
132 name
= fdt_getprop(itb
, cfg
, "kernel", NULL
);
134 error_setg(errp
, "no kernel specified by FIT configuration");
138 load_data
= data
= fit_load_image_alloc(itb
, name
, &img_off
, &sz
, errp
);
140 error_prepend(errp
, "unable to load kernel image from FIT: ");
144 err
= fit_image_addr(itb
, img_off
, "load", &load_addr
, errp
);
146 error_prepend(errp
, "unable to read kernel load address from FIT: ");
151 err
= fit_image_addr(itb
, img_off
, "entry", &entry_addr
, errp
);
153 error_prepend(errp
, "unable to read kernel entry address from FIT: ");
158 if (ldr
->kernel_filter
) {
159 load_data
= ldr
->kernel_filter(opaque
, data
, &load_addr
, &entry_addr
);
163 *pend
= load_addr
+ sz
;
166 load_addr
= ldr
->addr_to_phys(opaque
, load_addr
);
167 rom_add_blob_fixed(name
, load_data
, sz
, load_addr
);
171 g_free((void *) data
);
172 if (data
!= load_data
) {
173 g_free((void *) load_data
);
178 static int fit_load_fdt(const struct fit_loader
*ldr
, const void *itb
,
179 int cfg
, void *opaque
, const void *match_data
,
180 hwaddr kernel_end
, Error
**errp
)
184 const void *load_data
;
190 name
= fdt_getprop(itb
, cfg
, "fdt", NULL
);
195 load_data
= data
= fit_load_image_alloc(itb
, name
, &img_off
, &sz
, errp
);
197 error_prepend(errp
, "unable to load FDT image from FIT: ");
201 err
= fit_image_addr(itb
, img_off
, "load", &load_addr
, errp
);
202 if (err
== -ENOENT
) {
203 load_addr
= ROUND_UP(kernel_end
, 64 * KiB
) + (10 * MiB
);
206 error_prepend(errp
, "unable to read FDT load address from FIT: ");
211 if (ldr
->fdt_filter
) {
212 load_data
= ldr
->fdt_filter(opaque
, data
, match_data
, &load_addr
);
215 load_addr
= ldr
->addr_to_phys(opaque
, load_addr
);
216 sz
= fdt_totalsize(load_data
);
217 rom_add_blob_fixed(name
, load_data
, sz
, load_addr
);
221 g_free((void *) data
);
222 if (data
!= load_data
) {
223 g_free((void *) load_data
);
228 static bool fit_cfg_compatible(const void *itb
, int cfg
, const char *compat
)
231 const char *fdt_name
;
234 fdt_name
= fdt_getprop(itb
, cfg
, "fdt", NULL
);
239 fdt
= fit_load_image_alloc(itb
, fdt_name
, NULL
, NULL
, NULL
);
244 if (fdt_check_header(fdt
)) {
249 if (fdt_node_check_compatible(fdt
, 0, compat
)) {
256 g_free((void *) fdt
);
260 int load_fit(const struct fit_loader
*ldr
, const char *filename
, void *opaque
)
263 const struct fit_loader_match
*match
;
264 const void *itb
, *match_data
= NULL
;
265 const char *def_cfg_name
;
266 char path
[FIT_LOADER_MAX_PATH
];
267 int itb_size
, configs
, cfg_off
, off
;
271 itb
= load_device_tree(filename
, &itb_size
);
276 configs
= fdt_path_offset(itb
, "/configurations");
278 error_report("can't find node /configurations");
283 cfg_off
= -FDT_ERR_NOTFOUND
;
286 for (match
= ldr
->matches
; match
->compatible
; match
++) {
287 off
= fdt_first_subnode(itb
, configs
);
289 if (fit_cfg_compatible(itb
, off
, match
->compatible
)) {
291 match_data
= match
->data
;
295 off
= fdt_next_subnode(itb
, off
);
305 def_cfg_name
= fdt_getprop(itb
, configs
, "default", NULL
);
307 snprintf(path
, sizeof(path
), "/configurations/%s", def_cfg_name
);
308 cfg_off
= fdt_path_offset(itb
, path
);
313 error_report("can't find configuration");
318 ret
= fit_load_kernel(ldr
, itb
, cfg_off
, opaque
, &kernel_end
, &err
);
320 error_report_err(err
);
324 ret
= fit_load_fdt(ldr
, itb
, cfg_off
, opaque
, match_data
, kernel_end
,
327 error_report_err(err
);
333 g_free((void *) itb
);