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

x86/kexec: Move relocate_kernel to kernel .data section

Now that the copy is executed instead of the original, the relocate_kernel
page can live in the kernel's .text section. This will allow subsequent
commits to actually add real data to it and clean up the code somewhat as
well as making the control page ROX.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Link: https://lore.kernel.org/r/20241205153343.3275139-9-dwmw2@infradead.org

authored by

David Woodhouse and committed by
Ingo Molnar
cb33ff9e eeebbde5

+24 -7
+1
arch/x86/include/asm/sections.h
··· 5 5 #include <asm-generic/sections.h> 6 6 #include <asm/extable.h> 7 7 8 + extern char __relocate_kernel_start[], __relocate_kernel_end[]; 8 9 extern char __brk_base[], __brk_limit[]; 9 10 extern char __end_rodata_aligned[]; 10 11
+6
arch/x86/kernel/callthunks.c
··· 139 139 return true; 140 140 #endif 141 141 #ifdef CONFIG_KEXEC_CORE 142 + # ifdef CONFIG_X86_64 143 + if (dest >= (void *)__relocate_kernel_start && 144 + dest < (void *)__relocate_kernel_end) 145 + return true; 146 + # else 142 147 if (dest >= (void *)relocate_kernel && 143 148 dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE) 144 149 return true; 150 + # endif 145 151 #endif 146 152 #ifdef CONFIG_XEN 147 153 if (dest >= (void *)hypercall_page &&
+3 -1
arch/x86/kernel/machine_kexec_64.c
··· 307 307 int machine_kexec_prepare(struct kimage *image) 308 308 { 309 309 void *control_page = page_address(image->control_code_page); 310 + unsigned long reloc_start = (unsigned long)__relocate_kernel_start; 311 + unsigned long reloc_end = (unsigned long)__relocate_kernel_end; 310 312 int result; 311 313 312 314 /* Setup the identity mapped 64bit page table */ ··· 316 314 if (result) 317 315 return result; 318 316 319 - __memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE); 317 + __memcpy(control_page, __relocate_kernel_start, reloc_end - reloc_start); 320 318 321 319 set_memory_x((unsigned long)control_page, 1); 322 320
+1 -6
arch/x86/kernel/relocate_kernel_64.S
··· 41 41 #define CP_PA_BACKUP_PAGES_MAP DATA(0x30) 42 42 #define CP_VA_CONTROL_PAGE DATA(0x38) 43 43 44 - .text 45 - .align PAGE_SIZE 44 + .section .text.relocate_kernel,"ax"; 46 45 .code64 47 - SYM_CODE_START_NOALIGN(relocate_range) 48 46 SYM_CODE_START_NOALIGN(relocate_kernel) 49 47 UNWIND_HINT_END_OF_STACK 50 48 ANNOTATE_NOENDBR ··· 339 341 ret 340 342 int3 341 343 SYM_CODE_END(swap_pages) 342 - 343 - .skip KEXEC_CONTROL_CODE_MAX_SIZE - (. - relocate_kernel), 0xcc 344 - SYM_CODE_END(relocate_range);
+13
arch/x86/kernel/vmlinux.lds.S
··· 28 28 #include <asm/orc_lookup.h> 29 29 #include <asm/cache.h> 30 30 #include <asm/boot.h> 31 + #include <asm/kexec.h> 31 32 32 33 #undef i386 /* in case the preprocessor is a 32bit one */ 33 34 ··· 96 95 #define BSS_DECRYPTED 97 96 98 97 #endif 98 + #if defined(CONFIG_X86_64) && defined(CONFIG_KEXEC_CORE) 99 + #define KEXEC_RELOCATE_KERNEL \ 100 + . = ALIGN(0x100); \ 101 + __relocate_kernel_start = .; \ 102 + *(.text.relocate_kernel); \ 103 + __relocate_kernel_end = .; 99 104 105 + ASSERT(__relocate_kernel_end - __relocate_kernel_start <= KEXEC_CONTROL_CODE_MAX_SIZE, 106 + "relocate_kernel code too large!") 107 + #else 108 + #define KEXEC_RELOCATE_KERNEL 109 + #endif 100 110 PHDRS { 101 111 text PT_LOAD FLAGS(5); /* R_E */ 102 112 data PT_LOAD FLAGS(6); /* RW_ */ ··· 196 184 197 185 DATA_DATA 198 186 CONSTRUCTORS 187 + KEXEC_RELOCATE_KERNEL 199 188 200 189 /* rarely changed data like cpu maps */ 201 190 READ_MOSTLY_DATA(INTERNODE_CACHE_BYTES)