[Qemu-devel] [PATCH v2] PPC: e500: Fix duplicate kernel load and device tree overlap

David Engraf posted 1 patch 6 years, 2 months ago
Failed in applying to current master (apply log)
There is a newer version of this series
hw/ppc/e500.c | 112 ++++++++++++++++++++++++++++++++++------------------------
1 file changed, 65 insertions(+), 47 deletions(-)
[Qemu-devel] [PATCH v2] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Engraf 6 years, 2 months ago
This patch fixes an incorrect behavior when the -kernel argument has been
specified without -bios. In this case the kernel was loaded twice. At address
32M as a raw image and afterwards by load_elf/load_uimage at the
corresponding load address. In this case the region for the device tree and
the raw kernel image may overlap.

The patch fixes the behavior by loading the kernel image once with
load_elf/load_uimage and skips loading the raw image. It also ensures that
the device tree is generated behind bios/kernel/initrd.

When here do not use bios_name/size for the kernel and use a more generic
name called payload_name/size.

Signed-off-by: David Engraf <david.engraf@sysgo.com>
---
 hw/ppc/e500.c | 112 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 65 insertions(+), 47 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index c4fe06ea2a..d12b9d6121 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -776,7 +776,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     PCIBus *pci_bus;
     CPUPPCState *env = NULL;
-    uint64_t loadaddr;
     hwaddr kernel_base = -1LL;
     int kernel_size = 0;
     hwaddr dt_base = 0;
@@ -784,8 +783,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     int initrd_size = 0;
     hwaddr cur_base = 0;
     char *filename;
+    const char *payload_name;
+    bool kernel_as_payload;
     hwaddr bios_entry = 0;
-    target_long bios_size;
+    target_long payload_size;
     struct boot_info *boot_info;
     int dt_size;
     int i;
@@ -913,11 +914,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     /* Register spinning region */
     sysbus_create_simple("e500-spin", params->spin_base, NULL);
 
-    if (cur_base < (32 * 1024 * 1024)) {
-        /* u-boot occupies memory up to 32MB, so load blobs above */
-        cur_base = (32 * 1024 * 1024);
-    }
-
     if (params->has_mpc8xxx_gpio) {
         qemu_irq poweroff_irq;
 
@@ -952,36 +948,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
                                     sysbus_mmio_get_region(s, 0));
     }
 
-    /* Load kernel. */
-    if (machine->kernel_filename) {
-        kernel_base = cur_base;
-        kernel_size = load_image_targphys(machine->kernel_filename,
-                                          cur_base,
-                                          ram_size - cur_base);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    machine->kernel_filename);
-            exit(1);
-        }
-
-        cur_base += kernel_size;
-    }
-
-    /* Load initrd. */
-    if (machine->initrd_filename) {
-        initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
-        initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
-                                          ram_size - initrd_base);
-
-        if (initrd_size < 0) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    machine->initrd_filename);
-            exit(1);
-        }
-
-        cur_base = initrd_base + initrd_size;
-    }
-
     /*
      * Smart firmware defaults ahead!
      *
@@ -997,33 +963,85 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
      * This ensures backwards compatibility with how we used to expose
      * -kernel to users but allows them to run through u-boot as well.
      */
+    kernel_as_payload = false;
     if (bios_name == NULL) {
         if (machine->kernel_filename) {
-            bios_name = machine->kernel_filename;
+            payload_name = machine->kernel_filename;
+            kernel_as_payload = true;
         } else {
-            bios_name = "u-boot.e500";
+            payload_name = "u-boot.e500";
         }
+    } else {
+        payload_name = bios_name;
     }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 
-    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
-                         1, PPC_ELF_MACHINE, 0, 0);
-    if (bios_size < 0) {
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
+
+    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &cur_base, NULL,
+                            1, PPC_ELF_MACHINE, 0, 0);
+    if (payload_size < 0) {
         /*
          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
          * ePAPR compliant kernel
          */
-        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
-                                  NULL, NULL);
-        if (kernel_size < 0) {
+        payload_size = load_uimage(filename, &bios_entry, &cur_base, NULL,
+                                   NULL, NULL);
+        if (payload_size < 0) {
             fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
             exit(1);
         }
     }
+
     g_free(filename);
 
+    if (kernel_as_payload) {
+        kernel_base = cur_base;
+        kernel_size = payload_size;
+    }
+
+    cur_base += payload_size;
+
+    /* Load bare kernel only if no bios/u-boot has been provided */
+    if (machine->kernel_filename && !kernel_as_payload) {
+        kernel_base = cur_base;
+        kernel_size = load_image_targphys(machine->kernel_filename,
+                                          cur_base,
+                                          ram_size - cur_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    machine->kernel_filename);
+            exit(1);
+        }
+
+        cur_base += kernel_size;
+    }
+
+    if (cur_base < (32 * 1024 * 1024)) {
+        /* u-boot occupies memory up to 32MB, so load blobs above */
+        cur_base = (32 * 1024 * 1024);
+    }
+
+    /* Load initrd. */
+    if (machine->initrd_filename) {
+        initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
+        initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
+                                          ram_size - initrd_base);
+
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    machine->initrd_filename);
+            exit(1);
+        }
+
+        cur_base = initrd_base + initrd_size;
+    }
+
     /* Reserve space for dtb */
