diff --git a/docs/misc/arm/booting.txt b/docs/misc/arm/booting.txt index 3e0c03e065..bd7bfe7f28 100644 --- a/docs/misc/arm/booting.txt +++ b/docs/misc/arm/booting.txt @@ -23,6 +23,36 @@ 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 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 -------------------------------- @@ -39,3 +69,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 ) {