#define __ASM__
-#include <arch/i386/interrupts.h>
-#include <arch/i386/i386_asm.h>
-#include <arch/i386/tss.h>
+#include <sys/interrupts.h>
+#include <sys/abi.h>
+#include <sys/interrupt.S.inc>
+
#include <lunaix/syscall.h>
-#include <arch/i386/interrupt.S.inc>
#define __ASM_INTR_DIAGNOSIS
*/
.section .text
+ .type interrupt_wrapper, @function
.global interrupt_wrapper
interrupt_wrapper:
cld
pushl %ebx
pushl %eax
- movl __current, %eax
- movl proc_intr_ctx(%eax), %eax
- incl %eax
- pushl %eax # nested intr: current depth
+ pushl $0 // placeholder for depth accounting
movl ics(%esp), %eax /* 取出 %cs */
andl $0x3, %eax /* 判断 RPL */
movw %ax, %ds
movw %ax, %es
- movl __current, %ebx
+ movl current_thread, %ebx
+ movl iuesp(%esp), %eax
# Save x87 context to user stack, rather than kernel's memory.
# XXX what will happen if we triggered a page fault during fxsave?
- # FIXME can we remove this overhead?
- movl iuesp(%esp), %eax
- andl $stack_alignment, %eax
- subl $512, %eax
- fxsave (%eax)
+ # FIXME I think we should defer this to scheduler, and pratice lazy save/load
+ # Doing this will also make it safe from nested interrupt due to potential
+ # page fault when saving
+ # FIXME Also, generalise it to any FPU context, without constraining it to x87.
+
+ #andl $stack_alignment, %eax
+ #subl $512, %eax
+ #fxsave (%eax)
# 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。
- movl %eax, proc_ustack_top(%ebx) # 存入__current->ustack_top
+ movl %eax, thread_ustack_top(%ebx) # 存入__current->ustack_top
/* kernel space same-level switch */
1:
subl $16, %esp
movl %eax, (%esp)
+ xorl %ebp, %ebp # marks the boundary of stack walking
call intr_handler
movl (%esp), %eax
andl $3, %eax
jz 1f
- movl __current, %eax
- movl proc_ustack_top(%eax), %eax
+ ## FIXME x87 fpu context
+ movl current_thread, %eax
+ movl thread_ustack_top(%eax), %eax
test %eax, %eax
jz 1f
- fxrstor (%eax)
+ # fxrstor (%eax)
1:
popl %eax # discard isr_param::depth
movl 16(%esp), %esp
movl %eax, tmp_store
- movl __current, %eax
+ movl current_thread, %eax
# nested intr: restore saved context
- popl proc_intr_ctx(%eax)
+ popl thread_intr_ctx(%eax)
addl $8, %esp
iret
- .global switch_to
- switch_to:
- # 约定
- # arg1: 目标进程PCB地址 (next
+ .type do_switch, @function
+ .global do_switch
+ do_switch:
+ # Assumption: __current already hold the target process
- popl %ebx # next
- movl __current, %eax
- movl proc_page_table(%eax), %ecx # __current->pagetable
- movl proc_page_table(%ebx), %eax # next->pagetable
-
- cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
+ call proc_vmroot
+
+ movl %eax, %ebx
+ movl %cr3, %eax
+ xorl %ebx, %eax # avoid setting cr3 if just local thread switch.
jz 1f
- movl %eax, %cr3 # cpu_lcr3(next->pagetable)
- # }
- 1:
- movl %ebx, __current # __current = next
- # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
- # 需要使用一个临时的栈空间
+ movl %ebx, %cr3
+
+ 1:
+ # the address space could be changed. A temporary stack
+ # is required to prevent corrupt existing stack
movl $tmp_stack, %esp
call signal_dispatch # kernel/signal.c
+ movl current_thread, %ebx
test %eax, %eax # do we have signal to handle?
jz 1f
- # 更新 tss
- movl proc_intr_ctx(%ebx), %ecx # __current->intr_ctx
+ /*
+ 将tss.esp0设置为上次调度前的esp值。
+ 当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行
+ 信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行
+ 另一次调度。
+ 由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
+ 这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
+ */
+ movl thread_intr_ctx(%ebx), %ecx # __current->intr_ctx
movl %ecx, (tss_esp0_off + _tss)
jmp handle_signal
1:
- movl proc_intr_ctx(%ebx), %eax
+ movl thread_intr_ctx(%ebx), %eax
jmp soft_iret
+ .type handle_signal, @function
.global handle_signal
handle_signal:
# 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!