| .. | .. |
|---|
| 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 | +} |
|---|