Commit cb33ff9e authored by David Woodhouse's avatar David Woodhouse Committed by Ingo Molnar
Browse files

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: default avatarDavid Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: default avatarIngo 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
parent eeebbde5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <asm-generic/sections.h>
#include <asm/extable.h>

extern char __relocate_kernel_start[], __relocate_kernel_end[];
extern char __brk_base[], __brk_limit[];
extern char __end_rodata_aligned[];

+6 −0
Original line number Diff line number Diff line
@@ -139,10 +139,16 @@ static bool skip_addr(void *dest)
		return true;
#endif
#ifdef CONFIG_KEXEC_CORE
# ifdef CONFIG_X86_64
	if (dest >= (void *)__relocate_kernel_start &&
	    dest < (void *)__relocate_kernel_end)
		return true;
# else
	if (dest >= (void *)relocate_kernel &&
	    dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE)
		return true;
# endif
#endif
#ifdef CONFIG_XEN
	if (dest >= (void *)hypercall_page &&
	    dest < (void*)hypercall_page + PAGE_SIZE)
+3 −1
Original line number Diff line number Diff line
@@ -307,6 +307,8 @@ static void load_segments(void)
int machine_kexec_prepare(struct kimage *image)
{
	void *control_page = page_address(image->control_code_page);
	unsigned long reloc_start = (unsigned long)__relocate_kernel_start;
	unsigned long reloc_end = (unsigned long)__relocate_kernel_end;
	int result;

	/* Setup the identity mapped 64bit page table */
@@ -314,7 +316,7 @@ int machine_kexec_prepare(struct kimage *image)
	if (result)
		return result;

	__memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE);
	__memcpy(control_page, __relocate_kernel_start, reloc_end - reloc_start);

	set_memory_x((unsigned long)control_page, 1);

+1 −6
Original line number Diff line number Diff line
@@ -41,10 +41,8 @@
#define CP_PA_BACKUP_PAGES_MAP	DATA(0x30)
#define CP_VA_CONTROL_PAGE	DATA(0x38)

	.text
	.align PAGE_SIZE
	.section .text.relocate_kernel,"ax";
	.code64
SYM_CODE_START_NOALIGN(relocate_range)
SYM_CODE_START_NOALIGN(relocate_kernel)
	UNWIND_HINT_END_OF_STACK
	ANNOTATE_NOENDBR
@@ -341,6 +339,3 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
	ret
	int3
SYM_CODE_END(swap_pages)

	.skip KEXEC_CONTROL_CODE_MAX_SIZE - (. - relocate_kernel), 0xcc
SYM_CODE_END(relocate_range);
+14 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <asm/orc_lookup.h>
#include <asm/cache.h>
#include <asm/boot.h>
#include <asm/kexec.h>

#undef i386     /* in case the preprocessor is a 32bit one */

@@ -95,7 +96,18 @@ const_pcpu_hot = pcpu_hot;
#define BSS_DECRYPTED

#endif

#if defined(CONFIG_X86_64) && defined(CONFIG_KEXEC_CORE)
#define KEXEC_RELOCATE_KERNEL					\
	. = ALIGN(0x100);					\
	__relocate_kernel_start = .;				\
	*(.text.relocate_kernel);				\
	__relocate_kernel_end = .;

ASSERT(__relocate_kernel_end - __relocate_kernel_start <= KEXEC_CONTROL_CODE_MAX_SIZE,
	"relocate_kernel code too large!")
#else
#define KEXEC_RELOCATE_KERNEL
#endif
PHDRS {
	text PT_LOAD FLAGS(5);          /* R_E */
	data PT_LOAD FLAGS(6);          /* RW_ */
@@ -184,6 +196,7 @@ SECTIONS

		DATA_DATA
		CONSTRUCTORS
		KEXEC_RELOCATE_KERNEL

		/* rarely changed data like cpu maps */
		READ_MOSTLY_DATA(INTERNODE_CACHE_BYTES)