-    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+    dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+    if (dt_base + DTB_MAX_SIZE > ram_size) {
+            fprintf(stderr, "qemu: not enough memory for device tree\n");
+            exit(1);
+    }
 
     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
                                        initrd_base, initrd_size,
-- 
2.14.1


[Qemu-devel] [PATCH v3] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Engraf 6 years, 2 months ago
This patch fixes an incorrect behavior when the -kernel argument has been
specified without -bios. In this case the kernel was loaded twice. At address
32M as a raw image and afterwards by load_elf/load_uimage at the
corresponding load address. In this case the region for the device tree and
the raw kernel image may overlap.

The patch fixes the behavior by loading the kernel image once with
load_elf/load_uimage and skips loading the raw image.

When here do not use bios_name/size for the kernel and use a more generic
name called payload_name/size.

New in v3: dtb must be stored between kernel and initrd because Linux can
           handle the dtb only within the first 64MB. Add a comment to
           clarify the behavior.

Signed-off-by: David Engraf <david.engraf@sysgo.com>
---
 hw/ppc/e500.c | 116 +++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 70 insertions(+), 46 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index c4fe06ea2a..414c4beaab 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -784,8 +784,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     int initrd_size = 0;
     hwaddr cur_base = 0;
     char *filename;
+    const char *payload_name;
+    bool kernel_as_payload;
     hwaddr bios_entry = 0;
-    target_long bios_size;
+    target_long payload_size;
     struct boot_info *boot_info;
     int dt_size;
     int i;
@@ -913,11 +915,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     /* Register spinning region */
     sysbus_create_simple("e500-spin", params->spin_base, NULL);
 
-    if (cur_base < (32 * 1024 * 1024)) {
-        /* u-boot occupies memory up to 32MB, so load blobs above */
-        cur_base = (32 * 1024 * 1024);
-    }
-
     if (params->has_mpc8xxx_gpio) {
         qemu_irq poweroff_irq;
 
@@ -952,8 +949,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
                                     sysbus_mmio_get_region(s, 0));
     }
 
-    /* Load kernel. */
-    if (machine->kernel_filename) {
+    /*
+     * Smart firmware defaults ahead!
+     *
+     * We follow the following table to select which payload we execute.
+     *
+     *  -kernel | -bios | payload
+     * ---------+-------+---------
+     *     N    |   Y   | u-boot
+     *     N    |   N   | u-boot
+     *     Y    |   Y   | u-boot
+     *     Y    |   N   | kernel
+     *
+     * This ensures backwards compatibility with how we used to expose
+     * -kernel to users but allows them to run through u-boot as well.
+     */
+    kernel_as_payload = false;
+    if (bios_name == NULL) {
+        if (machine->kernel_filename) {
+            payload_name = machine->kernel_filename;
+            kernel_as_payload = true;
+        } else {
+            payload_name = "u-boot.e500";
+        }
+    } else {
+        payload_name = bios_name;
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
+
+    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
+                            1, PPC_ELF_MACHINE, 0, 0);
+    if (payload_size < 0) {
+        /*
+         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+         * ePAPR compliant kernel
+         */
+        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
+                                   NULL, NULL);
+        if (payload_size < 0) {
+            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
+            exit(1);
+        }
+    }
+
+    g_free(filename);
+
+    if (kernel_as_payload) {
+        kernel_base = loadaddr;
+        kernel_size = payload_size;
+    }
+
+    cur_base = loadaddr + payload_size;
+
+    /* Load bare kernel only if no bios/u-boot has been provided */
+    if (machine->kernel_filename && !kernel_as_payload) {
         kernel_base = cur_base;
         kernel_size = load_image_targphys(machine->kernel_filename,
                                           cur_base,
@@ -967,6 +1017,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
         cur_base += kernel_size;
     }
 
+    if (cur_base < (32 * 1024 * 1024)) {
+        /* u-boot occupies memory up to 32MB, so load blobs above */
+        cur_base = (32 * 1024 * 1024);
+    }
+
     /* Load initrd. */
     if (machine->initrd_filename) {
         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@@ -983,47 +1038,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     }
 
     /*
-     * Smart firmware defaults ahead!
-     *
-     * We follow the following table to select which payload we execute.
-     *
-     *  -kernel | -bios | payload
-     * ---------+-------+---------
-     *     N    |   Y   | u-boot
-     *     N    |   N   | u-boot
-     *     Y    |   Y   | u-boot
-     *     Y    |   N   | kernel
-     *
-     * This ensures backwards compatibility with how we used to expose
-     * -kernel to users but allows them to run through u-boot as well.
+     * Reserve space for dtb behind the kernel image because Linux has a bug
+     * where it can only handle the dtb if it's within the first 64MB of where
+     * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
+     * ensures enough space between kernel and initrd.
      */
-    if (bios_name == NULL) {
-        if (machine->kernel_filename) {
-            bios_name = machine->kernel_filename;
-        } else {
-            bios_name = "u-boot.e500";
-        }
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
-    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
-                         1, PPC_ELF_MACHINE, 0, 0);
-    if (bios_size < 0) {
-        /*
-         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
-         * ePAPR compliant kernel
-         */
-        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
-                                  NULL, NULL);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
+    dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+    if (dt_base + DTB_MAX_SIZE > ram_size) {
+            fprintf(stderr, "qemu: not enough memory for device tree\n");
             exit(1);
-        }
     }
