Merge branch 'master' of github.com:Minep/lunaix-os
[lunaix-os.git] / lunaix-os / kernel / asm / x86 / interrupt.S
1 #define __ASM__
2 #include <arch/x86/interrupts.h>
3 #include <lunaix/common.h>
4 #include <lunaix/syscall.h>
5 #define __ASM_INTR_DIAGNOSIS
6
7 .macro isr_template vector, no_error_code=1
8     .global _asm_isr\vector
9     .type _asm_isr\vector, @function
10     _asm_isr\vector:
11         .if \no_error_code
12             pushl $0x0
13         .endif
14         pushl $\vector
15         jmp interrupt_wrapper
16 .endm
17
18 #ifdef __ASM_INTR_DIAGNOSIS
19 .section .bss
20     .global debug_resv
21     debug_resv:
22         .skip 16
23 #endif
24
25 .section .bss
26     .align 16
27     lo_tmp_stack:
28         .skip 128
29     tmp_stack:
30
31 .section .text
32     isr_template FAULT_DIVISION_ERROR
33     isr_template FAULT_GENERAL_PROTECTION, no_error_code=0
34     isr_template FAULT_PAGE_FAULT, no_error_code=0
35     isr_template FAULT_STACK_SEG_FAULT, no_error_code=0
36
37     isr_template LUNAIX_SYS_PANIC
38     isr_template LUNAIX_SYS_CALL
39
40     isr_template APIC_ERROR_IV
41     isr_template APIC_LINT0_IV
42     isr_template APIC_TIMER_IV
43     isr_template APIC_SPIV_IV
44     isr_template RTC_TIMER_IV
45     isr_template PC_KBD_IV
46
47     interrupt_wrapper:
48         /*
49          Stack layout (layout of struct isr_param)
50     msa:   [ss]
51            [esp]
52            eflags     > offset = 48 + 16 = 64
53            cs
54            eip
55            err_code   
56            vector     > offset = 28 + 16 + 4 = 48
57            esp
58            gs
59            fs
60            es
61            ds         > offset = 7 * 4 = 28
62            esi
63            ebp
64            edi
65            edx
66            ecx
67            ebx
68     lsa:   eax        > offset = 0
69
70             las: Least Significant Address
71             msa: Most Significant Address
72         */
73         cld
74         pushl %esp
75
76         subl $16, %esp
77         movw %gs, 12(%esp)
78         movw %fs,  8(%esp)
79         movw %es,  4(%esp)
80         movw %ds,   (%esp)
81
82         pushl %esi
83         pushl %ebp
84         pushl %edi
85         pushl %edx
86         pushl %ecx
87         pushl %ebx
88         pushl %eax
89
90         movl 60(%esp), %eax   /* 取出 %cs */
91         andl $0x3, %eax          /* 判断 RPL */
92         jz 1f
93
94         movw $KDATA_SEG, %ax    /* 如果从用户模式转来,则切换至内核数据段 */
95         movw %ax, %gs
96         movw %ax, %fs
97         movw %ax, %ds
98         movw %ax, %es
99
100         # 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
101         # 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
102         movl (__current), %eax  
103         movl 68(%esp), %ebx     # 取出esp
104         movl %ebx, 84(%eax)     # 存入__current->ustack_top
105
106     1:
107         movl %esp, %eax
108         andl $0xfffffff0, %esp
109         subl $16, %esp
110         movl %eax, (%esp)
111
112         call intr_handler
113
114         movl (%esp), %eax
115
116     .global soft_iret
117     soft_iret:
118         movl %eax, %esp
119
120         popl %eax
121         popl %ebx
122         popl %ecx
123         popl %edx
124         popl %edi
125         popl %ebp
126         popl %esi
127         
128         movw   (%esp), %ds
129         movw  4(%esp), %es
130         movw  8(%esp), %fs
131         movw 12(%esp), %gs
132
133         movl 16(%esp), %esp
134
135         addl $8, %esp
136
137         pushl %eax
138 #ifdef __ASM_INTR_DIAGNOSIS
139         movl 4(%esp), %eax
140         movl %eax, debug_resv
141 #endif
142         # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
143         # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
144         # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
145         movl 8(%esp), %eax
146         andl $3, %eax
147         setnz %al
148         shll $3, %eax
149         addl $16, %eax
150         addl %esp, %eax
151         movl %eax, (_tss + 4)
152         popl %eax
153         iret
154
155     .global switch_to
156     switch_to:
157         # 约定
158         # arg1: 目标进程PCB地址 (next
159
160         popl %ecx               # next
161         movl __current, %eax    
162         movl 88(%eax), %ebx     # __current->pagetable
163         movl 88(%ecx), %eax     # next->pagetable
164         
165         cmpl %ebx, %eax         # if(next->pagtable != __current->pagetable) {
166         jz 1f
167         movl %eax, %cr3         #   cpu_lcr3(next->pagetable)
168                                 # }
169     1:
170         movl %ecx, __current    # __current = next
171
172         # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
173         # 需要使用一个临时的栈空间
174         movl $tmp_stack, %esp
175         call signal_dispatch    # kernel/signal.c
176
177         test %eax, %eax         # do we have signal to handle?
178         jz 1f
179         jmp handle_signal
180     1:
181         leal 8(%ecx), %eax
182         jmp soft_iret
183
184     .global handle_signal
185     handle_signal:
186         # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
187         # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
188         leal 8(%eax), %ebx      # arg1 in %eax: addr of proc_sig structure in user stack
189
190         pushl $UDATA_SEG        # proc_sig->prev_context.ss
191         pushl %eax              # esp
192         pushl 64(%ebx)          # proc_sig->prev_context.eflags
193         pushl $UCODE_SEG        # cs
194         pushl $sig_wrapper      # eip for sig wrapper
195
196         movw $UDATA_SEG, %cx    # switch data seg to user mode
197         movw %cx, %es
198         movw %cx, %ds
199         movw %cx, %fs
200         movw %cx, %gs
201
202         iret  
203
204 .section .usrtext
205     sig_wrapper:                # in user mode
206         movl %esp, %eax
207         and $0xfffffff0, %esp
208         subl $8, %esp
209         pushl %eax              # Addr to proc_sig structure 
210         pushl 4(%eax)           # proc_sig->sig_num     ---- 16 bytes aligned
211
212         call (%eax)             # invoke signal handler
213
214         # invoke the sigreturn syscall to exit the signal wrapper
215         movl $__SYSCALL_sigreturn, %eax
216         movl 4(%esp), %ebx
217         int $LUNAIX_SYS_CALL    
218
219         ud2                     # never reach!