Commit dc0a0839 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Will Deacon
Browse files

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: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20250531123005.3866382-2-ardb+git@google.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent e21560b7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@
#define INIT_DIR_SIZE (PAGE_SIZE * (EARLY_PAGES(SWAPPER_PGTABLE_LEVELS, KIMAGE_VADDR, _end, EXTRA_PAGE) \
				    + EARLY_SEGMENT_EXTRA_PAGES))

#define INIT_IDMAP_DIR_PAGES	(EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, _end, 1))
#define INIT_IDMAP_DIR_PAGES	(EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, kimage_limit, 1))
#define INIT_IDMAP_DIR_SIZE	((INIT_IDMAP_DIR_PAGES + EARLY_IDMAP_EXTRA_PAGES) * PAGE_SIZE)

#define INIT_IDMAP_FDT_PAGES	(EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, 0UL, UL(MAX_FDT_SIZE), 1) - 1)
+11 −0
Original line number Diff line number Diff line
@@ -146,6 +146,17 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
_kernel_codesize = ABSOLUTE(__inittext_end - _text);
#endif

/*
 * 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 kimage_limit, which is defined 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.
 */
kimage_limit = ALIGN(ABSOLUTE(_end + SZ_64K), SZ_2M);

#undef ASSERT

#endif /* __ARM64_KERNEL_IMAGE_VARS_H */