2 #include <arch/x86/interrupts.h>
3 #include <arch/x86/i386_asm.h>
4 #include <arch/x86/tss.h>
5 #include <lunaix/syscall.h>
6 #define __ASM_INTR_DIAGNOSIS
8 #ifdef __ASM_INTR_DIAGNOSIS
24 This perhaps the ugliest part in the project.
25 It contains code to handle arbitrary depth of
26 nested interrupt and all those corner cases and
29 Be aware the twists, offsets and hidden dependencies!
35 /* stack layout: saved interrupt context */
38 .struct idepth + regsize
40 .struct ieax + regsize
42 .struct iebx + regsize
44 .struct iecx + regsize
46 .struct iedx + regsize
48 .struct iedi + regsize
50 .struct iebp + regsize
52 .struct iesi + regsize
62 .struct iesp + regsize
64 .struct isave_prev + regsize
66 .struct ivec + regsize
68 .struct iecode + regsize
70 .struct ieip + regsize
74 .struct ieflags + regsize
76 .struct iuesp + regsize
80 /* stack layout: execution (flow-control) state context */
83 .struct exsave_prev + regsize
85 .struct exvec + regsize
87 .struct execode + regsize
89 .struct exeip + regsize
91 .struct excs + regsize
93 .struct exeflags + regsize
95 .struct exuesp + regsize
98 /* struct layout: critical section of struct proc_info */
101 .struct proc_pid + regsize
103 .struct proc_parent + regsize
105 .struct proc_intr_ctx + regsize
107 .struct proc_ustack_top + regsize
109 .struct proc_page_table + regsize
113 .global interrupt_wrapper
116 Stack layout (layout of struct isr_param)
123 vector > offset = 52 -> 4
124 [saved_prev_ctx] > offset = 0
130 ds > offset = 8 * 4 = 32
138 lsa: depth > offset = 0
140 las: Least Significant Address
141 msa: Most Significant Address
163 movl proc_intr_ctx(%eax), %eax
165 pushl %eax # nested intr: current depth
167 movl ics(%esp), %eax /* 取出 %cs */
168 andl $0x3, %eax /* 判断 RPL */
171 movw $KDATA_SEG, %ax /* 如果从用户模式转来,则切换至内核数据段 */
179 # FIXME: Save x87 context to user stack, rather than kernel's memory.
181 movl proc_fxstate(%eax), %ebx
184 # 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。
185 movl iuesp(%esp), %ebx # 取出esp
186 movl %ebx, proc_ustack_top(%eax) # 存入__current->ustack_top
190 andl $0xfffffff0, %esp
202 #ifdef __ASM_INTR_DIAGNOSIS
203 movl %eax, (debug_resv + 8)
204 movl iesp(%esp), %eax
205 movl exeip(%eax), %eax
206 movl %eax, (debug_resv + 4) # eip
209 movl proc_fxstate(%eax), %eax
211 test %eax, %eax # do we have stored x87 context?
216 popl %eax # discard isr_param::depth
236 # nested intr: restore saved context
237 popl proc_intr_ctx(%eax)
241 #ifdef __ASM_INTR_DIAGNOSIS
243 movl %eax, debug_resv
245 # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
246 # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
247 # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
254 movl %eax, (_tss + tss_esp0_off)
262 # arg1: 目标进程PCB地址 (next
266 movl proc_page_table(%eax), %ecx # __current->pagetable
267 movl proc_page_table(%ebx), %eax # next->pagetable
269 cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
271 movl %eax, %cr3 # cpu_lcr3(next->pagetable)
274 movl %ebx, __current # __current = next
276 # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
278 movl $tmp_stack, %esp
281 movl proc_intr_ctx(%ebx), %eax # proc->intr_ctx
282 movl iesp(%eax), %eax # intr_ctx->esp
283 movl %eax, (tss_esp0_off + _tss)
285 call signal_dispatch # kernel/signal.c
287 test %eax, %eax # do we have signal to handle?
291 movl proc_intr_ctx(%ebx), %eax
294 .global handle_signal
296 # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
297 # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
298 # arg1 in %eax: addr of proc_sig structure in user stack
299 leal 12(%eax), %ebx # %ebx = &proc_sig->prev_context
301 pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss
305 pushl 68(%ebx) # proc_sig->prev_context.proc_regs.execp->eflags
307 pushl $UCODE_SEG # cs
308 pushl 4(%eax) # %eip = proc_sig->sigact
310 movw $UDATA_SEG, %cx # switch data seg to user mode