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

Re: [Xen-devel] [PATCH v2 1/2] xen/arm: Rework the way to compute dom0 DTB base address



On 05/31/2013 12:45 PM, Ian Campbell wrote:

> On Thu, 2013-05-30 at 15:05 +0100, Julien Grall wrote:
>> If the DTB is loading right the after the kernel, on some setup, Linux will
>> overwrite the DTB during the decompression step.
>>
>> To be sure the DTB won't be overwritten by the decompression stage, load
>> the DTB near the end of the first memory bank and below 4Gib (if memory 
>> range is
>> greater).
>>
>> Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
>>
>> Changes in v2:
>>     - Align the DTB base address to 2Mib
>>     - Add dtb_check_overlap to check if the kernel will overlap the DTB
>>     - Fix typo
>> ---
>>  xen/arch/arm/domain_build.c |   51 
>> ++++++++++++++++++++++++++++++++++++++-----
>>  xen/arch/arm/kernel.c       |    2 ++
>>  xen/arch/arm/kernel.h       |    7 ++++++
>>  3 files changed, 54 insertions(+), 6 deletions(-)
>>
>> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
>> index b92c64b..515fabe 100644
>> --- a/xen/arch/arm/domain_build.c
>> +++ b/xen/arch/arm/domain_build.c
>> @@ -477,6 +477,7 @@ static int prepare_dtb(struct domain *d, struct 
>> kernel_info *kinfo)
>>      void *fdt;
>>      int new_size;
>>      int ret;
>> +    paddr_t end;
>>  
>>      kinfo->unassigned_mem = dom0_mem;
>>  
>> @@ -502,17 +503,25 @@ static int prepare_dtb(struct domain *d, struct 
>> kernel_info *kinfo)
>>          goto err;
>>  
>>      /*
>> -     * Put the device tree at the beginning of the first bank.  It
>> -     * must be below 4 GiB.
>> +     * DTB must be load below 4GiB and far enough to linux (Linux use
>                                                      ^from          ^uses
> 
>> +     * the space after it to decompress)
>> +     * Load the DTB at the end of the first bank or below 4Gib
>                                                    and below?
> 
> Perhaps clearer to write "Load the DTB at the end of the first bank,
> while ensure it is also below 4G"
>


Sound goods. I will send a new patch with this change.

>>       */
>> -    kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100;
>> -    if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) )
>> +    end = kinfo->mem.bank[0].start + kinfo->mem.bank[0].size;
>> +    end = MIN(1ull << 32, end);
>> +    kinfo->dtb_paddr = end - fdt_totalsize(kinfo->fdt);
>> +    /* Linux requires the address to be aligned to 2Mb */
> 
> Does it? I don't disagree with aligning it to 2MB but I'm sure that e.g.
> CONFIG_APPENDED_DTB handles the unaligned case (perhaps that is
> special)?


I didn't pay attention when I have replaced 4 bytes by 2Mb. Linux only
requires to have an address aligned to 4 bytes.

> 
>> +    kinfo->dtb_paddr &= ~((2 << 20) - 1);
>> +
>> +    if ( fdt_totalsize(kinfo->fdt) > end )
>>      {
>> -        printk("Not enough memory below 4 GiB for the device tree.");
>> +        printk(XENLOG_ERR "Not enough memory in the first bank for "
>> +               "the device tree.");
>>          ret = -FDT_ERR_XEN(EINVAL);
>>          goto err;
>>      }
>>  
>> +
>>      return 0;
>>  
>>    err:
>> @@ -521,9 +530,36 @@ static int prepare_dtb(struct domain *d, struct 
>> kernel_info *kinfo)
>>      return -EINVAL;
>>  }
>>  
>> +static int dtb_check_overlap(struct kernel_info *kinfo)
>> +{
>> +    paddr_t zimage_start = kinfo->zimage.load_addr;
>> +    paddr_t zimage_end = kinfo->zimage.load_addr + kinfo->zimage.len;
>> +    paddr_t dtb_start = kinfo->dtb_paddr;
>> +    paddr_t dtb_end = kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt);
>> +
>> +    /*
>> +     * Check the kernel won't overlap the kernel
>> +     * Only when it's a ZIMAGE
>> +     */
>> +    if ( kinfo->type != KERNEL_ZIMAGE )
>> +        return 0;
>> +
>> +    if ( !(MAX(zimage_start, dtb_end) < MIN(zimage_end, dtb_start)) )
>> +        return 0;
> 
> I had to draw quite a few pictures to convince myself this was right,
> and I'm still not entirely sure ;-)


