[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 2/2] xen/arm: Add support for booting gzip compressed uImages





On 01/02/2023 09:48, Michal Orzel wrote:
Hi Julien,

Hi Michal,


On 31/01/2023 21:20, Julien Grall wrote:


Hi,

On 31/01/2023 15:13, Michal Orzel wrote:
At the moment, Xen does not support booting gzip compressed uImages.
This is because we are trying to decompress the kernel before probing
the u-boot header. This leads to a failure as the header always appears
at the top of the image (and therefore obscuring the gzip header).

Move the call to kernel_uimage_probe before kernel_decompress and make
the function self-containing by taking the following actions:
   - take a pointer to struct bootmodule as a parameter,
   - check the comp field of a u-boot header to determine compression type,
   - in case of compressed image, modify boot module start address and size
     by taking the header size into account and call kernel_decompress,
   - set up zimage.{kernel_addr,len} accordingly,
   - return -ENOENT in case of a u-boot header not found to distinguish it
     amongst other return values and make it the only case for falling
     through to try to probe other image types.

This is done to avoid splitting the uImage probing into 2 stages (executed
before and after decompression) which otherwise would be necessary to
properly update boot module start and size before decompression and
zimage.{kernel_addr,len} afterwards.

AFAIU, it would be possible to have a zImage/Image header embedded in
the uImage. So any reason to only handle a compressed binary?
Not sure if I understand you correctly as what you say is already supported.
The split or moving decompression is only needed in case of compressed uImage,
as u-boot header (not being part of compression) appears before gzip header.
This is not the case for zImage/Image header that is embedded into image
and gzip header is at the top.

[...]


In case of uImage added on top of zImage/Image, the load address/entry point 
are taken
from uImage header so basically the zImage/Image header is not parsed (this is
documented in our booting.txt).

This is the case I am talking about. I think we need to parrse zImage/Image because it may contain additional information about the placement (for instance Image has a field to indicate the real size in memory).


This patch makes the uImage compression works as the other combinations work 
fine already.
You can boot what you can already:
- zImage/Image
- compressed zImage/Image
- zImage/Image,raw with u-boot header
+ this patch allows to boot:
- compressed uImage (i.e. zImage/Image/raw compressed with u-boot header)



Remove the limitation from the booting.txt documentation.

Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
---
   docs/misc/arm/booting.txt |  3 ---
   xen/arch/arm/kernel.c     | 51 ++++++++++++++++++++++++++++++++++-----
   2 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/docs/misc/arm/booting.txt b/docs/misc/arm/booting.txt
index bd7bfe7f284a..02f7bb65ec6d 100644
--- a/docs/misc/arm/booting.txt
+++ b/docs/misc/arm/booting.txt
@@ -50,9 +50,6 @@ Also, it is to be noted that if user provides the legacy 
image header on
   top of zImage or Image header, then Xen uses the attributes of legacy
   image header to determine the load address, entry point, etc.

-Known limitation: compressed kernels with a uboot headers are not
-working.
-

   Firmware/bootloader requirements
   --------------------------------
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index 068fbf88e492..ea5f9618169e 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -265,11 +265,14 @@ static __init int kernel_decompress(struct bootmodule 
*mod)
   #define IH_ARCH_ARM             2       /* ARM          */
   #define IH_ARCH_ARM64           22      /* ARM64        */

+/* uImage Compression Types */
+#define IH_COMP_GZIP            1
+
   /*
    * Check if the image is a uImage and setup kernel_info
    */
   static int __init kernel_uimage_probe(struct kernel_info *info,
-                                      paddr_t addr, paddr_t size)
+                                      struct bootmodule *mod)
   {
       struct {
           __be32 magic;   /* Image Header Magic Number */
@@ -287,6 +290,8 @@ static int __init kernel_uimage_probe(struct kernel_info 
*info,
       } uimage;

       uint32_t len;
+    paddr_t addr = mod->start;
+    paddr_t size = mod->size;

       if ( size < sizeof(uimage) )
           return -EINVAL;
@@ -294,13 +299,21 @@ static int __init kernel_uimage_probe(struct kernel_info 
*info,
       copy_from_paddr(&uimage, addr, sizeof(uimage));

       if ( be32_to_cpu(uimage.magic) != UIMAGE_MAGIC )
-        return -EINVAL;
+        return -ENOENT;

       len = be32_to_cpu(uimage.size);

       if ( len > size - sizeof(uimage) )
           return -EINVAL;

+    /* Only gzip compression is supported. */
+    if ( uimage.comp && uimage.comp != IH_COMP_GZIP )
+    {
+        printk(XENLOG_ERR
+               "Unsupported uImage compression type %"PRIu8"\n", uimage.comp);
+        return -EOPNOTSUPP;
+    }
+
       info->zimage.start = be32_to_cpu(uimage.load);
       info->entry = be32_to_cpu(uimage.ep);

@@ -330,8 +343,26 @@ static int __init kernel_uimage_probe(struct kernel_info 
*info,
           return -EINVAL;
       }

-    info->zimage.kernel_addr = addr + sizeof(uimage);
-    info->zimage.len = len;
+    if ( uimage.comp )
+    {
+        int rc;
+
+        /* Prepare start and size for decompression. */
+        mod->start += sizeof(uimage);
+        mod->size -= sizeof(uimage);

kernel_decompress() will free the compressed module once it is
decompressed. By updating the region it means the free page will be not
be freed (assuming start was previously page-aligned).
Ok, so the start address was previously page-aligned and by adding the uimage 
size
to it, it is no longer aligned. True. Do I understand you correctly that you 
refer
to the fw_unreserved_regions call from kernel_decompress where we will pass 
unaligned
address?

Correct.

This could be solved by doing (not harmful in my opinion for common case)
addr &= PAGE_MASK.
I don't quite understand your argument here. We need a check that work for everyone (not only in the common case).

Cheers,

--
Julien Grall



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.