The current arm64 Image relocation code in the UEFI stub assumes that the dram_base argument it receives is always a multiple of 2 MB. In reality, it is simply the lowest start address of all RAM entries in the UEFI memory map, which means it could be any multiple of 4 KB. Since the arm64 kernel Image needs to reside TEXT_OFFSET bytes beyond a 2 MB aligned base, or it will fail to boot, make sure we round dram_base to 2 MB before using it to calculate the relocation address.
Unified · Split
| @@ -25,10 +25,20 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, · 24 unmodified lines | ||
| 25 | 25 | unsigned long kernel_size, kernel_memsize = 0; |
| 26 | 26 | unsigned long nr_pages; |
| 27 | 27 | void *old_image_addr = (void *)*image_addr; |
| 28 | + unsigned long preferred_offset; | |
| 29 | + | |
| 30 | + /* | |
| 31 | + * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond | |
| 32 | + * a 2 MB aligned base, which itself may be lower than dram_base, as | |
| 33 | + * long as the resulting offset equals or exceeds it. | |
| 34 | + */ | |
| 35 | + preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET; | |
| 36 | + if (preferred_offset < dram_base) | |
| 37 | + preferred_offset += SZ_2M; | |
| 28 | 38 | |
| 29 | 39 | /* Relocate the image, if required. */ |
| 30 | 40 | kernel_size = _edata - _text; |
| 31 | − if (*image_addr != (dram_base + TEXT_OFFSET)) { | |
| 41 | + if (*image_addr != preferred_offset) { | |
| 32 | 42 | kernel_memsize = kernel_size + (_end - _edata); |
| 33 | 43 | |
| 34 | 44 | /* |
| @@ -42,7 +52,7 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, · 7 unmodified lines | ||
| 42 | 52 | * Mustang), we can still place the kernel at the address |
| 43 | 53 | * 'dram_base + TEXT_OFFSET'. |
| 44 | 54 | */ |
| 45 | − *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; | |
| 55 | + *image_addr = *reserve_addr = preferred_offset; | |
| 46 | 56 | nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / |
| 47 | 57 | EFI_PAGE_SIZE; |
| 48 | 58 | status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, |