aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-07-26 16:23:07 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-07-26 16:23:07 +0100
commitfff3159900d2b95613a9cb75fc3703e67a674729 (patch)
treeea85ccdfd9d85e97ecd0ce33d4ac22a77ceaa0d9
parentc985266ea5b50e46e07b3568c1346e10064205c9 (diff)
parent67505c114e6acc26f3a1a2b74833c61b6a34ff95 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190726' into staging
target-arm queue: * Fix broken migration on pl330 device * Fix broken migration on stellaris-input device * Add type checks to vmstate varry macros to avoid this class of bugs * hw/arm/boot: Fix some remaining cases where we would put the initrd on top of the kernel image # gpg: Signature made Fri 26 Jul 2019 16:19:17 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20190726: hw/arm/boot: Further improve initrd positioning code hw/arm/boot: Rename elf_{low, high}_addr to image_{low, high}_addr vmstate.h: Type check VMSTATE_STRUCT_VARRAY macros stellaris_input: Fix vmstate description of buttons field pl330: fix vmstate description Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/arm/boot.c37
-rw-r--r--hw/dma/pl330.c17
-rw-r--r--hw/input/stellaris_input.c10
-rw-r--r--include/migration/vmstate.h30
4 files changed, 66 insertions, 28 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 1fb24fbef2..c2b89b3bb9 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -986,7 +986,9 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
int kernel_size;
int initrd_size;
int is_linux = 0;
- uint64_t elf_entry, elf_low_addr, elf_high_addr;
+ uint64_t elf_entry;
+ /* Addresses of first byte used and first byte not used by the image */
+ uint64_t image_low_addr = 0, image_high_addr = 0;
int elf_machine;
hwaddr entry;
static const ARMInsnFixup *primary_loader;
@@ -1014,24 +1016,24 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
info->nb_cpus = 1;
/* Assume that raw images are linux kernels, and ELF images are not. */
- kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
- &elf_high_addr, elf_machine, as);
+ kernel_size = arm_load_elf(info, &elf_entry, &image_low_addr,
+ &image_high_addr, elf_machine, as);
if (kernel_size > 0 && have_dtb(info)) {
/*
* If there is still some room left at the base of RAM, try and put
* the DTB there like we do for images loaded with -bios or -pflash.
*/
- if (elf_low_addr > info->loader_start
- || elf_high_addr < info->loader_start) {
+ if (image_low_addr > info->loader_start
+ || image_high_addr < info->loader_start) {
/*
- * Set elf_low_addr as address limit for arm_load_dtb if it may be
+ * Set image_low_addr as address limit for arm_load_dtb if it may be
* pointing into RAM, otherwise pass '0' (no limit)
*/
- if (elf_low_addr < info->loader_start) {
- elf_low_addr = 0;
+ if (image_low_addr < info->loader_start) {
+ image_low_addr = 0;
}
info->dtb_start = info->loader_start;
- info->dtb_limit = elf_low_addr;
+ info->dtb_limit = image_low_addr;
}
}
entry = elf_entry;
@@ -1039,17 +1041,29 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
uint64_t loadaddr = info->loader_start + KERNEL_NOLOAD_ADDR;
kernel_size = load_uimage_as(info->kernel_filename, &entry, &loadaddr,
&is_linux, NULL, NULL, as);
+ if (kernel_size >= 0) {
+ image_low_addr = loadaddr;
+ image_high_addr = image_low_addr + kernel_size;
+ }
}
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
kernel_size = load_aarch64_image(info->kernel_filename,
info->loader_start, &entry, as);
is_linux = 1;
+ if (kernel_size >= 0) {
+ image_low_addr = entry;
+ image_high_addr = image_low_addr + kernel_size;
+ }
} else if (kernel_size < 0) {
/* 32-bit ARM */
entry = info->loader_start + KERNEL_LOAD_ADDR;
kernel_size = load_image_targphys_as(info->kernel_filename, entry,
ram_end - KERNEL_LOAD_ADDR, as);
is_linux = 1;
+ if (kernel_size >= 0) {
+ image_low_addr = entry;
+ image_high_addr = image_low_addr + kernel_size;
+ }
}
if (kernel_size < 0) {
error_report("could not load kernel '%s'", info->kernel_filename);
@@ -1081,7 +1095,10 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
* we might still make a bad choice here.
*/
info->initrd_start = info->loader_start +
- MAX(MIN(info->ram_size / 2, 128 * 1024 * 1024), kernel_size);
+ MIN(info->ram_size / 2, 128 * 1024 * 1024);
+ if (image_high_addr) {
+ info->initrd_start = MAX(info->initrd_start, image_high_addr);
+ }
info->initrd_start = TARGET_PAGE_ALIGN(info->initrd_start);
if (is_linux) {
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
index 58df965a46..a56a3e7771 100644
--- a/hw/dma/pl330.c
+++ b/hw/dma/pl330.c
@@ -218,11 +218,12 @@ typedef struct PL330Queue {
static const VMStateDescription vmstate_pl330_queue = {
.name = "pl330_queue",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
- vmstate_pl330_queue_entry, PL330QueueEntry),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(queue, PL330Queue, queue_size,
+ vmstate_pl330_queue_entry,
+ PL330QueueEntry),
VMSTATE_END_OF_LIST()
}
};
@@ -278,12 +279,12 @@ struct PL330State {
static const VMStateDescription vmstate_pl330 = {
.name = "pl330",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
- VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
- vmstate_pl330_chan, PL330Chan),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(chan, PL330State, num_chnls,
+ vmstate_pl330_chan, PL330Chan),
VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, num_chnls),
VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, num_chnls),
VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
index 20c87d86f4..3a666d61d4 100644
--- a/hw/input/stellaris_input.c
+++ b/hw/input/stellaris_input.c
@@ -60,12 +60,14 @@ static const VMStateDescription vmstate_stellaris_button = {
static const VMStateDescription vmstate_stellaris_gamepad = {
.name = "stellaris_gamepad",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_INT32(extension, gamepad_state),
- VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
- vmstate_stellaris_button, gamepad_button),
+ VMSTATE_STRUCT_VARRAY_POINTER_INT32(buttons, gamepad_state,
+ num_buttons,
+ vmstate_stellaris_button,
+ gamepad_button),
VMSTATE_END_OF_LIST()
}
};
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index ca68584eba..c2bfa7a7f0 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -227,8 +227,22 @@ extern const VMStateInfo vmstate_info_bitmap;
extern const VMStateInfo vmstate_info_qtailq;
#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
+/*
+ * Check that type t2 is an array of type t1 of size n,
+ * e.g. if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'
+ */
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+/*
+ * type of element 0 of the specified (array) field of the type.
+ * Note that if the field is a pointer then this will return the
+ * pointed-to type rather than complaining.
+ */
+#define typeof_elt_of_field(type, field) typeof(((type *)0)->field[0])
+/* Check that field f in struct type t2 is an array of t1, of any size */
+#define type_check_varray(t1, t2, f) \
+ (type_check(t1, typeof_elt_of_field(t2, f)) \
+ + QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(((t2 *)0)->f)))
#define vmstate_offset_value(_state, _field, _type) \
(offsetof(_state, _field) + \
@@ -253,6 +267,10 @@ extern const VMStateInfo vmstate_info_qtailq;
vmstate_offset_array(_state, _field, uint8_t, \
sizeof(typeof_field(_state, _field)))
+#define vmstate_offset_varray(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check_varray(_type, _state, _field))
+
/* In the macros below, if there is a _version, that means the macro's
* field will be processed only if the version being received is >=
* the _version specified. In general, if you add a new field, you
@@ -347,7 +365,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT32|VMS_MULTIPLY_ELEMENTS, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
@@ -376,7 +394,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_INT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
@@ -416,7 +434,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT16, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
@@ -520,7 +538,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_UINT8, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
/* a variable length array (i.e. _type *_field) but we know the
@@ -573,7 +591,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_INT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
@@ -583,7 +601,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_UINT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\