Skip to content

Commit

Permalink
x86/boot/32: Temporarily map initrd for microcode loading
Browse files Browse the repository at this point in the history
Early microcode loading on 32-bit runs in physical address mode because
the initrd is not covered by the initial page tables. That results in
a horrible mess all over the microcode loader code.

Provide a temporary mapping for the initrd in the initial page tables by
appending it to the actual initial mapping starting with a new PGD or
PMD depending on the configured page table levels ([non-]PAE).

The page table entries are located after _brk_end so they are not
permanently using memory space. The mapping is invalidated right away in
i386_start_kernel() after the early microcode loader has run.

This prepares for removing the physical address mode oddities from all
over the microcode loader code, which in turn allows further cleanups.

Provide the map and unmap code and document the place where the
microcode loader needs to be invoked with a comment.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20231017211722.292291436@linutronix.de
  • Loading branch information
Thomas Gleixner authored and Borislav Petkov (AMD) committed Oct 18, 2023
1 parent fdbd438 commit 4c585af
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
2 changes: 2 additions & 0 deletions arch/x86/include/asm/microcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static inline void load_ucode_ap(void) { }
static inline void microcode_bsp_resume(void) { }
#endif

extern unsigned long initrd_start_early;

#ifdef CONFIG_CPU_SUP_INTEL
/* Intel specific microcode defines. Public for IFS */
struct microcode_header_intel {
Expand Down
54 changes: 52 additions & 2 deletions arch/x86/kernel/head32.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,33 @@ static void __init i386_default_early_setup(void)
x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;
}

#ifdef CONFIG_MICROCODE_INITRD32
unsigned long __initdata initrd_start_early;
static pte_t __initdata *initrd_pl2p_start, *initrd_pl2p_end;

static void zap_early_initrd_mapping(void)
{
pte_t *pl2p = initrd_pl2p_start;

for (; pl2p < initrd_pl2p_end; pl2p++) {
*pl2p = (pte_t){ .pte = 0 };

if (!IS_ENABLED(CONFIG_X86_PAE))
*(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = (pte_t) {.pte = 0};
}
}
#else
static inline void zap_early_initrd_mapping(void) { }
#endif

asmlinkage __visible void __init __noreturn i386_start_kernel(void)
{
/* Make sure IDT is set up before any exception happens */
idt_setup_early_handler();

/* load_ucode_bsp() */
zap_early_initrd_mapping();

cr4_init_shadow();

sanitize_boot_params(&boot_params);
Expand Down Expand Up @@ -105,9 +127,9 @@ static __init __no_stack_protector pte_t init_map(pte_t pte, pte_t **ptep, pl2_t
void __init __no_stack_protector mk_early_pgtbl_32(void)
{
/* Enough space to fit pagetables for the low memory linear map */
const unsigned long limit = __pa_nodebug(_end) +
(PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT);
unsigned long limit = __pa_nodebug(_end) + (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT);
pte_t pte, *ptep = (pte_t *)__pa_nodebug(__brk_base);
struct boot_params __maybe_unused *params;
pl2_t *pl2p = (pl2_t *)__pa_nodebug(pl2_base);
unsigned long *ptr;

Expand All @@ -120,4 +142,32 @@ void __init __no_stack_protector mk_early_pgtbl_32(void)

ptr = (unsigned long *)__pa_nodebug(&_brk_end);
*ptr = (unsigned long)ptep + PAGE_OFFSET;

#ifdef CONFIG_MICROCODE_INITRD32
/* Running on a hypervisor? */
if (native_cpuid_ecx(1) & BIT(31))
return;

params = (struct boot_params *)__pa_nodebug(&boot_params);
if (!params->hdr.ramdisk_size || !params->hdr.ramdisk_image)
return;

/* Save the virtual start address */
ptr = (unsigned long *)__pa_nodebug(&initrd_start_early);
*ptr = (pte.pte & PTE_PFN_MASK) + PAGE_OFFSET;
*ptr += ((unsigned long)params->hdr.ramdisk_image) & ~PAGE_MASK;

/* Save PLP2 for cleanup */
ptr = (unsigned long *)__pa_nodebug(&initrd_pl2p_start);
*ptr = (unsigned long)pl2p + PAGE_OFFSET;

limit = (unsigned long)params->hdr.ramdisk_image;
pte.pte = PTE_IDENT_ATTR | PFN_ALIGN(limit);
limit = (unsigned long)params->hdr.ramdisk_image + params->hdr.ramdisk_size;

init_map(pte, &ptep, &pl2p, limit);

ptr = (unsigned long *)__pa_nodebug(&initrd_pl2p_end);
*ptr = (unsigned long)pl2p + PAGE_OFFSET;
#endif
}

0 comments on commit 4c585af

Please sign in to comment.