📄 entry.s
字号:
/* * linux/arch/i386/entry.S * * Copyright (C) 1991, 1992 Linus Torvalds *//* * entry.S contains the system-call and fault low-level handling routines. * This also contains the timer-interrupt handler, as well as all interrupts * and faults that can result in a task-switch. * * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * * I changed all the .align's to 4 (16 byte alignment), as that's faster * on a 486. * * Stack layout in 'ret_from_system_call': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be * updated in fork.c:copy_process, signal.c:do_signal, * ptrace.c and ptrace.h * * 0(%esp) - %ebx * 4(%esp) - %ecx * 8(%esp) - %edx * C(%esp) - %esi * 10(%esp) - %edi * 14(%esp) - %ebp * 18(%esp) - %eax * 1C(%esp) - %ds * 20(%esp) - %es * 24(%esp) - orig_eax * 28(%esp) - %eip * 2C(%esp) - %cs * 30(%esp) - %eflags * 34(%esp) - %oldesp * 38(%esp) - %oldss * * "current" is in register %ebx during any slow entries. */#include <linux/config.h>#include <linux/sys.h>#include <linux/linkage.h>#include <asm/segment.h>#include <asm/smp.h>EBX = 0x00ECX = 0x04EDX = 0x08ESI = 0x0CEDI = 0x10EBP = 0x14EAX = 0x18DS = 0x1CES = 0x20ORIG_EAX = 0x24EIP = 0x28CS = 0x2CEFLAGS = 0x30OLDESP = 0x34OLDSS = 0x38CF_MASK = 0x00000001TF_MASK = 0x00000100IF_MASK = 0x00000200DF_MASK = 0x00000400NT_MASK = 0x00004000VM_MASK = 0x00020000/* * these are offsets into the task-struct. */state = 0flags = 4sigpending = 8addr_limit = 12exec_domain = 16need_resched = 20tsk_ptrace = 24processor = 52ENOSYS = 38#define SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ pushl %eax; \ pushl %ebp; \ pushl %edi; \ pushl %esi; \ pushl %edx; \ pushl %ecx; \ pushl %ebx; \ movl $(__KERNEL_DS),%edx; \ movl %edx,%ds; \ movl %edx,%es;#define RESTORE_ALL \ popl %ebx; \ popl %ecx; \ popl %edx; \ popl %esi; \ popl %edi; \ popl %ebp; \ popl %eax; \1: popl %ds; \2: popl %es; \ addl $4,%esp; \3: iret; \.section .fixup,"ax"; \4: movl $0,(%esp); \ jmp 1b; \5: movl $0,(%esp); \ jmp 2b; \6: pushl %ss; \ popl %ds; \ pushl %ss; \ popl %es; \ pushl $11; \ call do_exit; \.previous; \.section __ex_table,"a";\ .align 4; \ .long 1b,4b; \ .long 2b,5b; \ .long 3b,6b; \.previous#define GET_CURRENT(reg) \ movl $-8192, reg; \ andl %esp, regENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. movl %eax,EFLAGS(%esp) # andl $~(NT_MASK|TF_MASK|DF_MASK), %eax pushl %eax popfl movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%ebx pushl %ebx andl $-8192,%ebx # GET_CURRENT movl exec_domain(%ebx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain pushl $0x7 call *%edx addl $4, %esp popl %eax jmp ret_from_sys_callENTRY(lcall27) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. movl %eax,EFLAGS(%esp) # andl $~(NT_MASK|TF_MASK|DF_MASK), %eax pushl %eax popfl movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%ebx pushl %ebx andl $-8192,%ebx # GET_CURRENT movl exec_domain(%ebx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain pushl $0x27 call *%edx addl $4, %esp popl %eax jmp ret_from_sys_callENTRY(ret_from_fork) sti pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys_exit jmp ret_from_sys_call/* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to * go as quickly as possible which is why some of this is * less clear than it otherwise should be. * * (c) Victor Yodaiken 1999 * RTLINUX_IRET emulates the turn on interrupts effect of * iret since, under RTLinux we may have pended interrupts * that will not be automatically enabled on an iret. */#ifdef CONFIG_RTLINUX#define RTLINUX_IRET \ movl rtl_emulate_iret,%eax; \ testl %eax, %eax; \ je 1f; \ call *%eax; \ 1:#else#define RTLINUX_IRET#endifENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL#ifdef CONFIG_RTLINUX movl rtl_syscall_intercept,%ebx testl %ebx, %ebx je 991f call *%ebx movl ORIG_EAX(%esp), %eax991:#endif GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys cmpl $(NR_syscalls),%eax jae badsys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return valueENTRY(ret_from_sys_call) call *(SYMBOL_NAME(irq_control)+8) # cli from irq_control structure cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return call *(SYMBOL_NAME(irq_control)+12) # sti from irq_control structure restore_all: RTLINUX_IRET RESTORE_ALL ALIGNsignal_return: call *(SYMBOL_NAME(irq_control)+12) # sti from irq_control structure RTLINUX_IRET testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return xorl %edx,%edx call SYMBOL_NAME(do_signal) jmp restore_all ALIGNv86_signal_return: call SYMBOL_NAME(save_v86_state) movl %eax,%esp xorl %edx,%edx call SYMBOL_NAME(do_signal) jmp restore_all ALIGNtracesys: movl $-ENOSYS,EAX(%esp) call SYMBOL_NAME(syscall_trace) movl ORIG_EAX(%esp),%eax cmpl $(NR_syscalls),%eax jae tracesys_exit call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return valuetracesys_exit: call SYMBOL_NAME(syscall_trace) jmp ret_from_sys_callbadsys: movl $-ENOSYS,EAX(%esp) jmp ret_from_sys_call ALIGNENTRY(ret_from_intr) GET_CURRENT(%ebx)ret_from_exception: movl EFLAGS(%esp),%eax # mix EFLAGS and CS movb CS(%esp),%al testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? jne ret_from_sys_call jmp restore_all ALIGNreschedule: call SYMBOL_NAME(schedule) # test jmp ret_from_sys_call#define RTL_PUSH_VECTOR(vector,routine) \1: cmpl $routine, %edi; \ jne 1f; \ pushl $vector; \ jmp 7f;ENTRY(divide_error) pushl $0 # no error code pushl $ SYMBOL_NAME(do_divide_error) ALIGNerror_code: pushl %ds pushl %eax xorl %eax,%eax pushl %ebp pushl %edi pushl %esi pushl %edx decl %eax # eax = -1 pushl %ecx pushl %ebx cld movl %es,%ecx movl ORIG_EAX(%esp), %esi # get the error code movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) movl %esp,%edx pushl %esi # push the error code pushl %edx # push the pt_regs pointer movl $(__KERNEL_DS),%edx movl %edx,%ds movl %edx,%es#ifdef CONFIG_RTLINUX movl rtl_exception_intercept,%eax testl %eax, %eax je 8f RTL_PUSH_VECTOR(0,do_divide_error) RTL_PUSH_VECTOR(1,do_debug) RTL_PUSH_VECTOR(3,do_int3) RTL_PUSH_VECTOR(4,do_overflow) RTL_PUSH_VECTOR(5,do_bounds) RTL_PUSH_VECTOR(6,do_invalid_op) RTL_PUSH_VECTOR(8,do_double_fault) RTL_PUSH_VECTOR(9,do_coprocessor_segment_overrun) RTL_PUSH_VECTOR(10,do_invalid_TSS) RTL_PUSH_VECTOR(11,do_segment_not_present) RTL_PUSH_VECTOR(12,do_stack_segment) RTL_PUSH_VECTOR(13,do_general_protection) RTL_PUSH_VECTOR(14,do_page_fault) RTL_PUSH_VECTOR(15,do_spurious_interrupt_bug) RTL_PUSH_VECTOR(16,do_coprocessor_error) RTL_PUSH_VECTOR(17,do_alignment_check) RTL_PUSH_VECTOR(18,do_machine_check) RTL_PUSH_VECTOR(19,do_simd_coprocessor_error)1: push $-17: mov %ecx, %ebx # ebx will not be corrupted by a C routine call *%eax popl %ecx mov %ebx, %ecx testl %eax, %eax je 8f addl $8,%esp RESTORE_ALL8:#endif GET_CURRENT(%ebx) call *%edi addl $8,%esp jmp ret_from_exceptionENTRY(coprocessor_error) pushl $0 pushl $ SYMBOL_NAME(do_coprocessor_error) jmp error_code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -