Skip to content

Commit

Permalink
x86/boot: Support for compressed kernel booting
Browse files Browse the repository at this point in the history
The 5-level paging mode is enabled in compressed kernel booting and it
uses the CPUID instruction to detect 5-level paging support. For PVM
guest, pvm_cpuid() should be used instead of the CPUID instruction, so
detect PVM hypervisor support early in configure_5level_paging().
Additionally, relocation for PVM guest during booting should be avoided.
This is because there is only the first 4G identity mapping, and if
physical address randomization is enabled, a #PF exception will occur if
the chosen output address is over the first 4G range. Therefore, for
simplification, physical address randomization should be avoided. As for
virtual address randomization, it should occur after entering the kernel
entry.

Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
Link: #6
  • Loading branch information
bysui committed Apr 25, 2024
1 parent 48eb9d3 commit 858242d
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
19 changes: 19 additions & 0 deletions arch/x86/boot/compressed/kaslr.c
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,22 @@ void choose_random_location(unsigned long input,

boot_params_ptr->hdr.loadflags |= KASLR_FLAG;

/*
* For PVM guest, both physical address randomization and virtual
* address randomization should be disabled. This is because if
* physical address randomization chooses an output address above 4GB,
* it will trigger a #PF during decompression. In order to handle this,
* PVM event handling initialization for the #PF handler needs to be
* done. For simplicity, physical address randomization should be
* skipped. As for virtual address randomization, PVM guest needs to
* detect the allowed range first, and thus it should also be skipped
* and can be done after kernel entry.
*/
if (IS_ENABLED(CONFIG_PVM_GUEST) && pvm_detected) {
warn("Skip relocation for PVM guest.");
return;
}

if (IS_ENABLED(CONFIG_X86_32))
mem_limit = KERNEL_IMAGE_SIZE;
else
Expand Down Expand Up @@ -918,6 +934,9 @@ unsigned long pie_randomize(void)
if (cmdline_find_option_bool("nokaslr"))
return 0;

if (IS_ENABLED(CONFIG_PVM_GUEST) && pvm_detected)
return 0;

total = 0;
for (i = 0; i < ARRAY_SIZE(available_slots); i++) {
available_slots[i].pud_slots = (available_slots[i].end -
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/boot/compressed/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ static inline unsigned long pie_randomize(void)
}
#endif

extern bool pvm_detected;

/* cpuflags.c */
bool has_cpuflag(int flag);

Expand Down
41 changes: 38 additions & 3 deletions arch/x86/boot/compressed/pgtable_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "misc.h"
#include <asm/e820/types.h>
#include <asm/processor.h>
#include <asm/pvm_para.h>
#include "pgtable.h"
#include "../string.h"
#include "efi.h"
Expand Down Expand Up @@ -100,6 +101,36 @@ static unsigned long find_trampoline_placement(void)
return bios_start - TRAMPOLINE_32BIT_SIZE;
}

#ifdef CONFIG_PVM_GUEST
bool pvm_detected __section(".data");
#endif

static bool detect_cpuid_la57(void)
{
#ifdef CONFIG_PVM_GUEST
if (pvm_detected) {
u32 eax, ebx, ecx, edx;

eax = 0;
pvm_cpuid(&eax, &ebx, &ecx, &edx);
if (eax >= 7) {
eax = 7;
ecx = 0;
pvm_cpuid(&eax, &ebx, &ecx, &edx);
if (ecx & (1 << (X86_FEATURE_LA57 & 31)))
return true;
}
return false;
}
#endif

if (native_cpuid_eax(0) >= 7 &&
(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
return true;

return false;
}

asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable)
{
void (*toggle_la57)(void *cr3);
Expand All @@ -108,6 +139,11 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable)
/* Initialize boot_params. Required for cmdline_find_option_bool(). */
boot_params_ptr = bp;

#ifdef CONFIG_PVM_GUEST
/* Detect PVM hypervisor support. Required for detect_cpuid(). */
pvm_detected = pvm_detect();
#endif

/*
* Check if LA57 is desired and supported.
*
Expand All @@ -121,9 +157,8 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable)
* That's substitute for boot_cpu_has() in early boot code.
*/
if (IS_ENABLED(CONFIG_X86_5LEVEL) &&
!cmdline_find_option_bool("no5lvl") &&
native_cpuid_eax(0) >= 7 &&
(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)))) {
!cmdline_find_option_bool("no5lvl") &&
detect_cpuid_la57()) {
l5_required = true;

/* Initialize variables for 5-level paging */
Expand Down

0 comments on commit 858242d

Please sign in to comment.