feat: User mode support.
[lunaix-os.git] / lunaix-os / kernel / asm / x86 / interrupt.S
1 #define __ASM__
2 #include <arch/x86/interrupts.h>
3 #include <lunaix/common.h>
4 #include <lunaix/syscall.h>
5 #define __ASM_INTR_DIAGNOSIS
6
7 .macro isr_template vector, no_error_code=1
8     .global _asm_isr\vector
9     .type _asm_isr\vector, @function
10     _asm_isr\vector:
11         .if \no_error_code
12             pushl $0x0
13         .endif
14         pushl $\vector
15         jmp interrupt_wrapper
16 .endm
17
18 #ifdef __ASM_INTR_DIAGNOSIS
19 .section .bss
20     .global debug_resv
21     debug_resv:
22         .skip 16
23 #endif
24
25 .section .text
26     isr_template FAULT_DIVISION_ERROR
27     isr_template FAULT_GENERAL_PROTECTION, no_error_code=0
28     isr_template FAULT_PAGE_FAULT, no_error_code=0
29     isr_template FAULT_STACK_SEG_FAULT, no_error_code=0
30
31     isr_template LUNAIX_SYS_PANIC
32     isr_template LUNAIX_SYS_CALL
33
34     isr_template APIC_ERROR_IV
35     isr_template APIC_LINT0_IV
36     isr_template APIC_TIMER_IV
37     isr_template APIC_SPIV_IV
38     isr_template RTC_TIMER_IV
39     isr_template PC_KBD_IV
40
41     interrupt_wrapper:
42         /*
43          Stack layout (layout of struct isr_param)
44     msa:   [ss]
45            [esp]
46            eflags     > offset = 48 + 16 = 64
47            cs
48            eip
49            err_code   
50            vector     > offset = 28 + 16 + 4 = 48
51            esp
52            gs
53            fs
54            es
55            ds         > offset = 7 * 4 = 28
56            esi
57            ebp
58            edi
59            edx
60            ecx
61            ebx
62     lsa:   eax        > offset = 0
63
64             las: Least Significant Address
65             msa: Most Significant Address
66         */
67         cld
68         pushl %esp
69
70         subl $16, %esp
71         movw %gs, 12(%esp)
72         movw %fs,  8(%esp)
73         movw %es,  4(%esp)
74         movw %ds,   (%esp)
75
76         pushl %esi
77         pushl %ebp
78         pushl %edi
79         pushl %edx
80         pushl %ecx
81         pushl %ebx
82         pushl %eax
83
84         movl 60(%esp), %eax   /* 取出 %cs */
85         andl $0x3, %eax          /* 判断 RPL */
86         jz 1f
87
88         movw $KDATA_SEG, %ax    /* 如果从用户模式转来,则切换至内核数据段 */
89         movw %ax, %gs
90         movw %ax, %fs
91         movw %ax, %ds
92         movw %ax, %es
93
94         # 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
95         # 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
96         movl (__current), %eax  
97         movl 68(%esp), %ebx     # 取出esp
98         movl %ebx, 84(%eax)     # 存入__current->ustack_top
99
100     1:
101         movl %esp, %eax
102         andl $0xfffffff0, %esp
103         subl $16, %esp
104         movl %eax, (%esp)
105
106         call intr_handler
107
108         movl (%esp), %eax
109
110     .global soft_iret
111     soft_iret:
112         movl %eax, %esp
113
114         popl %eax
115         popl %ebx
116         popl %ecx
117         popl %edx
118         popl %edi
119         popl %ebp
120         popl %esi
121         
122         movw   (%esp), %ds
123         movw  4(%esp), %es
124         movw  8(%esp), %fs
125         movw 12(%esp), %gs
126
127         movl 16(%esp), %esp
128
129         addl $8, %esp
130
131 #ifdef __ASM_INTR_DIAGNOSIS
132         pushl %eax
133         movl 4(%esp), %eax
134         movl %eax, debug_resv
135         popl %eax
136 #endif
137         iret
138
139     .global switch_to
140     switch_to:
141         # 约定
142         # arg1: 目标进程PCB地址 (next)
143         popl %ecx               # next
144
145         call signal_dispatch    # kernel/signal.c
146         movl %eax, %edx
147
148         movl __current, %eax    
149         movl 88(%eax), %ebx     # __current->pagetable
150         movl 88(%ecx), %eax     # next->pagetable
151         
152         cmpl %ebx, %eax         # if(next->pagtable != __current->pagetable) {
153         jz 1f
154         movl %eax, %cr3         #   cpu_lcr3(next->pagetable)
155                                 # }
156     1:
157         movl %ecx, __current    # __current = next
158
159         test %edx, %edx         # do we have signal to handle?
160         jz 1f
161         movl %edx, %eax
162         jmp handle_signal
163     1:
164         leal 8(%ecx), %eax
165         jmp soft_iret
166
167     .global handle_signal
168     handle_signal:
169         # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性!
170         # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
171         leal 8(%eax), %ebx      # arg1 in %eax: addr of proc_sig structure in user stack
172
173         pushl 72(%ebx)          # proc_sig->prev_context.ss
174         pushl %eax              # esp
175         pushl 64(%ebx)          # proc_sig->prev_context.eflags
176         pushl $UCODE_SEG        # cs
177         pushl $sig_wrapper      # eip for sig wrapper
178
179         movw $UDATA_SEG, %cx    # switch data seg to user mode
180         movw %cx, %es
181         movw %cx, %ds
182         movw %cx, %fs
183         movw %cx, %gs
184
185         iret  
186
187 .section .usrtext
188     sig_wrapper:                # in user mode
189         movl %esp, %eax
190         and $0xfffffff0, %esp
191         subl $8, %esp
192         pushl %eax              # Addr to proc_sig structure 
193         pushl 4(%eax)           # proc_sig->sig_num     ---- 16 bytes aligned
194
195         call (%eax)             # invoke signal handler
196
197         # invoke the sigreturn syscall to exit the signal wrapper
198         movl $__SYSCALL_sigreturn, %eax
199         movl 4(%esp), %ebx
200         int $LUNAIX_SYS_CALL    
201
202         ud2                     # never reach!