On Thu, May 7, 2020 at 12:22 PM James Morse <james.morse@xxxxxxx> wrote: > > Hi Pavel, > > On 26/03/2020 03:24, Pavel Tatashin wrote: > > Currently, kexec relocation function (arm64_relocate_new_kernel) accepts > > the following arguments: > > > > head: start of array that contains relocation information. > > entry: entry point for new kernel or purgatory. > > dtb_mem: first and only argument to entry. > > > The number of arguments cannot be easily expended, because this > > function is also called from HVC_SOFT_RESTART, which preserves only > > three arguments. And, also arm64_relocate_new_kernel is written in > > assembly but called without stack, thus no place to move extra > > arguments to free registers. > > > > Soon, we will need to pass more arguments: once we enable MMU we > > will need to pass information about page tables. > > > > Another benefit of allowing this function to accept more arguments, is that > > kernel can actually accept up to 4 arguments (x0-x3), however currently > > only one is used, but if in the future we will need for more (for example, > > pass information about when previous kernel exited to have a precise > > measurement in time spent in purgatory), we won't be easilty do that > > if arm64_relocate_new_kernel can't accept more arguments. > > This is a niche debug hack. > We really don't want an ABI with purgatory. I think the register values it gets were added > early for compatibility with kexec_file_load(). > > > > So, add a new struct: kern_reloc_arg, and place it in kexec safe page (i.e > > memory that is not overwritten during relocation). > > Thus, make arm64_relocate_new_kernel to only take one argument, that > > contains all the needed information. > > Do we really not have enough registers? > > The PCS[0] gives you 8 arguments. In this patch you use 6. > > > If this is really about the hyp-stub abi, please state that. Yes, this is a hypervisor abi limitation. I will improve the commit log to state it clearly. > > diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c > > index cee3be586384..b1122eea627e 100644 > > --- a/arch/arm64/kernel/machine_kexec.c > > +++ b/arch/arm64/kernel/machine_kexec.c > > @@ -59,13 +60,35 @@ void machine_kexec_cleanup(struct kimage *kimage) > > > int machine_kexec_post_load(struct kimage *kimage) > > { > > void *reloc_code = page_to_virt(kimage->control_code_page); > > + struct kern_reloc_arg *kern_reloc_arg = kexec_page_alloc(kimage); > > + > > + if (!kern_reloc_arg) > > + return -ENOMEM; > > > > memcpy(reloc_code, arm64_relocate_new_kernel, > > arm64_relocate_new_kernel_size); > > kimage->arch.kern_reloc = __pa(reloc_code); > > + kimage->arch.kern_reloc_arg = __pa(kern_reloc_arg); > > + kern_reloc_arg->head = kimage->head; > > + kern_reloc_arg->entry_addr = kimage->start; > > + kern_reloc_arg->kern_arg0 = kimage->arch.dtb_mem; > > These kern_reloc_arg values are written via the cacheable linear map. > They are read in arm64_relocate_new_kernel() where the MMU is disabled an all memory > access are non-cacheable. > > To ensure you read the values you wrote, you must clean kern_reloc_arg to the PoC. Thank you for catching this, I added: __flush_dcache_area(kern_reloc_arg, sizeof (struct kern_reloc_arg));