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

x86/paravirt: Make read_cr2() CALLEE_SAVE

The one paravirt read_cr2() implementation (Xen) is actually quite trivial
and doesn't need to clobber anything other than the return register.

Making read_cr2() CALLEE_SAVE avoids all the PUSH/POP nonsense and allows
more convenient use from assembly.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Juergen Gross <jgross@suse.com>
Cc: bp@alien8.de
Cc: rostedt@goodmis.org
Cc: luto@kernel.org
Cc: torvalds@linux-foundation.org
Cc: hpa@zytor.com
Cc: dave.hansen@linux.intel.com
Cc: zhe.he@windriver.com
Cc: joel@joelfernandes.org
Cc: devel@etsukata.com
Link: https://lkml.kernel.org/r/20190711114335.887392493@infradead.org

authored by

Peter Zijlstra and committed by
Thomas Gleixner
55aedddb 406de552

+45 -26
+6
arch/x86/entry/calling.h
··· 343 343 .Lafter_call_\@: 344 344 #endif 345 345 .endm 346 + 347 + #ifdef CONFIG_PARAVIRT_XXL 348 + #define GET_CR2_INTO(reg) GET_CR2_INTO_AX ; _ASM_MOV %_ASM_AX, reg 349 + #else 350 + #define GET_CR2_INTO(reg) _ASM_MOV %cr2, reg 351 + #endif
+13 -9
arch/x86/include/asm/paravirt.h
··· 116 116 117 117 static inline unsigned long read_cr2(void) 118 118 { 119 - return PVOP_CALL0(unsigned long, mmu.read_cr2); 119 + return PVOP_CALLEE0(unsigned long, mmu.read_cr2); 120 120 } 121 121 122 122 static inline void write_cr2(unsigned long x) ··· 909 909 ANNOTATE_RETPOLINE_SAFE; \ 910 910 call PARA_INDIRECT(pv_ops+PV_CPU_swapgs); \ 911 911 ) 912 - #endif 913 912 914 - #define GET_CR2_INTO_RAX \ 915 - ANNOTATE_RETPOLINE_SAFE; \ 916 - call PARA_INDIRECT(pv_ops+PV_MMU_read_cr2); 917 - 918 - #ifdef CONFIG_PARAVIRT_XXL 919 913 #define USERGS_SYSRET64 \ 920 914 PARA_SITE(PARA_PATCH(PV_CPU_usergs_sysret64), \ 921 915 ANNOTATE_RETPOLINE_SAFE; \ ··· 923 929 call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl); \ 924 930 PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) 925 931 #endif 926 - #endif 932 + #endif /* CONFIG_PARAVIRT_XXL */ 933 + #endif /* CONFIG_X86_64 */ 927 934 928 - #endif /* CONFIG_X86_32 */ 935 + #ifdef CONFIG_PARAVIRT_XXL 936 + 937 + #define GET_CR2_INTO_AX \ 938 + PARA_SITE(PARA_PATCH(PV_MMU_read_cr2), \ 939 + ANNOTATE_RETPOLINE_SAFE; \ 940 + call PARA_INDIRECT(pv_ops+PV_MMU_read_cr2); \ 941 + ) 942 + 943 + #endif /* CONFIG_PARAVIRT_XXL */ 944 + 929 945 930 946 #endif /* __ASSEMBLY__ */ 931 947 #else /* CONFIG_PARAVIRT */
+1 -1
arch/x86/include/asm/paravirt_types.h
··· 220 220 void (*exit_mmap)(struct mm_struct *mm); 221 221 222 222 #ifdef CONFIG_PARAVIRT_XXL 223 - unsigned long (*read_cr2)(void); 223 + struct paravirt_callee_save read_cr2; 224 224 void (*write_cr2)(unsigned long); 225 225 226 226 unsigned long (*read_cr3)(void);
+1
arch/x86/kernel/asm-offsets.c
··· 76 76 BLANK(); 77 77 OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); 78 78 OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending); 79 + OFFSET(XEN_vcpu_info_arch_cr2, vcpu_info, arch.cr2); 79 80 #endif 80 81 81 82 BLANK();
+1 -3
arch/x86/kernel/head_64.S
··· 29 29 #ifdef CONFIG_PARAVIRT_XXL 30 30 #include <asm/asm-offsets.h> 31 31 #include <asm/paravirt.h> 32 - #define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg 33 32 #else 34 - #define GET_CR2_INTO(reg) movq %cr2, reg 35 33 #define INTERRUPT_RETURN iretq 36 34 #endif 37 35 ··· 321 323 322 324 cmpq $14,%rsi /* Page fault? */ 323 325 jnz 10f 324 - GET_CR2_INTO(%rdi) /* Can clobber any volatile register if pv */ 326 + GET_CR2_INTO(%rdi) /* can clobber %rax if pv */ 325 327 call early_make_pgtable 326 328 andl %eax,%eax 327 329 jz 20f /* All good */
+1 -1
arch/x86/kernel/paravirt.c
··· 370 370 .mmu.exit_mmap = paravirt_nop, 371 371 372 372 #ifdef CONFIG_PARAVIRT_XXL 373 - .mmu.read_cr2 = native_read_cr2, 373 + .mmu.read_cr2 = __PV_IS_CALLEE_SAVE(native_read_cr2), 374 374 .mmu.write_cr2 = native_write_cr2, 375 375 .mmu.read_cr3 = __native_read_cr3, 376 376 .mmu.write_cr3 = native_write_cr3,
+2 -1
arch/x86/xen/enlighten_pv.c
··· 998 998 __PV_IS_CALLEE_SAVE(xen_irq_disable_direct); 999 999 pv_ops.irq.irq_enable = 1000 1000 __PV_IS_CALLEE_SAVE(xen_irq_enable_direct); 1001 - pv_ops.mmu.read_cr2 = xen_read_cr2_direct; 1001 + pv_ops.mmu.read_cr2 = 1002 + __PV_IS_CALLEE_SAVE(xen_read_cr2_direct); 1002 1003 } 1003 1004 } 1004 1005
+1 -11
arch/x86/xen/mmu_pv.c
··· 1307 1307 this_cpu_read(xen_vcpu)->arch.cr2 = cr2; 1308 1308 } 1309 1309 1310 - static unsigned long xen_read_cr2(void) 1311 - { 1312 - return this_cpu_read(xen_vcpu)->arch.cr2; 1313 - } 1314 - 1315 - unsigned long xen_read_cr2_direct(void) 1316 - { 1317 - return this_cpu_read(xen_vcpu_info.arch.cr2); 1318 - } 1319 - 1320 1310 static noinline void xen_flush_tlb(void) 1321 1311 { 1322 1312 struct mmuext_op *op; ··· 2387 2397 } 2388 2398 2389 2399 static const struct pv_mmu_ops xen_mmu_ops __initconst = { 2390 - .read_cr2 = xen_read_cr2, 2400 + .read_cr2 = __PV_IS_CALLEE_SAVE(xen_read_cr2), 2391 2401 .write_cr2 = xen_write_cr2, 2392 2402 2393 2403 .read_cr3 = xen_read_cr3,
+16
arch/x86/xen/xen-asm.S
··· 10 10 #include <asm/percpu.h> 11 11 #include <asm/processor-flags.h> 12 12 #include <asm/frame.h> 13 + #include <asm/asm.h> 13 14 14 15 #include <linux/linkage.h> 15 16 ··· 136 135 FRAME_END 137 136 ret 138 137 ENDPROC(check_events) 138 + 139 + ENTRY(xen_read_cr2) 140 + FRAME_BEGIN 141 + _ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX 142 + _ASM_MOV XEN_vcpu_info_arch_cr2(%_ASM_AX), %_ASM_AX 143 + FRAME_END 144 + ret 145 + ENDPROC(xen_read_cr2); 146 + 147 + ENTRY(xen_read_cr2_direct) 148 + FRAME_BEGIN 149 + _ASM_MOV PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_arch_cr2, %_ASM_AX 150 + FRAME_END 151 + ret 152 + ENDPROC(xen_read_cr2_direct);
+3
arch/x86/xen/xen-ops.h
··· 134 134 __visible unsigned long xen_save_fl_direct(void); 135 135 __visible void xen_restore_fl_direct(unsigned long); 136 136 137 + __visible unsigned long xen_read_cr2(void); 138 + __visible unsigned long xen_read_cr2_direct(void); 139 + 137 140 /* These are not functions, and cannot be called normally */ 138 141 __visible void xen_iret(void); 139 142 __visible void xen_sysret32(void);