This repository was archived by the owner on Mar 16, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkernel_entry.asm
295 lines (251 loc) · 6.01 KB
/
kernel_entry.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
; Copyright (c) 2019 Hongzheng Chen
; chenhzh37@mail2.sysu.edu.cn
; Ubuntu 18.04 + nasm 2.13.02
; Ensures that we jump straight into the kernel ’s entry function.
[ bits 32 ] ; We ’re in protected mode by now, so use 32-bit instructions
;;;;;; main entry ;;;;;
[ extern main ] ; Declate that we will be referencing the external symbol 'main',
; so the linker can substitute the final address
[ global _start ]
_start:
call main ; invoke main() in C kernel
jmp $ ; Hang forever when we return from the kernel
[ global load_gdt ]
[ extern _gdtr ]
load_gdt:
lgdt [ _gdtr ]
mov ax, 0x10 ; kernel data selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:load_gdt_ret
load_gdt_ret:
ret
;;;;; Show infrastructure ;;;;;
[ global show_static_string ]
%include "include/show.inc"
show_static_string:
push ebp
mov ebp, esp
push ecx
push edx
mov ecx, [ ebp + 8 ] ; argment 1 (string address)
mov dh, byte [ ebp + 12 ] ; argment 2 (row)
show_string_pm ecx, dh, 0
pop edx
pop ecx
pop ebp
ret
;;;;; Interrupt ;;;;;
[ global load_idt ]
[ global keyboard_handler ]
[ global pit_handler ]
[ global sys_interrupt_handler ]
[ global sys_pthread_handler ]
[ global sys_file_handler ]
[ extern keyboard_handler_main ]
[ extern pit_handler_main ]
[ extern sys_interrupt_handler_main ]
[ extern sys_pthread_handler_main ]
[ extern sys_file_handler_main ]
load_idt:
mov edx, [ esp + 4 ]
lidt [ edx ] ; load interrupt description table (IDT)
sti ; turn on interrupts
ret
keyboard_handler:
cli
call keyboard_handler_main
sti
iretd ; 32-bit return
pit_handler: ; handle process switching
cli
jmp pit_handler_entry ; DO NOT USE CALL!!! WILL DESTROY STACK
pit_handler_entry_ret:
sti
iretd
sys_interrupt_handler:
cli
jmp save_proc_entry
save_proc_entry_ret:
push eax ; Functional number
call sys_interrupt_handler_main
pop ebx ; Remember to pop out
; eax store the return value
sti
iretd
sys_pthread_handler:
cli
pusha ; ax,cx,dx,bx,sp,bp,si,di
push ds
push es
push fs
push gs
call save_proc
pop gs
pop fs
pop es
pop ds
popa
push eax ; Functional number
call sys_pthread_handler_main
pop ebx ; Remember to pop out
; eax store the return value
sti
iretd
sys_file_handler:
cli
pusha ; ax,cx,dx,bx,sp,bp,si,di
push ds
push es
push fs
push gs
call save_proc
pop gs
pop fs
pop es
pop ds
popa
push eax ; Functional number
call sys_file_handler_main
pop ebx ; Remember to pop out
; eax store the return value
sti
iretd
;;;;; user mode ;;;;;
[ global enter_usermode ]
; | ss | ; esp+16: the stack segment selector we want for user mode
; | esp | ; esp+12: the user mode stack pointer
; | eflags | ; esp+8: the control flags we want to use in user mode
; | cs | ; esp+4: the code segment selector
; | eip | ; esp: the instruction pointer of user mode code to execute
enter_usermode:
cli
push ebp
mov ebp, esp
mov ecx, [ebp + 8] ; user program address
mov ax, 0x23 ; user mode data selector is 0x20 (GDT entry 4). Also sets RPL to 3 (user mode)
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push 0x23 ; SS, notice it uses same selector as above
push eax ; ESP
pushf ; EFLAGS, remember to set up INTERRUPTS!!!
pop eax ; Get EFLAGS back into EAX. The only way to read EFLAGS is to pushf then pop
or eax, 0x200 ; Set the IF flag
push eax ; Push the new EFLAGS value back onto the stack
push 0x1b ; CS, user mode code selector is 0x18 (GDT 3). With RPL 3 is 0x1b
push ecx ; EIP
iret
;;;;; Process ;;;;;
[ global pit_handler_entry ]
[ extern save_proc ]
[ global restart_proc ]
;;;;;
; From Intel manual p2880:
; If the handler procedure is going to be executed
; at the same privilege level as the interrupted procedure:
; a. The processor saves the current state of the
; EFLAGS, CS, and EIP registers on the current stack
; b. If an exception causes an error code to be saved,
; it is pushed on the current stack after the EIP value
;
; If the handler procedure is going to be executed at a
; numerically lower privilege level, a stack switch occurs.
; When the stack switch occurs:
; a. The segment selector and stack pointer for the stack
; to be used by the handler are obtained from the TSS
; for the currently executing task.
; On this new stack, the processor pushes
; the stack segment selector and stack pointer
; of the interrupted procedure.
; b. The processor then saves the current state of the
; EFLAGS, CS, and EIP registers on the new stack
; c. If an exception causes an error code to be saved,
; it is pushed on the new stack after the EIP value.
;;;;;
; STACK CHANGE! (different privilege level)
; | ss |
; | esp | ; user stack esp!!!
; NO STACK CHANGE! (the same privilege level)
; | eflags |
; | cs |
; | eip |
; NO ERROR CODE!
; | ax |
; | cx |
; | dx |
; | bx |
; | sp | ; kernel stack esp
; | bp |
; | si |
; | di |
; | ds |
; | es |
; | fs |
; | gs |
; | ret-add| ; pit_handler_main
pit_handler_entry:
pusha ; ax,cx,dx,bx,sp,bp,si,di
push ds
push es
push fs
push gs
call pit_handler_main
pop gs
pop fs
pop es
pop ds
popa
jmp pit_handler_entry_ret
save_proc_entry:
pusha ; ax,cx,dx,bx,sp,bp,si,di
push ds
push es
push fs
push gs
call save_proc
pop gs
pop fs
pop es
pop ds
popa
jmp save_proc_entry_ret
; | ss | ; esp+16
; | esp | ; esp+12
; | eflags | ; esp+8
; | cs | ; esp+4
; | eip | ; esp (after `popa`)
; | eax |
; | ecx |
; | edx |
; | ebx |
; | esp |
; | ebp |
; | esi |
; | edi |
; | ds |
; | es |
; | fs |
; | gs | <- now esp
; | ret-add|
restart_proc:
cli
add esp, 4 ; skip return address
pop gs
pop fs
pop es
pop ds
popa
iretd ; flush cs:eip
;;;;; read process info ;;;;;
[ global read_eip ]
read_eip:
pop eax ; get return address
jmp eax ; return by jmp
testdata:
msg db "This is a test message!", 0