@@ -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
@@ -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
@@ -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 */
@@ -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);