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 "qemu/units.h"
22 #include "exec/memory.h"
23 #include "hw/loader.h"
24 #include "hw/loader-fit.h"
25 #include "qemu/cutils.h"
26 #include "qemu/error-report.h"
27 #include "sysemu/device_tree.h"
28 #include "sysemu/sysemu.h"
33 #define FIT_LOADER_MAX_PATH (128)
35 static const void *fit_load_image_alloc(const void *itb
, const char *name
,
36 int *poff
, size_t *psz
)
41 char path
[FIT_LOADER_MAX_PATH
];
45 snprintf(path
, sizeof(path
), "/images/%s", name
);
47 off
= fdt_path_offset(itb
, path
);
55 data
= fdt_getprop(itb
, off
, "data", &sz
);
60 comp
= fdt_getprop(itb
, off
, "compression", NULL
);
61 if (!comp
|| !strcmp(comp
, "none")) {
65 uncomp_data
= g_malloc(sz
);
66 memmove(uncomp_data
, data
, sz
);
70 if (!strcmp(comp
, "gzip")) {
71 uncomp_len
= UBOOT_MAX_GUNZIP_BYTES
;
72 uncomp_data
= g_malloc(uncomp_len
);
74 uncomp_len
= gunzip(uncomp_data
, uncomp_len
, (void *) data
, sz
);
76 error_printf("unable to decompress %s image\n", name
);
81 data
= g_realloc(uncomp_data
, uncomp_len
);
88 error_printf("unknown compression '%s'\n", comp
);
92 static int fit_image_addr(const void *itb
, int img
, const char *name
,
98 prop
= fdt_getprop(itb
, img
, name
, &len
);
105 *addr
= fdt32_to_cpu(*(fdt32_t
*)prop
);
108 *addr
= fdt64_to_cpu(*(fdt64_t
*)prop
);
111 error_printf("invalid %s address length %d\n", name
, len
);
116 static int fit_load_kernel(const struct fit_loader
*ldr
, const void *itb
,
117 int cfg
, void *opaque
, hwaddr
*pend
)
121 const void *load_data
;
122 hwaddr load_addr
, entry_addr
;
127 name
= fdt_getprop(itb
, cfg
, "kernel", NULL
);
129 error_printf("no kernel specified by FIT configuration\n");
133 load_data
= data
= fit_load_image_alloc(itb
, name
, &img_off
, &sz
);
135 error_printf("unable to load kernel image from FIT\n");
139 err
= fit_image_addr(itb
, img_off
, "load", &load_addr
);
141 error_printf("unable to read kernel load address from FIT\n");
146 err
= fit_image_addr(itb
, img_off
, "entry", &entry_addr
);
148 error_printf("unable to read kernel entry address from FIT\n");
153 if (ldr
->kernel_filter
) {
154 load_data
= ldr
->kernel_filter(opaque
, data
, &load_addr
, &entry_addr
);
158 *pend
= load_addr
+ sz
;
161 load_addr
= ldr
->addr_to_phys(opaque
, load_addr
);
162 rom_add_blob_fixed(name
, load_data
, sz
, load_addr
);
166 g_free((void *) data
);
167 if (data
!= load_data
) {
168 g_free((void *) load_data
);
173 static int fit_load_fdt(const struct fit_loader
*ldr
, const void *itb
,
174 int cfg
, void *opaque
, const void *match_data
,
179 const void *load_data
;
185 name
= fdt_getprop(itb
, cfg
, "fdt", NULL
);
190 load_data
= data
= fit_load_image_alloc(itb
, name
, &img_off
, &sz
);
192 error_printf("unable to load FDT image from FIT\n");
196 err
= fit_image_addr(itb
, img_off
, "load", &load_addr
);
197 if (err
== -ENOENT
) {
198 load_addr
= ROUND_UP(kernel_end
, 64 * KiB
) + (10 * MiB
);
204 if (ldr
->fdt_filter
) {
205 load_data
= ldr
->fdt_filter(opaque
, data
, match_data
, &load_addr
);
208 load_addr
= ldr
->addr_to_phys(opaque
, load_addr
);
209 sz
= fdt_totalsize(load_data
);
210 rom_add_blob_fixed(name
, load_data
, sz
, load_addr
);
214 g_free((void *) data
);
215 if (data
!= load_data
) {
216 g_free((void *) load_data
);
221 static bool fit_cfg_compatible(const void *itb
, int cfg
, const char *compat
)
224 const char *fdt_name
;
227 fdt_name
= fdt_getprop(itb
, cfg
, "fdt", NULL
);
232 fdt
= fit_load_image_alloc(itb
, fdt_name
, NULL
, NULL
);
237 if (fdt_check_header(fdt
)) {
242 if (fdt_node_check_compatible(fdt
, 0, compat
)) {
249 g_free((void *) fdt
);
253 int load_fit(const struct fit_loader
*ldr
, const char *filename
, void *opaque
)
255 const struct fit_loader_match
*match
;
256 const void *itb
, *match_data
= NULL
;
257 const char *def_cfg_name
;
258 char path
[FIT_LOADER_MAX_PATH
];
259 int itb_size
, configs
, cfg_off
, off
, err
;
263 itb
= load_device_tree(filename
, &itb_size
);
268 configs
= fdt_path_offset(itb
, "/configurations");
274 cfg_off
= -FDT_ERR_NOTFOUND
;
277 for (match
= ldr
->matches
; match
->compatible
; match
++) {
278 off
= fdt_first_subnode(itb
, configs
);
280 if (fit_cfg_compatible(itb
, off
, match
->compatible
)) {
282 match_data
= match
->data
;
286 off
= fdt_next_subnode(itb
, off
);
296 def_cfg_name
= fdt_getprop(itb
, configs
, "default", NULL
);
298 snprintf(path
, sizeof(path
), "/configurations/%s", def_cfg_name
);
299 cfg_off
= fdt_path_offset(itb
, path
);
304 /* couldn't find a configuration to use */
309 err
= fit_load_kernel(ldr
, itb
, cfg_off
, opaque
, &kernel_end
);
315 err
= fit_load_fdt(ldr
, itb
, cfg_off
, opaque
, match_data
, kernel_end
);
323 g_free((void *) itb
);