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

Re: [XEN v6] xen/arm: Probe the load/entry point address of an uImage correctly



On Wed, 25 Jan 2023, Ayan Kumar Halder wrote:
> Currently, kernel_uimage_probe() does not read the load/entry point address
> set in the uImge header. Thus, info->zimage.start is 0 (default value). This
> causes, kernel_zimage_place() to treat the binary (contained within uImage)
> as position independent executable. Thus, it loads it at an incorrect
> address.
> 
> The correct approach would be to read "uimage.load" and set
> info->zimage.start. This will ensure that the binary is loaded at the
> correct address. Also, read "uimage.ep" and set info->entry (ie kernel entry
> address).
> 
> If user provides load address (ie "uimage.load") as 0x0, then the image is
> treated as position independent executable. Xen can load such an image at
> any address it considers appropriate. A position independent executable
> cannot have a fixed entry point address.
> 
> This behavior is applicable for both arm32 and arm64 platforms.
> 
> Earlier for arm32 and arm64 platforms, Xen was ignoring the load and entry
> point address set in the uImage header. With this commit, Xen will use them.
> This makes the behavior of Xen consistent with uboot for uimage headers.
> 
> Users who want to use Xen with statically partitioned domains, can provide
> non zero load address and entry address for the dom0/domU kernel. It is
> required that the load and entry address provided must be within the memory
> region allocated by Xen.
> 
> A deviation from uboot behaviour is that we consider load address == 0x0,
> to denote that the image supports position independent execution. This
> is to make the behavior consistent across uImage and zImage.
>
> Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@xxxxxxx>
> ---
> 
> Changes from v1 :-
> 1. Added a check to ensure load address and entry address are the same.
> 2. Considered load address == 0x0 as position independent execution.
> 3. Ensured that the uImage header interpretation is consistent across
> arm32 and arm64.
> 
> v2 :-
> 1. Mentioned the change in existing behavior in booting.txt.
> 2. Updated booting.txt with a new section to document "Booting Guests".
> 
> v3 :-
> 1. Removed the constraint that the entry point should be same as the load
> address. Thus, Xen uses both the load address and entry point to determine
> where the image is to be copied and the start address.
> 2. Updated documentation to denote that load address and start address
> should be within the memory region allocated by Xen.
> 3. Added constraint that user cannot provide entry point for a position
> independent executable (PIE) image.
> 
> v4 :-
> 1. Explicitly mentioned the version in booting.txt from when the uImage
> probing behavior has changed.
> 2. Logged the requested load address and entry point parsed from the uImage
> header.
> 3. Some style issues.
> 
> v5 :-
> 1. Set info->zimage.text_offset = 0 in kernel_uimage_probe().
> 2. Mention that if the kernel has a legacy image header on top of 
> zImage/zImage64
> header, then the attrbutes from legacy image header is used to determine the 
> load
> address, entry point, etc. Thus, zImage/zImage64 header is effectively 
> ignored.
> 
> This is true because Xen currently does not support recursive probing of 
> kernel
> headers ie if uImage header is probed, then Xen will not attempt to see if 
> there
> is an underlying zImage/zImage64 header.
> 
>  docs/misc/arm/booting.txt         | 30 ++++++++++++++++
>  xen/arch/arm/include/asm/kernel.h |  2 +-
>  xen/arch/arm/kernel.c             | 58 +++++++++++++++++++++++++++++--
>  3 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/docs/misc/arm/booting.txt b/docs/misc/arm/booting.txt
> index 3e0c03e065..1837579aef 100644
> --- a/docs/misc/arm/booting.txt
> +++ b/docs/misc/arm/booting.txt
> @@ -23,6 +23,32 @@ The exceptions to this on 32-bit ARM are as follows:
>  
>  There are no exception on 64-bit ARM.
>  
> +Booting Guests
> +--------------
> +
> +Xen supports the legacy image header[3], zImage protocol for 32-bit
> +ARM Linux[1] and Image protocol defined for ARM64[2].
> +
> +Until Xen 4.17, in case of legacy image protocol, Xen ignored the load
> +address and entry point specified in the header. This has now changed.
> +
> +Now, it loads the image at the load address provided in the header.
> +And the entry point is used as the kernel start address.
> +
> +A deviation from uboot is that, Xen treats "load address == 0x0" as
> +position independent execution (PIE). Thus, Xen will load such an image
> +at an address it considers appropriate. Also, user cannot specify the
> +entry point of a PIE image since the start address cennot be
> +predetermined.
> +
> +Users who want to use Xen with statically partitioned domains, can provide
> +the fixed non zero load address and start address for the dom0/domU kernel.
> +The load address and start address specified by the user in the header must
> +be within the memory region allocated by Xen.
> +
> +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 attrbutes of legacy image header 
> only
                                             ^ attributes                    ^ 
remove only

> +to determine the load address, entry point, etc.

Also add:

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

These few minor changes to the documentation can be done on commit:

Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>



