// SPDX-License-Identifier: GPL-2.0-only1#include <asm/trap_pf.h>2#include <asm/segment.h>3#include <asm/trapnr.h>4#include "misc.h"56static void set_idt_entry(int vector, void (*handler)(void))7{8unsigned long address = (unsigned long)handler;9gate_desc entry;1011memset(&entry, 0, sizeof(entry));1213entry.offset_low = (u16)(address & 0xffff);14entry.segment = __KERNEL_CS;15entry.bits.type = GATE_TRAP;16entry.bits.p = 1;17entry.offset_middle = (u16)((address >> 16) & 0xffff);18entry.offset_high = (u32)(address >> 32);1920memcpy(&boot_idt[vector], &entry, sizeof(entry));21}2223/* Have this here so we don't need to include <asm/desc.h> */24static void load_boot_idt(const struct desc_ptr *dtr)25{26asm volatile("lidt %0"::"m" (*dtr));27}2829/* Setup IDT before kernel jumping to .Lrelocated */30void load_stage1_idt(void)31{32boot_idt_desc.address = (unsigned long)boot_idt;333435if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))36set_idt_entry(X86_TRAP_VC, boot_stage1_vc);3738load_boot_idt(&boot_idt_desc);39}4041/*42* Setup IDT after kernel jumping to .Lrelocated.43*44* initialize_identity_maps() needs a #PF handler to be setup45* in order to be able to fault-in identity mapping ranges; see46* do_boot_page_fault().47*48* This #PF handler setup needs to happen in load_stage2_idt() where the49* IDT is loaded and there the #VC IDT entry gets setup too.50*51* In order to be able to handle #VCs, one needs a GHCB which52* gets setup with an already set up pagetable, which is done in53* initialize_identity_maps(). And there's the catch 22: the boot #VC54* handler do_boot_stage2_vc() needs to call early_setup_ghcb() itself55* (and, especially set_page_decrypted()) because the SEV-ES setup code56* cannot initialize a GHCB as there's no #PF handler yet...57*/58void load_stage2_idt(void)59{60boot_idt_desc.address = (unsigned long)boot_idt;6162set_idt_entry(X86_TRAP_PF, boot_page_fault);63set_idt_entry(X86_TRAP_NMI, boot_nmi_trap);6465#ifdef CONFIG_AMD_MEM_ENCRYPT66/*67* Clear the second stage #VC handler in case guest types68* needing #VC have not been detected.69*/70if (sev_status & BIT(1))71set_idt_entry(X86_TRAP_VC, boot_stage2_vc);72else73set_idt_entry(X86_TRAP_VC, NULL);74#endif7576load_boot_idt(&boot_idt_desc);77}7879void cleanup_exception_handling(void)80{81/*82* Flush GHCB from cache and map it encrypted again when running as83* SEV-ES guest.84*/85sev_es_shutdown_ghcb();8687/* Set a null-idt, disabling #PF and #VC handling */88boot_idt_desc.size = 0;89boot_idt_desc.address = 0;90load_boot_idt(&boot_idt_desc);91}929394