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 | unsigned long kernel_size, kernel_memsize = 0; | 25 | unsigned long kernel_size, kernel_memsize = 0; |
| 26 | unsigned long nr_pages; | 26 | unsigned long nr_pages; |
| 27 | void *old_image_addr = (void *)*image_addr; | 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 | /* Relocate the image, if required. */ | 39 | /* Relocate the image, if required. */ |
| 30 | kernel_size = _edata - _text; | 40 | kernel_size = _edata - _text; |
| 31 | if (*image_addr != (dram_base + TEXT_OFFSET)) { | 41 | if (*image_addr != preferred_offset) { |
| 32 | kernel_memsize = kernel_size + (_end - _edata); | 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 | * Mustang), we can still place the kernel at the address | 52 | * Mustang), we can still place the kernel at the address |
| 43 | * 'dram_base + TEXT_OFFSET'. | 53 | * 'dram_base + TEXT_OFFSET'. |
| 44 | */ | 54 | */ |
| 45 | *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; | 55 | *image_addr = *reserve_addr = preferred_offset; |
| 46 | nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / | 56 | nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / |
| 47 | EFI_PAGE_SIZE; | 57 | EFI_PAGE_SIZE; |
| 48 | status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, | 58 | status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, |