| /* |
| * linux/kernel/sys_call.S |
| * |
| * Copyright (C) 1991, 1992 Linus Torvalds |
| */ |
| |
| /* |
| * sys_call.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) - %fs |
| * 28(%esp) - %gs |
| * 2C(%esp) - orig_eax |
| * 30(%esp) - %eip |
| * 34(%esp) - %cs |
| * 38(%esp) - %eflags |
| * 3C(%esp) - %oldesp |
| * 40(%esp) - %oldss |
| */ |
| |
| #include <linux/segment.h> |
| |
| EBX = 0x00 |
| ECX = 0x04 |
| EDX = 0x08 |
| ESI = 0x0C |
| EDI = 0x10 |
| EBP = 0x14 |
| EAX = 0x18 |
| DS = 0x1C |
| ES = 0x20 |
| FS = 0x24 |
| GS = 0x28 |
| ORIG_EAX = 0x2C |
| EIP = 0x30 |
| CS = 0x34 |
| EFLAGS = 0x38 |
| OLDESP = 0x3C |
| OLDSS = 0x40 |
| |
| CF_MASK = 0x00000001 |
| IF_MASK = 0x00000200 |
| NT_MASK = 0x00004000 |
| VM_MASK = 0x00020000 |
| |
| /* |
| * these are offsets into the task-struct. |
| */ |
| state = 0 |
| counter = 4 |
| priority = 8 |
| signal = 12 |
| blocked = 16 |
| flags = 20 |
| errno = 24 |
| |
| ENOSYS = 38 |
| |
| .globl _system_call,_sys_execve,_lcall7 |
| .globl _device_not_available, _coprocessor_error |
| .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op |
| .globl _double_fault,_coprocessor_segment_overrun |
| .globl _invalid_TSS,_segment_not_present,_stack_segment |
| .globl _general_protection,_reserved |
| .globl _alignment_check,_page_fault |
| .globl ret_from_sys_call |
| |
| #define SAVE_ALL \ |
| cld; \ |
| push %gs; \ |
| push %fs; \ |
| push %es; \ |
| push %ds; \ |
| pushl %eax; \ |
| pushl %ebp; \ |
| pushl %edi; \ |
| pushl %esi; \ |
| pushl %edx; \ |
| pushl %ecx; \ |
| pushl %ebx; \ |
| movl $KERNEL_DS,%edx; \ |
| mov %dx,%ds; \ |
| mov %dx,%es; \ |
| movl $USER_DS,%edx; \ |
| mov %dx,%fs |
| |
| #define RESTORE_ALL \ |
| popl %ebx; \ |
| popl %ecx; \ |
| popl %edx; \ |
| popl %esi; \ |
| popl %edi; \ |
| popl %ebp; \ |
| popl %eax; \ |
| pop %ds; \ |
| pop %es; \ |
| pop %fs; \ |
| pop %gs; \ |
| addl $4,%esp; \ |
| iret |
| |
| .align 4 |
| _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,%eax |
| pushl %eax |
| call _iABI_emulate |
| popl %eax |
| jmp ret_from_sys_call |
| |
| .align 4 |
| reschedule: |
| pushl $ret_from_sys_call |
| jmp _schedule |
| .align 4 |
| _system_call: |
| pushl %eax # save orig_eax |
| SAVE_ALL |
| movl $-ENOSYS,EAX(%esp) |
| cmpl _NR_syscalls,%eax |
| jae ret_from_sys_call |
| movl _current,%ebx |
| movl $0,errno(%ebx) |
| andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors |
| testl $0x20,flags(%ebx) # PF_TRACESYS |
| jne 1f |
| call _sys_call_table(,%eax,4) |
| movl %eax,EAX(%esp) # save the return value |
| movl _current,%eax |
| movl errno(%eax),%edx |
| negl %edx |
| je ret_from_sys_call |
| movl %edx,EAX(%esp) |
| orl $CF_MASK,EFLAGS(%esp) # set carry to indicate error |
| jmp ret_from_sys_call |
| .align 4 |
| 1: call _syscall_trace |
| movl ORIG_EAX(%esp),%eax |
| call _sys_call_table(,%eax,4) |
| movl %eax,EAX(%esp) # save the return value |
| movl _current,%eax |
| movl errno(%eax),%edx |
| negl %edx |
| je 1f |
| movl %edx,EAX(%esp) |
| orl $CF_MASK,EFLAGS(%esp) # set carry to indicate error |
| 1: call _syscall_trace |
| |
| .align 4,0x90 |
| ret_from_sys_call: |
| movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are |
| testl $VM_MASK,%eax # different then |
| jne 1f |
| cmpw $USER_CS,CS(%esp) # was old code segment supervisor ? |
| jne 2f |
| cmpw $USER_DS,OLDSS(%esp) # was stack segment user segment ? |
| jne 2f |
| 1: sti # slow interrupts get here with interrupts disabled |
| orl $IF_MASK,%eax # these just try to make sure |
| andl $~NT_MASK,%eax # the program doesn't do anything |
| movl %eax,EFLAGS(%esp) # stupid |
| cmpl $0,_need_resched |
| jne reschedule |
| movl _current,%eax |
| cmpl _task,%eax # task[0] cannot have signals |
| je 2f |
| cmpl $0,state(%eax) # state |
| jne reschedule |
| cmpl $0,counter(%eax) # counter |
| je reschedule |
| movl blocked(%eax),%ecx |
| movl %ecx,%ebx # save blocked in %ebx for signal handling |
| notl %ecx |
| andl signal(%eax),%ecx |
| jne signal_return |
| 2: RESTORE_ALL |
| .align 4 |
| signal_return: |
| movl %esp,%ecx |
| pushl %ecx |
| testl $VM_MASK,EFLAGS(%ecx) |
| jne v86_signal_return |
| pushl %ebx |
| call _do_signal |
| popl %ebx |
| popl %ebx |
| RESTORE_ALL |
| .align 4 |
| v86_signal_return: |
| call _save_v86_state |
| movl %eax,%esp |
| pushl %eax |
| pushl %ebx |
| call _do_signal |
| popl %ebx |
| popl %ebx |
| RESTORE_ALL |
| |
| .align 4 |
| _sys_execve: |
| lea (EIP+4)(%esp),%eax # don't forget about the return address. |
| pushl %eax |
| call _do_execve |
| addl $4,%esp |
| ret |
| |
| .align 4 |
| _divide_error: |
| pushl $0 # no error code |
| pushl $_do_divide_error |
| .align 4,0x90 |
| error_code: |
| push %fs |
| push %es |
| push %ds |
| pushl %eax |
| pushl %ebp |
| pushl %edi |
| pushl %esi |
| pushl %edx |
| pushl %ecx |
| pushl %ebx |
| cld |
| movl $-1, %eax |
| xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) |
| xorl %ebx,%ebx # zero ebx |
| mov %gs,%bx # get the lower order bits of gs |
| xchgl %ebx, GS(%esp) # get the address and save gs. |
| pushl %eax # push the error code |
| lea 4(%esp),%edx |
| pushl %edx |
| movl $KERNEL_DS,%edx |
| mov %dx,%ds |
| mov %dx,%es |
| movl $USER_DS,%edx |
| mov %dx,%fs |
| call *%ebx |
| addl $8,%esp |
| jmp ret_from_sys_call |
| |
| .align 4 |
| _coprocessor_error: |
| pushl $0 |
| pushl $_do_coprocessor_error |
| jmp error_code |
| |
| .align 4 |
| _device_not_available: |
| pushl $-1 # mark this as an int |
| SAVE_ALL |
| pushl $ret_from_sys_call |
| clts # clear TS so that we can use math |
| movl %cr0,%eax |
| testl $0x4,%eax # EM (math emulation bit) |
| je _math_state_restore |
| pushl $0 # temporary storage for ORIG_EIP |
| call _math_emulate |
| addl $4,%esp |
| ret |
| |
| .align 4 |
| _debug: |
| pushl $0 |
| pushl $_do_debug |
| jmp error_code |
| |
| .align 4 |
| _nmi: |
| pushl $0 |
| pushl $_do_nmi |
| jmp error_code |
| |
| .align 4 |
| _int3: |
| pushl $0 |
| pushl $_do_int3 |
| jmp error_code |
| |
| .align 4 |
| _overflow: |
| pushl $0 |
| pushl $_do_overflow |
| jmp error_code |
| |
| .align 4 |
| _bounds: |
| pushl $0 |
| pushl $_do_bounds |
| jmp error_code |
| |
| .align 4 |
| _invalid_op: |
| pushl $0 |
| pushl $_do_invalid_op |
| jmp error_code |
| |
| .align 4 |
| _coprocessor_segment_overrun: |
| pushl $0 |
| pushl $_do_coprocessor_segment_overrun |
| jmp error_code |
| |
| .align 4 |
| _reserved: |
| pushl $0 |
| pushl $_do_reserved |
| jmp error_code |
| |
| .align 4 |
| _double_fault: |
| pushl $_do_double_fault |
| jmp error_code |
| |
| .align 4 |
| _invalid_TSS: |
| pushl $_do_invalid_TSS |
| jmp error_code |
| |
| .align 4 |
| _segment_not_present: |
| pushl $_do_segment_not_present |
| jmp error_code |
| |
| .align 4 |
| _stack_segment: |
| pushl $_do_stack_segment |
| jmp error_code |
| |
| .align 4 |
| _general_protection: |
| pushl $_do_general_protection |
| jmp error_code |
| |
| .align 4 |
| _alignment_check: |
| pushl $_do_alignment_check |
| jmp error_code |
| |
| .align 4 |
| _page_fault: |
| pushl $_do_page_fault |
| jmp error_code |