blob: e8c3268cf7821243788a2e9c482892905f764199 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2015 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/* The magic number for the Multiboot header. */
26#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
27
28/* The flags for the Multiboot header. */
29#if defined(__ELF__) && 0
30#define MULTIBOOT_HEADER_FLAGS 0x00000002
31#else
32#define MULTIBOOT_HEADER_FLAGS 0x00010002
33#endif
34
35/* The magic number passed by a Multiboot-compliant boot loader. */
36#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
37
38#define NUM_INT 0x31
39#define NUM_EXC 0x14
40
41.section ".text.boot"
42.global _start
43_start:
44 jmp real_start
45
46.align 4
47
48.type multiboot_header,STT_OBJECT
49multiboot_header:
50 /* magic */
51 .int MULTIBOOT_HEADER_MAGIC
52 /* flags */
53 .int MULTIBOOT_HEADER_FLAGS
54 /* checksum */
55 .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
56
57#if !defined(__ELF__) || 1
58 /* header_addr */
59 .int multiboot_header
60 /* load_addr */
61 .int _start
62 /* load_end_addr */
63 .int __data_end
64 /* bss_end_addr */
65 .int __bss_end
66 /* entry_addr */
67 .int real_start
68#endif
69
70real_start:
71 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
72 jne 0f
73 movl %ebx, (_multiboot_info)
740:
75 /* setup isr stub descriptors in the idt */
76 movl $_isr, %esi
77 movl $_idt, %edi
78 movl $NUM_INT, %ecx
79
80.Lloop:
81 movl %esi, %ebx
82 movw %bx, (%edi) /* low word in IDT(n).low */
83 shrl $16, %ebx
84 movw %bx, 6(%edi) /* high word in IDT(n).high */
85
86 addl $isr_stub_len, %esi/* index the next ISR stub */
87 addl $8, %edi /* index the next IDT entry */
88
89 loop .Lloop
90
91 lidt _idtr
92 xorl %eax, %eax
93 movl %eax, %cr3
94
95 lgdt _gdtr
96
97 movw $datasel, %ax
98 movw %ax, %ds
99 movw %ax, %es
100 movw %ax, %fs
101 movw %ax, %ss
102 movw %ax, %gs
103 movw %ax, %ss
104
105 movl $_kstack, %esp
106 /*We jumped here in protected mode in a code segment that migh not longer
107 be valid , do a long jump to our code segment, we use retf instead of
108 ljmp to be able to use relative labels */
109 movl $codesel_32, %ecx /*Pushing our code segment */
110 push %ecx
111 movl $farjump, %ecx /*and jump address */
112 push %ecx
113 xorl %ecx, %ecx
114 retf /*This instruction will jump to codesel:farjump */
115farjump:
116 /* zero the bss section */
117 movl $__bss_start, %edi /* starting address of the bss */
118 movl $__bss_end, %ecx /* find the length of the bss in bytes */
119 subl %edi, %ecx
120 shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */
1212:
122 movl $0, (%edi)
123 addl $4, %edi
124 loop 2b
125
126#ifdef PAE_MODE_ENABLED
127
128 /* Preparing PAE paging, we will use 2MB pages covering 1GB
129 for initial bootstrap, this page table will be 1 to 1 */
130
131 /* Setting the First PDPTE with a PD table reference*/
132 xorl %eax, %eax
133 movl $pdp, %eax
134 orl $0x01, %eax
135 movl %eax, (pdpt)
136
137 movl $pdp, %esi
138 movl $0x1ff, %ecx
139
140fill_pdp:
141 movl $0x1ff, %eax
142 subl %ecx, %eax
143 shll $21,%eax
144 orl $0x83, %eax
145 movl %eax, (%esi)
146 addl $8,%esi
147 loop fill_pdp
148
149 /* Set PDPT in CR3 */
150 movl $pdpt, %eax
151 mov %eax, %cr3
152
153 /* Enabling PAE*/
154 mov %cr4, %eax
155 btsl $(5), %eax
156 mov %eax, %cr4
157
158 /* Enabling Paging and from this point we are in
159 32 bit compatibility mode */
160 mov %cr0, %eax
161 btsl $(31), %eax
162 mov %eax, %cr0
163
164#else
165 /* Set PD in CR3 */
166 movl $pd, %eax
167 mov %eax, %cr3
168
169 movl $pd, %esi
170 movl $0x100, %ecx
171
172fill_pd:
173 xor %eax, %eax
174 mov $0x100, %eax
175 sub %ecx, %eax
176 shll $22,%eax
177 orl $0x87, %eax
178 movl %eax, (%esi)
179 addl $4,%esi
180 loop fill_pd
181
182 /* Enabling Paging and from this point we are in */
183 xorl %eax, %eax
184 mov %cr4, %eax
185 orl $0x10, %eax
186 mov %eax, %cr4
187 xorl %eax, %eax
188 mov %cr0, %eax
189 btsl $(31), %eax
190 mov %eax, %cr0
191#endif
192
193 /* Flushing TLB's */
194 mov %cr3,%eax
195 mov %eax,%cr3
196
197main_lk:
198 /* call the main module */
199 call lk_main
2000: /* just sit around waiting for interrupts */
201 hlt /* interrupts will unhalt the processor */
202 pause
203 jmp 0b /* so jump back to halt to conserve power */
204
205/* interrupt service routine stubs */
206_isr:
207
208.set i, 0
209.rept NUM_INT
210
211.set isr_stub_start, .
212
213.if i == 8 || (i >= 10 && i <= 14) || i == 17
214 nop /* error code pushed by exception */
215 nop /* 2 nops are the same length as push byte */
216 pushl $i /* interrupt number */
217 jmp interrupt_common
218.else
219 pushl $0 /* fill in error code in iframe */
220 pushl $i /* interrupt number */
221 jmp interrupt_common
222.endif
223
224/* figure out the length of a single isr stub (usually 6 or 9 bytes) */
225.set isr_stub_len, . - isr_stub_start
226
227.set i, i + 1
228.endr
229
230/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */
231.fill 256
232
233interrupt_common:
234 pushl %gs /* save segment registers */
235 pushl %fs
236 pushl %es
237 pushl %ds
238 pusha /* save general purpose registers */
239 movl $datasel, %eax /* put known good value in segment registers */
240 movl %eax, %gs
241 movl %eax, %fs
242 movl %eax, %es
243 movl %eax, %ds
244 movl %esp, %eax /* store stack switch pivot. push esp has errata on some cpus, so use mov/push */
245 pushl %eax
246 movl %esp, %eax /* store pointer to iframe, using same method */
247 pushl %eax
248
249
250 call platform_irq
251
252 cmpl $0,%eax
253 je 0f
254 call thread_preempt
255
2560:
257
258 popl %eax /* drop pointer to iframe */
259 popl %eax /* restore task_esp, stack switch can occur here if task_esp is modified */
260 movl %eax, %esp
261 popa /* restore general purpose registers */
262 popl %ds /* restore segment registers */
263 popl %es
264 popl %fs
265 popl %gs
266 addl $8, %esp /* drop exception number and error code */
267 iret
268
269.data
270.align 4
271
272.global _multiboot_info
273_multiboot_info:
274 .int 0
275
276_gdtr:
277 .short _gdt_end - _gdt - 1
278 .int _gdt
279
280.global _gdt
281_gdt:
282 .int 0
283 .int 0
284
285/* ring 0 descriptors */
286.set codesel_32, . - _gdt
287_code_32_gde:
288 .short 0xffff /* limit 15:00 */
289 .short 0x0000 /* base 15:00 */
290 .byte 0x00 /* base 23:16 */
291 .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
292 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
293 .byte 0x0 /* base 31:24 */
294
295.set datasel, . - _gdt
296_data_gde:
297 .short 0xffff /* limit 15:00 */
298 .short 0x0000 /* base 15:00 */
299 .byte 0x00 /* base 23:16 */
300 .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
301 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
302 .byte 0x0 /* base 31:24 */
303
304.set user_codesel_32, . - _gdt
305_user_code_32_gde:
306 .short 0xffff /* limit 15:00 */
307 .short 0x0000 /* base 15:00 */
308 .byte 0x00 /* base 23:16 */
309 .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
310 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
311 .byte 0x0 /* base 31:24 */
312
313.set user_datasel, . - _gdt
314_user_data_32_gde:
315 .short 0xffff /* limit 15:00 */
316 .short 0x0000 /* base 15:00 */
317 .byte 0x00 /* base 23:16 */
318 .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
319 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
320 .byte 0x0 /* base 31:24 */
321
322.set codesel_64, . - _gdt
323_code_64_gde:
324 .short 0xffff /* limit 15:00 */
325 .short 0x0000 /* base 15:00 */
326 .byte 0x00 /* base 23:16 */
327 .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
328 .byte 0b10101111 /* G(1) D(0) L(1) AVL(0) limit 19:16 */
329 .byte 0x0 /* base 31:24 */
330
331.set datasel_64, . - _gdt
332_data_64_gde:
333 .short 0xffff /* limit 15:00 */
334 .short 0x0000 /* base 15:00 */
335 .byte 0x00 /* base 23:16 */
336 .byte 0b10010010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
337 .byte 0b11001111 /* G(1) B(1) 0 AVL(0) limit 19:16 */
338 .byte 0x0 /* base 31:24 */
339
340 .quad 0x0000000000000000
341 .quad 0x0000000000000000
342
343.set user_codesel_64, . - _gdt
344_user_code_64_gde:
345 .short 0xffff /* limit 15:00 */
346 .short 0x0000 /* base 15:00 */
347 .byte 0x00 /* base 23:16 */
348 .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
349 .byte 0b10101111 /* G(1) D(1) L(0) AVL(0) limit 19:16 */
350 .byte 0x0 /* base 31:24 */
351
352.set user_datasel_64, . - _gdt
353_user_data_64_gde:
354 .short 0xffff /* limit 15:00 */
355 .short 0x0000 /* base 15:00 */
356 .byte 0x00 /* base 23:16 */
357 .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
358 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
359 .byte 0x0 /* base 31:24 */
360
361.set null_2, . - _gdt
362_null_2:
363 .int 0
364 .int 0
365
366/* TSS descriptor */
367.set tsssel, . - _gdt
368_tss_gde:
369 .short 0 /* limit 15:00 */
370 .short 0 /* base 15:00 */
371 .byte 0 /* base 23:16 */
372 .byte 0x89 /* P(1) DPL(11) 0 10 B(0) 1 */
373 .byte 0x80 /* G(0) 0 0 AVL(0) limit 19:16 */
374 .short 0 /* base 31:24 */
375.global _gdt_end
376_gdt_end:
377
378.align 8
379.global _idtr
380_idtr:
381 .short _idt_end - _idt - 1 /* IDT limit */
382 .int _idt
383
384/* interrupt descriptor table (IDT) */
385.global _idt
386_idt:
387
388.set i, 0
389.rept NUM_INT-1
390 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
391 .short codesel_32 /* selector */
392 .byte 0
393 .byte 0x8e /* present, ring 0, 32-bit interrupt gate */
394 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
395
396.set i, i + 1
397.endr
398
399/* syscall int (ring 3) */
400_idt30:
401 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
402 .short codesel_32 /* selector */
403 .byte 0
404 .byte 0xee /* present, ring 3, 32-bit interrupt gate */
405 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
406
407.global _idt_end
408_idt_end:
409
410/* Memory for the initial page table, we will use 2 pages for a
411 1 to 1 mapping that covers 1GB of physical memory */
412.align 4096
413.fill 4096
414
415#ifdef PAE_MODE_ENABLED
416.align 4096
417pdpt:
418.fill 4096
419pdp:
420.fill 4096
421#else
422.align 4096
423pd:
424.fill 4096
425#endif
426
427.align 4096
428.fill 4096
429
430.bss
431.align 4096
432
433.global _kstack
434.fill 4096
435_kstack: