| /* |
| * system_call.s contains the system-call low-level handling routines. |
| * This also contains the timer-interrupt handler, as some of the code is |
| * the same. The hd-interrupt is also here. |
| * |
| * NOTE: This code handles signal-recognition, which happens every time |
| * after a timer-interrupt and after each system call. Ordinary interrupts |
| * don't handle signal-recognition, as that would clutter them up totally |
| * unnecessarily. |
| * |
| * Stack layout in 'ret_from_system_call': |
| * |
| * 0(%esp) - %eax |
| * 4(%esp) - %ebx |
| * 8(%esp) - %ecx |
| * C(%esp) - %edx |
| * 10(%esp) - %fs |
| * 14(%esp) - %es |
| * 18(%esp) - %ds |
| * 1C(%esp) - %eip |
| * 20(%esp) - %cs |
| * 24(%esp) - %eflags |
| * 28(%esp) - %oldesp |
| * 2C(%esp) - %oldss |
| */ |
| |
| SIG_CHLD = 17 |
| EAX = 0x00 |
| EBX = 0x04 |
| ECX = 0x08 |
| EDX = 0x0C |
| FS = 0x10 |
| ES = 0x14 |
| DS = 0x18 |
| EIP = 0x1C |
| CS = 0x20 |
| EFLAGS = 0x24 |
| OLDESP = 0x28 |
| OLDSS = 0x2C |
| |
| state = 0 # these are offsets into the task-struct. |
| counter = 4 |
| priority = 8 |
| signal = 12 |
| restorer = 16 # address of info-restorer |
| sig_fn = 20 # table of 32 signal addresses |
| |
| nr_system_calls = 67 |
| |
| .globl _system_call,_sys_fork,_timer_interrupt,_hd_interrupt,_sys_execve |
| |
| .align 2 |
| bad_sys_call: |
| movl $-1,%eax |
| iret |
| .align 2 |
| reschedule: |
| pushl $ret_from_sys_call |
| jmp _schedule |
| .align 2 |
| _system_call: |
| cmpl $nr_system_calls-1,%eax |
| ja bad_sys_call |
| push %ds |
| push %es |
| push %fs |
| pushl %edx |
| pushl %ecx # push %ebx,%ecx,%edx as parameters |
| pushl %ebx # to the system call |
| movl $0x10,%edx # set up ds,es to kernel space |
| mov %dx,%ds |
| mov %dx,%es |
| movl $0x17,%edx # fs points to local data space |
| mov %dx,%fs |
| call _sys_call_table(,%eax,4) |
| pushl %eax |
| movl _current,%eax |
| cmpl $0,state(%eax) # state |
| jne reschedule |
| cmpl $0,counter(%eax) # counter |
| je reschedule |
| ret_from_sys_call: |
| movl _current,%eax # task[0] cannot have signals |
| cmpl _task,%eax |
| je 3f |
| movl CS(%esp),%ebx # was old code segment supervisor |
| testl $3,%ebx # mode? If so - don't check signals |
| je 3f |
| cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? |
| jne 3f |
| 2: movl signal(%eax),%ebx # signals (bitmap, 32 signals) |
| bsfl %ebx,%ecx # %ecx is signal nr, return if none |
| je 3f |
| btrl %ecx,%ebx # clear it |
| movl %ebx,signal(%eax) |
| movl sig_fn(%eax,%ecx,4),%ebx # %ebx is signal handler address |
| cmpl $1,%ebx |
| jb default_signal # 0 is default signal handler - exit |
| je 2b # 1 is ignore - find next signal |
| movl $0,sig_fn(%eax,%ecx,4) # reset signal handler address |
| incl %ecx |
| xchgl %ebx,EIP(%esp) # put new return address on stack |
| subl $28,OLDESP(%esp) |
| movl OLDESP(%esp),%edx # push old return address on stack |
| pushl %eax # but first check that it's ok. |
| pushl %ecx |
| pushl $28 |
| pushl %edx |
| call _verify_area |
| popl %edx |
| addl $4,%esp |
| popl %ecx |
| popl %eax |
| movl restorer(%eax),%eax |
| movl %eax,%fs:(%edx) # flag/reg restorer |
| movl %ecx,%fs:4(%edx) # signal nr |
| movl EAX(%esp),%eax |
| movl %eax,%fs:8(%edx) # old eax |
| movl ECX(%esp),%eax |
| movl %eax,%fs:12(%edx) # old ecx |
| movl EDX(%esp),%eax |
| movl %eax,%fs:16(%edx) # old edx |
| movl EFLAGS(%esp),%eax |
| movl %eax,%fs:20(%edx) # old eflags |
| movl %ebx,%fs:24(%edx) # old return addr |
| 3: popl %eax |
| popl %ebx |
| popl %ecx |
| popl %edx |
| pop %fs |
| pop %es |
| pop %ds |
| iret |
| |
| default_signal: |
| incl %ecx |
| cmpl $SIG_CHLD,%ecx |
| je 2b |
| pushl %ecx |
| call _do_exit # remember to set bit 7 when dumping core |
| addl $4,%esp |
| jmp 3b |
| |
| .align 2 |
| _timer_interrupt: |
| push %ds # save ds,es and put kernel data space |
| push %es # into them. %fs is used by _system_call |
| push %fs |
| pushl %edx # we save %eax,%ecx,%edx as gcc doesn't |
| pushl %ecx # save those across function calls. %ebx |
| pushl %ebx # is saved as we use that in ret_sys_call |
| pushl %eax |
| movl $0x10,%eax |
| mov %ax,%ds |
| mov %ax,%es |
| movl $0x17,%eax |
| mov %ax,%fs |
| incl _jiffies |
| movb $0x20,%al # EOI to interrupt controller #1 |
| outb %al,$0x20 |
| movl CS(%esp),%eax |
| andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor) |
| pushl %eax |
| call _do_timer # 'do_timer(long CPL)' does everything from |
| addl $4,%esp # task switching to accounting ... |
| jmp ret_from_sys_call |
| |
| .align 2 |
| _sys_execve: |
| lea EIP(%esp),%eax |
| pushl %eax |
| call _do_execve |
| addl $4,%esp |
| ret |
| |
| .align 2 |
| _sys_fork: |
| call _find_empty_process |
| testl %eax,%eax |
| js 1f |
| push %gs |
| pushl %esi |
| pushl %edi |
| pushl %ebp |
| pushl %eax |
| call _copy_process |
| addl $20,%esp |
| 1: ret |
| |
| _hd_interrupt: |
| pushl %eax |
| pushl %ecx |
| pushl %edx |
| push %ds |
| push %es |
| push %fs |
| movl $0x10,%eax |
| mov %ax,%ds |
| mov %ax,%es |
| movl $0x17,%eax |
| mov %ax,%fs |
| movb $0x20,%al |
| outb %al,$0x20 # EOI to interrupt controller #1 |
| jmp 1f # give port chance to breathe |
| 1: jmp 1f |
| 1: outb %al,$0xA0 # same to controller #2 |
| movl _do_hd,%eax |
| testl %eax,%eax |
| jne 1f |
| movl $_unexpected_hd_interrupt,%eax |
| 1: call *%eax # "interesting" way of handling intr. |
| pop %fs |
| pop %es |
| pop %ds |
| popl %edx |
| popl %ecx |
| popl %eax |
| iret |
| |