4 #include <sys/interrupt32.S.inc>
6 #include <lunaix/syscall.h>
9 #define __ASM_INTR_DIAGNOSIS
11 #ifdef __ASM_INTR_DIAGNOSIS
27 This perhaps the ugliest part in the project.
28 It contains code to handle arbitrary depth of
29 nested interrupt and all those corner cases and
32 Be aware the twists, offsets and hidden dependencies!
37 .type interrupt_wrapper, @function
38 .global interrupt_wrapper
42 subl $4, %esp # prealloc slot for parent linkage
59 pushl $0 // placeholder for depth accounting
61 movl ics(%esp), %eax /* 取出 %cs */
62 andl $0x3, %eax /* 判断 RPL */
65 /* crossing the user/kernel boundary */
72 movl current_thread, %ebx
73 movl iuesp(%esp), %eax
75 # Save x87 context to user stack, rather than kernel's memory.
76 # XXX what will happen if we triggered a page fault during fxsave?
77 # FIXME I think we should defer this to scheduler, and pratice lazy save/load
78 # Doing this will also make it safe from nested interrupt due to potential
79 # page fault when saving
80 # FIXME Also, generalise it to any FPU context, without constraining it to x87.
82 #andl $stack_alignment, %eax
86 # 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。
87 movl %eax, thread_ustack_top(%ebx) # 存入__current->ustack_top
89 /* kernel space same-level switch */
92 andl $stack_alignment, %esp
96 xorl %ebp, %ebp # marks the boundary of stack walking
105 #ifdef __ASM_INTR_DIAGNOSIS
106 movl %eax, (debug_resv + 8)
107 movl iesp(%esp), %eax
108 movl exeip(%eax), %eax
109 movl %eax, (debug_resv + 4) # eip
116 # # FIXME x87 fpu context
117 # movl current_thread, %eax
118 # movl thread_ustack_top(%eax), %eax
124 popl %eax # discard struct hart_state::depth
141 movl current_thread, %eax
143 # nested intr: restore saved context
144 popl thread_hstate(%eax)
148 #ifdef __ASM_INTR_DIAGNOSIS
150 movl %eax, debug_resv
152 # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
153 # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
154 # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
161 movl %eax, (_tss + tss_esp0_off)
166 .type do_switch, @function
169 # Assumption: __current already hold the target process
175 xorl %ebx, %eax # avoid setting cr3 if just local thread switch.
181 # the address space could be changed. A temporary stack
182 # is required to prevent corrupt existing stack
183 movl $tmp_stack, %esp
185 call switch_signposting # kernel/process/switch.c
187 movl current_thread, %ebx
188 test %eax, %eax # do we have signal to handle?
192 将tss.esp0设置为上次调度前的esp值。
193 当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行
194 信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行
196 由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
197 这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
206 movl thread_hstate(%ebx), %eax
209 .type handle_signal, @function
210 .global handle_signal
212 # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
213 # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
214 # arg1 in %eax: addr of proc_sig structure in user stack
215 movl psig_saved_hstate(%eax), %ebx # %ebx = &proc_sig->saved_hstate
220 movl iexecp(%ebx), %ebx
221 pushl exeflags(%ebx) # proc_sig->saved_hstate->execp->eflags
223 pushl $UCODE_SEG # cs
224 pushl psig_sigact(%eax) # %eip = proc_sig->sigact
226 movw $UDATA_SEG, %cx # switch data seg to user mode