|
|
391fb8 |
From a4510adeb278b6781b16a5cc61cc5b7f00612130 Mon Sep 17 00:00:00 2001
|
|
|
391fb8 |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
391fb8 |
Date: Mon, 22 Dec 2014 13:11:44 +0100
|
|
|
391fb8 |
Subject: [PATCH 13/15] hw/arm: pass pristine kernel image to guest firmware
|
|
|
391fb8 |
over fw_cfg
|
|
|
391fb8 |
|
|
|
391fb8 |
Introduce the new boolean field "arm_boot_info.firmware_loaded". When this
|
|
|
391fb8 |
field is set, it means that the portion of guest DRAM that the VCPU
|
|
|
391fb8 |
normally starts to execute, or the pflash chip that the VCPU normally
|
|
|
391fb8 |
starts to execute, has been populated by board-specific code with
|
|
|
391fb8 |
full-fledged guest firmware code, before the board calls
|
|
|
391fb8 |
arm_load_kernel().
|
|
|
391fb8 |
|
|
|
391fb8 |
Simultaneously, "arm_boot_info.firmware_loaded" guarantees that the board
|
|
|
391fb8 |
code has set up the global firmware config instance, for arm_load_kernel()
|
|
|
391fb8 |
to find with fw_cfg_find().
|
|
|
391fb8 |
|
|
|
391fb8 |
Guest kernel (-kernel) and guest firmware (-bios, -pflash) has always been
|
|
|
391fb8 |
possible to specify independently on the command line. The following cases
|
|
|
391fb8 |
should be considered:
|
|
|
391fb8 |
|
|
|
391fb8 |
nr -bios -pflash -kernel description
|
|
|
391fb8 |
unit#0
|
|
|
391fb8 |
-- ------- ------- ------- -------------------------------------------
|
|
|
391fb8 |
1 present present absent Board code rejects this case, -bios and
|
|
|
391fb8 |
present present present -pflash unit#0 are exclusive. Left intact
|
|
|
391fb8 |
by this patch.
|
|
|
391fb8 |
|
|
|
391fb8 |
2 absent absent present Traditional kernel loading, with qemu's
|
|
|
391fb8 |
minimal board firmware. Left intact by this
|
|
|
391fb8 |
patch.
|
|
|
391fb8 |
|
|
|
391fb8 |
3 absent present absent Preexistent case for booting guest firmware
|
|
|
391fb8 |
present absent absent loaded with -bios or -pflash. Left intact
|
|
|
391fb8 |
by this patch.
|
|
|
391fb8 |
|
|
|
391fb8 |
4 absent absent absent Preexistent case for not loading any
|
|
|
391fb8 |
firmware or kernel up-front. Left intact by
|
|
|
391fb8 |
this patch.
|
|
|
391fb8 |
|
|
|
391fb8 |
5 present absent present New case introduced by this patch: kernel
|
|
|
391fb8 |
absent present present image is passed to externally loaded
|
|
|
391fb8 |
firmware in unmodified form, using fw_cfg.
|
|
|
391fb8 |
|
|
|
391fb8 |
An easy way to see that this patch doesn't interfere with existing cases
|
|
|
391fb8 |
is to realize that "info->firmware_loaded" is constant zero at this point.
|
|
|
391fb8 |
Which makes the "outer" condition unchanged, and the "inner" condition
|
|
|
391fb8 |
(with the fw_cfg-related code) dead.
|
|
|
391fb8 |
|
|
|
391fb8 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
391fb8 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
391fb8 |
Message-id: 1419250305-31062-11-git-send-email-pbonzini@redhat.com
|
|
|
391fb8 |
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
|
|
391fb8 |
(cherry picked from commit 07abe45c4814d42f3aca879d7932c5bc90d98bdf)
|
|
|
391fb8 |
---
|
|
|
391fb8 |
hw/arm/boot.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
|
391fb8 |
include/hw/arm/arm.h | 5 +++
|
|
|
391fb8 |
2 files changed, 88 insertions(+), 5 deletions(-)
|
|
|
391fb8 |
|
|
|
391fb8 |
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
|
|
|
391fb8 |
index e6a3c5b..17bdaee 100644
|
|
|
391fb8 |
--- a/hw/arm/boot.c
|
|
|
391fb8 |
+++ b/hw/arm/boot.c
|
|
|
391fb8 |
@@ -478,6 +478,55 @@ static void do_cpu_reset(void *opaque)
|
|
|
391fb8 |
}
|
|
|
391fb8 |
}
|
|
|
391fb8 |
|
|
|
391fb8 |
+/**
|
|
|
391fb8 |
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
|
|
391fb8 |
+ * by key.
|
|
|
391fb8 |
+ * @fw_cfg: The firmware config instance to store the data in.
|
|
|
391fb8 |
+ * @size_key: The firmware config key to store the size of the loaded
|
|
|
391fb8 |
+ * data under, with fw_cfg_add_i32().
|
|
|
391fb8 |
+ * @data_key: The firmware config key to store the loaded data under,
|
|
|
391fb8 |
+ * with fw_cfg_add_bytes().
|
|
|
391fb8 |
+ * @image_name: The name of the image file to load. If it is NULL, the
|
|
|
391fb8 |
+ * function returns without doing anything.
|
|
|
391fb8 |
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
|
|
|
391fb8 |
+ * adding it to fw_cfg. If decompression fails, the image is
|
|
|
391fb8 |
+ * loaded as-is.
|
|
|
391fb8 |
+ *
|
|
|
391fb8 |
+ * In case of failure, the function prints an error message to stderr and the
|
|
|
391fb8 |
+ * process exits with status 1.
|
|
|
391fb8 |
+ */
|
|
|
391fb8 |
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
|
|
391fb8 |
+ uint16_t data_key, const char *image_name,
|
|
|
391fb8 |
+ bool try_decompress)
|
|
|
391fb8 |
+{
|
|
|
391fb8 |
+ size_t size = -1;
|
|
|
391fb8 |
+ uint8_t *data;
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ if (image_name == NULL) {
|
|
|
391fb8 |
+ return;
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ if (try_decompress) {
|
|
|
391fb8 |
+ size = load_image_gzipped_buffer(image_name,
|
|
|
391fb8 |
+ LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ if (size == (size_t)-1) {
|
|
|
391fb8 |
+ gchar *contents;
|
|
|
391fb8 |
+ gsize length;
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
|
|
391fb8 |
+ fprintf(stderr, "failed to load \"%s\"\n", image_name);
|
|
|
391fb8 |
+ exit(1);
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+ size = length;
|
|
|
391fb8 |
+ data = (uint8_t *)contents;
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ fw_cfg_add_i32(fw_cfg, size_key, size);
|
|
|
391fb8 |
+ fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
|
|
391fb8 |
+}
|
|
|
391fb8 |
+
|
|
|
391fb8 |
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|
|
391fb8 |
{
|
|
|
391fb8 |
CPUState *cs;
|
|
|
391fb8 |
@@ -500,19 +549,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|
|
391fb8 |
}
|
|
|
391fb8 |
|
|
|
391fb8 |
/* Load the kernel. */
|
|
|
391fb8 |
- if (!info->kernel_filename) {
|
|
|
391fb8 |
+ if (!info->kernel_filename || info->firmware_loaded) {
|
|
|
391fb8 |
|
|
|
391fb8 |
if (have_dtb(info)) {
|
|
|
391fb8 |
- /* If we have a device tree blob, but no kernel to supply it to,
|
|
|
391fb8 |
- * copy it to the base of RAM for a bootloader to pick up.
|
|
|
391fb8 |
+ /* If we have a device tree blob, but no kernel to supply it to (or
|
|
|
391fb8 |
+ * the kernel is supposed to be loaded by the bootloader), copy the
|
|
|
391fb8 |
+ * DTB to the base of RAM for the bootloader to pick up.
|
|
|
391fb8 |
*/
|
|
|
391fb8 |
if (load_dtb(info->loader_start, info, 0) < 0) {
|
|
|
391fb8 |
exit(1);
|
|
|
391fb8 |
}
|
|
|
391fb8 |
}
|
|
|
391fb8 |
|
|
|
391fb8 |
- /* If no kernel specified, do nothing; we will start from address 0
|
|
|
391fb8 |
- * (typically a boot ROM image) in the same way as hardware.
|
|
|
391fb8 |
+ if (info->kernel_filename) {
|
|
|
391fb8 |
+ FWCfgState *fw_cfg;
|
|
|
391fb8 |
+ bool try_decompressing_kernel;
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ fw_cfg = fw_cfg_find();
|
|
|
391fb8 |
+ try_decompressing_kernel = arm_feature(&cpu->env,
|
|
|
391fb8 |
+ ARM_FEATURE_AARCH64);
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ /* Expose the kernel, the command line, and the initrd in fw_cfg.
|
|
|
391fb8 |
+ * We don't process them here at all, it's all left to the
|
|
|
391fb8 |
+ * firmware.
|
|
|
391fb8 |
+ */
|
|
|
391fb8 |
+ load_image_to_fw_cfg(fw_cfg,
|
|
|
391fb8 |
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
|
|
391fb8 |
+ info->kernel_filename,
|
|
|
391fb8 |
+ try_decompressing_kernel);
|
|
|
391fb8 |
+ load_image_to_fw_cfg(fw_cfg,
|
|
|
391fb8 |
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
|
|
391fb8 |
+ info->initrd_filename, false);
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ if (info->kernel_cmdline) {
|
|
|
391fb8 |
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
|
|
391fb8 |
+ strlen(info->kernel_cmdline) + 1);
|
|
|
391fb8 |
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
|
|
391fb8 |
+ info->kernel_cmdline);
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+ }
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ /* We will start from address 0 (typically a boot ROM image) in the
|
|
|
391fb8 |
+ * same way as hardware.
|
|
|
391fb8 |
*/
|
|
|
391fb8 |
return;
|
|
|
391fb8 |
}
|
|
|
391fb8 |
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
|
|
|
391fb8 |
index cefc9e6..dd69d66 100644
|
|
|
391fb8 |
--- a/include/hw/arm/arm.h
|
|
|
391fb8 |
+++ b/include/hw/arm/arm.h
|
|
|
391fb8 |
@@ -66,6 +66,11 @@ struct arm_boot_info {
|
|
|
391fb8 |
hwaddr initrd_start;
|
|
|
391fb8 |
hwaddr initrd_size;
|
|
|
391fb8 |
hwaddr entry;
|
|
|
391fb8 |
+
|
|
|
391fb8 |
+ /* Boot firmware has been loaded, typically at address 0, with -bios or
|
|
|
391fb8 |
+ * -pflash. It also implies that fw_cfg_find() will succeed.
|
|
|
391fb8 |
+ */
|
|
|
391fb8 |
+ bool firmware_loaded;
|
|
|
391fb8 |
};
|
|
|
391fb8 |
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
|
|
|
391fb8 |
|
|
|
391fb8 |
--
|
|
|
391fb8 |
2.1.0
|
|
|
391fb8 |
|