blob: 789dbfd5e6eb95ca04f2b25dd3c33fc8dd61ee75 [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#define MSR_EFER 0xc0000080
42#define EFER_LME 0x00000100
43
44.section ".text.boot"
45.code32
46.global _start
47_start:
48 jmp real_start
49
50.align 8
51
52.type multiboot_header,STT_OBJECT
53multiboot_header:
54 /* magic */
55 .int MULTIBOOT_HEADER_MAGIC
56 /* flags */
57 .int MULTIBOOT_HEADER_FLAGS
58 /* checksum */
59 .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
60
61#if !defined(__ELF__) || 1
62 /* header_addr */
63 .int multiboot_header
64 /* load_addr */
65 .int _start
66 /* load_end_addr */
67 .int __data_end
68 /* bss_end_addr */
69 .int __bss_end
70 /* entry_addr */
71 .int real_start
72#endif
73
74real_start:
75 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
76 jne 0f
77 movl %ebx, (_multiboot_info)
780:
79 /* setup isr stub descriptors in the idt */
80 movl $_isr, %esi
81 movl $_idt, %edi
82 movl $NUM_INT, %ecx
83
84.Lloop:
85 movl %esi, %ebx
86 movw %bx, (%edi) /* low word in IDT(n).low */
87 shrl $16, %ebx
88 movw %bx, 6(%edi) /* high word in IDT(n).high */
89 shrl $16, %ebx
90 movl $0, %ebx
91 movl %ebx, 8(%edi)
92 shrl $16, %ebx
93 movl %ebx, 12(%edi)
94 shrl $16, %ebx
95
96 addl $isr_stub_len, %esi /* index the next ISR stub */
97 addl $16, %edi /* index the next IDT entry */
98
99
100 loop .Lloop
101
102
103 lidt _idtr
104 xorl %eax, %eax
105 mov %eax, %cr3
106
107 lgdt _gdtr
108
109
110 movw $datasel, %ax
111 movw %ax, %ds
112 movw %ax, %es
113 movw %ax, %fs
114 movw %ax, %ss
115 movw %ax, %gs
116 movw %ax, %ss
117
118 movl $_kstack, %esp
119
120 /* We need to jump to our sane 32 bit CS
121 executing a far jump using retf */
122 movl $codesel_32, %ecx
123 pushl %ecx
124 movl $farjump, %ecx
125 pushl %ecx
126 xorl %ecx, %ecx
127 retf
128
129farjump:
130 movl $tsssel, %eax
131 ltr %ax
132 /* zero the bss section */
133 movl $__bss_start, %edi /* starting address of the bss */
134 movl $__bss_end, %ecx /* find the length of the bss in bytes */
135 subl %edi, %ecx
136 shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */
1372:
138 movl $0, (%edi)
139 addl $4, %edi
140 loop 2b
141
142
143 /* Preparing 64 bit paging, we will use 2MB pages covering 1GB
144 for initial bootstrap, this page table will be 1 to 1 */
145
146 /* PAE bit must be enabled for 64 bit paging*/
147 mov %cr4, %eax
148 btsl $(5), %eax
149 mov %eax, %cr4 /*Enabling PAE*/
150
151 movl $pml4, %eax
152 mov %eax, %cr3
153
154 /* Long Mode Enabled at this point*/
155 movl $MSR_EFER ,%ecx
156 rdmsr
157 orl $EFER_LME,%eax
158 wrmsr
159
160 /* Setting the First PML4E with a PDP table reference*/
161 xorl %eax, %eax
162 movl $pdp, %eax
163 orl $0x7, %eax
164 movl %eax, (pml4)
165
166 /* Setting the First PDPTE with a Page table reference*/
167 xorl %eax, %eax
168 movl $pte, %eax
169 orl $0x7, %eax
170 movl %eax, (pdp)
171
172 movl $pte, %esi
173 movl $0x1ff, %ecx
174
175 /* We need 256 entries of 2MB each to cover 1GB */
176fill_pte:
177 movl $0x1ff, %eax
178 subl %ecx, %eax
179 shll $21,%eax
180 orl $0x87, %eax
181 movl %eax, (%esi)
182 addl $8,%esi
183 loop fill_pte
184
185 /* Enabling Paging and from this point we are in
186 32 bit compatibility mode*/
187 mov %cr0, %eax
188 btsl $(31), %eax
189 mov %eax, %cr0
190
191 /* Flushing TLB's */
192 mov %cr3,%eax
193 mov %eax,%cr3
194
195 /* Using another long jump to be on 64 bit mode
196 after this we will be on real 64 bit mode */
197 movl $codesel_64, %ecx /*Need to put it in a the right CS*/
198 pushl %ecx
199 movl $farjump64, %ecx
200 pushl %ecx
201 retf
202
203.align 8
204.code64
205farjump64:
206 lidt _idtr
207 /* call the main module */
208 call lk_main
209
2100: /* just sit around waiting for interrupts */
211 hlt /* interrupts will unhalt the processor */
212 pause
213 jmp 0b /* so jump back to halt to conserve power */
214
215/* interrupt service routine stubs */
216_isr:
217.set i, 0
218.rept NUM_INT
219
220.set isr_stub_start, .
221
222.if i == 8 || (i >= 10 && i <= 14) || i == 17
223 nop /* error code pushed by exception */
224 nop /* 2 nops are the same length as push byte */
225 pushq $i /* interrupt number */
226 jmp interrupt_common
227.else
228 pushq $0 /* fill in error code in iframe */
229 pushq $i /* interrupt number */
230 jmp interrupt_common
231.endif
232
233/* figure out the length of a single isr stub (usually 6 or 9 bytes) */
234.set isr_stub_len, . - isr_stub_start
235
236.set i, i + 1
237.endr
238
239/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */
240.fill 256
241
242interrupt_common:
243
244 /* save general purpose registers */
245 pushq %r15
246 pushq %r14
247 pushq %r13
248 pushq %r12
249 pushq %r11
250 pushq %r10
251 pushq %r9
252 pushq %r8
253 pushq %rax
254 pushq %rcx
255 pushq %rdx
256 pushq %rbx
257 pushq %rbp
258 pushq %rsi
259 pushq %rdi
260
261 /* store stack switch pivot.
262 push rsp has errata on some cpus, so use mov/push */
263 movq %rsp, %rax
264 pushq %rax
265 movq %rsp, %rdi /* pass the iframe using rdi */
266
267 call platform_irq
268
269 cmpq $0,%rax
270 je 0f
271 call thread_preempt
272
2730:
274 /* restore task_rsp, stack switch can occur here
275 if task_rsp is modified */
276 popq %rax
277 movq %rax, %rsp
278
279 /* restore general purpose registers */
280 popq %rdi
281 popq %rsi
282 popq %rbp
283 popq %rbx
284 popq %rdx
285 popq %rcx
286 popq %rax
287 popq %r8
288 popq %r9
289 popq %r10
290 popq %r11
291 popq %r12
292 popq %r13
293 popq %r14
294 popq %r15
295
296 /* drop vector number and error code*/
297 addq $16, %rsp
298 iretq
299
300.data
301.align 8
302
303/* define the heap end as read-write data containing the default end of the
304 * heap. dynamic memory length discovery can update this value during init.
305 * other archs can define this statically based on the memory layout of the
306 * platform.
307 */
308#.global _heap_end
309#_heap_end:
310# .int 4096*1024 /* default to 4MB total */
311
312.global _multiboot_info
313_multiboot_info:
314 .int 0
315 .int 0
316.align 8
317.global _gdtr
318_gdtr:
319 .short _gdt_end - _gdt - 1
320 .int _gdt
321.align 8
322.global _gdt
323_gdt:
324 .int 0 /* NULL Descriptor_L*/
325 .int 0 /* NULL Descriptor_H */
326/* ring 0 descriptors */
327.set codesel_32, . - _gdt
328_code_32_gde:
329 .short 0xffff /* limit 15:00 */
330 .short 0x0000 /* base 15:00 */
331 .byte 0x00 /* base 23:16 */
332 .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
333 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
334 .byte 0x0 /* base 31:24 */
335
336.set datasel, . - _gdt
337_data_gde:
338 .short 0xffff /* limit 15:00 */
339 .short 0x0000 /* base 15:00 */
340 .byte 0x00 /* base 23:16 */
341 .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
342 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
343 .byte 0x0 /* base 31:24 */
344
345.set videosel, . - _gdt
346_video_gde:
347 .short 0xffff /* limit 15:00 */
348 .short 0x8000 /* base 15:00 */
349 .byte 0x0b /* base 23:16 */
350 .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
351 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
352 .byte 0x0 /* base 31:24 */
353
354.set user_codesel_32, . - _gdt
355_user_code_32_gde:
356 .short 0xffff /* limit 15:00 */
357 .short 0x0000 /* base 15:00 */
358 .byte 0x00 /* base 23:16 */
359 .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
360 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
361 .byte 0x0 /* base 31:24 */
362
363.set user_datasel, . - _gdt
364_user_data_32_gde:
365 .short 0xffff /* limit 15:00 */
366 .short 0x0000 /* base 15:00 */
367 .byte 0x00 /* base 23:16 */
368 .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
369 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
370 .byte 0x0 /* base 31:24 */
371
372.set codesel_64, . - _gdt
373_code_64_gde:
374 .short 0xffff /* limit 15:00 */
375 .short 0x0000 /* base 15:00 */
376 .byte 0x00 /* base 23:16 */
377 .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
378 .byte 0b10101111 /* G(1) D(0) L(1) AVL(0) limit 19:16 */
379 .byte 0x0 /* base 31:24 */
380
381.set datasel_64, . - _gdt
382_data_64_gde:
383 .short 0xffff /* limit 15:00 */
384 .short 0x0000 /* base 15:00 */
385 .byte 0x00 /* base 23:16 */
386 .byte 0b10010010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
387 .byte 0b11001111 /* G(1) B(1) 0 AVL(0) limit 19:16 */
388 .byte 0x0 /* base 31:24 */
389
390 .quad 0x0000000000000000
391 .quad 0x0000000000000000
392
393.set user_codesel_64, . - _gdt
394_user_code_64_gde:
395 .short 0xffff /* limit 15:00 */
396 .short 0x0000 /* base 15:00 */
397 .byte 0x00 /* base 23:16 */
398 .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
399 .byte 0b10101111 /* G(1) D(1) L(0) AVL(0) limit 19:16 */
400 .byte 0x0 /* base 31:24 */
401
402.set user_datasel_64, . - _gdt
403_user_data_64_gde:
404 .short 0xffff /* limit 15:00 */
405 .short 0x0000 /* base 15:00 */
406 .byte 0x00 /* base 23:16 */
407 .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
408 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
409 .byte 0x0 /* base 31:24 */
410
411/* TSS descriptor */
412.set tsssel, . - _gdt
413_tss_gde:
414 .short 0 /* limit 15:00 */
415 .short 0 /* base 15:00 */
416 .byte 0 /* base 23:16 */
417 .byte 0x89 /* P(1) DPL(11) 0 10 B(0) 1 */
418 .byte 0x80 /* G(0) 0 0 AVL(0) limit 19:16 */
419 .byte 0 /* base 31:24 */
420 .quad 0x0000000000000000
421.global _gdt_end
422_gdt_end:
423
424.align 8
425.global _idtr
426_idtr:
427 .short _idt_end - _idt - 1 /* IDT limit */
428 .long _idt
429.fill 8
430.align 8
431/* interrupt descriptor table (IDT) */
432.global _idt
433_idt:
434
435.set i, 0
436.rept NUM_INT-1
437 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
438 .short codesel_64 /* selector */
439 .byte 0
440 .byte 0x8e /* present, ring 0, 64-bit interrupt gate */
441 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
442 .short 0 /* ISR offset */
443 .short 0 /* ISR offset */
444 .short 0 /* 32bits Reserved */
445 .short 0 /* 32bits Reserved */
446
447
448.set i, i + 1
449.endr
450
451.global _idt_end
452_idt_end:
453
454/* Memory for the initial page table, we will use 3 pages for a
455 1 to 1 mapping that covers 1GB of physycal memory */
456.align 4096
457pml4:
458.fill 4096
459pdp:
460.fill 4096
461pte:
462.fill 4096
463
464.bss
465.align 4096
466
467.global _kstack
468.fill 4096
469_kstack: