qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI
@ 2014-12-05 18:36 Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 1/3] hw/loader: split out load_image_gzipped_buffer() Laszlo Ersek
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Laszlo Ersek @ 2014-12-05 18:36 UTC (permalink / raw)
  To: rjones, crobinso, Peter Maydell, Drew Jones, Wei Huang,
	Ard Biesheuvel, qemu devel list, lersek

A number of tools depend on passing the kernel image, the initial
ramdisk, and the kernel command line to the guest on the QEMU command
line (options -kernel, -initrd, -append, respectively). At the moment,
these QEMU options work, but the guest kernel loaded this way is
launched by a minimal binary firmware that is dynamically composed by
QEMU. As a consequence, such a kernel has no UEFI environment.

In this patchset the kernel, initrd and cmdline blobs are passed to the
guest firmware to process & load. This mode is activated when both
-kernel and -pflash unit#0 (or -bios) are specified.

Here's an inter-series dependency map:

  kernel  qemu  edk2  topic
  ------  ----  ----  --------------------------------------------------
  [0]                 device tree binding spec for the fw_cfg device
   ^
   |
   +------[1]<--[2]   fw_cfg device implementation
           ^     ^    and bootorder handling
           |     |
           |     |
          [3]<--[4]   -kernel / -initrd / -append booting on top of UEFI


  [0] http://thread.gmane.org/gmane.linux.drivers.devicetree/101276
      [kernel PATCH v2 0/2] devicetree: document ARM bindings for QEMU's
                            Firmware Config interface

      ACKed by Peter, queued by Rob Herring

  [1] http://thread.gmane.org/gmane.comp.emulators.qemu/308650
      [qemu-devel] [PATCH v2] arm: add fw_cfg to "virt" board

      pending review

  [2] http://thread.gmane.org/gmane.comp.bios.tianocore.devel/11591
      [edk2] [PATCH v2 00/12] consume fw_cfg boot order in
                              ArmVirtualizationQemu

      pending review

  [3] this patchset

      [qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd
                               -append on top of UEFI

  [4] to be posted

Thanks
Laszlo

Laszlo Ersek (3):
  hw/loader: split out load_image_gzipped_buffer()
  hw/arm: pass pristine kernel image to guest firmware over fw_cfg
  hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI
    firmware

 include/hw/arm/arm.h |  5 +++
 include/hw/loader.h  |  9 ++++++
 hw/arm/boot.c        | 91 +++++++++++++++++++++++++++++++++++++++++++++++++---
 hw/arm/virt.c        |  1 +
 hw/core/loader.c     | 30 +++++++++++------
 5 files changed, 122 insertions(+), 14 deletions(-)

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 1/3] hw/loader: split out load_image_gzipped_buffer()
  2014-12-05 18:36 [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Laszlo Ersek
@ 2014-12-05 18:36 ` Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 2/3] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Laszlo Ersek
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2014-12-05 18:36 UTC (permalink / raw)
  To: rjones, crobinso, Peter Maydell, Drew Jones, Wei Huang,
	Ard Biesheuvel, qemu devel list, lersek

In the next patch we'd like to reuse the image decompression facility
without installing the output as a ROM at a specific guest-phys address.

In addition, expose LOAD_IMAGE_MAX_GUNZIP_BYTES, because that's a
straightforward "max_sz" argument for the new load_image_gzipped_buffer().

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/loader.h |  9 +++++++++
 hw/core/loader.c    | 30 +++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/include/hw/loader.h b/include/hw/loader.h
index 6481639..8997620 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -16,6 +16,15 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
 ssize_t load_image_size(const char *filename, void *addr, size_t size);
 int load_image_targphys(const char *filename, hwaddr,
                         uint64_t max_sz);
+
+/* This is the limit on the maximum uncompressed image size that
+ * load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents
+ * g_malloc() in those functions from allocating a huge amount of memory.
+ */
+#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
+
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+                              uint8_t **buffer);
 int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
 
 #define ELF_LOAD_FAILED       -1
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 7527fd3..933ab64 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -614,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
                             NULL, NULL);
 }
 
-/* This simply prevents g_malloc in the function below from allocating
- * a huge amount of memory, by placing a limit on the maximum
- * uncompressed image size that load_image_gzipped will read.
- */
-#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
-
-/* Load a gzip-compressed kernel. */
-int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+                              uint8_t **buffer)
 {
     uint8_t *compressed_data = NULL;
     uint8_t *data = NULL;
@@ -653,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
         goto out;
     }
 
-    rom_add_blob_fixed(filename, data, bytes, addr);
+    /* trim to actual size and return to caller */
+    *buffer = g_realloc(data, bytes);
     ret = bytes;
+    /* ownership has been transferred to caller */
+    data = NULL;
 
  out:
     g_free(compressed_data);
@@ -662,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
     return ret;
 }
 
+/* Load a gzip-compressed kernel. */
+int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+{
+    int bytes;
+    uint8_t *data;
+
+    bytes = load_image_gzipped_buffer (filename, max_sz, &data);
+    if (bytes != -1) {
+        rom_add_blob_fixed(filename, data, bytes, addr);
+        g_free(data);
+    }
+    return bytes;
+}
+
 /*
  * Functions for reboot-persistent memory regions.
  *  - used for vga bios and option roms.
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 2/3] hw/arm: pass pristine kernel image to guest firmware over fw_cfg
  2014-12-05 18:36 [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 1/3] hw/loader: split out load_image_gzipped_buffer() Laszlo Ersek
@ 2014-12-05 18:36 ` Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 3/3] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Laszlo Ersek
  2014-12-05 18:55 ` [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Peter Maydell
  3 siblings, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2014-12-05 18:36 UTC (permalink / raw)
  To: rjones, crobinso, Peter Maydell, Drew Jones, Wei Huang,
	Ard Biesheuvel, qemu devel list, lersek

Introduce the new boolean field "arm_boot_info.firmware_loaded". When this
field is set, it means that the portion of guest DRAM that the VCPU
normally starts to execute, or the pflash chip that the VCPU normally
starts to execute, has been populated by board-specific code with
full-fledged guest firmware code, before the board calls
arm_load_kernel().

Simultaneously, "arm_boot_info.firmware_loaded" guarantees that the board
code has set up the global firmware config instance, for arm_load_kernel()
to find with fw_cfg_find().

Guest kernel (-kernel) and guest firmware (-bios, -pflash) has always been
possible to specify independently on the command line. The following cases
should be considered:

nr  -bios    -pflash  -kernel  description
             unit#0
--  -------  -------  -------  -------------------------------------------
1   present  present  absent   Board code rejects this case, -bios and
    present  present  present  -pflash unit#0 are exclusive. Left intact
                               by this patch.

2   absent   absent   present  Traditional kernel loading, with qemu's
                               minimal board firmware. Left intact by this
                               patch.

3   absent   present  absent   Preexistent case for booting guest firmware
    present  absent   absent   loaded with -bios or -pflash. Left intact
                               by this patch.

4   absent   absent   absent   Preexistent case for not loading any
                               firmware or kernel up-front. Left intact by
                               this patch.

5   present  absent   present  New case introduced by this patch: kernel
    absent   present  present  image is passed to externally loaded
                               firmware in unmodified form, using fw_cfg.

An easy way to see that this patch doesn't interfere with existing cases
is to realize that "info->firmware_loaded" is constant zero at this point.
Which makes the "outer" condition unchanged, and the "inner" condition
(with the fw_cfg-related code) dead.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/arm/arm.h |  5 +++
 hw/arm/boot.c        | 91 +++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index cefc9e6..dd69d66 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -66,6 +66,11 @@ struct arm_boot_info {
     hwaddr initrd_start;
     hwaddr initrd_size;
     hwaddr entry;
+
+    /* Boot firmware has been loaded, typically at address 0, with -bios or
+     * -pflash. It also implies that fw_cfg_find() will succeed.
+     */
+    bool firmware_loaded;
 };
 void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
 
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 0014c34..01d6d3d 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -476,6 +476,60 @@ static void do_cpu_reset(void *opaque)
     }
 }
 
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ *                          by key.
+ * @fw_cfg:     The firmware config instance to store the data in.
+ * @size_key:   The firmware config key to store the size of the loaded data
+ *              under, with fw_cfg_add_i32().
+ * @data_key:   The firmware config key to store the loaded data under, with
+ *              fw_cfg_add_bytes().
+ * @image_name: The name of the image file to load. If it is NULL, the function
+ *              returns without doing anything.
+ * @decompress: Whether the image should be  decompressed (gunzipped) before
+ *              adding it to fw_cfg.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+                                 uint16_t data_key, const char *image_name,
+                                 bool decompress)
+{
+    size_t size;
+    uint8_t *data;
+
+    if (image_name == NULL) {
+        return;
+    }
+
+    if (decompress) {
+        int bytes;
+
+        bytes = load_image_gzipped_buffer (image_name,
+                                           LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+        if (bytes == -1) {
+            fprintf(stderr, "failed to load and decompress \"%s\"\n",
+                    image_name);
+            exit(1);
+        }
+        size = bytes;
+    } else {
+        gchar *contents;
+        gsize length;
+
+        if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+            fprintf(stderr, "failed to load \"%s\"\n", image_name);
+            exit(1);
+        }
+        size = length;
+        data = (uint8_t *)contents;
+    }
+
+    fw_cfg_add_i32(fw_cfg, size_key, size);
+    fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
 void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
 {
     CPUState *cs;
@@ -498,19 +552,46 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
     }
 
     /* Load the kernel.  */
-    if (!info->kernel_filename) {
+    if (!info->kernel_filename || info->firmware_loaded) {
 
         if (have_dtb(info)) {
-            /* If we have a device tree blob, but no kernel to supply it to,
-             * copy it to the base of RAM for a bootloader to pick up.
+            /* If we have a device tree blob, but no kernel to supply it to (or
+             * the kernel is supposed to be loaded by the bootloader), copy the
+             * DTB to the base of RAM for the bootloader to pick up.
              */
             if (load_dtb(info->loader_start, info, 0) < 0) {
                 exit(1);
             }
         }
 
-        /* If no kernel specified, do nothing; we will start from address 0
-         * (typically a boot ROM image) in the same way as hardware.
+        if (info->kernel_filename) {
+            FWCfgState *fw_cfg;
+            bool decompress_kernel;
+
+            fw_cfg = fw_cfg_find();
+            decompress_kernel = arm_feature(&cpu->env, ARM_FEATURE_AARCH64);
+
+            /* Expose the kernel, the command line, and the initrd in fw_cfg.
+             * We don't process them here at all, it's all left to the
+             * firmware.
+             */
+            load_image_to_fw_cfg(fw_cfg,
+                                 FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+                                 info->kernel_filename, decompress_kernel);
+            load_image_to_fw_cfg(fw_cfg,
+                                 FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+                                 info->initrd_filename, false);
+
+            if (info->kernel_cmdline) {
+                fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                               strlen(info->kernel_cmdline) + 1);
+                fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+                                  info->kernel_cmdline);
+            }
+        }
+
+        /* We will start from address 0 (typically a boot ROM image) in the
+         * same way as hardware.
          */
         return;
     }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 3/3] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware
  2014-12-05 18:36 [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 1/3] hw/loader: split out load_image_gzipped_buffer() Laszlo Ersek
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 2/3] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Laszlo Ersek
@ 2014-12-05 18:36 ` Laszlo Ersek
  2014-12-05 18:55 ` [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Peter Maydell
  3 siblings, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2014-12-05 18:36 UTC (permalink / raw)
  To: rjones, crobinso, Peter Maydell, Drew Jones, Wei Huang,
	Ard Biesheuvel, qemu devel list, lersek

The virt board already ensures mutual exclusion between -bios and -pflash
unit#0; we only need to set "bootinfo.firmware_loaded", introduced in the
previous patch, if either of those options was used to load the guest
firmware.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 hw/arm/virt.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index af794ea..584c40d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -633,6 +633,7 @@ static void machvirt_init(MachineState *machine)
     vbi->bootinfo.board_id = -1;
     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
     vbi->bootinfo.get_dtb = machvirt_dtb;
+    vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
     arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI
  2014-12-05 18:36 [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Laszlo Ersek
                   ` (2 preceding siblings ...)
  2014-12-05 18:36 ` [Qemu-devel] [PATCH 3/3] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Laszlo Ersek
@ 2014-12-05 18:55 ` Peter Maydell
  2014-12-09  0:07   ` Laszlo Ersek
  3 siblings, 1 reply; 6+ messages in thread
From: Peter Maydell @ 2014-12-05 18:55 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Wei Huang, Drew Jones, Ard Biesheuvel, qemu devel list

On 5 December 2014 at 18:36, Laszlo Ersek <lersek@redhat.com> wrote:
> A number of tools depend on passing the kernel image, the initial
> ramdisk, and the kernel command line to the guest on the QEMU command
> line (options -kernel, -initrd, -append, respectively). At the moment,
> these QEMU options work, but the guest kernel loaded this way is
> launched by a minimal binary firmware that is dynamically composed by
> QEMU. As a consequence, such a kernel has no UEFI environment.
>
> In this patchset the kernel, initrd and cmdline blobs are passed to the
> guest firmware to process & load. This mode is activated when both
> -kernel and -pflash unit#0 (or -bios) are specified.

...so we avoid back-compat problems on the assumption that
nobody was previously trying to provide both -bios and
-kernel at once. I *think* that's probably a reasonable
assumption...

-- PMM

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI
  2014-12-05 18:55 ` [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Peter Maydell
@ 2014-12-09  0:07   ` Laszlo Ersek
  0 siblings, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2014-12-09  0:07 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Wei Huang, Drew Jones, Ard Biesheuvel, qemu devel list

On 12/05/14 19:55, Peter Maydell wrote:
> On 5 December 2014 at 18:36, Laszlo Ersek <lersek@redhat.com> wrote:
>> A number of tools depend on passing the kernel image, the initial
>> ramdisk, and the kernel command line to the guest on the QEMU command
>> line (options -kernel, -initrd, -append, respectively). At the moment,
>> these QEMU options work, but the guest kernel loaded this way is
>> launched by a minimal binary firmware that is dynamically composed by
>> QEMU. As a consequence, such a kernel has no UEFI environment.
>>
>> In this patchset the kernel, initrd and cmdline blobs are passed to the
>> guest firmware to process & load. This mode is activated when both
>> -kernel and -pflash unit#0 (or -bios) are specified.
> 
> ...so we avoid back-compat problems on the assumption that
> nobody was previously trying to provide both -bios and
> -kernel at once. I *think* that's probably a reasonable
> assumption...

I'm including these three too in the new patchset that I'll post soon,
so no need to keep these queued.

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-12-09  0:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-05 18:36 [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Laszlo Ersek
2014-12-05 18:36 ` [Qemu-devel] [PATCH 1/3] hw/loader: split out load_image_gzipped_buffer() Laszlo Ersek
2014-12-05 18:36 ` [Qemu-devel] [PATCH 2/3] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Laszlo Ersek
2014-12-05 18:36 ` [Qemu-devel] [PATCH 3/3] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Laszlo Ersek
2014-12-05 18:55 ` [Qemu-devel] [PATCH 0/3] hw/arm/virt: boot with -kernel -initrd -append on top of UEFI Peter Maydell
2014-12-09  0:07   ` Laszlo Ersek

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).