On 6/1/20 9:53 PM, Michael Walle wrote: > On ARM64, a 64kb region is reserved for the runtime services code. > Unfortunately, this code overlaps with the spin table code, which also > needs to be reserved. Thus now that the code is relocatable, allocate a > new page from EFI, copy the spin table code into it, update any pointers > to the old region and the start the secondary CPUs. > > Signed-off-by: Michael Walle <mich...@walle.cc> > --- > arch/arm/cpu/armv8/fsl-layerscape/mp.c | 36 ++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c > b/arch/arm/cpu/armv8/fsl-layerscape/mp.c > index d50c5a437b..bd85351705 100644 > --- a/arch/arm/cpu/armv8/fsl-layerscape/mp.c > +++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c > @@ -79,6 +79,10 @@ int fsl_layerscape_wake_seconday_cores(void) > u32 cores, cpu_up_mask = 1; > int i, timeout = 10; > u64 *table; > +#ifdef CONFIG_EFI_LOADER > + u64 reloc_addr = U32_MAX; > + efi_status_t ret; > +#endif > > #ifdef COUNTER_FREQUENCY_REAL > /* update for secondary cores */ > @@ -87,6 +91,38 @@ int fsl_layerscape_wake_seconday_cores(void) > (unsigned long)&__real_cntfrq + 8); > #endif > > +#ifdef CONFIG_EFI_LOADER > + /* > + * EFI will reserve 64kb for its runtime services. This will probably > + * overlap with our spin table code, which is why we have to relocate > + * it. > + * Keep this after the __real_cntfrq update, so we have it when we > + * copy the complete section here. > + */ > + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, > + EFI_RESERVED_MEMORY_TYPE, > + efi_size_in_pages(secondary_boot_code_size), > + &reloc_addr); > + if (ret == EFI_SUCCESS) { > + debug("Relocating spin table from %llx to %llx (size %lx)\n", > + (u64)secondary_boot_code_start, reloc_addr, > + secondary_boot_code_size); > + memcpy((void *)reloc_addr, secondary_boot_code_start, > + secondary_boot_code_size); > + flush_dcache_range(reloc_addr, > + reloc_addr + secondary_boot_code_size); > + > + /* set new entry point for secondary cores */ > + secondary_boot_addr += (void *)reloc_addr - > + secondary_boot_code_start; > + flush_dcache_range((unsigned long)&secondary_boot_addr, > + (unsigned long)&secondary_boot_addr + 8);
Wouldn't you want to flush the complete target range of memcpy() and afterwards call invalidate_icache_all(). At least this is what we do in other cases after copying instructions. Cf. efi_runtime_relocate(). Best regards Heinrich > + > + /* this will be used to reserve the memory */ > + secondary_boot_code_start = (void *)reloc_addr; > + } > +#endif > + > cores = cpu_mask(); > /* Clear spin table so that secondary processors > * observe the correct value after waking up from wfe. >