4 * Copyright (C) 2014 Li Guang
5 * Copyright (C) 2016 Xilinx Inc.
6 * Written by Li Guang <lig.fnst@cn.fujitsu.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * Internally inside QEMU this is a device. It is a strange device that
22 * provides no hardware interface but allows QEMU to monkey patch memory
23 * specified when it is created. To be able to do this it has a reset
24 * callback that does the memory operations.
26 * This device allows the user to monkey patch memory. To be able to do
27 * this it needs a backend to manage the datas, the same as other
28 * memory-related devices. In this case as the backend is so trivial we
29 * have merged it with the frontend instead of creating and maintaining a
33 #include "qemu/osdep.h"
34 #include "hw/core/cpu.h"
35 #include "sysemu/dma.h"
36 #include "sysemu/reset.h"
37 #include "hw/boards.h"
38 #include "hw/loader.h"
39 #include "hw/qdev-properties.h"
40 #include "qapi/error.h"
41 #include "qemu/module.h"
42 #include "hw/core/generic-loader.h"
44 #define CPU_NONE 0xFFFFFFFF
46 static void generic_loader_reset(void *opaque
)
48 GenericLoaderState
*s
= GENERIC_LOADER(opaque
);
51 CPUClass
*cc
= CPU_GET_CLASS(s
->cpu
);
54 cc
->set_pc(s
->cpu
, s
->addr
);
59 assert(s
->data_len
< sizeof(s
->data
));
60 dma_memory_write(s
->cpu
->as
, s
->addr
, &s
->data
, s
->data_len
);
64 static void generic_loader_realize(DeviceState
*dev
, Error
**errp
)
66 GenericLoaderState
*s
= GENERIC_LOADER(dev
);
73 /* Perform some error checking on the user's options */
74 if (s
->data
|| s
->data_len
|| s
->data_be
) {
75 /* User is loading memory values */
77 error_setg(errp
, "Specifying a file is not supported when loading "
80 } else if (s
->force_raw
) {
81 error_setg(errp
, "Specifying force-raw is not supported when "
82 "loading memory values");
84 } else if (!s
->data_len
) {
85 /* We can't check for !data here as a value of 0 is still valid. */
86 error_setg(errp
, "Both data and data-len must be specified");
88 } else if (s
->data_len
> 8) {
89 error_setg(errp
, "data-len cannot be greater then 8 bytes");
92 } else if (s
->file
|| s
->force_raw
) {
93 /* User is loading an image */
94 if (s
->data
|| s
->data_len
|| s
->data_be
) {
95 error_setg(errp
, "data can not be specified when loading an "
99 /* The user specified a file, only set the PC if they also specified
102 if (s
->cpu_num
!= CPU_NONE
) {
105 } else if (s
->addr
) {
106 /* User is setting the PC */
107 if (s
->data
|| s
->data_len
|| s
->data_be
) {
108 error_setg(errp
, "data can not be specified when setting a "
111 } else if (s
->cpu_num
== CPU_NONE
) {
112 error_setg(errp
, "cpu_num must be specified when setting a "
118 /* Did the user specify anything? */
119 error_setg(errp
, "please include valid arguments");
123 qemu_register_reset(generic_loader_reset
, dev
);
125 if (s
->cpu_num
!= CPU_NONE
) {
126 s
->cpu
= qemu_get_cpu(s
->cpu_num
);
128 error_setg(errp
, "Specified boot CPU#%d is nonexistent",
136 big_endian
= target_words_bigendian();
139 AddressSpace
*as
= s
->cpu
? s
->cpu
->as
: NULL
;
142 size
= load_elf_as(s
->file
, NULL
, NULL
, NULL
, &entry
, NULL
, NULL
,
143 NULL
, big_endian
, 0, 0, 0, as
);
146 size
= load_uimage_as(s
->file
, &entry
, NULL
, NULL
, NULL
, NULL
,
151 size
= load_targphys_hex_as(s
->file
, &entry
, as
);
155 if (size
< 0 || s
->force_raw
) {
156 /* Default to the maximum size being the machine's ram size */
157 size
= load_image_targphys_as(s
->file
, s
->addr
, current_machine
->ram_size
, as
);
163 error_setg(errp
, "Cannot load specified image %s", s
->file
);
168 /* Convert the data endiannes */
170 s
->data
= cpu_to_be64(s
->data
);
172 s
->data
= cpu_to_le64(s
->data
);
176 static void generic_loader_unrealize(DeviceState
*dev
)
178 qemu_unregister_reset(generic_loader_reset
, dev
);
181 static Property generic_loader_props
[] = {
182 DEFINE_PROP_UINT64("addr", GenericLoaderState
, addr
, 0),
183 DEFINE_PROP_UINT64("data", GenericLoaderState
, data
, 0),
184 DEFINE_PROP_UINT8("data-len", GenericLoaderState
, data_len
, 0),
185 DEFINE_PROP_BOOL("data-be", GenericLoaderState
, data_be
, false),
186 DEFINE_PROP_UINT32("cpu-num", GenericLoaderState
, cpu_num
, CPU_NONE
),
187 DEFINE_PROP_BOOL("force-raw", GenericLoaderState
, force_raw
, false),
188 DEFINE_PROP_STRING("file", GenericLoaderState
, file
),
189 DEFINE_PROP_END_OF_LIST(),
192 static void generic_loader_class_init(ObjectClass
*klass
, void *data
)
194 DeviceClass
*dc
= DEVICE_CLASS(klass
);
196 /* The reset function is not registered here and is instead registered in
197 * the realize function to allow this device to be added via the device_add
198 * command in the QEMU monitor.
199 * TODO: Improve the device_add functionality to allow resets to be
202 dc
->realize
= generic_loader_realize
;
203 dc
->unrealize
= generic_loader_unrealize
;
204 device_class_set_props(dc
, generic_loader_props
);
205 dc
->desc
= "Generic Loader";
206 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
209 static TypeInfo generic_loader_info
= {
210 .name
= TYPE_GENERIC_LOADER
,
211 .parent
= TYPE_DEVICE
,
212 .instance_size
= sizeof(GenericLoaderState
),
213 .class_init
= generic_loader_class_init
,
216 static void generic_loader_register_type(void)
218 type_register_static(&generic_loader_info
);
221 type_init(generic_loader_register_type
)