Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/paravirt: Switch functions with custom code to ALTERNATIVE

Instead of using paravirt patching for custom code sequences use
ALTERNATIVE for the functions with custom code replacements.

Instead of patching an ud2 instruction for unpopulated vector entries
into the caller site, use a simple function just calling BUG() as a
replacement.

Simplify the register defines for assembler paravirt calling, as there
isn't much usage left.

Signed-off-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20210311142319.4723-14-jgross@suse.com

authored by

Juergen Gross and committed by
Borislav Petkov
fafe5e74 00aa3193

+58 -157
+1 -1
arch/x86/entry/entry_64.S
··· 305 305 .macro DEBUG_ENTRY_ASSERT_IRQS_OFF 306 306 #ifdef CONFIG_DEBUG_ENTRY 307 307 pushq %rax 308 - SAVE_FLAGS(CLBR_RAX) 308 + SAVE_FLAGS 309 309 testl $X86_EFLAGS_IF, %eax 310 310 jz .Lokay_\@ 311 311 ud2
+1 -1
arch/x86/include/asm/irqflags.h
··· 111 111 112 112 #ifdef CONFIG_X86_64 113 113 #ifdef CONFIG_DEBUG_ENTRY 114 - #define SAVE_FLAGS(x) pushfq; popq %rax 114 + #define SAVE_FLAGS pushfq; popq %rax 115 115 #endif 116 116 117 117 #define INTERRUPT_RETURN jmp native_iret
+50 -51
arch/x86/include/asm/paravirt.h
··· 135 135 136 136 static inline unsigned long read_cr2(void) 137 137 { 138 - return PVOP_CALLEE0(unsigned long, mmu.read_cr2); 138 + return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2, 139 + "mov %%cr2, %%rax;", 140 + ALT_NOT(X86_FEATURE_XENPV)); 139 141 } 140 142 141 143 static inline void write_cr2(unsigned long x) ··· 147 145 148 146 static inline unsigned long __read_cr3(void) 149 147 { 150 - return PVOP_CALL0(unsigned long, mmu.read_cr3); 148 + return PVOP_ALT_CALL0(unsigned long, mmu.read_cr3, 149 + "mov %%cr3, %%rax;", ALT_NOT(X86_FEATURE_XENPV)); 151 150 } 152 151 153 152 static inline void write_cr3(unsigned long x) 154 153 { 155 - PVOP_VCALL1(mmu.write_cr3, x); 154 + PVOP_ALT_VCALL1(mmu.write_cr3, x, 155 + "mov %%rdi, %%cr3", ALT_NOT(X86_FEATURE_XENPV)); 156 156 } 157 157 158 158 static inline void __write_cr4(unsigned long x) ··· 174 170 175 171 static inline void wbinvd(void) 176 172 { 177 - PVOP_VCALL0(cpu.wbinvd); 173 + PVOP_ALT_VCALL0(cpu.wbinvd, "wbinvd", ALT_NOT(X86_FEATURE_XENPV)); 178 174 } 179 175 180 176 static inline u64 paravirt_read_msr(unsigned msr) ··· 388 384 389 385 static inline pte_t __pte(pteval_t val) 390 386 { 391 - return (pte_t) { PVOP_CALLEE1(pteval_t, mmu.make_pte, val) }; 387 + return (pte_t) { PVOP_ALT_CALLEE1(pteval_t, mmu.make_pte, val, 388 + "mov %%rdi, %%rax", 389 + ALT_NOT(X86_FEATURE_XENPV)) }; 392 390 } 393 391 394 392 static inline pteval_t pte_val(pte_t pte) 395 393 { 396 - return PVOP_CALLEE1(pteval_t, mmu.pte_val, pte.pte); 394 + return PVOP_ALT_CALLEE1(pteval_t, mmu.pte_val, pte.pte, 395 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 397 396 } 398 397 399 398 static inline pgd_t __pgd(pgdval_t val) 400 399 { 401 - return (pgd_t) { PVOP_CALLEE1(pgdval_t, mmu.make_pgd, val) }; 400 + return (pgd_t) { PVOP_ALT_CALLEE1(pgdval_t, mmu.make_pgd, val, 401 + "mov %%rdi, %%rax", 402 + ALT_NOT(X86_FEATURE_XENPV)) }; 402 403 } 403 404 404 405 static inline pgdval_t pgd_val(pgd_t pgd) 405 406 { 406 - return PVOP_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd); 407 + return PVOP_ALT_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd, 408 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 407 409 } 408 410 409 411 #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION ··· 442 432 443 433 static inline pmd_t __pmd(pmdval_t val) 444 434 { 445 - return (pmd_t) { PVOP_CALLEE1(pmdval_t, mmu.make_pmd, val) }; 435 + return (pmd_t) { PVOP_ALT_CALLEE1(pmdval_t, mmu.make_pmd, val, 436 + "mov %%rdi, %%rax", 437 + ALT_NOT(X86_FEATURE_XENPV)) }; 446 438 } 447 439 448 440 static inline pmdval_t pmd_val(pmd_t pmd) 449 441 { 450 - return PVOP_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd); 442 + return PVOP_ALT_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd, 443 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 451 444 } 452 445 453 446 static inline void set_pud(pud_t *pudp, pud_t pud) ··· 462 449 { 463 450 pudval_t ret; 464 451 465 - ret = PVOP_CALLEE1(pudval_t, mmu.make_pud, val); 452 + ret = PVOP_ALT_CALLEE1(pudval_t, mmu.make_pud, val, 453 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 466 454 467 455 return (pud_t) { ret }; 468 456 } 469 457 470 458 static inline pudval_t pud_val(pud_t pud) 471 459 { 472 - return PVOP_CALLEE1(pudval_t, mmu.pud_val, pud.pud); 460 + return PVOP_ALT_CALLEE1(pudval_t, mmu.pud_val, pud.pud, 461 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 473 462 } 474 463 475 464 static inline void pud_clear(pud_t *pudp) ··· 490 475 491 476 static inline p4d_t __p4d(p4dval_t val) 492 477 { 493 - p4dval_t ret = PVOP_CALLEE1(p4dval_t, mmu.make_p4d, val); 478 + p4dval_t ret = PVOP_ALT_CALLEE1(p4dval_t, mmu.make_p4d, val, 479 + "mov %%rdi, %%rax", 480 + ALT_NOT(X86_FEATURE_XENPV)); 494 481 495 482 return (p4d_t) { ret }; 496 483 } 497 484 498 485 static inline p4dval_t p4d_val(p4d_t p4d) 499 486 { 500 - return PVOP_CALLEE1(p4dval_t, mmu.p4d_val, p4d.p4d); 487 + return PVOP_ALT_CALLEE1(p4dval_t, mmu.p4d_val, p4d.p4d, 488 + "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); 501 489 } 502 490 503 491 static inline void __set_pgd(pgd_t *pgdp, pgd_t pgd) ··· 587 569 588 570 static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock) 589 571 { 590 - PVOP_VCALLEE1(lock.queued_spin_unlock, lock); 572 + PVOP_ALT_VCALLEE1(lock.queued_spin_unlock, lock, 573 + "movb $0, (%%" _ASM_ARG1 ");", 574 + ALT_NOT(X86_FEATURE_PVUNLOCK)); 591 575 } 592 576 593 577 static __always_inline void pv_wait(u8 *ptr, u8 val) ··· 604 584 605 585 static __always_inline bool pv_vcpu_is_preempted(long cpu) 606 586 { 607 - return PVOP_CALLEE1(bool, lock.vcpu_is_preempted, cpu); 587 + return PVOP_ALT_CALLEE1(bool, lock.vcpu_is_preempted, cpu, 588 + "xor %%" _ASM_AX ", %%" _ASM_AX ";", 589 + ALT_NOT(X86_FEATURE_VCPUPREEMPT)); 608 590 } 609 591 610 592 void __raw_callee_save___native_queued_spin_unlock(struct qspinlock *lock); ··· 680 658 #ifdef CONFIG_PARAVIRT_XXL 681 659 static inline notrace unsigned long arch_local_save_flags(void) 682 660 { 683 - return PVOP_CALLEE0(unsigned long, irq.save_fl); 661 + return PVOP_ALT_CALLEE0(unsigned long, irq.save_fl, "pushf; pop %%rax;", 662 + ALT_NOT(X86_FEATURE_XENPV)); 684 663 } 685 664 686 665 static inline notrace void arch_local_irq_disable(void) 687 666 { 688 - PVOP_VCALLEE0(irq.irq_disable); 667 + PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT(X86_FEATURE_XENPV)); 689 668 } 690 669 691 670 static inline notrace void arch_local_irq_enable(void) 692 671 { 693 - PVOP_VCALLEE0(irq.irq_enable); 672 + PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT(X86_FEATURE_XENPV)); 694 673 } 695 674 696 675 static inline notrace unsigned long arch_local_irq_save(void) ··· 736 713 .popsection 737 714 738 715 739 - #define COND_PUSH(set, mask, reg) \ 740 - .if ((~(set)) & mask); push %reg; .endif 741 - #define COND_POP(set, mask, reg) \ 742 - .if ((~(set)) & mask); pop %reg; .endif 743 - 744 716 #ifdef CONFIG_X86_64 745 717 #ifdef CONFIG_PARAVIRT_XXL 746 - 747 - #define PV_SAVE_REGS(set) \ 748 - COND_PUSH(set, CLBR_RAX, rax); \ 749 - COND_PUSH(set, CLBR_RCX, rcx); \ 750 - COND_PUSH(set, CLBR_RDX, rdx); \ 751 - COND_PUSH(set, CLBR_RSI, rsi); \ 752 - COND_PUSH(set, CLBR_RDI, rdi); \ 753 - COND_PUSH(set, CLBR_R8, r8); \ 754 - COND_PUSH(set, CLBR_R9, r9); \ 755 - COND_PUSH(set, CLBR_R10, r10); \ 756 - COND_PUSH(set, CLBR_R11, r11) 757 - #define PV_RESTORE_REGS(set) \ 758 - COND_POP(set, CLBR_R11, r11); \ 759 - COND_POP(set, CLBR_R10, r10); \ 760 - COND_POP(set, CLBR_R9, r9); \ 761 - COND_POP(set, CLBR_R8, r8); \ 762 - COND_POP(set, CLBR_RDI, rdi); \ 763 - COND_POP(set, CLBR_RSI, rsi); \ 764 - COND_POP(set, CLBR_RDX, rdx); \ 765 - COND_POP(set, CLBR_RCX, rcx); \ 766 - COND_POP(set, CLBR_RAX, rax) 767 718 768 719 #define PARA_PATCH(off) ((off) / 8) 769 720 #define PARA_SITE(ptype, ops) _PVSITE(ptype, ops, .quad, 8) ··· 749 752 X86_FEATURE_XENPV, "jmp xen_iret;", "jmp native_iret;") 750 753 751 754 #ifdef CONFIG_DEBUG_ENTRY 752 - #define SAVE_FLAGS(clobbers) \ 753 - PARA_SITE(PARA_PATCH(PV_IRQ_save_fl), \ 754 - PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ 755 - ANNOTATE_RETPOLINE_SAFE; \ 756 - call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl); \ 757 - PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) 755 + .macro PARA_IRQ_save_fl 756 + PARA_SITE(PARA_PATCH(PV_IRQ_save_fl), 757 + ANNOTATE_RETPOLINE_SAFE; 758 + call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);) 759 + .endm 760 + 761 + #define SAVE_FLAGS ALTERNATIVE "PARA_IRQ_save_fl;", "pushf; pop %rax;", \ 762 + ALT_NOT(X86_FEATURE_XENPV) 758 763 #endif 759 764 #endif /* CONFIG_PARAVIRT_XXL */ 760 765 #endif /* CONFIG_X86_64 */
-6
arch/x86/include/asm/paravirt_types.h
··· 3 3 #define _ASM_X86_PARAVIRT_TYPES_H 4 4 5 5 /* Bitmask of what can be clobbered: usually at least eax. */ 6 - #define CLBR_NONE 0 7 6 #define CLBR_EAX (1 << 0) 8 7 #define CLBR_ECX (1 << 1) 9 8 #define CLBR_EDX (1 << 2) ··· 14 15 15 16 #define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX) 16 17 #define CLBR_RET_REG (CLBR_EAX | CLBR_EDX) 17 - #define CLBR_SCRATCH (0) 18 18 #else 19 19 #define CLBR_RAX CLBR_EAX 20 20 #define CLBR_RCX CLBR_ECX ··· 30 32 #define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \ 31 33 CLBR_RCX | CLBR_R8 | CLBR_R9) 32 34 #define CLBR_RET_REG (CLBR_RAX) 33 - #define CLBR_SCRATCH (CLBR_R10 | CLBR_R11) 34 35 35 36 #endif /* X86_64 */ 36 - 37 - #define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG) 38 37 39 38 #ifndef __ASSEMBLY__ 40 39 ··· 317 322 /* Simple instruction patching code. */ 318 323 #define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t" 319 324 320 - unsigned paravirt_patch_ident_64(void *insn_buff, unsigned len); 321 325 unsigned paravirt_patch_default(u8 type, void *insn_buff, unsigned long addr, unsigned len); 322 326 unsigned paravirt_patch_insns(void *insn_buff, unsigned len, const char *start, const char *end); 323 327
+6 -10
arch/x86/kernel/paravirt.c
··· 53 53 } 54 54 55 55 /* Undefined instruction for dealing with missing ops pointers. */ 56 - static const unsigned char ud2a[] = { 0x0f, 0x0b }; 56 + static void paravirt_BUG(void) 57 + { 58 + BUG(); 59 + } 57 60 58 61 struct branch { 59 62 unsigned char opcode; ··· 110 107 unsigned ret; 111 108 112 109 if (opfunc == NULL) 113 - /* If there's no function, patch it with a ud2a (BUG) */ 114 - ret = paravirt_patch_insns(insn_buff, len, ud2a, ud2a+sizeof(ud2a)); 110 + /* If there's no function, patch it with paravirt_BUG() */ 111 + ret = paravirt_patch_call(insn_buff, paravirt_BUG, addr, len); 115 112 else if (opfunc == _paravirt_nop) 116 113 ret = 0; 117 - 118 - #ifdef CONFIG_PARAVIRT_XXL 119 - /* identity functions just return their single argument */ 120 - else if (opfunc == _paravirt_ident_64) 121 - ret = paravirt_patch_ident_64(insn_buff, len); 122 - 123 - #endif 124 114 else 125 115 /* Otherwise call the function. */ 126 116 ret = paravirt_patch_call(insn_buff, opfunc, addr, len);
-88
arch/x86/kernel/paravirt_patch.c
··· 4 4 #include <asm/paravirt.h> 5 5 #include <asm/asm-offsets.h> 6 6 7 - #define PSTART(d, m) \ 8 - patch_data_##d.m 9 - 10 - #define PEND(d, m) \ 11 - (PSTART(d, m) + sizeof(patch_data_##d.m)) 12 - 13 - #define PATCH(d, m, insn_buff, len) \ 14 - paravirt_patch_insns(insn_buff, len, PSTART(d, m), PEND(d, m)) 15 - 16 - #define PATCH_CASE(ops, m, data, insn_buff, len) \ 17 - case PARAVIRT_PATCH(ops.m): \ 18 - return PATCH(data, ops##_##m, insn_buff, len) 19 - 20 - #ifdef CONFIG_PARAVIRT_XXL 21 - struct patch_xxl { 22 - const unsigned char irq_irq_disable[1]; 23 - const unsigned char irq_irq_enable[1]; 24 - const unsigned char irq_save_fl[2]; 25 - const unsigned char mmu_read_cr2[3]; 26 - const unsigned char mmu_read_cr3[3]; 27 - const unsigned char mmu_write_cr3[3]; 28 - const unsigned char cpu_wbinvd[2]; 29 - const unsigned char mov64[3]; 30 - }; 31 - 32 - static const struct patch_xxl patch_data_xxl = { 33 - .irq_irq_disable = { 0xfa }, // cli 34 - .irq_irq_enable = { 0xfb }, // sti 35 - .irq_save_fl = { 0x9c, 0x58 }, // pushf; pop %[re]ax 36 - .mmu_read_cr2 = { 0x0f, 0x20, 0xd0 }, // mov %cr2, %[re]ax 37 - .mmu_read_cr3 = { 0x0f, 0x20, 0xd8 }, // mov %cr3, %[re]ax 38 - .mmu_write_cr3 = { 0x0f, 0x22, 0xdf }, // mov %rdi, %cr3 39 - .cpu_wbinvd = { 0x0f, 0x09 }, // wbinvd 40 - .mov64 = { 0x48, 0x89, 0xf8 }, // mov %rdi, %rax 41 - }; 42 - 43 - unsigned int paravirt_patch_ident_64(void *insn_buff, unsigned int len) 44 - { 45 - return PATCH(xxl, mov64, insn_buff, len); 46 - } 47 - # endif /* CONFIG_PARAVIRT_XXL */ 48 - 49 - #ifdef CONFIG_PARAVIRT_SPINLOCKS 50 - struct patch_lock { 51 - unsigned char queued_spin_unlock[3]; 52 - unsigned char vcpu_is_preempted[2]; 53 - }; 54 - 55 - static const struct patch_lock patch_data_lock = { 56 - .vcpu_is_preempted = { 0x31, 0xc0 }, // xor %eax, %eax 57 - 58 - # ifdef CONFIG_X86_64 59 - .queued_spin_unlock = { 0xc6, 0x07, 0x00 }, // movb $0, (%rdi) 60 - # else 61 - .queued_spin_unlock = { 0xc6, 0x00, 0x00 }, // movb $0, (%eax) 62 - # endif 63 - }; 64 - #endif /* CONFIG_PARAVIRT_SPINLOCKS */ 65 - 66 7 unsigned int native_patch(u8 type, void *insn_buff, unsigned long addr, 67 8 unsigned int len) 68 9 { 69 - switch (type) { 70 - 71 - #ifdef CONFIG_PARAVIRT_XXL 72 - PATCH_CASE(irq, save_fl, xxl, insn_buff, len); 73 - PATCH_CASE(irq, irq_enable, xxl, insn_buff, len); 74 - PATCH_CASE(irq, irq_disable, xxl, insn_buff, len); 75 - 76 - PATCH_CASE(mmu, read_cr2, xxl, insn_buff, len); 77 - PATCH_CASE(mmu, read_cr3, xxl, insn_buff, len); 78 - PATCH_CASE(mmu, write_cr3, xxl, insn_buff, len); 79 - 80 - PATCH_CASE(cpu, wbinvd, xxl, insn_buff, len); 81 - #endif 82 - 83 - #ifdef CONFIG_PARAVIRT_SPINLOCKS 84 - case PARAVIRT_PATCH(lock.queued_spin_unlock): 85 - if (pv_is_native_spin_unlock()) 86 - return PATCH(lock, queued_spin_unlock, insn_buff, len); 87 - break; 88 - 89 - case PARAVIRT_PATCH(lock.vcpu_is_preempted): 90 - if (pv_is_native_vcpu_is_preempted()) 91 - return PATCH(lock, vcpu_is_preempted, insn_buff, len); 92 - break; 93 - #endif 94 - default: 95 - break; 96 - } 97 - 98 10 return paravirt_patch_default(type, insn_buff, addr, len); 99 11 }