2 #include <sys/interrupts.h>
4 #include <sys/interrupt.S.inc>
6 #include <lunaix/syscall.h>
8 #define __ASM_INTR_DIAGNOSIS
10 #ifdef __ASM_INTR_DIAGNOSIS
26 This perhaps the ugliest part in the project.
27 It contains code to handle arbitrary depth of
28 nested interrupt and all those corner cases and
31 Be aware the twists, offsets and hidden dependencies!
36 .type interrupt_wrapper, @function
37 .global interrupt_wrapper
59 movl proc_intr_ctx(%eax), %eax
61 pushl %eax # nested intr: current depth
63 movl ics(%esp), %eax /* 取出 %cs */
64 andl $0x3, %eax /* 判断 RPL */
67 /* crossing the user/kernel boundary */
76 # Save x87 context to user stack, rather than kernel's memory.
77 # XXX what will happen if we triggered a page fault during fxsave?
78 # FIXME can we remove this overhead?
79 movl iuesp(%esp), %eax
80 andl $stack_alignment, %eax
84 # 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。
85 movl %eax, proc_ustack_top(%ebx) # 存入__current->ustack_top
87 /* kernel space same-level switch */
90 andl $stack_alignment, %esp
94 xorl %ebp, %ebp # marks the boundary of stack walking
103 #ifdef __ASM_INTR_DIAGNOSIS
104 movl %eax, (debug_resv + 8)
105 movl iesp(%esp), %eax
106 movl exeip(%eax), %eax
107 movl %eax, (debug_resv + 4) # eip
115 movl proc_ustack_top(%eax), %eax
121 popl %eax # discard isr_param::depth
140 # nested intr: restore saved context
141 popl proc_intr_ctx(%eax)
145 #ifdef __ASM_INTR_DIAGNOSIS
147 movl %eax, debug_resv
149 # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
150 # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
151 # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
158 movl %eax, (_tss + tss_esp0_off)
163 .type switch_to, @function
167 # arg1: 目标进程PCB地址 (next
169 movl %eax, %ebx # next
171 movl proc_page_table(%eax), %ecx # __current->pagetable
172 movl proc_page_table(%ebx), %eax # next->pagetable
174 cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
176 movl %eax, %cr3 # cpu_lcr3(next->pagetable)
179 movl %ebx, __current # __current = next
181 # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
183 movl $tmp_stack, %esp
185 call signal_dispatch # kernel/signal.c
187 test %eax, %eax # do we have signal to handle?
191 将tss.esp0设置为上次调度前的esp值。
192 当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行
193 信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行
195 由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
196 这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
198 movl proc_intr_ctx(%ebx), %ecx # __current->intr_ctx
199 movl %ecx, (tss_esp0_off + _tss)
204 movl proc_intr_ctx(%ebx), %eax
207 .type handle_signal, @function
208 .global handle_signal
210 # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
211 # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
212 # arg1 in %eax: addr of proc_sig structure in user stack
213 movl psig_saved_ictx(%eax), %ebx # %ebx = &proc_sig->saved_ictx
218 movl iexecp(%ebx), %ebx
219 pushl exeflags(%ebx) # proc_sig->saved_ictx->execp->eflags
221 pushl $UCODE_SEG # cs
222 pushl psig_sigact(%eax) # %eip = proc_sig->sigact
224 movw $UDATA_SEG, %cx # switch data seg to user mode