>  Firmware/bootloader requirements
>  --------------------------------
> @@ -39,3 +65,7 @@ Latest version: 
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/t
>  
>  [2] linux/Documentation/arm64/booting.rst
>  Latest version: 
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/booting.rst
> +
> +[3] legacy format header
> +Latest version: 
> https://source.denx.de/u-boot/u-boot/-/blob/master/include/image.h#L315
> +https://linux.die.net/man/1/mkimage
> diff --git a/xen/arch/arm/include/asm/kernel.h 
> b/xen/arch/arm/include/asm/kernel.h
> index 5bb30c3f2f..4617cdc83b 100644
> --- a/xen/arch/arm/include/asm/kernel.h
> +++ b/xen/arch/arm/include/asm/kernel.h
> @@ -72,7 +72,7 @@ struct kernel_info {
>  #ifdef CONFIG_ARM_64
>              paddr_t text_offset; /* 64-bit Image only */
>  #endif
> -            paddr_t start; /* 32-bit zImage only */
> +            paddr_t start; /* Must be 0 for 64-bit Image */
>          } zimage;
>      };
>  };
> diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
> index 23b840ea9e..36081e73f1 100644
> --- a/xen/arch/arm/kernel.c
> +++ b/xen/arch/arm/kernel.c
> @@ -127,7 +127,7 @@ static paddr_t __init kernel_zimage_place(struct 
> kernel_info *info)
>      paddr_t load_addr;
>  
>  #ifdef CONFIG_ARM_64
> -    if ( info->type == DOMAIN_64BIT )
> +    if ( (info->type == DOMAIN_64BIT) && (info->zimage.start == 0) )
>          return info->mem.bank[0].start + info->zimage.text_offset;
>  #endif
>  
> @@ -162,7 +162,12 @@ static void __init kernel_zimage_load(struct kernel_info 
> *info)
>      void *kernel;
>      int rc;
>  
> -    info->entry = load_addr;
> +    /*
> +     * If the image does not have a fixed entry point, then use the load
> +     * address as the entry point.
> +     */
> +    if ( info->entry == 0 )
> +        info->entry = load_addr;
>  
>      place_modules(info, load_addr, load_addr + len);
>  
> @@ -223,10 +228,38 @@ static int __init kernel_uimage_probe(struct 
> kernel_info *info,
>      if ( len > size - sizeof(uimage) )
>          return -EINVAL;
>  
> +    info->zimage.start = be32_to_cpu(uimage.load);
> +    info->entry = be32_to_cpu(uimage.ep);
> +
> +    /*
> +     * While uboot considers 0x0 to be a valid load/start address, for Xen
> +     * to maintain parity with zImage, we consider 0x0 to denote position
> +     * independent image. That means Xen is free to load such an image at
> +     * any valid address.
> +     */
> +    if ( info->zimage.start == 0 )
> +        printk(XENLOG_INFO
> +               "No load address provided. Xen will decide where to load 
> it.\n");
> +    else
> +        printk(XENLOG_INFO
> +               "Provided load address: %"PRIpaddr" and entry address: 
> %"PRIpaddr"\n",
> +               info->zimage.start, info->entry);
> +
> +    /*
> +     * If the image supports position independent execution, then user cannot
> +     * provide an entry point as Xen will load such an image at any 
> appropriate
> +     * memory address. Thus, we need to return error.
> +     */
> +    if ( (info->zimage.start == 0) && (info->entry != 0) )
> +    {
> +        printk(XENLOG_ERR
> +               "Entry point cannot be non zero for PIE image.\n");
> +        return -EINVAL;
> +    }
> +
>      info->zimage.kernel_addr = addr + sizeof(uimage);
>      info->zimage.len = len;
>  
> -    info->entry = info->zimage.start;
>      info->load = kernel_zimage_load;
>  
>  #ifdef CONFIG_ARM_64
> @@ -242,6 +275,15 @@ static int __init kernel_uimage_probe(struct kernel_info 
> *info,
>          printk(XENLOG_ERR "Unsupported uImage arch type %d\n", uimage.arch);
>          return -EINVAL;
>      }
> +
> +    /*
> +     * If there is a uImage header, then we do not parse zImage or zImage64
> +     * header. In other words if the user provides a uImage header on top of
> +     * zImage or zImage64 header, Xen uses the attributes of uImage header 
> only.
> +     * Thus, Xen uses uimage.load attribute to determine the load address and
> +     * zimage.text_offset is ignored.
> +     */
> +    info->zimage.text_offset = 0;
>  #endif
>  
>      return 0;
> @@ -366,6 +408,7 @@ static int __init kernel_zimage64_probe(struct 
> kernel_info *info,
>      info->zimage.kernel_addr = addr;
>      info->zimage.len = end - start;
>      info->zimage.text_offset = zimage.text_offset;
> +    info->zimage.start = 0;
>  
>      info->load = kernel_zimage_load;
>  
> @@ -436,6 +479,15 @@ int __init kernel_probe(struct kernel_info *info,
>      u64 kernel_addr, initrd_addr, dtb_addr, size;
>      int rc;
>  
> +    /*
> +     * We need to initialize start to 0. This field may be populated during
> +     * kernel_xxx_probe() if the image has a fixed entry point (for e.g.
> +     * uimage.ep).
> +     * We will use this to determine if the image has a fixed entry point or
> +     * the load address should be used as the start address.
> +     */
> +    info->entry = 0;
> +
>      /* domain is NULL only for the hardware domain */
>      if ( domain == NULL )
>      {
> -- 
> 2.17.1
> 



 


Rackspace

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