* [Qemu-devel] [PATCH v13 0/2] Add a generic loader @ 2016-09-30 0:25 Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 1/2] generic-loader: " Alistair Francis ` (2 more replies) 0 siblings, 3 replies; 6+ messages in thread From: Alistair Francis @ 2016-09-30 0:25 UTC (permalink / raw) To: qemu-devel, peter.maydell Cc: alistair.francis, crosthwaitepeter, armbru, cov, pbonzini This work is based on the original work by Li Guang with extra features added by Peter C and myself. The idea of this loader is to allow the user to load multiple images or values into QEMU at startup. Memory values can be loaded like this: -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 Images can be loaded like this: -device loader,file=./images/u-boot.elf,cpu=0 This can be useful and we use it a lot in Xilinx to load multiple images into a machine at creation (ATF, Kernel and DTB for example). Tested with the latest Xilinx ZynqMP machine, if I enable EL3 and EL2 I can boot ATF through to u-boot using the loader to load the images. It can also be used to set registers. This patch series makes the load_elf() function more generic by not requiring an architecture. It also adds new functions load_elf_as(), load_uimage_as and load_image_targphys_as which allows custom AddressSpaces when loading images. V12: - All patches have been reviewed - Most patches have been merged - The commit message of the actual device patch has been updated to justify why it is a device. Alistair Francis (2): generic-loader: Add a generic loader docs: Add a generic loader explanation document MAINTAINERS | 6 ++ docs/generic-loader.txt | 84 ++++++++++++++++ hw/core/Makefile.objs | 2 + hw/core/generic-loader.c | 211 +++++++++++++++++++++++++++++++++++++++ include/hw/core/generic-loader.h | 46 +++++++++ 5 files changed, 349 insertions(+) create mode 100644 docs/generic-loader.txt create mode 100644 hw/core/generic-loader.c create mode 100644 include/hw/core/generic-loader.h -- 2.7.4 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v13 1/2] generic-loader: Add a generic loader 2016-09-30 0:25 [Qemu-devel] [PATCH v13 0/2] Add a generic loader Alistair Francis @ 2016-09-30 0:25 ` Alistair Francis 2024-11-27 16:08 ` Philippe Mathieu-Daudé 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 2/2] docs: Add a generic loader explanation document Alistair Francis 2016-09-30 1:44 ` [Qemu-devel] [PATCH v13 0/2] Add a generic loader Peter Maydell 2 siblings, 1 reply; 6+ messages in thread From: Alistair Francis @ 2016-09-30 0:25 UTC (permalink / raw) To: qemu-devel, peter.maydell Cc: alistair.francis, crosthwaitepeter, armbru, cov, pbonzini Add a generic loader to QEMU which can be used to load images or set memory values. Internally inside QEMU this is a device. It is a strange device that provides no hardware interface but allows QEMU to monkey patch memory specified when it is created. To be able to do this it has a reset callback that does the memory operations. This device allows the user to monkey patch memory. To be able to do this it needs a backend to manage the datas, the same as other memory-related devices. In this case as the backend is so trivial we have merged it with the frontend instead of creating and maintaining a seperate backend. Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Acked-by: Markus Armbruster <armbru@redhat.com> --- V13: - Include the commit message in the c file. V12: - Update commit message to justify using -device V11: - Small corrections - Don't check for !data as writing a value of 0 is valid. V10: - Split out the PC setting and data loading V9: - Fix error messages - Updated some incorrect logic - Add address space loading support for all image types - Explain why the reset is manually registered V8: - Code corrections - Rebase V7: - Rebase V6: - Add error checking V5: - Rebase V4: - Allow the loader to work with every architecture - Move the file to hw/core - Increase the maximum number of CPUs - Make the CPU operations conditional - Convert the cpu option to cpu-num - Require the user to specify endianess V3: - Pass the ram_size to load_image_targphys() V2: - Add maintainers entry - Perform bounds checking - Register and unregister the reset in the realise/unrealise Changes since RFC: - Add BE support MAINTAINERS | 6 ++ hw/core/Makefile.objs | 2 + hw/core/generic-loader.c | 211 +++++++++++++++++++++++++++++++++++++++ include/hw/core/generic-loader.h | 46 +++++++++ 4 files changed, 265 insertions(+) create mode 100644 hw/core/generic-loader.c create mode 100644 include/hw/core/generic-loader.h diff --git a/MAINTAINERS b/MAINTAINERS index f3c1f7f..9ecaaa5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1013,6 +1013,12 @@ M: Dmitry Fleytman <dmitry@daynix.com> S: Maintained F: hw/net/e1000e* +Generic Loader +M: Alistair Francis <alistair.francis@xilinx.com> +S: Maintained +F: hw/core/generic-loader.c +F: include/hw/core/generic-loader.h + Subsystems ---------- Audio diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index cfd4840..939c94e 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -17,3 +17,5 @@ common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o + +obj-$(CONFIG_SOFTMMU) += generic-loader.o diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c new file mode 100644 index 0000000..79ab6df --- /dev/null +++ b/hw/core/generic-loader.c @@ -0,0 +1,211 @@ +/* + * Generic Loader + * + * Copyright (C) 2014 Li Guang + * Copyright (C) 2016 Xilinx Inc. + * Written by Li Guang <lig.fnst@cn.fujitsu.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +/* + * Internally inside QEMU this is a device. It is a strange device that + * provides no hardware interface but allows QEMU to monkey patch memory + * specified when it is created. To be able to do this it has a reset + * callback that does the memory operations. + + * This device allows the user to monkey patch memory. To be able to do + * this it needs a backend to manage the datas, the same as other + * memory-related devices. In this case as the backend is so trivial we + * have merged it with the frontend instead of creating and maintaining a + * seperate backend. + */ + +#include "qemu/osdep.h" +#include "qom/cpu.h" +#include "hw/sysbus.h" +#include "sysemu/dma.h" +#include "hw/loader.h" +#include "qapi/error.h" +#include "hw/core/generic-loader.h" + +#define CPU_NONE 0xFFFFFFFF + +static void generic_loader_reset(void *opaque) +{ + GenericLoaderState *s = GENERIC_LOADER(opaque); + + if (s->set_pc) { + CPUClass *cc = CPU_GET_CLASS(s->cpu); + cpu_reset(s->cpu); + if (cc) { + cc->set_pc(s->cpu, s->addr); + } + } + + if (s->data_len) { + assert(s->data_len < sizeof(s->data)); + dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len); + } +} + +static void generic_loader_realize(DeviceState *dev, Error **errp) +{ + GenericLoaderState *s = GENERIC_LOADER(dev); + hwaddr entry; + int big_endian; + int size = 0; + + s->set_pc = false; + + /* Perform some error checking on the user's options */ + if (s->data || s->data_len || s->data_be) { + /* User is loading memory values */ + if (s->file) { + error_setg(errp, "Specifying a file is not supported when loading " + "memory values"); + return; + } else if (s->force_raw) { + error_setg(errp, "Specifying force-raw is not supported when " + "loading memory values"); + return; + } else if (!s->data_len) { + /* We cant' check for !data here as a value of 0 is still valid. */ + error_setg(errp, "Both data and data-len must be specified"); + return; + } else if (s->data_len > 8) { + error_setg(errp, "data-len cannot be greater then 8 bytes"); + return; + } + } else if (s->file || s->force_raw) { + /* User is loading an image */ + if (s->data || s->data_len || s->data_be) { + error_setg(errp, "data can not be specified when loading an " + "image"); + return; + } + s->set_pc = true; + } else if (s->addr) { + /* User is setting the PC */ + if (s->data || s->data_len || s->data_be) { + error_setg(errp, "data can not be specified when setting a " + "program counter"); + return; + } else if (!s->cpu_num) { + error_setg(errp, "cpu_num must be specified when setting a " + "program counter"); + return; + } + s->set_pc = true; + } else { + /* Did the user specify anything? */ + error_setg(errp, "please include valid arguments"); + return; + } + + qemu_register_reset(generic_loader_reset, dev); + + if (s->cpu_num != CPU_NONE) { + s->cpu = qemu_get_cpu(s->cpu_num); + if (!s->cpu) { + error_setg(errp, "Specified boot CPU#%d is nonexistent", + s->cpu_num); + return; + } + } else { + s->cpu = first_cpu; + } + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + if (s->file) { + if (!s->force_raw) { + size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL, + big_endian, 0, 0, 0, s->cpu->as); + + if (size < 0) { + size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL, + s->cpu->as); + } + } + + if (size < 0 || s->force_raw) { + /* Default to the maximum size being the machine's ram size */ + size = load_image_targphys_as(s->file, s->addr, ram_size, + s->cpu->as); + } else { + s->addr = entry; + } + + if (size < 0) { + error_setg(errp, "Cannot load specified image %s", s->file); + return; + } + } + + /* Convert the data endiannes */ + if (s->data_be) { + s->data = cpu_to_be64(s->data); + } else { + s->data = cpu_to_le64(s->data); + } +} + +static void generic_loader_unrealize(DeviceState *dev, Error **errp) +{ + qemu_unregister_reset(generic_loader_reset, dev); +} + +static Property generic_loader_props[] = { + DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0), + DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0), + DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0), + DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false), + DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE), + DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false), + DEFINE_PROP_STRING("file", GenericLoaderState, file), + DEFINE_PROP_END_OF_LIST(), +}; + +static void generic_loader_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + /* The reset function is not registered here and is instead registered in + * the realize function to allow this device to be added via the device_add + * command in the QEMU monitor. + * TODO: Improve the device_add functionality to allow resets to be + * connected + */ + dc->realize = generic_loader_realize; + dc->unrealize = generic_loader_unrealize; + dc->props = generic_loader_props; + dc->desc = "Generic Loader"; +} + +static TypeInfo generic_loader_info = { + .name = TYPE_GENERIC_LOADER, + .parent = TYPE_DEVICE, + .instance_size = sizeof(GenericLoaderState), + .class_init = generic_loader_class_init, +}; + +static void generic_loader_register_type(void) +{ + type_register_static(&generic_loader_info); +} + +type_init(generic_loader_register_type) diff --git a/include/hw/core/generic-loader.h b/include/hw/core/generic-loader.h new file mode 100644 index 0000000..dd27c42 --- /dev/null +++ b/include/hw/core/generic-loader.h @@ -0,0 +1,46 @@ +/* + * Generic Loader + * + * Copyright (C) 2014 Li Guang + * Written by Li Guang <lig.fnst@cn.fujitsu.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef GENERIC_LOADER_H +#define GENERIC_LOADER_H + +#include "elf.h" + +typedef struct GenericLoaderState { + /* <private> */ + DeviceState parent_obj; + + /* <public> */ + CPUState *cpu; + + uint64_t addr; + uint64_t data; + uint8_t data_len; + uint32_t cpu_num; + + char *file; + + bool force_raw; + bool data_be; + bool set_pc; +} GenericLoaderState; + +#define TYPE_GENERIC_LOADER "loader" +#define GENERIC_LOADER(obj) OBJECT_CHECK(GenericLoaderState, (obj), \ + TYPE_GENERIC_LOADER) + +#endif -- 2.7.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v13 1/2] generic-loader: Add a generic loader 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 1/2] generic-loader: " Alistair Francis @ 2024-11-27 16:08 ` Philippe Mathieu-Daudé 2024-11-28 0:41 ` Alistair Francis 0 siblings, 1 reply; 6+ messages in thread From: Philippe Mathieu-Daudé @ 2024-11-27 16:08 UTC (permalink / raw) To: Alistair Francis, Edgar E. Iglesias Cc: qemu-devel, peter.maydell, pbonzini, Thomas Huth Hi, [very old patch merged as commit e481a1f63c93] On 30/9/16 02:25, Alistair Francis wrote: > Add a generic loader to QEMU which can be used to load images or set > memory values. > > Internally inside QEMU this is a device. It is a strange device that > provides no hardware interface but allows QEMU to monkey patch memory > specified when it is created. To be able to do this it has a reset > callback that does the memory operations. > > This device allows the user to monkey patch memory. To be able to do > this it needs a backend to manage the datas, the same as other > memory-related devices. In this case as the backend is so trivial we > have merged it with the frontend instead of creating and maintaining a > seperate backend. > > Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> > Reviewed-by: Peter Maydell <peter.maydell@linaro.org> > Acked-by: Markus Armbruster <armbru@redhat.com> > --- > diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c > new file mode 100644 > index 0000000..79ab6df > --- /dev/null > +++ b/hw/core/generic-loader.c > @@ -0,0 +1,211 @@ > +/* > + * Generic Loader > + * > + * Copyright (C) 2014 Li Guang > + * Copyright (C) 2016 Xilinx Inc. > + * Written by Li Guang <lig.fnst@cn.fujitsu.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > + * for more details. > + * > + */ > + > +/* > + * Internally inside QEMU this is a device. It is a strange device that > + * provides no hardware interface but allows QEMU to monkey patch memory > + * specified when it is created. To be able to do this it has a reset > + * callback that does the memory operations. > + > + * This device allows the user to monkey patch memory. To be able to do > + * this it needs a backend to manage the datas, the same as other > + * memory-related devices. In this case as the backend is so trivial we > + * have merged it with the frontend instead of creating and maintaining a > + * seperate backend. > + */ > + > +#include "qemu/osdep.h" > +#include "qom/cpu.h" > +#include "hw/sysbus.h" > +#include "sysemu/dma.h" > +#include "hw/loader.h" > +#include "qapi/error.h" > +#include "hw/core/generic-loader.h" > + > +#define CPU_NONE 0xFFFFFFFF > + > +static void generic_loader_reset(void *opaque) > +{ > + GenericLoaderState *s = GENERIC_LOADER(opaque); > + > + if (s->set_pc) { > + CPUClass *cc = CPU_GET_CLASS(s->cpu); > + cpu_reset(s->cpu); > + if (cc) { > + cc->set_pc(s->cpu, s->addr); > + } > + } > + > + if (s->data_len) { > + assert(s->data_len < sizeof(s->data)); > + dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len); > + } > +} > + > +static void generic_loader_realize(DeviceState *dev, Error **errp) > +{ > + GenericLoaderState *s = GENERIC_LOADER(dev); > + hwaddr entry; > + int big_endian; > + int size = 0; > + > + s->set_pc = false; > + > + /* Perform some error checking on the user's options */ > + if (s->data || s->data_len || s->data_be) { > + /* User is loading memory values */ > + if (s->file) { > + error_setg(errp, "Specifying a file is not supported when loading " > + "memory values"); > + return; > + } else if (s->force_raw) { > + error_setg(errp, "Specifying force-raw is not supported when " > + "loading memory values"); > + return; > + } else if (!s->data_len) { > + /* We cant' check for !data here as a value of 0 is still valid. */ > + error_setg(errp, "Both data and data-len must be specified"); > + return; > + } else if (s->data_len > 8) { > + error_setg(errp, "data-len cannot be greater then 8 bytes"); If s->data_len < 8 (like 4 or 2) ... > + return; > + } > + } else if (s->file || s->force_raw) { > + /* User is loading an image */ > + if (s->data || s->data_len || s->data_be) { > + error_setg(errp, "data can not be specified when loading an " > + "image"); > + return; > + } > + s->set_pc = true; > + } else if (s->addr) { > + /* User is setting the PC */ > + if (s->data || s->data_len || s->data_be) { > + error_setg(errp, "data can not be specified when setting a " > + "program counter"); > + return; > + } else if (!s->cpu_num) { > + error_setg(errp, "cpu_num must be specified when setting a " > + "program counter"); > + return; > + } > + s->set_pc = true; > + } else { > + /* Did the user specify anything? */ > + error_setg(errp, "please include valid arguments"); > + return; > + } > + > + qemu_register_reset(generic_loader_reset, dev); > + > + if (s->cpu_num != CPU_NONE) { > + s->cpu = qemu_get_cpu(s->cpu_num); > + if (!s->cpu) { > + error_setg(errp, "Specified boot CPU#%d is nonexistent", > + s->cpu_num); > + return; > + } > + } else { > + s->cpu = first_cpu; > + } > + > +#ifdef TARGET_WORDS_BIGENDIAN > + big_endian = 1; > +#else > + big_endian = 0; > +#endif > + > + if (s->file) { > + if (!s->force_raw) { > + size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL, > + big_endian, 0, 0, 0, s->cpu->as); > + > + if (size < 0) { > + size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL, > + s->cpu->as); > + } > + } > + > + if (size < 0 || s->force_raw) { > + /* Default to the maximum size being the machine's ram size */ > + size = load_image_targphys_as(s->file, s->addr, ram_size, > + s->cpu->as); > + } else { > + s->addr = entry; > + } > + > + if (size < 0) { > + error_setg(errp, "Cannot load specified image %s", s->file); > + return; > + } > + } > + > + /* Convert the data endiannes */ > + if (s->data_be) { > + s->data = cpu_to_be64(s->data); > + } else { > + s->data = cpu_to_le64(s->data); ... and if we swap, we ignore the data-len and swap 64-bit regardless, returning invalid data. I.e. data=0x1122, data-len=2, once swapped we get data=0x0000. Is that expected? > + } > +} > + > +static void generic_loader_unrealize(DeviceState *dev, Error **errp) > +{ > + qemu_unregister_reset(generic_loader_reset, dev); > +} > + > +static Property generic_loader_props[] = { > + DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0), > + DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0), > + DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0), > + DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false), > + DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE), > + DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false), > + DEFINE_PROP_STRING("file", GenericLoaderState, file), > + DEFINE_PROP_END_OF_LIST(), > +}; ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v13 1/2] generic-loader: Add a generic loader 2024-11-27 16:08 ` Philippe Mathieu-Daudé @ 2024-11-28 0:41 ` Alistair Francis 0 siblings, 0 replies; 6+ messages in thread From: Alistair Francis @ 2024-11-28 0:41 UTC (permalink / raw) To: Philippe Mathieu-Daudé Cc: Alistair Francis, Edgar E. Iglesias, qemu-devel, peter.maydell, pbonzini, Thomas Huth On Thu, Nov 28, 2024 at 2:09 AM Philippe Mathieu-Daudé <philmd@linaro.org> wrote: > > Hi, > > [very old patch merged as commit e481a1f63c93] > > On 30/9/16 02:25, Alistair Francis wrote: > > Add a generic loader to QEMU which can be used to load images or set > > memory values. > > > > Internally inside QEMU this is a device. It is a strange device that > > provides no hardware interface but allows QEMU to monkey patch memory > > specified when it is created. To be able to do this it has a reset > > callback that does the memory operations. > > > > This device allows the user to monkey patch memory. To be able to do > > this it needs a backend to manage the datas, the same as other > > memory-related devices. In this case as the backend is so trivial we > > have merged it with the frontend instead of creating and maintaining a > > seperate backend. > > > > Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> > > Reviewed-by: Peter Maydell <peter.maydell@linaro.org> > > Acked-by: Markus Armbruster <armbru@redhat.com> > > --- > > > diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c > > new file mode 100644 > > index 0000000..79ab6df > > --- /dev/null > > +++ b/hw/core/generic-loader.c > > @@ -0,0 +1,211 @@ > > +/* > > + * Generic Loader > > + * > > + * Copyright (C) 2014 Li Guang > > + * Copyright (C) 2016 Xilinx Inc. > > + * Written by Li Guang <lig.fnst@cn.fujitsu.com> > > + * > > + * This program is free software; you can redistribute it and/or modify it > > + * under the terms of the GNU General Public License as published by the > > + * Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, but WITHOUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > > + * for more details. > > + * > > + */ > > + > > +/* > > + * Internally inside QEMU this is a device. It is a strange device that > > + * provides no hardware interface but allows QEMU to monkey patch memory > > + * specified when it is created. To be able to do this it has a reset > > + * callback that does the memory operations. > > + > > + * This device allows the user to monkey patch memory. To be able to do > > + * this it needs a backend to manage the datas, the same as other > > + * memory-related devices. In this case as the backend is so trivial we > > + * have merged it with the frontend instead of creating and maintaining a > > + * seperate backend. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qom/cpu.h" > > +#include "hw/sysbus.h" > > +#include "sysemu/dma.h" > > +#include "hw/loader.h" > > +#include "qapi/error.h" > > +#include "hw/core/generic-loader.h" > > + > > +#define CPU_NONE 0xFFFFFFFF > > + > > +static void generic_loader_reset(void *opaque) > > +{ > > + GenericLoaderState *s = GENERIC_LOADER(opaque); > > + > > + if (s->set_pc) { > > + CPUClass *cc = CPU_GET_CLASS(s->cpu); > > + cpu_reset(s->cpu); > > + if (cc) { > > + cc->set_pc(s->cpu, s->addr); > > + } > > + } > > + > > + if (s->data_len) { > > + assert(s->data_len < sizeof(s->data)); > > + dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len); > > + } > > +} > > + > > +static void generic_loader_realize(DeviceState *dev, Error **errp) > > +{ > > + GenericLoaderState *s = GENERIC_LOADER(dev); > > + hwaddr entry; > > + int big_endian; > > + int size = 0; > > + > > + s->set_pc = false; > > + > > + /* Perform some error checking on the user's options */ > > + if (s->data || s->data_len || s->data_be) { > > + /* User is loading memory values */ > > + if (s->file) { > > + error_setg(errp, "Specifying a file is not supported when loading " > > + "memory values"); > > + return; > > + } else if (s->force_raw) { > > + error_setg(errp, "Specifying force-raw is not supported when " > > + "loading memory values"); > > + return; > > + } else if (!s->data_len) { > > + /* We cant' check for !data here as a value of 0 is still valid. */ > > + error_setg(errp, "Both data and data-len must be specified"); > > + return; > > + } else if (s->data_len > 8) { > > + error_setg(errp, "data-len cannot be greater then 8 bytes"); > > If s->data_len < 8 (like 4 or 2) ... > > > + return; > > + } > > + } else if (s->file || s->force_raw) { > > + /* User is loading an image */ > > + if (s->data || s->data_len || s->data_be) { > > + error_setg(errp, "data can not be specified when loading an " > > + "image"); > > + return; > > + } > > + s->set_pc = true; > > + } else if (s->addr) { > > + /* User is setting the PC */ > > + if (s->data || s->data_len || s->data_be) { > > + error_setg(errp, "data can not be specified when setting a " > > + "program counter"); > > + return; > > + } else if (!s->cpu_num) { > > + error_setg(errp, "cpu_num must be specified when setting a " > > + "program counter"); > > + return; > > + } > > + s->set_pc = true; > > + } else { > > + /* Did the user specify anything? */ > > + error_setg(errp, "please include valid arguments"); > > + return; > > + } > > + > > + qemu_register_reset(generic_loader_reset, dev); > > + > > + if (s->cpu_num != CPU_NONE) { > > + s->cpu = qemu_get_cpu(s->cpu_num); > > + if (!s->cpu) { > > + error_setg(errp, "Specified boot CPU#%d is nonexistent", > > + s->cpu_num); > > + return; > > + } > > + } else { > > + s->cpu = first_cpu; > > + } > > + > > +#ifdef TARGET_WORDS_BIGENDIAN > > + big_endian = 1; > > +#else > > + big_endian = 0; > > +#endif > > + > > + if (s->file) { > > + if (!s->force_raw) { > > + size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL, > > + big_endian, 0, 0, 0, s->cpu->as); > > + > > + if (size < 0) { > > + size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL, > > + s->cpu->as); > > + } > > + } > > + > > + if (size < 0 || s->force_raw) { > > + /* Default to the maximum size being the machine's ram size */ > > + size = load_image_targphys_as(s->file, s->addr, ram_size, > > + s->cpu->as); > > + } else { > > + s->addr = entry; > > + } > > + > > + if (size < 0) { > > + error_setg(errp, "Cannot load specified image %s", s->file); > > + return; > > + } > > + } > > + > > + /* Convert the data endiannes */ > > + if (s->data_be) { > > + s->data = cpu_to_be64(s->data); > > + } else { > > + s->data = cpu_to_le64(s->data); > > ... and if we swap, we ignore the data-len and swap 64-bit > regardless, returning invalid data. > > I.e. data=0x1122, data-len=2, once swapped we get data=0x0000. > > Is that expected? I don't think that's expected Alistair ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v13 2/2] docs: Add a generic loader explanation document 2016-09-30 0:25 [Qemu-devel] [PATCH v13 0/2] Add a generic loader Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 1/2] generic-loader: " Alistair Francis @ 2016-09-30 0:25 ` Alistair Francis 2016-09-30 1:44 ` [Qemu-devel] [PATCH v13 0/2] Add a generic loader Peter Maydell 2 siblings, 0 replies; 6+ messages in thread From: Alistair Francis @ 2016-09-30 0:25 UTC (permalink / raw) To: qemu-devel, peter.maydell Cc: alistair.francis, crosthwaitepeter, armbru, cov, pbonzini Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- V11: - Fix corrections V10: - Split the data loading and PC setting V9: - Clarify the image loading options V8: - Improve documentation V6: - Fixup documentation V4: - Re-write to be more comprehensive docs/generic-loader.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/generic-loader.txt diff --git a/docs/generic-loader.txt b/docs/generic-loader.txt new file mode 100644 index 0000000..8fcb550 --- /dev/null +++ b/docs/generic-loader.txt @@ -0,0 +1,84 @@ +Copyright (c) 2016 Xilinx Inc. + +This work is licensed under the terms of the GNU GPL, version 2 or later. See +the COPYING file in the top-level directory. + + +The 'loader' device allows the user to load multiple images or values into +QEMU at startup. + +Loading Data into Memory Values +--------------------- +The loader device allows memory values to be set from the command line. This +can be done by following the syntax below: + + -device loader,addr=<addr>,data=<data>,data-len=<data-len> + [,data-be=<data-be>][,cpu-num=<cpu-num>] + + <addr> - The address to store the data in. + <data> - The value to be written to the address. The maximum size of + the data is 8 bytes. + <data-len> - The length of the data in bytes. This argument must be + included if the data argument is. + <data-be> - Set to true if the data to be stored on the guest should be + written as big endian data. The default is to write little + endian data. + <cpu-num> - The number of the CPU's address space where the data should + be loaded. If not specified the address space of the first + CPU is used. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of loading value 0x8000000e to address 0xfd1a0104 is: + -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 + +Setting a CPU's Program Counter +--------------------- +The loader device allows the CPU's PC to be set from the command line. This +can be done by following the syntax below: + + -device loader,addr=<addr>,cpu-num=<cpu-num> + + <addr> - The value to use as the CPU's PC. + <cpu-num> - The number of the CPU whose PC should be set to the + specified value. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of setting CPU 0's PC to 0x8000 is: + -device loader,addr=0x8000,cpu-num=0 + +Loading Files +--------------------- +The loader device also allows files to be loaded into memory. This can be done +similarly to setting memory values. The syntax is shown below: + + -device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>] + + <file> - A file to be loaded into memory + <addr> - The addr in memory that the file should be loaded. This is + ignored if you are using an ELF (unless force-raw is true). + This is required if you aren't loading an ELF. + <cpu-num> - This specifies the CPU that should be used. This is an + optional argument and will cause the CPU's PC to be set to + where the image is stored or in the case of an ELF file to + the value in the header. This option should only be used + for the boot image. + This will also cause the image to be written to the specified + CPU's address space. If not specified, the default is CPU 0. + <force-raw> - Forces the file to be treated as a raw image. This can be + used to specify the load address of ELF files. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of loading an ELF file which CPU0 will boot is shown below: + -device loader,file=./images/boot.elf,cpu-num=0 -- 2.7.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v13 0/2] Add a generic loader 2016-09-30 0:25 [Qemu-devel] [PATCH v13 0/2] Add a generic loader Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 1/2] generic-loader: " Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 2/2] docs: Add a generic loader explanation document Alistair Francis @ 2016-09-30 1:44 ` Peter Maydell 2 siblings, 0 replies; 6+ messages in thread From: Peter Maydell @ 2016-09-30 1:44 UTC (permalink / raw) To: Alistair Francis Cc: QEMU Developers, Peter Crosthwaite, Markus Armbruster, Christopher Covington, Paolo Bonzini On 29 September 2016 at 17:25, Alistair Francis <alistair.francis@xilinx.com> wrote: > This work is based on the original work by Li Guang with extra > features added by Peter C and myself. > > The idea of this loader is to allow the user to load multiple images > or values into QEMU at startup. > > Memory values can be loaded like this: -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 > > Images can be loaded like this: -device loader,file=./images/u-boot.elf,cpu=0 > > This can be useful and we use it a lot in Xilinx to load multiple images > into a machine at creation (ATF, Kernel and DTB for example). > > Tested with the latest Xilinx ZynqMP machine, if I enable EL3 and EL2 I can > boot ATF through to u-boot using the loader to load the images. > > It can also be used to set registers. > > This patch series makes the load_elf() function more generic by not > requiring an architecture. It also adds new functions load_elf_as(), > load_uimage_as and load_image_targphys_as which allows custom > AddressSpaces when loading images. > > V12: > - All patches have been reviewed > - Most patches have been merged > - The commit message of the actual device patch has been updated to > justify why it is a device. > > > Alistair Francis (2): > generic-loader: Add a generic loader > docs: Add a generic loader explanation document Applied to target-arm.next, thanks. -- PMM ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-11-28 0:42 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-09-30 0:25 [Qemu-devel] [PATCH v13 0/2] Add a generic loader Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 1/2] generic-loader: " Alistair Francis 2024-11-27 16:08 ` Philippe Mathieu-Daudé 2024-11-28 0:41 ` Alistair Francis 2016-09-30 0:25 ` [Qemu-devel] [PATCH v13 2/2] docs: Add a generic loader explanation document Alistair Francis 2016-09-30 1:44 ` [Qemu-devel] [PATCH v13 0/2] Add a generic loader Peter Maydell
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).