Patchwork [1/2] hw/loader: Support ramdisk with u-boot header

login
register
mail settings
Submitter Soren Brinkmann
Date June 14, 2013, 4:36 p.m.
Message ID <1371227783-23086-2-git-send-email-soren.brinkmann@xilinx.com>
Download mbox | patch
Permalink /patch/251459/
State New
Headers show

Comments

Soren Brinkmann - June 14, 2013, 4:36 p.m.
Introduce 'load_ramdisk()' which can load "normal" ramdisks and ramdisks
with a u-boot header.
To enable this and leverage synergies 'load_uimage()' is refactored to
accomodate this additional use case.

Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
---
 hw/core/loader.c    | 86 +++++++++++++++++++++++++++++++++++++----------------
 include/hw/loader.h |  1 +
 2 files changed, 61 insertions(+), 26 deletions(-)
Peter Maydell - June 14, 2013, 4:56 p.m.
On 14 June 2013 17:36, Soren Brinkmann <soren.brinkmann@xilinx.com> wrote:
> Introduce 'load_ramdisk()' which can load "normal" ramdisks and ramdisks
> with a u-boot header.
> To enable this and leverage synergies 'load_uimage()' is refactored to
> accomodate this additional use case.

Hi; thanks for this patch; some review comments below.

>
> Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
> ---
>  hw/core/loader.c    | 86 +++++++++++++++++++++++++++++++++++++----------------
>  include/hw/loader.h |  1 +
>  2 files changed, 61 insertions(+), 26 deletions(-)
>
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index 7507914..e72d682 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -434,15 +434,17 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
>  }
>
>  /* Load a U-Boot image.  */
> -int load_uimage(const char *filename, hwaddr *ep,
> -                hwaddr *loadaddr, int *is_linux)
> +static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
> +                            int *is_linux)
>  {
>      int fd;
>      int size;
> +    hwaddr address;
>      uboot_image_header_t h;
>      uboot_image_header_t *hdr = &h;
>      uint8_t *data = NULL;
>      int ret = -1;
> +    int do_uncompress = 0;
>
>      fd = open(filename, O_RDONLY | O_BINARY);
>      if (fd < 0)
> @@ -458,31 +460,48 @@ int load_uimage(const char *filename, hwaddr *ep,
>          goto out;
>
>      /* TODO: Implement other image types.  */

Doesn't this patch fix this TODO item?

> -    if (hdr->ih_type != IH_TYPE_KERNEL) {
> -        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
> -        goto out;
> -    }
> +    switch (hdr->ih_type) {
> +    case IH_TYPE_KERNEL:
> +        address = hdr->ih_load;
> +        if (loadaddr) {
> +            *loadaddr = hdr->ih_load;
> +        }
> +
> +        switch (hdr->ih_comp) {
> +        case IH_COMP_NONE:
> +            break;
> +        case IH_COMP_GZIP:
> +            do_uncompress = 1;
> +            break;
> +        default:
> +            fprintf(stderr,
> +                    "Unable to load u-boot images with compression type %d\n",
> +                    hdr->ih_comp);
> +            goto out;
> +        }
> +
> +        if (ep) {
> +            *ep = hdr->ih_ep;
> +        }
>
> -    switch (hdr->ih_comp) {
> -    case IH_COMP_NONE:
> -    case IH_COMP_GZIP:
> +        /* TODO: Check CPU type.  */
> +        if (is_linux) {
> +            if (hdr->ih_os == IH_OS_LINUX) {
> +                *is_linux = 1;
> +            } else {
> +                *is_linux = 0;
> +            }
> +        }
> +
> +        break;
> +    case IH_TYPE_RAMDISK:
> +        address = *loadaddr;
>          break;
>      default:
> -        fprintf(stderr,
> -                "Unable to load u-boot images with compression type %d\n",
> -                hdr->ih_comp);
> +        fprintf(stderr, "Unsupported u-boot image type\n");

You could include the type byte here, the way we do for
unknown compression types.

>          goto out;
>      }
>
> -    /* TODO: Check CPU type.  */
> -    if (is_linux) {
> -        if (hdr->ih_os == IH_OS_LINUX)
> -            *is_linux = 1;
> -        else
> -            *is_linux = 0;
> -    }
> -
> -    *ep = hdr->ih_ep;
>      data = g_malloc(hdr->ih_size);
>
>      if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
> @@ -490,7 +509,7 @@ int load_uimage(const char *filename, hwaddr *ep,
>          goto out;
>      }
>
> -    if (hdr->ih_comp == IH_COMP_GZIP) {
> +    if (do_uncompress) {
>          uint8_t *compressed_data;
>          size_t max_bytes;
>          ssize_t bytes;
> @@ -508,10 +527,7 @@ int load_uimage(const char *filename, hwaddr *ep,
>          hdr->ih_size = bytes;
>      }
>
> -    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
> -
> -    if (loadaddr)
> -        *loadaddr = hdr->ih_load;
> +    rom_add_blob_fixed(filename, data, hdr->ih_size, address);
>
>      ret = hdr->ih_size;
>
> @@ -522,6 +538,24 @@ out:
>      return ret;
>  }
>
> +int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
> +                int *is_linux)
> +{
> +    return load_uboot_image(filename, ep, loadaddr, is_linux);
> +}
> +
> +/* Load a ramdisk.  */
> +int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
> +{
> +    int size = load_uboot_image(filename, NULL, &addr, NULL);
> +
> +    if (size < 0) {
> +        size = load_image_targphys(filename, addr, max_sz);
> +    }

So I can sort of see why we end up this way, but it's a bit
asymmetric that we handle 'uimage or raw' ramdisk at this
level, but require the caller to do it for the kernel.

> +
> +    return size;
> +}

If we're providing separate functions for kernel and
ramdisk loading shouldn't they check that the uimage
has the appropriate type?

> +
>  /*
>   * Functions for reboot-persistent memory regions.
>   *  - used for vga bios and option roms.
> diff --git a/include/hw/loader.h b/include/hw/loader.h
> index 0958f06..8ef403e 100644
> --- a/include/hw/loader.h
> +++ b/include/hw/loader.h
> @@ -15,6 +15,7 @@ int load_aout(const char *filename, hwaddr addr, int max_sz,
>                int bswap_needed, hwaddr target_page_size);
>  int load_uimage(const char *filename, hwaddr *ep,
>                  hwaddr *loadaddr, int *is_linux);
> +int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz);

Since this is a new function, it should have a suitably
formatted documentation comment. (the extract and deposit
functions at the bottom of include/qemu/bitops.h are the
examples of the format that I usually crib from.)

thanks
-- PMM
Soren Brinkmann - June 14, 2013, 5:14 p.m.
Hi Peter,

On Fri, Jun 14, 2013 at 05:56:31PM +0100, Peter Maydell wrote:
> On 14 June 2013 17:36, Soren Brinkmann <soren.brinkmann@xilinx.com> wrote:
> > Introduce 'load_ramdisk()' which can load "normal" ramdisks and ramdisks
> > with a u-boot header.
> > To enable this and leverage synergies 'load_uimage()' is refactored to
> > accomodate this additional use case.
> 
> Hi; thanks for this patch; some review comments below.
> 
> >
> > Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
> > ---
> >  hw/core/loader.c    | 86 +++++++++++++++++++++++++++++++++++++----------------
> >  include/hw/loader.h |  1 +
> >  2 files changed, 61 insertions(+), 26 deletions(-)
> >
> > diff --git a/hw/core/loader.c b/hw/core/loader.c
> > index 7507914..e72d682 100644
> > --- a/hw/core/loader.c
> > +++ b/hw/core/loader.c
> > @@ -434,15 +434,17 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
> >  }
> >
> >  /* Load a U-Boot image.  */
> > -int load_uimage(const char *filename, hwaddr *ep,
> > -                hwaddr *loadaddr, int *is_linux)
> > +static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
> > +                            int *is_linux)
> >  {
> >      int fd;
> >      int size;
> > +    hwaddr address;
> >      uboot_image_header_t h;
> >      uboot_image_header_t *hdr = &h;
> >      uint8_t *data = NULL;
> >      int ret = -1;
> > +    int do_uncompress = 0;
> >
> >      fd = open(filename, O_RDONLY | O_BINARY);
> >      if (fd < 0)
> > @@ -458,31 +460,48 @@ int load_uimage(const char *filename, hwaddr *ep,
> >          goto out;
> >
> >      /* TODO: Implement other image types.  */
> 
> Doesn't this patch fix this TODO item?
Well, partly. There are a couple of more image types which are still
not supported. So, I didnt' bother touching this comment just because
this adds support for a second out of 10 or something types.

> 
> > -    if (hdr->ih_type != IH_TYPE_KERNEL) {
> > -        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
> > -        goto out;
> > -    }
> > +    switch (hdr->ih_type) {
> > +    case IH_TYPE_KERNEL:
> > +        address = hdr->ih_load;
> > +        if (loadaddr) {
> > +            *loadaddr = hdr->ih_load;
> > +        }
> > +
> > +        switch (hdr->ih_comp) {
> > +        case IH_COMP_NONE:
> > +            break;
> > +        case IH_COMP_GZIP:
> > +            do_uncompress = 1;
> > +            break;
> > +        default:
> > +            fprintf(stderr,
> > +                    "Unable to load u-boot images with compression type %d\n",
> > +                    hdr->ih_comp);
> > +            goto out;
> > +        }
> > +
> > +        if (ep) {
> > +            *ep = hdr->ih_ep;
> > +        }
> >
> > -    switch (hdr->ih_comp) {
> > -    case IH_COMP_NONE:
> > -    case IH_COMP_GZIP:
> > +        /* TODO: Check CPU type.  */
> > +        if (is_linux) {
> > +            if (hdr->ih_os == IH_OS_LINUX) {
> > +                *is_linux = 1;
> > +            } else {
> > +                *is_linux = 0;
> > +            }
> > +        }
> > +
> > +        break;
> > +    case IH_TYPE_RAMDISK:
> > +        address = *loadaddr;
> >          break;
> >      default:
> > -        fprintf(stderr,
> > -                "Unable to load u-boot images with compression type %d\n",
> > -                hdr->ih_comp);
> > +        fprintf(stderr, "Unsupported u-boot image type\n");
> 
> You could include the type byte here, the way we do for
> unknown compression types.
good call. I'll add that.

> 
> >          goto out;
> >      }
> >
> > -    /* TODO: Check CPU type.  */
> > -    if (is_linux) {
> > -        if (hdr->ih_os == IH_OS_LINUX)
> > -            *is_linux = 1;
> > -        else
> > -            *is_linux = 0;
> > -    }
> > -
> > -    *ep = hdr->ih_ep;
> >      data = g_malloc(hdr->ih_size);
> >
> >      if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
> > @@ -490,7 +509,7 @@ int load_uimage(const char *filename, hwaddr *ep,
> >          goto out;
> >      }
> >
> > -    if (hdr->ih_comp == IH_COMP_GZIP) {
> > +    if (do_uncompress) {
> >          uint8_t *compressed_data;
> >          size_t max_bytes;
> >          ssize_t bytes;
> > @@ -508,10 +527,7 @@ int load_uimage(const char *filename, hwaddr *ep,
> >          hdr->ih_size = bytes;
> >      }
> >
> > -    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
> > -
> > -    if (loadaddr)
> > -        *loadaddr = hdr->ih_load;
> > +    rom_add_blob_fixed(filename, data, hdr->ih_size, address);
> >
> >      ret = hdr->ih_size;
> >
> > @@ -522,6 +538,24 @@ out:
> >      return ret;
> >  }
> >
> > +int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
> > +                int *is_linux)
> > +{
> > +    return load_uboot_image(filename, ep, loadaddr, is_linux);
> > +}
> > +
> > +/* Load a ramdisk.  */
> > +int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
> > +{
> > +    int size = load_uboot_image(filename, NULL, &addr, NULL);
> > +
> > +    if (size < 0) {
> > +        size = load_image_targphys(filename, addr, max_sz);
> > +    }
> 
> So I can sort of see why we end up this way, but it's a bit
> asymmetric that we handle 'uimage or raw' ramdisk at this
> level, but require the caller to do it for the kernel.
I agree it's not symmetric. The question is: Leaving this as is and hope
somebody changes the kernel loading. Or should this be changed with
having the "normal" ramdisk fallback at caller level?
I like this solution better, but well, that's probably just me.

> 
> > +
> > +    return size;
> > +}
> 
> If we're providing separate functions for kernel and
> ramdisk loading shouldn't they check that the uimage
> has the appropriate type?
I'm not sure I understand what you mean here. Moving the check for the
appropriate u-boot header type down here? I tried to find some
reasonable way to further split the load_uboot_image() routine to move
some of it's functionality into the two functions down here. But it all
seemed pretty messy and I left pretty much all functionality in
load_uboot_image() and just pass errors through.

> 
> > +
> >  /*
> >   * Functions for reboot-persistent memory regions.
> >   *  - used for vga bios and option roms.
> > diff --git a/include/hw/loader.h b/include/hw/loader.h
> > index 0958f06..8ef403e 100644
> > --- a/include/hw/loader.h
> > +++ b/include/hw/loader.h
> > @@ -15,6 +15,7 @@ int load_aout(const char *filename, hwaddr addr, int max_sz,
> >                int bswap_needed, hwaddr target_page_size);
> >  int load_uimage(const char *filename, hwaddr *ep,
> >                  hwaddr *loadaddr, int *is_linux);
> > +int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz);
> 
> Since this is a new function, it should have a suitably
> formatted documentation comment. (the extract and deposit
> functions at the bottom of include/qemu/bitops.h are the
> examples of the format that I usually crib from.)
Okay, I'll have a look at those.

	Sören
Peter Maydell - June 14, 2013, 5:36 p.m.
On 14 June 2013 18:14, Sören Brinkmann <soren.brinkmann@xilinx.com> wrote:
> On Fri, Jun 14, 2013 at 05:56:31PM +0100, Peter Maydell wrote:
>> If we're providing separate functions for kernel and
>> ramdisk loading shouldn't they check that the uimage
>> has the appropriate type?
> I'm not sure I understand what you mean here. Moving the check for the
> appropriate u-boot header type down here? I tried to find some
> reasonable way to further split the load_uboot_image() routine to move
> some of it's functionality into the two functions down here. But it all
> seemed pretty messy and I left pretty much all functionality in
> load_uboot_image() and just pass errors through.

I had in mind that these functions should pass the "expected"
type byte in to the load_uboot_image() function so it can
fail if the blob it is passed isn't actually the right type
(eg you pass the kernel to -initrd and vice-versa).

thanks
-- PMM
Soren Brinkmann - June 14, 2013, 5:42 p.m.
On Fri, Jun 14, 2013 at 06:36:06PM +0100, Peter Maydell wrote:
> On 14 June 2013 18:14, Sören Brinkmann <soren.brinkmann@xilinx.com> wrote:
> > On Fri, Jun 14, 2013 at 05:56:31PM +0100, Peter Maydell wrote:
> >> If we're providing separate functions for kernel and
> >> ramdisk loading shouldn't they check that the uimage
> >> has the appropriate type?
> > I'm not sure I understand what you mean here. Moving the check for the
> > appropriate u-boot header type down here? I tried to find some
> > reasonable way to further split the load_uboot_image() routine to move
> > some of it's functionality into the two functions down here. But it all
> > seemed pretty messy and I left pretty much all functionality in
> > load_uboot_image() and just pass errors through.
> 
> I had in mind that these functions should pass the "expected"
> type byte in to the load_uboot_image() function so it can
> fail if the blob it is passed isn't actually the right type
> (eg you pass the kernel to -initrd and vice-versa).
Thanks for the clarification. I agree. I'll add such a check.

	Sören
Peter Crosthwaite - June 18, 2013, 11:22 p.m.
Hi Soren,

On Sat, Jun 15, 2013 at 3:14 AM, Sören Brinkmann
<soren.brinkmann@xilinx.com> wrote:
> Hi Peter,
>
> On Fri, Jun 14, 2013 at 05:56:31PM +0100, Peter Maydell wrote:
>> On 14 June 2013 17:36, Soren Brinkmann <soren.brinkmann@xilinx.com> wrote:
>> > Introduce 'load_ramdisk()' which can load "normal" ramdisks and ramdisks
>> > with a u-boot header.
>> > To enable this and leverage synergies 'load_uimage()' is refactored to
>> > accomodate this additional use case.
[snip]
>> > +int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
>> > +                int *is_linux)
>> > +{
>> > +    return load_uboot_image(filename, ep, loadaddr, is_linux);
>> > +}
>> > +
>> > +/* Load a ramdisk.  */
>> > +int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
>> > +{
>> > +    int size = load_uboot_image(filename, NULL, &addr, NULL);
>> > +
>> > +    if (size < 0) {
>> > +        size = load_image_targphys(filename, addr, max_sz);
>> > +    }
>>
>> So I can sort of see why we end up this way, but it's a bit
>> asymmetric that we handle 'uimage or raw' ramdisk at this
>> level, but require the caller to do it for the kernel.
> I agree it's not symmetric. The question is: Leaving this as is and hope
> somebody changes the kernel loading. Or should this be changed with
> having the "normal" ramdisk fallback at caller level?
> I like this solution better, but well, that's probably just me.
>

I prefer the symmetric approach, The if-else logic on image types is a
board/arch specific policy (even though it arguably shouldn't be).
Fixing this I think is best left to when we get around to doing a
bootloader overhaul. Can we just drop this if and push the targphys
fallback to the arch bootloaders?

Regards,
Peter

Patch

diff --git a/hw/core/loader.c b/hw/core/loader.c
index 7507914..e72d682 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -434,15 +434,17 @@  static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
 }
 
 /* Load a U-Boot image.  */
-int load_uimage(const char *filename, hwaddr *ep,
-                hwaddr *loadaddr, int *is_linux)
+static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+                            int *is_linux)
 {
     int fd;
     int size;
+    hwaddr address;
     uboot_image_header_t h;
     uboot_image_header_t *hdr = &h;
     uint8_t *data = NULL;
     int ret = -1;
+    int do_uncompress = 0;
 
     fd = open(filename, O_RDONLY | O_BINARY);
     if (fd < 0)
@@ -458,31 +460,48 @@  int load_uimage(const char *filename, hwaddr *ep,
         goto out;
 
     /* TODO: Implement other image types.  */
-    if (hdr->ih_type != IH_TYPE_KERNEL) {
-        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
-        goto out;
-    }
+    switch (hdr->ih_type) {
+    case IH_TYPE_KERNEL:
+        address = hdr->ih_load;
+        if (loadaddr) {
+            *loadaddr = hdr->ih_load;
+        }
+
+        switch (hdr->ih_comp) {
+        case IH_COMP_NONE:
+            break;
+        case IH_COMP_GZIP:
+            do_uncompress = 1;
+            break;
+        default:
+            fprintf(stderr,
+                    "Unable to load u-boot images with compression type %d\n",
+                    hdr->ih_comp);
+            goto out;
+        }
+
+        if (ep) {
+            *ep = hdr->ih_ep;
+        }
 
-    switch (hdr->ih_comp) {
-    case IH_COMP_NONE:
-    case IH_COMP_GZIP:
+        /* TODO: Check CPU type.  */
+        if (is_linux) {
+            if (hdr->ih_os == IH_OS_LINUX) {
+                *is_linux = 1;
+            } else {
+                *is_linux = 0;
+            }
+        }
+
+        break;
+    case IH_TYPE_RAMDISK:
+        address = *loadaddr;
         break;
     default:
-        fprintf(stderr,
-                "Unable to load u-boot images with compression type %d\n",
-                hdr->ih_comp);
+        fprintf(stderr, "Unsupported u-boot image type\n");
         goto out;
     }
 
-    /* TODO: Check CPU type.  */
-    if (is_linux) {
-        if (hdr->ih_os == IH_OS_LINUX)
-            *is_linux = 1;
-        else
-            *is_linux = 0;
-    }
-
-    *ep = hdr->ih_ep;
     data = g_malloc(hdr->ih_size);
 
     if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
@@ -490,7 +509,7 @@  int load_uimage(const char *filename, hwaddr *ep,
         goto out;
     }
 
-    if (hdr->ih_comp == IH_COMP_GZIP) {
+    if (do_uncompress) {
         uint8_t *compressed_data;
         size_t max_bytes;
         ssize_t bytes;
@@ -508,10 +527,7 @@  int load_uimage(const char *filename, hwaddr *ep,
         hdr->ih_size = bytes;
     }
 
-    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
-
-    if (loadaddr)
-        *loadaddr = hdr->ih_load;
+    rom_add_blob_fixed(filename, data, hdr->ih_size, address);
 
     ret = hdr->ih_size;
 
@@ -522,6 +538,24 @@  out:
     return ret;
 }
 
+int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+                int *is_linux)
+{
+    return load_uboot_image(filename, ep, loadaddr, is_linux);
+}
+
+/* Load a ramdisk.  */
+int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
+{
+    int size = load_uboot_image(filename, NULL, &addr, NULL);
+
+    if (size < 0) {
+        size = load_image_targphys(filename, addr, max_sz);
+    }
+
+    return size;
+}
+
 /*
  * Functions for reboot-persistent memory regions.
  *  - used for vga bios and option roms.
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 0958f06..8ef403e 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -15,6 +15,7 @@  int load_aout(const char *filename, hwaddr addr, int max_sz,
               int bswap_needed, hwaddr target_page_size);
 int load_uimage(const char *filename, hwaddr *ep,
                 hwaddr *loadaddr, int *is_linux);
+int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz);
 
 ssize_t read_targphys(const char *name,
                       int fd, hwaddr dst_addr, size_t nbytes);