4 * Copyright (C) 2020 Linaro
5 * Written by Alex Bennée <alex.bennee@linaro.org>
6 * (based on the generic-loader by Li Guang <lig.fnst@cn.fujitsu.com>)
8 * SPDX-License-Identifier: GPL-2.0-or-later
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
15 * Much like the generic-loader this is treated as a special device
16 * inside QEMU. However unlike the generic-loader this device is used
17 * to load guest images for hypervisors. As part of that process the
18 * hypervisor needs to have platform information passed to it by the
19 * lower levels of the stack (e.g. firmware/bootloader). If you boot
20 * the hypervisor directly you use the guest-loader to load the Dom0
21 * or equivalent guest images in the right place in the same way a
24 * This is only relevant for full system emulation.
27 #include "qemu/osdep.h"
28 #include "hw/core/cpu.h"
29 #include "sysemu/dma.h"
30 #include "hw/loader.h"
31 #include "hw/qdev-properties.h"
32 #include "qapi/error.h"
33 #include "qemu/module.h"
34 #include "guest-loader.h"
35 #include "sysemu/device_tree.h"
36 #include "hw/boards.h"
39 * Insert some FDT nodes for the loaded blob.
41 static void loader_insert_platform_data(GuestLoaderState
*s
, int size
,
44 MachineState
*machine
= MACHINE(qdev_get_machine());
45 void *fdt
= machine
->fdt
;
46 g_autofree
char *node
= g_strdup_printf("/chosen/module@0x%08" PRIx64
,
48 uint64_t reg_attr
[2] = {cpu_to_be64(s
->addr
), cpu_to_be64(size
)};
51 error_setg(errp
, "Cannot modify FDT fields if the machine has none");
55 qemu_fdt_add_subnode(fdt
, node
);
56 qemu_fdt_setprop(fdt
, node
, "reg", ®_attr
, sizeof(reg_attr
));
59 const char *compat
[2] = { "multiboot,module", "multiboot,kernel" };
60 if (qemu_fdt_setprop_string_array(fdt
, node
, "compatible",
62 ARRAY_SIZE(compat
)) < 0) {
63 error_setg(errp
, "couldn't set %s/compatible", node
);
67 if (qemu_fdt_setprop_string(fdt
, node
, "bootargs", s
->args
) < 0) {
68 error_setg(errp
, "couldn't set %s/bootargs", node
);
71 } else if (s
->initrd
) {
72 const char *compat
[2] = { "multiboot,module", "multiboot,ramdisk" };
73 if (qemu_fdt_setprop_string_array(fdt
, node
, "compatible",
75 ARRAY_SIZE(compat
)) < 0) {
76 error_setg(errp
, "couldn't set %s/compatible", node
);
82 static void guest_loader_realize(DeviceState
*dev
, Error
**errp
)
84 GuestLoaderState
*s
= GUEST_LOADER(dev
);
85 char *file
= s
->kernel
? s
->kernel
: s
->initrd
;
88 /* Perform some error checking on the user's options */
89 if (s
->kernel
&& s
->initrd
) {
90 error_setg(errp
, "Cannot specify a kernel and initrd in same stanza");
92 } else if (!s
->kernel
&& !s
->initrd
) {
93 error_setg(errp
, "Need to specify a kernel or initrd image");
95 } else if (!s
->addr
) {
96 error_setg(errp
, "Need to specify the address of guest blob");
98 } else if (s
->args
&& !s
->kernel
) {
99 error_setg(errp
, "Boot args only relevant to kernel blobs");
102 /* Default to the maximum size being the machine's ram size */
103 size
= load_image_targphys_as(file
, s
->addr
, current_machine
->ram_size
,
106 error_setg(errp
, "Cannot load specified image %s", file
);
110 /* Now the image is loaded we need to update the platform data */
111 loader_insert_platform_data(s
, size
, errp
);
114 static Property guest_loader_props
[] = {
115 DEFINE_PROP_UINT64("addr", GuestLoaderState
, addr
, 0),
116 DEFINE_PROP_STRING("kernel", GuestLoaderState
, kernel
),
117 DEFINE_PROP_STRING("bootargs", GuestLoaderState
, args
),
118 DEFINE_PROP_STRING("initrd", GuestLoaderState
, initrd
),
119 DEFINE_PROP_END_OF_LIST(),
122 static void guest_loader_class_init(ObjectClass
*klass
, void *data
)
124 DeviceClass
*dc
= DEVICE_CLASS(klass
);
126 dc
->realize
= guest_loader_realize
;
127 device_class_set_props(dc
, guest_loader_props
);
128 dc
->desc
= "Guest Loader";
129 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
132 static const TypeInfo guest_loader_info
= {
133 .name
= TYPE_GUEST_LOADER
,
134 .parent
= TYPE_DEVICE
,
135 .instance_size
= sizeof(GuestLoaderState
),
136 .class_init
= guest_loader_class_init
,
139 static void guest_loader_register_type(void)
141 type_register_static(&guest_loader_info
);
144 type_init(guest_loader_register_type
)