mirror of https://gitee.com/openkylin/linux.git
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm updates from Ingo Molnar: "Misc updates: - Remove last remaining calls to exception_enter/exception_exit() and simplify the entry code some more. - Remove force_iret() - Add support for "Fast Short Rep Mov", which is available starting with Ice Lake Intel CPUs - and make the x86 assembly version of memmove() use REP MOV for all sizes when FSRM is available. - Micro-optimize/simplify the 32-bit boot code a bit. - Use a more future-proof SYSRET instruction mnemonic" * 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/boot: Simplify calculation of output address x86/entry/64: Add instruction suffix to SYSRET x86: Remove force_iret() x86/cpufeatures: Add support for fast short REP; MOVSB x86/context-tracking: Remove exception_enter/exit() from KVM_PV_REASON_PAGE_NOT_PRESENT async page fault x86/context-tracking: Remove exception_enter/exit() from do_page_fault()
This commit is contained in:
commit
bcc8aff6af
|
@ -189,11 +189,9 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
|
||||||
/* push arguments for extract_kernel: */
|
/* push arguments for extract_kernel: */
|
||||||
pushl $z_output_len /* decompressed length, end of relocs */
|
pushl $z_output_len /* decompressed length, end of relocs */
|
||||||
|
|
||||||
movl BP_init_size(%esi), %eax
|
leal _end(%ebx), %eax
|
||||||
subl $_end, %eax
|
subl BP_init_size(%esi), %eax
|
||||||
movl %ebx, %ebp
|
pushl %eax /* output address */
|
||||||
subl %eax, %ebp
|
|
||||||
pushl %ebp /* output address */
|
|
||||||
|
|
||||||
pushl $z_input_len /* input_len */
|
pushl $z_input_len /* input_len */
|
||||||
leal input_data(%ebx), %eax
|
leal input_data(%ebx), %eax
|
||||||
|
|
|
@ -1728,7 +1728,7 @@ SYM_CODE_END(nmi)
|
||||||
SYM_CODE_START(ignore_sysret)
|
SYM_CODE_START(ignore_sysret)
|
||||||
UNWIND_HINT_EMPTY
|
UNWIND_HINT_EMPTY
|
||||||
mov $-ENOSYS, %eax
|
mov $-ENOSYS, %eax
|
||||||
sysret
|
sysretl
|
||||||
SYM_CODE_END(ignore_sysret)
|
SYM_CODE_END(ignore_sysret)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -114,8 +114,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
||||||
|
|
||||||
err |= fpu__restore_sig(buf, 1);
|
err |= fpu__restore_sig(buf, 1);
|
||||||
|
|
||||||
force_iret();
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,7 @@
|
||||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
|
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
|
||||||
#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
|
#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
|
||||||
#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
|
#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
|
||||||
|
#define X86_FEATURE_FSRM (18*32+ 4) /* Fast Short Rep Mov */
|
||||||
#define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */
|
#define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */
|
||||||
#define X86_FEATURE_MD_CLEAR (18*32+10) /* VERW clears CPU buffers */
|
#define X86_FEATURE_MD_CLEAR (18*32+10) /* VERW clears CPU buffers */
|
||||||
#define X86_FEATURE_TSX_FORCE_ABORT (18*32+13) /* "" TSX_FORCE_ABORT */
|
#define X86_FEATURE_TSX_FORCE_ABORT (18*32+13) /* "" TSX_FORCE_ABORT */
|
||||||
|
|
|
@ -339,22 +339,6 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
|
||||||
|
|
||||||
#define ARCH_HAS_USER_SINGLE_STEP_REPORT
|
#define ARCH_HAS_USER_SINGLE_STEP_REPORT
|
||||||
|
|
||||||
/*
|
|
||||||
* When hitting ptrace_stop(), we cannot return using SYSRET because
|
|
||||||
* that does not restore the full CPU state, only a minimal set. The
|
|
||||||
* ptracer can change arbitrary register values, which is usually okay
|
|
||||||
* because the usual ptrace stops run off the signal delivery path which
|
|
||||||
* forces IRET; however, ptrace_event() stops happen in arbitrary places
|
|
||||||
* in the kernel and don't force IRET path.
|
|
||||||
*
|
|
||||||
* So force IRET path after a ptrace stop.
|
|
||||||
*/
|
|
||||||
#define arch_ptrace_stop_needed(code, info) \
|
|
||||||
({ \
|
|
||||||
force_iret(); \
|
|
||||||
false; \
|
|
||||||
})
|
|
||||||
|
|
||||||
struct user_desc;
|
struct user_desc;
|
||||||
extern int do_get_thread_area(struct task_struct *p, int idx,
|
extern int do_get_thread_area(struct task_struct *p, int idx,
|
||||||
struct user_desc __user *info);
|
struct user_desc __user *info);
|
||||||
|
|
|
@ -239,15 +239,6 @@ static inline int arch_within_stack_frames(const void * const stack,
|
||||||
current_thread_info()->status & TS_COMPAT)
|
current_thread_info()->status & TS_COMPAT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Force syscall return via IRET by making it look as if there was
|
|
||||||
* some work pending. IRET is our most capable (but slowest) syscall
|
|
||||||
* return path, which is able to restore modified SS, CS and certain
|
|
||||||
* EFLAGS values that other (fast) syscall return instructions
|
|
||||||
* are not able to restore properly.
|
|
||||||
*/
|
|
||||||
#define force_iret() set_thread_flag(TIF_NOTIFY_RESUME)
|
|
||||||
|
|
||||||
extern void arch_task_cache_init(void);
|
extern void arch_task_cache_init(void);
|
||||||
extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
||||||
extern void arch_release_task_struct(struct task_struct *tsk);
|
extern void arch_release_task_struct(struct task_struct *tsk);
|
||||||
|
|
|
@ -245,17 +245,13 @@ NOKPROBE_SYMBOL(kvm_read_and_reset_pf_reason);
|
||||||
dotraplinkage void
|
dotraplinkage void
|
||||||
do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
|
do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
|
||||||
{
|
{
|
||||||
enum ctx_state prev_state;
|
|
||||||
|
|
||||||
switch (kvm_read_and_reset_pf_reason()) {
|
switch (kvm_read_and_reset_pf_reason()) {
|
||||||
default:
|
default:
|
||||||
do_page_fault(regs, error_code, address);
|
do_page_fault(regs, error_code, address);
|
||||||
break;
|
break;
|
||||||
case KVM_PV_REASON_PAGE_NOT_PRESENT:
|
case KVM_PV_REASON_PAGE_NOT_PRESENT:
|
||||||
/* page is swapped out by the host. */
|
/* page is swapped out by the host. */
|
||||||
prev_state = exception_enter();
|
|
||||||
kvm_async_pf_task_wait((u32)address, !user_mode(regs));
|
kvm_async_pf_task_wait((u32)address, !user_mode(regs));
|
||||||
exception_exit(prev_state);
|
|
||||||
break;
|
break;
|
||||||
case KVM_PV_REASON_PAGE_READY:
|
case KVM_PV_REASON_PAGE_READY:
|
||||||
rcu_irq_enter();
|
rcu_irq_enter();
|
||||||
|
|
|
@ -124,7 +124,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
|
||||||
regs->ip = new_ip;
|
regs->ip = new_ip;
|
||||||
regs->sp = new_sp;
|
regs->sp = new_sp;
|
||||||
regs->flags = X86_EFLAGS_IF;
|
regs->flags = X86_EFLAGS_IF;
|
||||||
force_iret();
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(start_thread);
|
EXPORT_SYMBOL_GPL(start_thread);
|
||||||
|
|
||||||
|
|
|
@ -394,7 +394,6 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
|
||||||
regs->cs = _cs;
|
regs->cs = _cs;
|
||||||
regs->ss = _ss;
|
regs->ss = _ss;
|
||||||
regs->flags = X86_EFLAGS_IF;
|
regs->flags = X86_EFLAGS_IF;
|
||||||
force_iret();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -151,8 +151,6 @@ static int restore_sigcontext(struct pt_regs *regs,
|
||||||
|
|
||||||
err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32));
|
err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32));
|
||||||
|
|
||||||
force_iret();
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -381,7 +381,6 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
|
||||||
mark_screen_rdonly(tsk->mm);
|
mark_screen_rdonly(tsk->mm);
|
||||||
|
|
||||||
memcpy((struct kernel_vm86_regs *)regs, &vm86regs, sizeof(vm86regs));
|
memcpy((struct kernel_vm86_regs *)regs, &vm86regs, sizeof(vm86regs));
|
||||||
force_iret();
|
|
||||||
return regs->ax;
|
return regs->ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,7 @@
|
||||||
SYM_FUNC_START_ALIAS(memmove)
|
SYM_FUNC_START_ALIAS(memmove)
|
||||||
SYM_FUNC_START(__memmove)
|
SYM_FUNC_START(__memmove)
|
||||||
|
|
||||||
/* Handle more 32 bytes in loop */
|
|
||||||
mov %rdi, %rax
|
mov %rdi, %rax
|
||||||
cmp $0x20, %rdx
|
|
||||||
jb 1f
|
|
||||||
|
|
||||||
/* Decide forward/backward copy mode */
|
/* Decide forward/backward copy mode */
|
||||||
cmp %rdi, %rsi
|
cmp %rdi, %rsi
|
||||||
|
@ -42,7 +39,9 @@ SYM_FUNC_START(__memmove)
|
||||||
cmp %rdi, %r8
|
cmp %rdi, %r8
|
||||||
jg 2f
|
jg 2f
|
||||||
|
|
||||||
|
/* FSRM implies ERMS => no length checks, do the copy directly */
|
||||||
.Lmemmove_begin_forward:
|
.Lmemmove_begin_forward:
|
||||||
|
ALTERNATIVE "cmp $0x20, %rdx; jb 1f", "", X86_FEATURE_FSRM
|
||||||
ALTERNATIVE "", "movq %rdx, %rcx; rep movsb; retq", X86_FEATURE_ERMS
|
ALTERNATIVE "", "movq %rdx, %rcx; rep movsb; retq", X86_FEATURE_ERMS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -114,6 +113,8 @@ SYM_FUNC_START(__memmove)
|
||||||
*/
|
*/
|
||||||
.p2align 4
|
.p2align 4
|
||||||
2:
|
2:
|
||||||
|
cmp $0x20, %rdx
|
||||||
|
jb 1f
|
||||||
cmp $680, %rdx
|
cmp $680, %rdx
|
||||||
jb 6f
|
jb 6f
|
||||||
cmp %dil, %sil
|
cmp %dil, %sil
|
||||||
|
|
|
@ -1487,27 +1487,6 @@ void do_user_addr_fault(struct pt_regs *regs,
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(do_user_addr_fault);
|
NOKPROBE_SYMBOL(do_user_addr_fault);
|
||||||
|
|
||||||
/*
|
|
||||||
* Explicitly marked noinline such that the function tracer sees this as the
|
|
||||||
* page_fault entry point.
|
|
||||||
*/
|
|
||||||
static noinline void
|
|
||||||
__do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
|
|
||||||
unsigned long address)
|
|
||||||
{
|
|
||||||
prefetchw(¤t->mm->mmap_sem);
|
|
||||||
|
|
||||||
if (unlikely(kmmio_fault(regs, address)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Was the fault on kernel-controlled part of the address space? */
|
|
||||||
if (unlikely(fault_in_kernel_space(address)))
|
|
||||||
do_kern_addr_fault(regs, hw_error_code, address);
|
|
||||||
else
|
|
||||||
do_user_addr_fault(regs, hw_error_code, address);
|
|
||||||
}
|
|
||||||
NOKPROBE_SYMBOL(__do_page_fault);
|
|
||||||
|
|
||||||
static __always_inline void
|
static __always_inline void
|
||||||
trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
|
trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
|
||||||
unsigned long address)
|
unsigned long address)
|
||||||
|
@ -1522,13 +1501,19 @@ trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
dotraplinkage void
|
dotraplinkage void
|
||||||
do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
|
do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
|
||||||
|
unsigned long address)
|
||||||
{
|
{
|
||||||
enum ctx_state prev_state;
|
prefetchw(¤t->mm->mmap_sem);
|
||||||
|
trace_page_fault_entries(regs, hw_error_code, address);
|
||||||
|
|
||||||
prev_state = exception_enter();
|
if (unlikely(kmmio_fault(regs, address)))
|
||||||
trace_page_fault_entries(regs, error_code, address);
|
return;
|
||||||
__do_page_fault(regs, error_code, address);
|
|
||||||
exception_exit(prev_state);
|
/* Was the fault on kernel-controlled part of the address space? */
|
||||||
|
if (unlikely(fault_in_kernel_space(address)))
|
||||||
|
do_kern_addr_fault(regs, hw_error_code, address);
|
||||||
|
else
|
||||||
|
do_user_addr_fault(regs, hw_error_code, address);
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(do_page_fault);
|
NOKPROBE_SYMBOL(do_page_fault);
|
||||||
|
|
Loading…
Reference in New Issue