📄 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>#define ASSEMBLY#include <asm/smp.h>EBX = 0x00ECX = 0x04EDX = 0x08ESI = 0x0CEDI = 0x10EBP = 0x14EAX = 0x18DS = 0x1CES = 0x20ORIG_EAX = 0x24EIP = 0x28CS = 0x2CEFLAGS = 0x30OLDESP = 0x34OLDSS = 0x38CF_MASK = 0x00000001IF_MASK = 0x00000200NT_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; \ cmpl $__KERNEL_DS,(%esp); \ je 4f ; \1: popl %ds; \2: popl %es; \ addl $4,%esp; \3: iret; \4: addl $12,%esp; \ 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) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%ebx pushl %ebx GET_CURRENT(%ebx) # Using GET_CURRENT means we load %esp into # %ebx twice, but this means we're safe # against future changes. 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) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%ebx pushl %ebx GET_CURRENT(%ebx) # Using GET_CURRENT means we load %esp into # %ebx twice, but this means we're safe # against future changes. 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) 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. */ENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL GET_CURRENT(%ebx) cmpl $(NR_syscalls),%eax jae badsys testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return valueENTRY(ret_from_sys_call) cli # need_resched and signals atomic test cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_returnrestore_all: RESTORE_ALL ALIGNsignal_return: sti # we can get here from an interrupt handler 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_callENTRY(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 cmpl %edx,%ecx jz 1f movl %edx,%ds movl %edx,%es1: GET_CURRENT(%ebx) call *%edi addl $8,%esp jmp ret_from_exceptionENTRY(coprocessor_error) pushl $0 pushl $ SYMBOL_NAME(do_coprocessor_error) jmp error_codeENTRY(simd_coprocessor_error) pushl $0 pushl $ SYMBOL_NAME(do_simd_coprocessor_error) jmp error_codeENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL GET_CURRENT(%ebx) movl %cr0,%eax testl $0x4,%eax # EM (math emulation bit) jne device_not_available_emulate call SYMBOL_NAME(math_state_restore) jmp ret_from_exceptiondevice_not_available_emulate: pushl $0 # temporary storage for ORIG_EIP call SYMBOL_NAME(math_emulate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -