diff --git a/system_call.s b/system_call.s new file mode 100644 index 0000000..9d53ce3 --- /dev/null +++ b/system_call.s @@ -0,0 +1,293 @@ +/* + * linux/kernel/system_call.s + * + * (C) 1991 Linus Torvalds + */ + +/* + * 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- and flopppy-interrupts are 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 +sigaction = 16 # MUST be 16 (=len of sigaction) +blocked = (33*16) + +# offsets within sigaction +sa_handler = 0 +sa_mask = 4 +sa_flags = 8 +sa_restorer = 12 + +nr_system_calls = 91 /* 72 */ + +/* + * Ok, I get parallel printer interrupts while using the floppy for some + * strange reason. Urgel. Now I just ignore them. + */ +.globl system_call,sys_fork,timer_interrupt,sys_execve,sys_execve2 +.globl hd_interrupt,floppy_interrupt,parallel_interrupt +.globl device_not_available, coprocessor_error + +.align 4 +bad_sys_call: + movl $-1,%eax + iret +.align 4 +reschedule: + pushl $ret_from_sys_call + jmp schedule +.align 4 +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 + cmpw $0x0f,CS(%esp) # was old code segment supervisor ? + jne 3f + cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? + jne 3f + movl signal(%eax),%ebx + movl blocked(%eax),%ecx + notl %ecx + andl %ebx,%ecx + bsfl %ecx,%ecx + je 3f + btrl %ecx,%ebx + movl %ebx,signal(%eax) + incl %ecx + pushl %ecx + call do_signal + popl %eax +3: popl %eax + popl %ebx + popl %ecx + popl %edx + pop %fs + pop %es + pop %ds + iret + +.align 4 +coprocessor_error: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + pushl $ret_from_sys_call + jmp math_error + +.align 2 +device_not_available: + push %ds + push %es + push %fs + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + movl $0x10,%eax + mov %ax,%ds + mov %ax,%es + movl $0x17,%eax + mov %ax,%fs + 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 %ebp + pushl %esi + pushl %edi + call math_emulate + popl %edi + popl %esi + popl %ebp + ret + +.align 4 +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 4 +sys_execve: + lea EIP(%esp),%eax + pushl %eax + call do_execve + addl $4,%esp + ret + +.align 4 +sys_execve2: + lea EIP(%esp),%eax + pushl %eax + call do_execve2 + addl $4,%esp + ret + +.align 4 +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,$0xA0 # EOI to interrupt controller #1 + jmp 1f # give port chance to breathe +1: jmp 1f +1: xorl %edx,%edx + xchgl do_hd,%edx + testl %edx,%edx + jne 1f + movl $unexpected_hd_interrupt,%edx +1: outb %al,$0x20 + call *%edx # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +floppy_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 + xorl %eax,%eax + xchgl do_floppy,%eax + testl %eax,%eax + jne 1f + movl $unexpected_floppy_interrupt,%eax +1: call *%eax # "interesting" way of handling intr. + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +parallel_interrupt: + pushl %eax + movb $0x20,%al + outb %al,$0x20 + popl %eax + iret