[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240226143630.33643-56-jiangshanlai@gmail.com>
Date: Mon, 26 Feb 2024 22:36:12 +0800
From: Lai Jiangshan <jiangshanlai@...il.com>
To: linux-kernel@...r.kernel.org
Cc: Hou Wenlong <houwenlong.hwl@...group.com>,
Lai Jiangshan <jiangshan.ljs@...group.com>,
Linus Torvalds <torvalds@...ux-foundation.org>,
Peter Zijlstra <peterz@...radead.org>,
Sean Christopherson <seanjc@...gle.com>,
Thomas Gleixner <tglx@...utronix.de>,
Borislav Petkov <bp@...en8.de>,
Ingo Molnar <mingo@...hat.com>,
kvm@...r.kernel.org,
Paolo Bonzini <pbonzini@...hat.com>,
x86@...nel.org,
Kees Cook <keescook@...omium.org>,
Juergen Gross <jgross@...e.com>,
Dave Hansen <dave.hansen@...ux.intel.com>,
"H. Peter Anvin" <hpa@...or.com>,
David Woodhouse <dwmw@...zon.co.uk>,
Brian Gerst <brgerst@...il.com>,
Josh Poimboeuf <jpoimboe@...nel.org>,
Thomas Garnier <thgarnie@...omium.org>,
Ard Biesheuvel <ardb@...nel.org>,
Tom Lendacky <thomas.lendacky@....com>
Subject: [RFC PATCH 55/73] x86/pvm: Relocate kernel image to specific virtual address range
From: Hou Wenlong <houwenlong.hwl@...group.com>
For a PVM guest, it is only allowed to run in the specific virtual
address range provided by the hypervisor. Therefore, the PVM guest needs
to be a PIE kernel and perform relocation during the booting process.
Additionally, for a compressed kernel image, kaslr needs to be disabled;
otherwise, it will fail to boot.
Signed-off-by: Hou Wenlong <houwenlong.hwl@...group.com>
Signed-off-by: Lai Jiangshan <jiangshan.ljs@...group.com>
---
arch/x86/Kconfig | 3 ++-
arch/x86/kernel/head64_identity.c | 27 +++++++++++++++++++++++++++
arch/x86/kernel/head_64.S | 13 +++++++++++++
arch/x86/kernel/pvm.c | 5 ++++-
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2ccc8a27e081..1b4bea3db53d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -853,7 +853,8 @@ config KVM_GUEST
config PVM_GUEST
bool "PVM Guest support"
- depends on X86_64 && KVM_GUEST
+ depends on X86_64 && KVM_GUEST && X86_PIE
+ select RELOCATABLE_UNCOMPRESSED_KERNEL
default n
help
This option enables the kernel to run as a PVM guest under the PVM
diff --git a/arch/x86/kernel/head64_identity.c b/arch/x86/kernel/head64_identity.c
index 4548ad615ecf..4e6a073d9e6c 100644
--- a/arch/x86/kernel/head64_identity.c
+++ b/arch/x86/kernel/head64_identity.c
@@ -20,6 +20,7 @@
#include <asm/trapnr.h>
#include <asm/sev.h>
#include <asm/init.h>
+#include <asm/pvm_para.h>
extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
extern unsigned int next_early_pgt;
@@ -385,3 +386,29 @@ void __head __relocate_kernel(unsigned long physbase, unsigned long virtbase)
}
}
#endif
+
+#ifdef CONFIG_PVM_GUEST
+extern unsigned long pvm_range_start;
+extern unsigned long pvm_range_end;
+
+static void __head detect_pvm_range(void)
+{
+ unsigned long msr_val;
+ unsigned long pml4_index_start, pml4_index_end;
+
+ msr_val = __rdmsr(MSR_PVM_LINEAR_ADDRESS_RANGE);
+ pml4_index_start = msr_val & 0x1ff;
+ pml4_index_end = (msr_val >> 16) & 0x1ff;
+ pvm_range_start = (0x1fffe00 | pml4_index_start) * P4D_SIZE;
+ pvm_range_end = (0x1fffe00 | pml4_index_end) * P4D_SIZE;
+}
+
+void __head pvm_relocate_kernel(unsigned long physbase)
+{
+ if (!pvm_detect())
+ return;
+
+ detect_pvm_range();
+ __relocate_kernel(physbase, pvm_range_end - (2UL << 30));
+}
+#endif
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index b8278f05bbd0..1d931bab4393 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -91,6 +91,19 @@ SYM_CODE_START_NOALIGN(startup_64)
movq %rdx, PER_CPU_VAR(this_cpu_off)
#endif
+#ifdef CONFIG_PVM_GUEST
+ leaq _text(%rip), %rdi
+ call pvm_relocate_kernel
+#ifdef CONFIG_SMP
+ /* Fill __per_cpu_offset[0] again, because it got relocated. */
+ movabs $__per_cpu_load, %rdx
+ movabs $__per_cpu_start, %rax
+ subq %rax, %rdx
+ movq %rdx, __per_cpu_offset(%rip)
+ movq %rdx, PER_CPU_VAR(this_cpu_off)
+#endif
+#endif
+
call startup_64_setup_env
/* Now switch to __KERNEL_CS so IRET works reliably */
diff --git a/arch/x86/kernel/pvm.c b/arch/x86/kernel/pvm.c
index 2d27044eaf25..fc82c71b305b 100644
--- a/arch/x86/kernel/pvm.c
+++ b/arch/x86/kernel/pvm.c
@@ -13,9 +13,12 @@
#include <asm/cpufeature.h>
#include <asm/pvm_para.h>
+unsigned long pvm_range_start __initdata;
+unsigned long pvm_range_end __initdata;
+
void __init pvm_early_setup(void)
{
- if (!pvm_detect())
+ if (!pvm_range_end)
return;
setup_force_cpu_cap(X86_FEATURE_KVM_PVM_GUEST);
--
2.19.1.6.gb485710b
Powered by blists - more mailing lists