Message ID | 1425485909-5091-3-git-send-email-eric.auger@linaro.org |
---|---|
State | Superseded |
Headers | show |
Eric Auger <eric.auger@linaro.org> writes: > Device tree nodes for the platform bus and its children dynamic sysbus > devices are added in a machine init done notifier. To load the dtb once, > after those latter nodes are built and before ROM freeze, the actual > arm_load_kernel existing code is moved into a notifier notify function, > arm_load_kernel_notify. arm_load_kernel now only registers the > corresponding notifier. > > Machine files that do not support platform bus stay unchanged. Machine > files willing to support dynamic sysbus devices must call arm_load_kernel > before sysbus-fdt arm_register_platform_bus_fdt_creator to make sure > dynamic sysbus device nodes are integrated in the dtb. > > Signed-off-by: Eric Auger <eric.auger@linaro.org> > Reviewed-by: Shannon Zhao <zhaoshenglong@huawei.com> > Reviewed-by: Alexander Graf <agraf@suse.de> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> > > --- > > v8 -> v9: > - fix compilation with arm-linux-user > - reorder fields in ArmLoadKernelNotifier and use DO_UPCAST > > v7 -> v8: > - Add Reviewed-by from Alex & Shannon > - rebase on 2.2.0 > > v6: creation of this patch file > --- > hw/arm/boot.c | 14 +++++++++++++- > include/hw/arm/arm.h | 28 ++++++++++++++++++++++++++++ > 2 files changed, 41 insertions(+), 1 deletion(-) > > diff --git a/hw/arm/boot.c b/hw/arm/boot.c > index a48d1b2..5ac5479 100644 > --- a/hw/arm/boot.c > +++ b/hw/arm/boot.c > @@ -555,7 +555,7 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, > fw_cfg_add_bytes(fw_cfg, data_key, data, size); > } > > -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) > +static void arm_load_kernel_notify(Notifier *notifier, void *data) > { > CPUState *cs; > int kernel_size; > @@ -566,6 +566,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) > hwaddr entry, kernel_load_offset; > int big_endian; > static const ARMInsnFixup *primary_loader; > + ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier, > + notifier, notifier); > + ARMCPU *cpu = n->cpu; > + struct arm_boot_info *info = > + container_of(n, struct arm_boot_info, load_kernel_notifier); > > /* CPU objects (unlike devices) are not automatically reset on system > * reset, so we must always register a handler to do so. If we're > @@ -773,3 +778,10 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) > ARM_CPU(cs)->env.boot_info = info; > } > } > + > +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) > +{ > + info->load_kernel_notifier.cpu = cpu; > + info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify; > + qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier); > +} > diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h > index 5c940eb..760804c 100644 > --- a/include/hw/arm/arm.h > +++ b/include/hw/arm/arm.h > @@ -13,11 +13,21 @@ > > #include "exec/memory.h" > #include "hw/irq.h" > +#include "qemu/notify.h" > > /* armv7m.c */ > qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, > const char *kernel_filename, const char *cpu_model); > > +/* > + * struct used as a parameter of the arm_load_kernel machine init > + * done notifier > + */ > +typedef struct { > + Notifier notifier; /* actual notifier */ > + ARMCPU *cpu; /* handle to the first cpu object */ > +} ArmLoadKernelNotifier; > + > /* arm_boot.c */ > struct arm_boot_info { > uint64_t ram_size; > @@ -64,6 +74,8 @@ struct arm_boot_info { > * the user it should implement this hook. > */ > void (*modify_dtb)(const struct arm_boot_info *info, void *fdt); > + /* machine init done notifier executing arm_load_dtb */ > + ArmLoadKernelNotifier load_kernel_notifier; > /* Used internally by arm_boot.c */ > int is_linux; > hwaddr initrd_start; > @@ -75,6 +87,22 @@ struct arm_boot_info { > */ > bool firmware_loaded; > }; > + > +/** > + * arm_load_kernel - Loads memory with everything needed to boot > + * > + * @cpu: handle to the first CPU object > + * @info: handle to the boot info struct > + * Registers a machine init done notifier that copies to memory > + * everything needed to boot, depending on machine and user options: > + * kernel image, boot loaders, initrd, dtb. Also registers the CPU > + * reset handler. > + * > + * In case the machine file supports the platform bus device and its > + * dynamically instantiable sysbus devices, this function must be called > + * before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the > + * machine init done notifiers are called in registration reverse order. > + */ > void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); > > /* Multiplication factor to convert from system clock ticks to qemu timer
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index a48d1b2..5ac5479 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -555,7 +555,7 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, fw_cfg_add_bytes(fw_cfg, data_key, data, size); } -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) +static void arm_load_kernel_notify(Notifier *notifier, void *data) { CPUState *cs; int kernel_size; @@ -566,6 +566,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) hwaddr entry, kernel_load_offset; int big_endian; static const ARMInsnFixup *primary_loader; + ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier, + notifier, notifier); + ARMCPU *cpu = n->cpu; + struct arm_boot_info *info = + container_of(n, struct arm_boot_info, load_kernel_notifier); /* CPU objects (unlike devices) are not automatically reset on system * reset, so we must always register a handler to do so. If we're @@ -773,3 +778,10 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) ARM_CPU(cs)->env.boot_info = info; } } + +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) +{ + info->load_kernel_notifier.cpu = cpu; + info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify; + qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier); +} diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h index 5c940eb..760804c 100644 --- a/include/hw/arm/arm.h +++ b/include/hw/arm/arm.h @@ -13,11 +13,21 @@ #include "exec/memory.h" #include "hw/irq.h" +#include "qemu/notify.h" /* armv7m.c */ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, const char *kernel_filename, const char *cpu_model); +/* + * struct used as a parameter of the arm_load_kernel machine init + * done notifier + */ +typedef struct { + Notifier notifier; /* actual notifier */ + ARMCPU *cpu; /* handle to the first cpu object */ +} ArmLoadKernelNotifier; + /* arm_boot.c */ struct arm_boot_info { uint64_t ram_size; @@ -64,6 +74,8 @@ struct arm_boot_info { * the user it should implement this hook. */ void (*modify_dtb)(const struct arm_boot_info *info, void *fdt); + /* machine init done notifier executing arm_load_dtb */ + ArmLoadKernelNotifier load_kernel_notifier; /* Used internally by arm_boot.c */ int is_linux; hwaddr initrd_start; @@ -75,6 +87,22 @@ struct arm_boot_info { */ bool firmware_loaded; }; + +/** + * arm_load_kernel - Loads memory with everything needed to boot + * + * @cpu: handle to the first CPU object + * @info: handle to the boot info struct + * Registers a machine init done notifier that copies to memory + * everything needed to boot, depending on machine and user options: + * kernel image, boot loaders, initrd, dtb. Also registers the CPU + * reset handler. + * + * In case the machine file supports the platform bus device and its + * dynamically instantiable sysbus devices, this function must be called + * before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the + * machine init done notifiers are called in registration reverse order. + */ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); /* Multiplication factor to convert from system clock ticks to qemu timer