2 #include <arch/x86/interrupts.h>
3 #include <arch/x86/i386_asm.h>
4 #include <lunaix/syscall.h>
5 #define __ASM_INTR_DIAGNOSIS
7 #ifdef __ASM_INTR_DIAGNOSIS
23 This perhaps the ugliest part in the project.
24 It contains code to handle arbitrary depth of
25 nested interrupt and all those corner cases and
28 Be aware the twists, offsets and hidden dependencies!
33 .global interrupt_wrapper
36 Stack layout (layout of struct isr_param)
44 [saved_prev_ctx] > offset = 0
50 ds > offset = 7 * 4 = 28 + 4
58 lsa: depth > offset = 0
60 las: Least Significant Address
61 msa: Most Significant Address
85 pushl %eax # nested intr: current depth
87 movl 116(%esp), %eax /* 取出 %cs */
88 andl $0x3, %eax /* 判断 RPL */
91 movw $KDATA_SEG, %ax /* 如果从用户模式转来,则切换至内核数据段 */
97 # 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
98 # 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
105 movl 124(%esp), %ebx # 取出esp
106 movl %ebx, 60(%eax) # 存入__current->ustack_top
110 andl $0xfffffff0, %esp
122 #ifdef __ASM_INTR_DIAGNOSIS
123 movl %eax, (debug_resv + 8)
126 movl %eax, (debug_resv + 4) # eip
131 test %eax, %eax # do we have stored x87 context?
135 popl %eax # discard isr_param::depth
153 # nested intr: restore saved context
170 #ifdef __ASM_INTR_DIAGNOSIS
172 movl %eax, debug_resv
174 # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
175 # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
176 # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
183 movl %eax, (_tss + 4)
190 # arg1: 目标进程PCB地址 (next
194 movl 64(%eax), %ecx # __current->pagetable
195 movl 64(%ebx), %eax # next->pagetable
197 cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
199 movl %eax, %cr3 # cpu_lcr3(next->pagetable)
202 movl %ebx, __current # __current = next
204 # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
206 movl $tmp_stack, %esp
207 call signal_dispatch # kernel/signal.c
209 test %eax, %eax # do we have signal to handle?
216 .global handle_signal
218 # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
219 # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
220 leal 8(%eax), %ebx # arg1 in %eax: addr of proc_sig structure in user stack
222 pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss
225 pushl 68(%ebx) # proc_sig->prev_context.proc_regs.execp->eflags
226 pushl $UCODE_SEG # cs
227 pushl $sig_wrapper # eip for sig wrapper
229 movw $UDATA_SEG, %cx # switch data seg to user mode
238 sig_wrapper: # in user mode
240 and $0xfffffff0, %esp
242 pushl %eax # Addr to proc_sig structure
243 pushl 4(%eax) # proc_sig->sig_num ---- 16 bytes aligned
245 call *(%eax) # invoke signal handler
247 # invoke the sigreturn syscall to exit the signal wrapper
248 movl $__SYSCALL_sigreturn, %eax