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"
35 #include "hw/sysbus.h"
36 #include "sysemu/dma.h"
37 #include "hw/loader.h"
38 #include "qapi/error.h"
39 #include "hw/core/generic-loader.h"
41 #define CPU_NONE 0xFFFFFFFF
43 static void generic_loader_reset(void *opaque
)
45 GenericLoaderState
*s
= GENERIC_LOADER(opaque
);
48 CPUClass
*cc
= CPU_GET_CLASS(s
->cpu
);
51 cc
->set_pc(s
->cpu
, s
->addr
);
56 assert(s
->data_len
< sizeof(s
->data
));
57 dma_memory_write(s
->cpu
->as
, s
->addr
, &s
->data
, s
->data_len
);
61 static void generic_loader_realize(DeviceState
*dev
, Error
**errp
)
63 GenericLoaderState
*s
= GENERIC_LOADER(dev
);
70 /* Perform some error checking on the user's options */
71 if (s
->data
|| s
->data_len
|| s
->data_be
) {
72 /* User is loading memory values */
74 error_setg(errp
, "Specifying a file is not supported when loading "
77 } else if (s
->force_raw
) {
78 error_setg(errp
, "Specifying force-raw is not supported when "
79 "loading memory values");
81 } else if (!s
->data_len
) {
82 /* We can't check for !data here as a value of 0 is still valid. */
83 error_setg(errp
, "Both data and data-len must be specified");
85 } else if (s
->data_len
> 8) {
86 error_setg(errp
, "data-len cannot be greater then 8 bytes");
89 } else if (s
->file
|| s
->force_raw
) {
90 /* User is loading an image */
91 if (s
->data
|| s
->data_len
|| s
->data_be
) {
92 error_setg(errp
, "data can not be specified when loading an "
96 /* The user specified a file, only set the PC if they also specified
99 if (s
->cpu_num
!= CPU_NONE
) {
102 } else if (s
->addr
) {
103 /* User is setting the PC */
104 if (s
->data
|| s
->data_len
|| s
->data_be
) {
105 error_setg(errp
, "data can not be specified when setting a "
108 } else if (s
->cpu_num
== CPU_NONE
) {
109 error_setg(errp
, "cpu_num must be specified when setting a "
115 /* Did the user specify anything? */
116 error_setg(errp
, "please include valid arguments");
120 qemu_register_reset(generic_loader_reset
, dev
);
122 if (s
->cpu_num
!= CPU_NONE
) {
123 s
->cpu
= qemu_get_cpu(s
->cpu_num
);
125 error_setg(errp
, "Specified boot CPU#%d is nonexistent",
133 #ifdef TARGET_WORDS_BIGENDIAN
140 AddressSpace
*as
= s
->cpu
? s
->cpu
->as
: NULL
;
143 size
= load_elf_as(s
->file
, NULL
, NULL
, &entry
, NULL
, NULL
,
144 big_endian
, 0, 0, 0, as
);
147 size
= load_uimage_as(s
->file
, &entry
, NULL
, NULL
, NULL
, NULL
,
152 size
= load_targphys_hex_as(s
->file
, &entry
, as
);
156 if (size
< 0 || s
->force_raw
) {
157 /* Default to the maximum size being the machine's ram size */
158 size
= load_image_targphys_as(s
->file
, s
->addr
, ram_size
, as
);
164 error_setg(errp
, "Cannot load specified image %s", s
->file
);
169 /* Convert the data endiannes */
171 s
->data
= cpu_to_be64(s
->data
);
173 s
->data
= cpu_to_le64(s
->data
);
177 static void generic_loader_unrealize(DeviceState
*dev
, Error
**errp
)
179 qemu_unregister_reset(generic_loader_reset
, dev
);
182 static Property generic_loader_props
[] = {
183 DEFINE_PROP_UINT64("addr", GenericLoaderState
, addr
, 0),
184 DEFINE_PROP_UINT64("data", GenericLoaderState
, data
, 0),
185 DEFINE_PROP_UINT8("data-len", GenericLoaderState
, data_len
, 0),
186 DEFINE_PROP_BOOL("data-be", GenericLoaderState
, data_be
, false),
187 DEFINE_PROP_UINT32("cpu-num", GenericLoaderState
, cpu_num
, CPU_NONE
),
188 DEFINE_PROP_BOOL("force-raw", GenericLoaderState
, force_raw
, false),
189 DEFINE_PROP_STRING("file", GenericLoaderState
, file
),
190 DEFINE_PROP_END_OF_LIST(),
193 static void generic_loader_class_init(ObjectClass
*klass
, void *data
)
195 DeviceClass
*dc
= DEVICE_CLASS(klass
);
197 /* The reset function is not registered here and is instead registered in
198 * the realize function to allow this device to be added via the device_add
199 * command in the QEMU monitor.
200 * TODO: Improve the device_add functionality to allow resets to be
203 dc
->realize
= generic_loader_realize
;
204 dc
->unrealize
= generic_loader_unrealize
;
205 dc
->props
= generic_loader_props
;
206 dc
->desc
= "Generic Loader";
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
)