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
,
61 MEMTXATTRS_UNSPECIFIED
);
65 static void generic_loader_realize(DeviceState
*dev
, Error
**errp
)
67 GenericLoaderState
*s
= GENERIC_LOADER(dev
);
74 /* Perform some error checking on the user's options */
75 if (s
->data
|| s
->data_len
|| s
->data_be
) {
76 /* User is loading memory values */
78 error_setg(errp
, "Specifying a file is not supported when loading "
81 } else if (s
->force_raw
) {
82 error_setg(errp
, "Specifying force-raw is not supported when "
83 "loading memory values");
85 } else if (!s
->data_len
) {
86 /* We can't check for !data here as a value of 0 is still valid. */
87 error_setg(errp
, "Both data and data-len must be specified");
89 } else if (s
->data_len
> 8) {
90 error_setg(errp
, "data-len cannot be greater then 8 bytes");
93 } else if (s
->file
|| s
->force_raw
) {
94 /* User is loading an image */
95 if (s
->data
|| s
->data_len
|| s
->data_be
) {
96 error_setg(errp
, "data can not be specified when loading an "
100 /* The user specified a file, only set the PC if they also specified
103 if (s
->cpu_num
!= CPU_NONE
) {
106 } else if (s
->addr
) {
107 /* User is setting the PC */
108 if (s
->data
|| s
->data_len
|| s
->data_be
) {
109 error_setg(errp
, "data can not be specified when setting a "
112 } else if (s
->cpu_num
== CPU_NONE
) {
113 error_setg(errp
, "cpu_num must be specified when setting a "
119 /* Did the user specify anything? */
120 error_setg(errp
, "please include valid arguments");
124 qemu_register_reset(generic_loader_reset
, dev
);
126 if (s
->cpu_num
!= CPU_NONE
) {
127 s
->cpu
= qemu_get_cpu(s
->cpu_num
);
129 error_setg(errp
, "Specified boot CPU#%d is nonexistent",
137 big_endian
= target_words_bigendian();
140 AddressSpace
*as
= s
->cpu
? s
->cpu
->as
: NULL
;
143 size
= load_elf_as(s
->file
, NULL
, NULL
, NULL
, &entry
, NULL
, NULL
,
144 NULL
, 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
, current_machine
->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
)
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 device_class_set_props(dc
, generic_loader_props
);
206 dc
->desc
= "Generic Loader";
207 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
210 static const TypeInfo generic_loader_info
= {
211 .name
= TYPE_GENERIC_LOADER
,
212 .parent
= TYPE_DEVICE
,
213 .instance_size
= sizeof(GenericLoaderState
),
214 .class_init
= generic_loader_class_init
,
217 static void generic_loader_register_type(void)
219 type_register_static(&generic_loader_info
);
222 type_init(generic_loader_register_type
)