Blame 0013-hw-arm-pass-pristine-kernel-image-to-guest-firmware-.patch

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