In fact it's totally wrong :/. What about this check?

if ( (dtb_start < zimage_end) || (dtb_end < zimage_start) )

> 
>> +
>> +    printk(XENLOG_ERR "The kernel(0x%"PRIpaddr"-0x%"PRIpaddr
>> +           ") is overlapping the DTB(0x%"PRIpaddr"-0x%"PRIpaddr":\n",
> 
> Missing a closing ) on the DTB range. Also why the trailing ":"?


I planned to have a different sentence. I will replace the ":" by ")".

> 
>> +           zimage_start, zimage_end, dtb_start, dtb_end);
>> +    xfree(kinfo->fdt);
> 
> This seems like an odd place to free this.
> 
> Returning an error here is only going to cause us to give up and panic
> anyway. I'd suggest to just panic here directly and not bother
> propagating an error code.
> 
> Not really sure why construct_dom0 has a return code at all, instead of
> it (or the functions it calls) just panicing. But lets not worry about
> that now.
> 
>> +
>> +    return -EINVAL;
>> +}
>> +
>>  static void dtb_load(struct kernel_info *kinfo)
>>  {
>>      void * __user dtb_virt = (void * __user)(register_t)kinfo->dtb_paddr;
> 
> Blank line here please.
> 
>> +    printk("Loading dom0 DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
>> +           kinfo->dtb_paddr, kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt));
> 
>>  
>>      raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt));
>>      xfree(kinfo->fdt);
>> @@ -559,10 +595,13 @@ int construct_dom0(struct domain *d)
>>      if ( rc < 0 )
>>          return rc;
>>  
>> +    rc = dtb_check_overlap(&kinfo);
>> +    if ( rc < 0 )
>> +        return rc;
>> +
>>      /* The following loads use the domain's p2m */
>>      p2m_load_VTTBR(d);
>>  
>> -    kinfo.dtb_paddr = kinfo.zimage.load_addr + kinfo.zimage.len;
>>      kernel_load(&kinfo);
>>      dtb_load(&kinfo);
>>  
>> diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
>> index 8f4a60d..f8c8850 100644
>> --- a/xen/arch/arm/kernel.c
>> +++ b/xen/arch/arm/kernel.c
>> @@ -152,6 +152,7 @@ static int kernel_try_zimage_prepare(struct kernel_info 
>> *info,
>>  
>>      info->entry = info->zimage.load_addr;
>>      info->load = kernel_zimage_load;
>> +    info->type = KERNEL_ZIMAGE;
>>  
>>      return 0;
>>  }
>> @@ -193,6 +194,7 @@ static int kernel_try_elf_prepare(struct kernel_info 
>> *info,
>>       */
>>      info->entry = info->elf.parms.virt_entry;
>>      info->load = kernel_elf_load;
>> +    info->type = KERNEL_ELF;
>>  
>>      return 0;
>>  err:
>> diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h
>> index 1776a4d..b4ecd30 100644
>> --- a/xen/arch/arm/kernel.h
>> +++ b/xen/arch/arm/kernel.h
>> @@ -9,6 +9,12 @@
>>  #include <xen/libelf.h>
>>  #include <xen/device_tree.h>
>>  
>> +enum kernel_type
>> +{
>> +    KERNEL_ELF,
>> +    KERNEL_ZIMAGE,
>> +};
>> +
>>  struct kernel_info {
>>  #ifdef CONFIG_ARM_64
>>      enum domain_type type;
>> @@ -23,6 +29,7 @@ struct kernel_info {
>>  
>>      void *kernel_img;
>>      unsigned kernel_order;
>> +    enum kernel_type type;
>>  
>>      union {
>>          struct {
> 
> 



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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