-    g_free(filename);
-
-    /* Reserve space for dtb */
-    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
 
     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
                                        initrd_base, initrd_size,
-- 
2.14.1


Re: [Qemu-devel] [PATCH v3] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Gibson 6 years, 1 month ago
On Thu, Feb 15, 2018 at 10:36:00AM +0100, David Engraf wrote:
> This patch fixes an incorrect behavior when the -kernel argument has been
> specified without -bios. In this case the kernel was loaded twice. At address
> 32M as a raw image and afterwards by load_elf/load_uimage at the
> corresponding load address. In this case the region for the device tree and
> the raw kernel image may overlap.
> 
> The patch fixes the behavior by loading the kernel image once with
> load_elf/load_uimage and skips loading the raw image.
> 
> When here do not use bios_name/size for the kernel and use a more generic
> name called payload_name/size.
> 
> New in v3: dtb must be stored between kernel and initrd because Linux can
>            handle the dtb only within the first 64MB. Add a comment to
>            clarify the behavior.
> 
> Signed-off-by: David Engraf <david.engraf@sysgo.com>

Sorry I've taken so long to reply to this.  It looks fine to me,
however, other changes mean it longer quite applies to the
ppc-for-2.12 tree.  Can you fix that up and repost please.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  hw/ppc/e500.c | 116 +++++++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 70 insertions(+), 46 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index c4fe06ea2a..414c4beaab 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -784,8 +784,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      int initrd_size = 0;
>      hwaddr cur_base = 0;
>      char *filename;
> +    const char *payload_name;
> +    bool kernel_as_payload;
>      hwaddr bios_entry = 0;
> -    target_long bios_size;
> +    target_long payload_size;
>      struct boot_info *boot_info;
>      int dt_size;
>      int i;
> @@ -913,11 +915,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      /* Register spinning region */
>      sysbus_create_simple("e500-spin", params->spin_base, NULL);
>  
> -    if (cur_base < (32 * 1024 * 1024)) {
> -        /* u-boot occupies memory up to 32MB, so load blobs above */
> -        cur_base = (32 * 1024 * 1024);
> -    }
> -
>      if (params->has_mpc8xxx_gpio) {
>          qemu_irq poweroff_irq;
>  
> @@ -952,8 +949,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>                                      sysbus_mmio_get_region(s, 0));
>      }
>  
> -    /* Load kernel. */
> -    if (machine->kernel_filename) {
> +    /*
> +     * Smart firmware defaults ahead!
> +     *
> +     * We follow the following table to select which payload we execute.
> +     *
> +     *  -kernel | -bios | payload
> +     * ---------+-------+---------
> +     *     N    |   Y   | u-boot
> +     *     N    |   N   | u-boot
> +     *     Y    |   Y   | u-boot
> +     *     Y    |   N   | kernel
> +     *
> +     * This ensures backwards compatibility with how we used to expose
> +     * -kernel to users but allows them to run through u-boot as well.
> +     */
> +    kernel_as_payload = false;
> +    if (bios_name == NULL) {
> +        if (machine->kernel_filename) {
> +            payload_name = machine->kernel_filename;
> +            kernel_as_payload = true;
> +        } else {
> +            payload_name = "u-boot.e500";
> +        }
> +    } else {
> +        payload_name = bios_name;
> +    }
> +
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
> +
> +    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
> +                            1, PPC_ELF_MACHINE, 0, 0);
> +    if (payload_size < 0) {
> +        /*
> +         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
> +         * ePAPR compliant kernel
> +         */
> +        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
> +                                   NULL, NULL);
> +        if (payload_size < 0) {
> +            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
> +            exit(1);
> +        }
> +    }
> +
> +    g_free(filename);
> +
> +    if (kernel_as_payload) {
> +        kernel_base = loadaddr;
> +        kernel_size = payload_size;
> +    }
> +
> +    cur_base = loadaddr + payload_size;
> +
> +    /* Load bare kernel only if no bios/u-boot has been provided */
> +    if (machine->kernel_filename && !kernel_as_payload) {
>          kernel_base = cur_base;
>          kernel_size = load_image_targphys(machine->kernel_filename,
>                                            cur_base,
> @@ -967,6 +1017,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>          cur_base += kernel_size;
>      }
>  
> +    if (cur_base < (32 * 1024 * 1024)) {
> +        /* u-boot occupies memory up to 32MB, so load blobs above */
> +        cur_base = (32 * 1024 * 1024);
> +    }
> +
>      /* Load initrd. */
>      if (machine->initrd_filename) {
>          initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
> @@ -983,47 +1038,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      }
>  
>      /*
> -     * Smart firmware defaults ahead!
> -     *
> -     * We follow the following table to select which payload we execute.
> -     *
> -     *  -kernel | -bios | payload
> -     * ---------+-------+---------
> -     *     N    |   Y   | u-boot
> -     *     N    |   N   | u-boot
> -     *     Y    |   Y   | u-boot
> -     *     Y    |   N   | kernel
> -     *
> -     * This ensures backwards compatibility with how we used to expose
> -     * -kernel to users but allows them to run through u-boot as well.
> +     * Reserve space for dtb behind the kernel image because Linux has a bug
> +     * where it can only handle the dtb if it's within the first 64MB of where
> +     * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
> +     * ensures enough space between kernel and initrd.
>       */
> -    if (bios_name == NULL) {
> -        if (machine->kernel_filename) {
> -            bios_name = machine->kernel_filename;
> -        } else {
> -            bios_name = "u-boot.e500";
> -        }
> -    }
> -    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> -
> -    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
> -                         1, PPC_ELF_MACHINE, 0, 0);
> -    if (bios_size < 0) {
> -        /*
> -         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
> -         * ePAPR compliant kernel
> -         */
> -        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
> -                                  NULL, NULL);
> -        if (kernel_size < 0) {
> -            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
> +    dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
> +    if (dt_base + DTB_MAX_SIZE > ram_size) {
> +            fprintf(stderr, "qemu: not enough memory for device tree\n");
>              exit(1);
> -        }
>      }
> -    g_free(filename);
> -
> -    /* Reserve space for dtb */
> -    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
>  
>      dt_size = ppce500_prep_device_tree(machine, params, dt_base,
>                                         initrd_base, initrd_size,

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Engraf 6 years, 1 month ago
Am 02.03.2018 um 02:45 schrieb David Gibson:
> On Thu, Feb 15, 2018 at 10:36:00AM +0100, David Engraf wrote:
>> This patch fixes an incorrect behavior when the -kernel argument has been
>> specified without -bios. In this case the kernel was loaded twice. At address
>> 32M as a raw image and afterwards by load_elf/load_uimage at the
>> corresponding load address. In this case the region for the device tree and
>> the raw kernel image may overlap.
>>
>> The patch fixes the behavior by loading the kernel image once with
>> load_elf/load_uimage and skips loading the raw image.
>>
>> When here do not use bios_name/size for the kernel and use a more generic
>> name called payload_name/size.
>>
>> New in v3: dtb must be stored between kernel and initrd because Linux can
>>             handle the dtb only within the first 64MB. Add a comment to
>>             clarify the behavior.
>>
>> Signed-off-by: David Engraf <david.engraf@sysgo.com>
> 
> Sorry I've taken so long to reply to this.  It looks fine to me,
> however, other changes mean it longer quite applies to the
> ppc-for-2.12 tree.  Can you fix that up and repost please.

What other changes do you mean? In v3 I just restored the old behavior 
by putting the dtb right after the kernel image. This behavior has been 
changed by mistake in v1/v2. v3 now uses the correct storage location again.

Best regards
- David


> 
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> 
>> ---
>>   hw/ppc/e500.c | 116 +++++++++++++++++++++++++++++++++++-----------------------
>>   1 file changed, 70 insertions(+), 46 deletions(-)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index c4fe06ea2a..414c4beaab 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -784,8 +784,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>       int initrd_size = 0;
>>       hwaddr cur_base = 0;
>>       char *filename;
>> +    const char *payload_name;
>> +    bool kernel_as_payload;
>>       hwaddr bios_entry = 0;
>> -    target_long bios_size;
>> +    target_long payload_size;
>>       struct boot_info *boot_info;
>>       int dt_size;
>>       int i;
>> @@ -913,11 +915,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>       /* Register spinning region */
>>       sysbus_create_simple("e500-spin", params->spin_base, NULL);
>>   
>> -    if (cur_base < (32 * 1024 * 1024)) {
>> -        /* u-boot occupies memory up to 32MB, so load blobs above */
>> -        cur_base = (32 * 1024 * 1024);
>> -    }
>> -
>>       if (params->has_mpc8xxx_gpio) {
>>           qemu_irq poweroff_irq;
>>   
>> @@ -952,8 +949,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>                                       sysbus_mmio_get_region(s, 0));
>>       }
>>   
>> -    /* Load kernel. */
>> -    if (machine->kernel_filename) {
>> +    /*
>> +     * Smart firmware defaults ahead!
>> +     *
>> +     * We follow the following table to select which payload we execute.
>> +     *
>> +     *  -kernel | -bios | payload
>> +     * ---------+-------+---------
>> +     *     N    |   Y   | u-boot
>> +     *     N    |   N   | u-boot
>> +     *     Y    |   Y   | u-boot
>> +     *     Y    |   N   | kernel
>> +     *
>> +     * This ensures backwards compatibility with how we used to expose
>> +     * -kernel to users but allows them to run through u-boot as well.
>> +     */
>> +    kernel_as_payload = false;
>> +    if (bios_name == NULL) {
>> +        if (machine->kernel_filename) {
>> +            payload_name = machine->kernel_filename;
>> +            kernel_as_payload = true;
>> +        } else {
>> +            payload_name = "u-boot.e500";
>> +        }
>> +    } else {
>> +        payload_name = bios_name;
>> +    }
>> +
>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
>> +
>> +    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
>> +                            1, PPC_ELF_MACHINE, 0, 0);
>> +    if (payload_size < 0) {
>> +        /*
>> +         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
>> +         * ePAPR compliant kernel
>> +         */
>> +        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
>> +                                   NULL, NULL);
>> +        if (payload_size < 0) {
>> +            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
>> +            exit(1);
>> +        }
>> +    }
>> +
>> +    g_free(filename);
>> +
>> +    if (kernel_as_payload) {
>> +        kernel_base = loadaddr;
>> +        kernel_size = payload_size;
>> +    }
>> +
>> +    cur_base = loadaddr + payload_size;
>> +
>> +    /* Load bare kernel only if no bios/u-boot has been provided */
>> +    if (machine->kernel_filename && !kernel_as_payload) {
>>           kernel_base = cur_base;
>>           kernel_size = load_image_targphys(machine->kernel_filename,
>>                                             cur_base,
>> @@ -967,6 +1017,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>           cur_base += kernel_size;
>>       }
>>   
>> +    if (cur_base < (32 * 1024 * 1024)) {
>> +        /* u-boot occupies memory up to 32MB, so load blobs above */
>> +        cur_base = (32 * 1024 * 1024);
>> +    }
>> +
>>       /* Load initrd. */
>>       if (machine->initrd_filename) {
>>           initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
>> @@ -983,47 +1038,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>>       }
>>   
>>       /*
>> -     * Smart firmware defaults ahead!
>> -     *
>> -     * We follow the following table to select which payload we execute.
>> -     *
>> -     *  -kernel | -bios | payload
>> -     * ---------+-------+---------
>> -     *     N    |   Y   | u-boot
>> -     *     N    |   N   | u-boot
>> -     *     Y    |   Y   | u-boot
>> -     *     Y    |   N   | kernel
>> -     *
>> -     * This ensures backwards compatibility with how we used to expose
>> -     * -kernel to users but allows them to run through u-boot as well.
>> +     * Reserve space for dtb behind the kernel image because Linux has a bug
>> +     * where it can only handle the dtb if it's within the first 64MB of where
>> +     * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
>> +     * ensures enough space between kernel and initrd.
>>        */
>> -    if (bios_name == NULL) {
>> -        if (machine->kernel_filename) {
>> -            bios_name = machine->kernel_filename;
>> -        } else {
>> -            bios_name = "u-boot.e500";
>> -        }
>> -    }
>> -    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>> -
>> -    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
>> -                         1, PPC_ELF_MACHINE, 0, 0);
>> -    if (bios_size < 0) {
>> -        /*
>> -         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
>> -         * ePAPR compliant kernel
>> -         */
>> -        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
>> -                                  NULL, NULL);
>> -        if (kernel_size < 0) {
>> -            fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
>> +    dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
>> +    if (dt_base + DTB_MAX_SIZE > ram_size) {
>> +            fprintf(stderr, "qemu: not enough memory for device tree\n");
>>               exit(1);
>> -        }
>>       }
>> -    g_free(filename);
>> -
>> -    /* Reserve space for dtb */
>> -    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
>>   
>>       dt_size = ppce500_prep_device_tree(machine, params, dt_base,
>>                                          initrd_base, initrd_size,
> 

-- 
Mit freundlichen Grüßen/Best regards,

David Engraf
Product Engineer

SYSGO AG
Office Mainz
Am Pfaffenstein 14 / D-55270 Klein-Winternheim / Germany

Phone: +49-6136-9948-0 / Fax: +49-6136-9948-10
E-mail: david.engraf@sysgo.com
_________________________________________________________________________________

Web: https://www.sysgo.com
Blog: https://www.sysgo.com/blog
Events: https://www.sysgo.com/events
Newsletter: https://www.sysgo.com/newsletter
_________________________________________________________________________________

Handelsregister/Commercial Registry: HRB Mainz 90 HRB 8066
Vorstand/Executive Board: Etienne Butery (CEO), Kai Sablotny (COO)
Aufsichtsratsvorsitzender/Supervisory Board Chairman: Marc Darmon
USt-Id-Nr./VAT-Id-No.: DE 149062328

Re: [Qemu-devel] [Qemu-ppc] [PATCH v3] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by Mark Cave-Ayland 6 years, 1 month ago
On 02/03/18 08:53, David Engraf wrote:

> Am 02.03.2018 um 02:45 schrieb David Gibson:
>> On Thu, Feb 15, 2018 at 10:36:00AM +0100, David Engraf wrote:
>>> This patch fixes an incorrect behavior when the -kernel argument has 
>>> been
>>> specified without -bios. In this case the kernel was loaded twice. At 
>>> address
>>> 32M as a raw image and afterwards by load_elf/load_uimage at the
>>> corresponding load address. In this case the region for the device 
>>> tree and
>>> the raw kernel image may overlap.
>>>
>>> The patch fixes the behavior by loading the kernel image once with
>>> load_elf/load_uimage and skips loading the raw image.
>>>
>>> When here do not use bios_name/size for the kernel and use a more 
>>> generic
>>> name called payload_name/size.
>>>
>>> New in v3: dtb must be stored between kernel and initrd because Linux 
>>> can
>>>             handle the dtb only within the first 64MB. Add a comment to
>>>             clarify the behavior.
>>>
>>> Signed-off-by: David Engraf <david.engraf@sysgo.com>
>>
>> Sorry I've taken so long to reply to this.  It looks fine to me,
>> however, other changes mean it longer quite applies to the
>> ppc-for-2.12 tree.  Can you fix that up and repost please.
> 
> What other changes do you mean? In v3 I just restored the old behavior 
> by putting the dtb right after the kernel image. This behavior has been 
> changed by mistake in v1/v2. v3 now uses the correct storage location 
> again.

Hi David,

I think what David means is that when he tried to apply your v3 patch to 
his ppc-for-2.12 tree at 
https://github.com/dgibson/qemu/commits/ppc-for-2.12 using git-am then 
it failed - presumably because someone else has made other changes to 
that code since you submitted your v3 patch.

Please can you submit a v4 rebased on top of the current ppc-for-2.12 
branch?


ATB,

Mark.

Re: [Qemu-devel] [Qemu-ppc] [PATCH v3] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Engraf 6 years, 1 month ago
Am 02.03.2018 um 10:11 schrieb Mark Cave-Ayland:
> On 02/03/18 08:53, David Engraf wrote:
> 
>> Am 02.03.2018 um 02:45 schrieb David Gibson:
>>> On Thu, Feb 15, 2018 at 10:36:00AM +0100, David Engraf wrote:
>>>> This patch fixes an incorrect behavior when the -kernel argument has 
>>>> been
>>>> specified without -bios. In this case the kernel was loaded twice. 
>>>> At address
>>>> 32M as a raw image and afterwards by load_elf/load_uimage at the
>>>> corresponding load address. In this case the region for the device 
>>>> tree and
>>>> the raw kernel image may overlap.
>>>>
>>>> The patch fixes the behavior by loading the kernel image once with
>>>> load_elf/load_uimage and skips loading the raw image.
>>>>
>>>> When here do not use bios_name/size for the kernel and use a more 
>>>> generic
>>>> name called payload_name/size.
>>>>
>>>> New in v3: dtb must be stored between kernel and initrd because 
>>>> Linux can
>>>>             handle the dtb only within the first 64MB. Add a comment to
>>>>             clarify the behavior.
>>>>
>>>> Signed-off-by: David Engraf <david.engraf@sysgo.com>
>>>
>>> Sorry I've taken so long to reply to this.  It looks fine to me,
>>> however, other changes mean it longer quite applies to the
>>> ppc-for-2.12 tree.  Can you fix that up and repost please.
>>
>> What other changes do you mean? In v3 I just restored the old behavior 
>> by putting the dtb right after the kernel image. This behavior has 
>> been changed by mistake in v1/v2. v3 now uses the correct storage 
>> location again.
> 
> Hi David,
> 
> I think what David means is that when he tried to apply your v3 patch to 
> his ppc-for-2.12 tree at 
> https://github.com/dgibson/qemu/commits/ppc-for-2.12 using git-am then 
> it failed - presumably because someone else has made other changes to 
> that code since you submitted your v3 patch.
> 
> Please can you submit a v4 rebased on top of the current ppc-for-2.12 
> branch?

Hi Mark,

thanks for the info. I will provide an updated version.

Best regards
- David



[Qemu-devel] [PATCH v4] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Engraf 6 years, 1 month ago
This patch fixes an incorrect behavior when the -kernel argument has been
specified without -bios. In this case the kernel was loaded twice. At address
32M as a raw image and afterwards by load_elf/load_uimage at the
corresponding load address. In this case the region for the device tree and
the raw kernel image may overlap.

The patch fixes the behavior by loading the kernel image once with
load_elf/load_uimage and skips loading the raw image.

When here do not use bios_name/size for the kernel and use a more generic
name called payload_name/size.

New in v3: dtb must be stored between kernel and initrd because Linux can
           handle the dtb only within the first 64MB. Add a comment to
           clarify the behavior.

Signed-off-by: David Engraf <david.engraf@sysgo.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/e500.c | 116 +++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 70 insertions(+), 46 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index ef541a00be..43c15d18c4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -792,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     int initrd_size = 0;
     hwaddr cur_base = 0;
     char *filename;
+    const char *payload_name;
+    bool kernel_as_payload;
     hwaddr bios_entry = 0;
-    target_long bios_size;
+    target_long payload_size;
     struct boot_info *boot_info;
     int dt_size;
     int i;
@@ -921,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     /* Register spinning region */
     sysbus_create_simple("e500-spin", params->spin_base, NULL);
 
-    if (cur_base < (32 * 1024 * 1024)) {
-        /* u-boot occupies memory up to 32MB, so load blobs above */
-        cur_base = (32 * 1024 * 1024);
-    }
-
     if (params->has_mpc8xxx_gpio) {
         qemu_irq poweroff_irq;
 
@@ -960,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
                                     sysbus_mmio_get_region(s, 0));
     }
 
