Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: Work around convergence issue with LLD linker

LLD will occasionally error out with a '__init_end does not converge'
error if INIT_IDMAP_DIR_SIZE is defined in terms of _end, as this
results in a circular dependency.

Counter this by dimensioning the initial IDMAP page tables based on a
new boundary marker 'kimage_limit', and define it such that its value
should not change as a result of the initdata segment being pushed over
a 64k segment boundary due to changes in INIT_IDMAP_DIR_SIZE, provided
that its value doesn't change by more than 2M between linker passes.

Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20250531123005.3866382-2-ardb+git@google.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Ard Biesheuvel and committed by
Will Deacon
dc0a0839 e21560b7

+12 -1
+1 -1
arch/arm64/include/asm/kernel-pgtable.h
··· 58 58 #define INIT_DIR_SIZE (PAGE_SIZE * (EARLY_PAGES(SWAPPER_PGTABLE_LEVELS, KIMAGE_VADDR, _end, EXTRA_PAGE) \ 59 59 + EARLY_SEGMENT_EXTRA_PAGES)) 60 60 61 - #define INIT_IDMAP_DIR_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, _end, 1)) 61 + #define INIT_IDMAP_DIR_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, kimage_limit, 1)) 62 62 #define INIT_IDMAP_DIR_SIZE ((INIT_IDMAP_DIR_PAGES + EARLY_IDMAP_EXTRA_PAGES) * PAGE_SIZE) 63 63 64 64 #define INIT_IDMAP_FDT_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, 0UL, UL(MAX_FDT_SIZE), 1) - 1)
+11
arch/arm64/kernel/image-vars.h
··· 146 146 _kernel_codesize = ABSOLUTE(__inittext_end - _text); 147 147 #endif 148 148 149 + /* 150 + * LLD will occasionally error out with a '__init_end does not converge' error 151 + * if INIT_IDMAP_DIR_SIZE is defined in terms of _end, as this results in a 152 + * circular dependency. Counter this by dimensioning the initial IDMAP page 153 + * tables based on kimage_limit, which is defined such that its value should 154 + * not change as a result of the initdata segment being pushed over a 64k 155 + * segment boundary due to changes in INIT_IDMAP_DIR_SIZE, provided that its 156 + * value doesn't change by more than 2M between linker passes. 157 + */ 158 + kimage_limit = ALIGN(ABSOLUTE(_end + SZ_64K), SZ_2M); 159 + 149 160 #undef ASSERT 150 161 151 162 #endif /* __ARM64_KERNEL_IMAGE_VARS_H */