14cecebf2SArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 24cecebf2SArd Biesheuvel 34cecebf2SArd Biesheuvel #include <linux/linkage.h> 44cecebf2SArd Biesheuvel #include <linux/types.h> 54cecebf2SArd Biesheuvel 64cecebf2SArd Biesheuvel #include <asm/desc.h> 74cecebf2SArd Biesheuvel #include <asm/init.h> 84cecebf2SArd Biesheuvel #include <asm/setup.h> 94cecebf2SArd Biesheuvel #include <asm/sev.h> 104cecebf2SArd Biesheuvel #include <asm/trapnr.h> 114cecebf2SArd Biesheuvel 124cecebf2SArd Biesheuvel /* 134cecebf2SArd Biesheuvel * Data structures and code used for IDT setup in head_64.S. The bringup-IDT is 144cecebf2SArd Biesheuvel * used until the idt_table takes over. On the boot CPU this happens in 154cecebf2SArd Biesheuvel * x86_64_start_kernel(), on secondary CPUs in start_secondary(). In both cases 164cecebf2SArd Biesheuvel * this happens in the functions called from head_64.S. 174cecebf2SArd Biesheuvel * 184cecebf2SArd Biesheuvel * The idt_table can't be used that early because all the code modifying it is 194cecebf2SArd Biesheuvel * in idt.c and can be instrumented by tracing or KASAN, which both don't work 204cecebf2SArd Biesheuvel * during early CPU bringup. Also the idt_table has the runtime vectors 214cecebf2SArd Biesheuvel * configured which require certain CPU state to be setup already (like TSS), 224cecebf2SArd Biesheuvel * which also hasn't happened yet in early CPU bringup. 234cecebf2SArd Biesheuvel */ 244cecebf2SArd Biesheuvel static gate_desc bringup_idt_table[NUM_EXCEPTION_VECTORS] __page_aligned_data; 254cecebf2SArd Biesheuvel 264cecebf2SArd Biesheuvel /* This may run while still in the direct mapping */ 27*bd4a58beSArd Biesheuvel void __head startup_64_load_idt(void *vc_handler) 284cecebf2SArd Biesheuvel { 294cecebf2SArd Biesheuvel struct desc_ptr desc = { 304cecebf2SArd Biesheuvel .address = (unsigned long)rip_rel_ptr(bringup_idt_table), 314cecebf2SArd Biesheuvel .size = sizeof(bringup_idt_table) - 1, 324cecebf2SArd Biesheuvel }; 334cecebf2SArd Biesheuvel struct idt_data data; 344cecebf2SArd Biesheuvel gate_desc idt_desc; 354cecebf2SArd Biesheuvel 364cecebf2SArd Biesheuvel /* @vc_handler is set only for a VMM Communication Exception */ 374cecebf2SArd Biesheuvel if (vc_handler) { 384cecebf2SArd Biesheuvel init_idt_data(&data, X86_TRAP_VC, vc_handler); 394cecebf2SArd Biesheuvel idt_init_desc(&idt_desc, &data); 404cecebf2SArd Biesheuvel native_write_idt_entry((gate_desc *)desc.address, X86_TRAP_VC, &idt_desc); 414cecebf2SArd Biesheuvel } 424cecebf2SArd Biesheuvel 434cecebf2SArd Biesheuvel native_load_idt(&desc); 444cecebf2SArd Biesheuvel } 454cecebf2SArd Biesheuvel 464cecebf2SArd Biesheuvel /* 474cecebf2SArd Biesheuvel * Setup boot CPU state needed before kernel switches to virtual addresses. 484cecebf2SArd Biesheuvel */ 494cecebf2SArd Biesheuvel void __head startup_64_setup_gdt_idt(void) 504cecebf2SArd Biesheuvel { 514cecebf2SArd Biesheuvel struct gdt_page *gp = rip_rel_ptr((void *)(__force unsigned long)&gdt_page); 524cecebf2SArd Biesheuvel void *handler = NULL; 534cecebf2SArd Biesheuvel 544cecebf2SArd Biesheuvel struct desc_ptr startup_gdt_descr = { 554cecebf2SArd Biesheuvel .address = (unsigned long)gp->gdt, 564cecebf2SArd Biesheuvel .size = GDT_SIZE - 1, 574cecebf2SArd Biesheuvel }; 584cecebf2SArd Biesheuvel 594cecebf2SArd Biesheuvel /* Load GDT */ 604cecebf2SArd Biesheuvel native_load_gdt(&startup_gdt_descr); 614cecebf2SArd Biesheuvel 624cecebf2SArd Biesheuvel /* New GDT is live - reload data segment registers */ 634cecebf2SArd Biesheuvel asm volatile("movl %%eax, %%ds\n" 644cecebf2SArd Biesheuvel "movl %%eax, %%ss\n" 654cecebf2SArd Biesheuvel "movl %%eax, %%es\n" : : "a"(__KERNEL_DS) : "memory"); 664cecebf2SArd Biesheuvel 674cecebf2SArd Biesheuvel if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) 684cecebf2SArd Biesheuvel handler = rip_rel_ptr(vc_no_ghcb); 694cecebf2SArd Biesheuvel 704cecebf2SArd Biesheuvel startup_64_load_idt(handler); 714cecebf2SArd Biesheuvel } 72