2b154104788cf039cf7e8dd11d34d3910c038d1a
[lunaix-os.git] / lunaix-os / arch / x86 / exceptions / interrupt64.S
1 #define __ASM__
2 #include <sys/hart.h>
3 #include <sys/abi.h>
4 #include <sys/interrupt64.S.inc>
5
6 #include <lunaix/syscall.h>
7
8 .section .bss
9     .align 16
10     tmp_store:
11         .skip 8
12     lo_tmp_stack:
13         .skip 256
14     tmp_stack:
15     
16
17 /*
18     This perhaps the ugliest part in the project. 
19     It contains code to handle arbitrary depth of 
20     nested interrupt and all those corner cases and 
21     nasty gotchas.
22
23     Be aware the twists, offsets and hidden dependencies!
24
25 */
26
27 .section .text
28     .type interrupt_wrapper, @function
29     .global interrupt_wrapper
30     interrupt_wrapper:
31         cld
32
33         subq $8, %rsp
34         pushq %rsp
35
36         pushq %r15
37         pushq %r14
38         pushq %r13
39         pushq %r12
40         pushq %r11
41         pushq %r10
42         pushq %r9
43         pushq %r8
44
45         pushq %rsi
46         pushq %rbp
47         pushq %rdi
48         pushq %rdx
49         pushq %rcx
50         pushq %rbx
51         pushq %rax
52
53         pushq $0      // placeholder for depth accounting
54
55         movq ics(%rsp), %rax   /* 取出 %cs */
56         andq $0x3, %rax          /* 判断 RPL */
57         jz 1f
58
59     /* crossing the user/kernel boundary */
60         # x86_64 ignore {d,e}s, Lunaix does not use {f,g}s
61
62         movq current_thread, %rbx
63         movq iursp(%rsp), %rax
64
65         # Save x87 context to user stack, rather than kernel's memory.
66         # XXX what will happen if we triggered a page fault during fxsave?
67         # FIXME I think we should defer this to scheduler, and pratice lazy save/load
68         #       Doing this will also make it safe from nested interrupt due to potential 
69         #       page fault when saving
70         # FIXME Also, generalise it to any FPU context, without constraining it to x87.
71
72         #andl $stack_alignment, %eax 
73         #subl $512, %eax
74         #fxsave (%eax)
75
76         # 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。
77         movq %rax, thread_ustack_top(%rbx)     # 存入__current->ustack_top
78
79     /* kernel space same-level switch */
80     1:
81         movq %rsp, %rax
82         andq $stack_alignment, %rsp
83                 
84         movq %rax, %rdi
85
86         xorq %rbp, %rbp     # marks the boundary of stack walking
87         call intr_handler
88
89     .global soft_iret
90     soft_iret:
91         movq %rax, %rsp
92
93         movq ics(%rsp), %rax
94         andq $3, %rax
95         jz 1f 
96
97         # # FIXME x87 fpu context 
98         # movl current_thread, %eax
99         # movl thread_ustack_top(%eax), %eax
100         # test %eax, %eax
101         # jz 1f
102         # fxrstor (%eax)
103
104 1:
105         popq %rax   # discard struct hart_state::depth
106
107         popq %rax
108         popq %rbx
109         popq %rcx
110         popq %rdx
111         popq %rdi
112         popq %rbp
113         popq %rsi
114         
115         popq %r8
116         popq %r9
117         popq %r10
118         popq %r11
119         popq %r12
120         popq %r13
121         popq %r14
122         popq %r15
123
124         popq %rsp
125
126         movq %rax, tmp_store
127         movq current_thread, %rax
128
129         # nested intr: restore saved context
130         popq thread_hstate(%rax)
131
132         movq tmp_store, %rax
133
134         addq $16, %rsp  # skip: err_code and vector
135
136         # calculate stack after iretq
137         # Thank god they finally make things consistent in x86_64
138         addq $40, %rsp
139         movq %rsp, (_tss + rsp_0)
140         subq $40, %rsp
141
142         iretq
143
144     .type do_switch, @function
145     .global do_switch
146     do_switch:
147         # Assumption: __current already hold the target process
148
149         call proc_vmroot
150
151         movq %rax, %rbx
152         movq %cr3, %rax
153         xorq %rbx, %rax         # avoid setting cr3 if just local thread switch.
154         jz 1f
155
156         movq %rbx, %cr3         
157
158     1:
159         # the address space could be changed. A temporary stack
160         # is required to prevent corrupt existing stack
161         movq $tmp_stack, %rsp
162
163         call signal_dispatch    # kernel/signal.c
164
165         movq current_thread, %rbx
166         test %rax, %rax         # do we have signal to handle?
167         jz 1f
168
169         /*
170             将tss.esp0设置为上次调度前的esp值。
171             当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行
172             信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行
173             另一次调度。
174             由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
175             这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
176         */
177         pushq %rax
178         call update_tss
179
180         popq %rax
181         jmp handle_signal
182
183     1:
184         movq thread_hstate(%rbx), %rax
185         jmp soft_iret
186
187     .type handle_signal, @function 
188     .global handle_signal
189     handle_signal:
190         # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
191         # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
192         # arg1 in %rax: addr of proc_sig structure in user stack
193         movq psig_saved_hstate(%rax), %rbx      # %rbx = &proc_sig->saved_hstate
194
195         pushq $UDATA_SEG
196         pushq %rax              # esp
197
198         movq iexecp(%rbx), %rbx
199         pushq exrflags(%rbx)          # proc_sig->saved_hstate->execp->eflags
200         
201         pushq $UCODE_SEG        # cs
202         pushq psig_sigact(%rax)           # %rip = proc_sig->sigact
203
204         iretq