.. | .. |
---|
20 | 20 | #include <linux/io.h> |
---|
21 | 21 | #include <linux/memblock.h> |
---|
22 | 22 | #include <linux/mem_encrypt.h> |
---|
| 23 | +#include <linux/pgtable.h> |
---|
23 | 24 | |
---|
24 | 25 | #include <asm/processor.h> |
---|
25 | 26 | #include <asm/proto.h> |
---|
26 | 27 | #include <asm/smp.h> |
---|
27 | 28 | #include <asm/setup.h> |
---|
28 | 29 | #include <asm/desc.h> |
---|
29 | | -#include <asm/pgtable.h> |
---|
30 | 30 | #include <asm/tlbflush.h> |
---|
31 | 31 | #include <asm/sections.h> |
---|
32 | 32 | #include <asm/kdebug.h> |
---|
.. | .. |
---|
36 | 36 | #include <asm/microcode.h> |
---|
37 | 37 | #include <asm/kasan.h> |
---|
38 | 38 | #include <asm/fixmap.h> |
---|
| 39 | +#include <asm/realmode.h> |
---|
| 40 | +#include <asm/desc.h> |
---|
| 41 | +#include <asm/extable.h> |
---|
| 42 | +#include <asm/trapnr.h> |
---|
| 43 | +#include <asm/sev-es.h> |
---|
39 | 44 | |
---|
40 | 45 | /* |
---|
41 | 46 | * Manage page tables very early on. |
---|
.. | .. |
---|
61 | 66 | EXPORT_SYMBOL(vmemmap_base); |
---|
62 | 67 | #endif |
---|
63 | 68 | |
---|
64 | | -#define __head __section(.head.text) |
---|
| 69 | +/* |
---|
| 70 | + * GDT used on the boot CPU before switching to virtual addresses. |
---|
| 71 | + */ |
---|
| 72 | +static struct desc_struct startup_gdt[GDT_ENTRIES] = { |
---|
| 73 | + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), |
---|
| 74 | + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), |
---|
| 75 | + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), |
---|
| 76 | +}; |
---|
| 77 | + |
---|
| 78 | +/* |
---|
| 79 | + * Address needs to be set at runtime because it references the startup_gdt |
---|
| 80 | + * while the kernel still uses a direct mapping. |
---|
| 81 | + */ |
---|
| 82 | +static struct desc_ptr startup_gdt_descr = { |
---|
| 83 | + .size = sizeof(startup_gdt), |
---|
| 84 | + .address = 0, |
---|
| 85 | +}; |
---|
| 86 | + |
---|
| 87 | +#define __head __section(".head.text") |
---|
65 | 88 | |
---|
66 | 89 | static void __head *fixup_pointer(void *ptr, unsigned long physaddr) |
---|
67 | 90 | { |
---|
.. | .. |
---|
297 | 320 | } |
---|
298 | 321 | |
---|
299 | 322 | /* Create a new PMD entry */ |
---|
300 | | -int __init __early_make_pgtable(unsigned long address, pmdval_t pmd) |
---|
| 323 | +bool __init __early_make_pgtable(unsigned long address, pmdval_t pmd) |
---|
301 | 324 | { |
---|
302 | 325 | unsigned long physaddr = address - __PAGE_OFFSET; |
---|
303 | 326 | pgdval_t pgd, *pgd_p; |
---|
.. | .. |
---|
307 | 330 | |
---|
308 | 331 | /* Invalid address or early pgt is done ? */ |
---|
309 | 332 | if (physaddr >= MAXMEM || read_cr3_pa() != __pa_nodebug(early_top_pgt)) |
---|
310 | | - return -1; |
---|
| 333 | + return false; |
---|
311 | 334 | |
---|
312 | 335 | again: |
---|
313 | 336 | pgd_p = &early_top_pgt[pgd_index(address)].pgd; |
---|
.. | .. |
---|
364 | 387 | } |
---|
365 | 388 | pmd_p[pmd_index(address)] = pmd; |
---|
366 | 389 | |
---|
367 | | - return 0; |
---|
| 390 | + return true; |
---|
368 | 391 | } |
---|
369 | 392 | |
---|
370 | | -int __init early_make_pgtable(unsigned long address) |
---|
| 393 | +static bool __init early_make_pgtable(unsigned long address) |
---|
371 | 394 | { |
---|
372 | 395 | unsigned long physaddr = address - __PAGE_OFFSET; |
---|
373 | 396 | pmdval_t pmd; |
---|
.. | .. |
---|
377 | 400 | return __early_make_pgtable(address, pmd); |
---|
378 | 401 | } |
---|
379 | 402 | |
---|
| 403 | +void __init do_early_exception(struct pt_regs *regs, int trapnr) |
---|
| 404 | +{ |
---|
| 405 | + if (trapnr == X86_TRAP_PF && |
---|
| 406 | + early_make_pgtable(native_read_cr2())) |
---|
| 407 | + return; |
---|
| 408 | + |
---|
| 409 | + if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT) && |
---|
| 410 | + trapnr == X86_TRAP_VC && handle_vc_boot_ghcb(regs)) |
---|
| 411 | + return; |
---|
| 412 | + |
---|
| 413 | + early_fixup_exception(regs, trapnr); |
---|
| 414 | +} |
---|
| 415 | + |
---|
380 | 416 | /* Don't add a printk in there. printk relies on the PDA which is not initialized |
---|
381 | 417 | yet. */ |
---|
382 | 418 | static void __init clear_bss(void) |
---|
383 | 419 | { |
---|
384 | 420 | memset(__bss_start, 0, |
---|
385 | 421 | (unsigned long) __bss_stop - (unsigned long) __bss_start); |
---|
| 422 | + memset(__brk_base, 0, |
---|
| 423 | + (unsigned long) __brk_limit - (unsigned long) __brk_base); |
---|
386 | 424 | } |
---|
387 | 425 | |
---|
388 | 426 | static unsigned long get_cmd_line_ptr(void) |
---|
.. | .. |
---|
405 | 443 | */ |
---|
406 | 444 | sme_map_bootdata(real_mode_data); |
---|
407 | 445 | |
---|
408 | | - memcpy(&boot_params, real_mode_data, sizeof boot_params); |
---|
| 446 | + memcpy(&boot_params, real_mode_data, sizeof(boot_params)); |
---|
409 | 447 | sanitize_boot_params(&boot_params); |
---|
410 | 448 | cmd_line_ptr = get_cmd_line_ptr(); |
---|
411 | 449 | if (cmd_line_ptr) { |
---|
.. | .. |
---|
489 | 527 | |
---|
490 | 528 | start_kernel(); |
---|
491 | 529 | } |
---|
| 530 | + |
---|
| 531 | +/* |
---|
| 532 | + * Data structures and code used for IDT setup in head_64.S. The bringup-IDT is |
---|
| 533 | + * used until the idt_table takes over. On the boot CPU this happens in |
---|
| 534 | + * x86_64_start_kernel(), on secondary CPUs in start_secondary(). In both cases |
---|
| 535 | + * this happens in the functions called from head_64.S. |
---|
| 536 | + * |
---|
| 537 | + * The idt_table can't be used that early because all the code modifying it is |
---|
| 538 | + * in idt.c and can be instrumented by tracing or KASAN, which both don't work |
---|
| 539 | + * during early CPU bringup. Also the idt_table has the runtime vectors |
---|
| 540 | + * configured which require certain CPU state to be setup already (like TSS), |
---|
| 541 | + * which also hasn't happened yet in early CPU bringup. |
---|
| 542 | + */ |
---|
| 543 | +static gate_desc bringup_idt_table[NUM_EXCEPTION_VECTORS] __page_aligned_data; |
---|
| 544 | + |
---|
| 545 | +static struct desc_ptr bringup_idt_descr = { |
---|
| 546 | + .size = (NUM_EXCEPTION_VECTORS * sizeof(gate_desc)) - 1, |
---|
| 547 | + .address = 0, /* Set at runtime */ |
---|
| 548 | +}; |
---|
| 549 | + |
---|
| 550 | +static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler) |
---|
| 551 | +{ |
---|
| 552 | +#ifdef CONFIG_AMD_MEM_ENCRYPT |
---|
| 553 | + struct idt_data data; |
---|
| 554 | + gate_desc desc; |
---|
| 555 | + |
---|
| 556 | + init_idt_data(&data, n, handler); |
---|
| 557 | + idt_init_desc(&desc, &data); |
---|
| 558 | + native_write_idt_entry(idt, n, &desc); |
---|
| 559 | +#endif |
---|
| 560 | +} |
---|
| 561 | + |
---|
| 562 | +/* This runs while still in the direct mapping */ |
---|
| 563 | +static void startup_64_load_idt(unsigned long physbase) |
---|
| 564 | +{ |
---|
| 565 | + struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase); |
---|
| 566 | + gate_desc *idt = fixup_pointer(bringup_idt_table, physbase); |
---|
| 567 | + |
---|
| 568 | + |
---|
| 569 | + if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) { |
---|
| 570 | + void *handler; |
---|
| 571 | + |
---|
| 572 | + /* VMM Communication Exception */ |
---|
| 573 | + handler = fixup_pointer(vc_no_ghcb, physbase); |
---|
| 574 | + set_bringup_idt_handler(idt, X86_TRAP_VC, handler); |
---|
| 575 | + } |
---|
| 576 | + |
---|
| 577 | + desc->address = (unsigned long)idt; |
---|
| 578 | + native_load_idt(desc); |
---|
| 579 | +} |
---|
| 580 | + |
---|
| 581 | +/* This is used when running on kernel addresses */ |
---|
| 582 | +void early_setup_idt(void) |
---|
| 583 | +{ |
---|
| 584 | + /* VMM Communication Exception */ |
---|
| 585 | + if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) |
---|
| 586 | + set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb); |
---|
| 587 | + |
---|
| 588 | + bringup_idt_descr.address = (unsigned long)bringup_idt_table; |
---|
| 589 | + native_load_idt(&bringup_idt_descr); |
---|
| 590 | +} |
---|
| 591 | + |
---|
| 592 | +/* |
---|
| 593 | + * Setup boot CPU state needed before kernel switches to virtual addresses. |
---|
| 594 | + */ |
---|
| 595 | +void __head startup_64_setup_env(unsigned long physbase) |
---|
| 596 | +{ |
---|
| 597 | + /* Load GDT */ |
---|
| 598 | + startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase); |
---|
| 599 | + native_load_gdt(&startup_gdt_descr); |
---|
| 600 | + |
---|
| 601 | + /* New GDT is live - reload data segment registers */ |
---|
| 602 | + asm volatile("movl %%eax, %%ds\n" |
---|
| 603 | + "movl %%eax, %%ss\n" |
---|
| 604 | + "movl %%eax, %%es\n" : : "a"(__KERNEL_DS) : "memory"); |
---|
| 605 | + |
---|
| 606 | + startup_64_load_idt(physbase); |
---|
| 607 | +} |
---|