-    /* Load kernel. */
-    if (machine->kernel_filename) {
+    /*
+     * Smart firmware defaults ahead!
+     *
+     * We follow the following table to select which payload we execute.
+     *
+     *  -kernel | -bios | payload
+     * ---------+-------+---------
+     *     N    |   Y   | u-boot
+     *     N    |   N   | u-boot
+     *     Y    |   Y   | u-boot
+     *     Y    |   N   | kernel
+     *
+     * This ensures backwards compatibility with how we used to expose
+     * -kernel to users but allows them to run through u-boot as well.
+     */
+    kernel_as_payload = false;
+    if (bios_name == NULL) {
+        if (machine->kernel_filename) {
+            payload_name = machine->kernel_filename;
+            kernel_as_payload = true;
+        } else {
+            payload_name = "u-boot.e500";
+        }
+    } else {
+        payload_name = bios_name;
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
+
+    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
+                            1, PPC_ELF_MACHINE, 0, 0);
+    if (payload_size < 0) {
+        /*
+         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+         * ePAPR compliant kernel
+         */
+        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
+                                   NULL, NULL);
+        if (payload_size < 0) {
+            error_report("qemu: could not load firmware '%s'", filename);
+            exit(1);
+        }
+    }
+
+    g_free(filename);
+
+    if (kernel_as_payload) {
+        kernel_base = loadaddr;
+        kernel_size = payload_size;
+    }
+
+    cur_base = loadaddr + payload_size;
+
+    /* Load bare kernel only if no bios/u-boot has been provided */
+    if (machine->kernel_filename && !kernel_as_payload) {
         kernel_base = cur_base;
         kernel_size = load_image_targphys(machine->kernel_filename,
                                           cur_base,
@@ -975,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
         cur_base += kernel_size;
     }
 
+    if (cur_base < (32 * 1024 * 1024)) {
+        /* u-boot occupies memory up to 32MB, so load blobs above */
+        cur_base = (32 * 1024 * 1024);
+    }
+
     /* Load initrd. */
     if (machine->initrd_filename) {
         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@@ -991,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
     }
 
     /*
-     * Smart firmware defaults ahead!
-     *
-     * We follow the following table to select which payload we execute.
-     *
-     *  -kernel | -bios | payload
-     * ---------+-------+---------
-     *     N    |   Y   | u-boot
-     *     N    |   N   | u-boot
-     *     Y    |   Y   | u-boot
-     *     Y    |   N   | kernel
-     *
-     * This ensures backwards compatibility with how we used to expose
-     * -kernel to users but allows them to run through u-boot as well.
+     * Reserve space for dtb behind the kernel image because Linux has a bug
+     * where it can only handle the dtb if it's within the first 64MB of where
+     * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
+     * ensures enough space between kernel and initrd.
      */
-    if (bios_name == NULL) {
-        if (machine->kernel_filename) {
-            bios_name = machine->kernel_filename;
-        } else {
-            bios_name = "u-boot.e500";
-        }
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
-    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
-                         1, PPC_ELF_MACHINE, 0, 0);
-    if (bios_size < 0) {
-        /*
-         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
-         * ePAPR compliant kernel
-         */
-        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
-                                  NULL, NULL);
-        if (kernel_size < 0) {
-            error_report("could not load firmware '%s'", filename);
+    dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+    if (dt_base + DTB_MAX_SIZE > ram_size) {
+            error_report("qemu: not enough memory for device tree");
             exit(1);
-        }
     }
-    g_free(filename);
-
-    /* Reserve space for dtb */
-    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
 
     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
                                        initrd_base, initrd_size,
-- 
2.14.1


Re: [Qemu-devel] [PATCH v4] PPC: e500: Fix duplicate kernel load and device tree overlap
Posted by David Gibson 6 years, 1 month ago
On Fri, Mar 02, 2018 at 12:20:13PM +0100, David Engraf wrote:
> This patch fixes an incorrect behavior when the -kernel argument has been
> specified without -bios. In this case the kernel was loaded twice. At address
> 32M as a raw image and afterwards by load_elf/load_uimage at the
> corresponding load address. In this case the region for the device tree and
> the raw kernel image may overlap.
> 
> The patch fixes the behavior by loading the kernel image once with
> load_elf/load_uimage and skips loading the raw image.
> 
> When here do not use bios_name/size for the kernel and use a more generic
> name called payload_name/size.
> 
> New in v3: dtb must be stored between kernel and initrd because Linux can
>            handle the dtb only within the first 64MB. Add a comment to
>            clarify the behavior.
> 
> Signed-off-by: David Engraf <david.engraf@sysgo.com>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

Applied, thanks.

> ---
>  hw/ppc/e500.c | 116 +++++++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 70 insertions(+), 46 deletions(-)
> 
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index ef541a00be..43c15d18c4 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -792,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      int initrd_size = 0;
>      hwaddr cur_base = 0;
>      char *filename;
> +    const char *payload_name;
> +    bool kernel_as_payload;
>      hwaddr bios_entry = 0;
> -    target_long bios_size;
> +    target_long payload_size;
>      struct boot_info *boot_info;
>      int dt_size;
>      int i;
> @@ -921,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      /* Register spinning region */
>      sysbus_create_simple("e500-spin", params->spin_base, NULL);
>  
> -    if (cur_base < (32 * 1024 * 1024)) {
> -        /* u-boot occupies memory up to 32MB, so load blobs above */
> -        cur_base = (32 * 1024 * 1024);
> -    }
> -
>      if (params->has_mpc8xxx_gpio) {
>          qemu_irq poweroff_irq;
>  
> @@ -960,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>                                      sysbus_mmio_get_region(s, 0));
>      }
>  
> -    /* Load kernel. */
> -    if (machine->kernel_filename) {
> +    /*
> +     * Smart firmware defaults ahead!
> +     *
> +     * We follow the following table to select which payload we execute.
> +     *
> +     *  -kernel | -bios | payload
> +     * ---------+-------+---------
> +     *     N    |   Y   | u-boot
> +     *     N    |   N   | u-boot
> +     *     Y    |   Y   | u-boot
> +     *     Y    |   N   | kernel
> +     *
> +     * This ensures backwards compatibility with how we used to expose
> +     * -kernel to users but allows them to run through u-boot as well.
> +     */
> +    kernel_as_payload = false;
> +    if (bios_name == NULL) {
> +        if (machine->kernel_filename) {
> +            payload_name = machine->kernel_filename;
> +            kernel_as_payload = true;
> +        } else {
> +            payload_name = "u-boot.e500";
> +        }
> +    } else {
> +        payload_name = bios_name;
> +    }
> +
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
> +
> +    payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
> +                            1, PPC_ELF_MACHINE, 0, 0);
> +    if (payload_size < 0) {
> +        /*
> +         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
> +         * ePAPR compliant kernel
> +         */
> +        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
> +                                   NULL, NULL);
> +        if (payload_size < 0) {
> +            error_report("qemu: could not load firmware '%s'", filename);
> +            exit(1);
> +        }
> +    }
> +
> +    g_free(filename);
> +
> +    if (kernel_as_payload) {
> +        kernel_base = loadaddr;
> +        kernel_size = payload_size;
> +    }
> +
> +    cur_base = loadaddr + payload_size;
> +
> +    /* Load bare kernel only if no bios/u-boot has been provided */
> +    if (machine->kernel_filename && !kernel_as_payload) {
>          kernel_base = cur_base;
>          kernel_size = load_image_targphys(machine->kernel_filename,
>                                            cur_base,
> @@ -975,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>          cur_base += kernel_size;
>      }
>  
> +    if (cur_base < (32 * 1024 * 1024)) {
> +        /* u-boot occupies memory up to 32MB, so load blobs above */
> +        cur_base = (32 * 1024 * 1024);
> +    }
> +
>      /* Load initrd. */
>      if (machine->initrd_filename) {
>          initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
> @@ -991,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
>      }
>  
>      /*
> -     * Smart firmware defaults ahead!
> -     *
> -     * We follow the following table to select which payload we execute.
> -     *
> -     *  -kernel | -bios | payload
> -     * ---------+-------+---------
> -     *     N    |   Y   | u-boot
> -     *     N    |   N   | u-boot
> -     *     Y    |   Y   | u-boot
> -     *     Y    |   N   | kernel
> -     *
> -     * This ensures backwards compatibility with how we used to expose
> -     * -kernel to users but allows them to run through u-boot as well.
> +     * Reserve space for dtb behind the kernel image because Linux has a bug
> +     * where it can only handle the dtb if it's within the first 64MB of where
> +     * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
> +     * ensures enough space between kernel and initrd.
>       */
> -    if (bios_name == NULL) {
> -        if (machine->kernel_filename) {
> -            bios_name = machine->kernel_filename;
> -        } else {
> -            bios_name = "u-boot.e500";
> -        }
> -    }
> -    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> -
> -    bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
> -                         1, PPC_ELF_MACHINE, 0, 0);
> -    if (bios_size < 0) {
> -        /*
> -         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
> -         * ePAPR compliant kernel
> -         */
> -        kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
> -                                  NULL, NULL);
> -        if (kernel_size < 0) {
> -            error_report("could not load firmware '%s'", filename);
> +    dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
> +    if (dt_base + DTB_MAX_SIZE > ram_size) {
> +            error_report("qemu: not enough memory for device tree");
>              exit(1);
> -        }
>      }
> -    g_free(filename);
> -
> -    /* Reserve space for dtb */
> -    dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
>  
>      dt_size = ppce500_prep_device_tree(machine, params, dt_base,
>                                         initrd_base, initrd_size,

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson