[PATCH RFC 0/7] x86/head/64: Build the head code as PIE

From: Hou Wenlong
Date: Tue Jul 11 2023 - 23:31:24 EST


During the early boot stage, the head code runs at a low identity
address, which means that all absolute references would be incorrect.
However, when accessing globals, the compiler does not have to generate
PC-relative references. To work around this problem, every global
variable access must be adjusted using fixup_pointer() in
arch/x86/kernel/head64.c.
However, some global variable accesses in the current code do not use
fixup_pointer(), and they may work correctly because the compiler can
generate the right PC-relative references. But the behavior differs
between GCC and CLANG, which has caused problems before. For example,
commit c1887159eb48 ("x86/boot/64: Add missing fixup_pointer() for
next_early_pgt access") stated that CLANG would generate absolute
references for 'next_early_pgt' without fixup_pointer(), which leads to
booting failure. Moreover, the rule is not always clear. For instance,
'pgdir_shift' is a non-static global variable similar to
'next_early_pgt', but the compiler can generate the right PC-relative
reference, so fixup_pointer() is not applied to pgdir_shift when using
the PGDIR_SHIFT macro.

In addition, the code in arch/x86/mm/mem_encrypt_identity.c also runs at
identity address, but it uses inline assembly to use RIP-relative
reference for some globals instead of fixup_pointer(). However, not all
global references are changed into inline assembly.

To avoid such cases and also prepare for building the kernel as PIE, the
head code could be built as PIE to force the generation of PC-relative
references. This can eliminate the need for fixup_pointer() and inline
assembly. However, there are still a few functions that are called by
the head code but are not in head64.c and mem_encrypt_identity.c, such
as snp_init() and early_snp_set_memory_shared(). Moving them into a
separate compile unit and building them as PIE is a little complicated,
so for now, they will remain unchanged.

Note: The change in mem_encrypt_identity.c has not been tested since I
don't have the necessary environment available.

Hou Wenlong (7):
x86/head/64: Mark startup_gdt and startup_gdt_descr as __initdata
x86/head/64: Add missing __head annotation to startup_64_load_idt()
x86/head/64: Move all head code from head64.c into another file
x86/boot/compressed: Adapt sed command if head code is built as PIE
x86/head/64: Build the head code as PIE
x86/sme: Mark code as __head in mem_encrypt_identity.c
x86/sme: Build the code in mem_encrypt_identity.c as PIE

arch/x86/boot/compressed/Makefile | 2 +-
arch/x86/include/asm/desc.h | 12 ++
arch/x86/include/asm/init.h | 2 +
arch/x86/include/asm/mem_encrypt.h | 8 +-
arch/x86/include/asm/setup.h | 2 +-
arch/x86/kernel/Makefile | 16 +-
arch/x86/kernel/head64.c | 307 +----------------------------
arch/x86/kernel/head64_identity.c | 282 ++++++++++++++++++++++++++
arch/x86/kernel/head_64.S | 2 -
arch/x86/mm/Makefile | 3 +
arch/x86/mm/mem_encrypt_identity.c | 58 ++----
11 files changed, 342 insertions(+), 352 deletions(-)
create mode 100644 arch/x86/kernel/head64_identity.c


base-commit: 1a2945f27157825a561be7840023e3664111ab2f
--
2.31.1