source: mainline/kernel/arch/amd64/src/boot/multiboot.S@ 17aa6d1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 17aa6d1 was 17aa6d1, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Deduplicate bootstrap code

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/*
2 * Copyright (c) 2005 Ondrej Palkovsky
3 * Copyright (c) 2006 Martin Decky
4 * Copyright (c) 2008 Jakub Jermar
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <abi/asmtool.h>
32#include <arch/boot/boot.h>
33#include <arch/mm/page.h>
34#include <arch/mm/ptl.h>
35#include <arch/pm.h>
36#include <genarch/multiboot/multiboot.h>
37#include <arch/cpuid.h>
38#include <arch/cpu.h>
39
40// TODO: most of this file can be rewritten in C
41
42// TODO: FB state should be checked dynamically from provided multiboot info.
43// Currently we only enable EGA statically, which forces us to rebuild
44// the image to get very early debug output.
45
46#define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE)
47
48.section K_TEXT_START, "ax"
49
50.code32
51
52.macro pm_error msg
53 movl \msg, %esi
54 jmp pm_error_halt
55.endm
56
57.macro pm_status msg
58#if defined(CONFIG_EGA) && !defined(CONFIG_FB)
59 pushl %esi
60 movl \msg, %esi
61 call pm_early_puts
62 popl %esi
63#endif
64.endm
65
66.macro pm2_status msg
67#ifndef CONFIG_FB
68 pm_status \msg
69#endif
70.endm
71
72.align 4
73multiboot_header:
74 .long MULTIBOOT_HEADER_MAGIC
75#ifdef CONFIG_FB
76 .long MULTIBOOT_HEADER_FLAGS
77 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* checksum */
78#else
79 .long MULTIBOOT_HEADER_FLAGS_NOFB
80 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS_NOFB) /* checksum */
81#endif
82 .long multiboot_header
83 .long unmapped_start
84 .long 0
85 .long 0
86 .long multiboot_image_start
87#ifdef CONFIG_FB
88 .long 0
89 .long CONFIG_BFB_WIDTH
90 .long CONFIG_BFB_HEIGHT
91 .long CONFIG_BFB_BPP
92#endif
93
94SYMBOL(multiboot_image_start)
95 cli
96 cld
97
98 /* Initialize stack pointer */
99 movl $START_STACK, %esp
100
101 /*
102 * Initialize Global Descriptor Table and
103 * Interrupt Descriptor Table registers
104 */
105 lgdtl bootstrap_gdtr
106 lidtl bootstrap_idtr
107
108 /* Kernel data + stack */
109 movw $GDT_SELECTOR(KDATA_DES), %cx
110 movw %cx, %es
111 movw %cx, %ds
112 movw %cx, %ss
113
114 /*
115 * Simics seems to remove hidden part of GS on entering user mode
116 * when _visible_ part of GS does not point to user-mode segment.
117 */
118 movw $GDT_SELECTOR(UDATA_DES), %cx
119 movw %cx, %fs
120 movw %cx, %gs
121
122 jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot_meeting_point
123 multiboot_meeting_point:
124
125 /*
126 * Protected 32-bit. We want to reuse the code-seg descriptor,
127 * the Default operand size must not be 1 when entering long mode.
128 */
129
130 /* Save multiboot arguments */
131 movl %eax, multiboot_eax
132 movl %ebx, multiboot_ebx
133
134 pm_status $status_prot
135
136 movl $(INTEL_CPUID_EXTENDED), %eax
137 cpuid
138 cmp $(INTEL_CPUID_EXTENDED), %eax
139 ja extended_cpuid_supported
140
141 pm_error $err_extended_cpuid
142
143 extended_cpuid_supported:
144
145 movl $(AMD_CPUID_EXTENDED), %eax
146 cpuid
147 bt $(AMD_EXT_LONG_MODE), %edx
148 jc long_mode_supported
149
150 pm_error $err_long_mode
151
152 long_mode_supported:
153
154 bt $(AMD_EXT_NOEXECUTE), %edx
155 jc noexecute_supported
156
157 pm_error $err_noexecute
158
159 noexecute_supported:
160
161 movl $(INTEL_CPUID_STANDARD), %eax
162 cpuid
163 bt $(INTEL_FXSAVE), %edx
164 jc fx_supported
165
166 pm_error $err_fx
167
168 fx_supported:
169
170 bt $(INTEL_SSE2), %edx
171 jc sse2_supported
172
173 pm_error $err_sse2
174
175 sse2_supported:
176
177 pm2_status $status_prot2
178
179 /*
180 * Enable 64-bit page translation entries - CR4.PAE = 1.
181 * Paging is not enabled until after long mode is enabled.
182 */
183
184 movl %cr4, %eax
185 orl $CR4_PAE, %eax
186 movl %eax, %cr4
187
188 /* Set up paging tables */
189 leal ptl_0, %eax
190 movl %eax, %cr3
191
192 /* Enable long mode */
193 movl $AMD_MSR_EFER, %ecx
194 rdmsr /* read EFER */
195 orl $AMD_LME, %eax /* set LME = 1 */
196 wrmsr
197
198 /* Enable paging to activate long mode (set CR0.PG = 1) */
199 movl %cr0, %eax
200 orl $CR0_PG, %eax
201 movl %eax, %cr0
202
203 /* At this point we are in compatibility mode */
204 jmpl $GDT_SELECTOR(KTEXT_DES), $start64
205
206/** Print string to EGA display (in light red) and halt.
207 *
208 * Should be executed from 32 bit protected mode with paging
209 * turned off. Stack is not required. This routine is used even
210 * if CONFIG_EGA is not enabled. Since we are going to halt the
211 * CPU anyway, it is always better to at least try to print
212 * some hints.
213 *
214 * @param %esi Pointer to the NULL-terminated string
215 * to be print.
216 *
217 */
218pm_error_halt:
219 movl $0xb8000, %edi /* base of EGA text mode memory */
220 xorl %eax, %eax
221
222 /* Read bits 8 - 15 of the cursor address */
223 movw $0x3d4, %dx
224 movb $0xe, %al
225 outb %al, %dx
226
227 movw $0x3d5, %dx
228 inb %dx, %al
229 shl $8, %ax
230
231 /* Read bits 0 - 7 of the cursor address */
232 movw $0x3d4, %dx
233 movb $0xf, %al
234 outb %al, %dx
235
236 movw $0x3d5, %dx
237 inb %dx, %al
238
239 /* Sanity check for the cursor on screen */
240 cmp $2000, %ax
241 jb err_cursor_ok
242
243 movw $1998, %ax
244
245 err_cursor_ok:
246
247 movw %ax, %bx
248 shl $1, %eax
249 addl %eax, %edi
250
251 err_ploop:
252 lodsb
253
254 cmp $0, %al
255 je err_ploop_end
256
257 movb $0x0c, %ah /* black background, light red foreground */
258 stosw
259
260 /* Sanity check for the cursor on the last line */
261 inc %bx
262 cmp $2000, %bx
263 jb err_ploop
264
265 /* Scroll the screen (24 rows) */
266 movl %esi, %edx
267 movl $0xb80a0, %esi
268 movl $0xb8000, %edi
269 movl $960, %ecx
270 rep movsl
271
272 /* Clear the 24th row */
273 xorl %eax, %eax
274 movl $40, %ecx
275 rep stosl
276
277 /* Go to row 24 */
278 movl %edx, %esi
279 movl $0xb8f00, %edi
280 movw $1920, %bx
281
282 jmp err_ploop
283 err_ploop_end:
284
285 /* Write bits 8 - 15 of the cursor address */
286 movw $0x3d4, %dx
287 movb $0xe, %al
288 outb %al, %dx
289
290 movw $0x3d5, %dx
291 movb %bh, %al
292 outb %al, %dx
293
294 /* Write bits 0 - 7 of the cursor address */
295 movw $0x3d4, %dx
296 movb $0xf, %al
297 outb %al, %dx
298
299 movw $0x3d5, %dx
300 movb %bl, %al
301 outb %al, %dx
302
303 cli
304 hlt1:
305 hlt
306 jmp hlt1
307
308/** Print string to EGA display (in light green).
309 *
310 * Should be called from 32 bit protected mode with paging
311 * turned off. A stack space of at least 24 bytes is required,
312 * but the function does not establish a stack frame.
313 *
314 * Macros such as pm_status and pm2_status take care that
315 * this function is used only when CONFIG_EGA is enabled
316 * and CONFIG_FB is disabled.
317 *
318 * @param %esi Pointer to the NULL-terminated string
319 * to be print.
320 *
321 */
322pm_early_puts:
323 pushl %eax
324 pushl %ebx
325 pushl %ecx
326 pushl %edx
327 pushl %edi
328
329 movl $0xb8000, %edi /* base of EGA text mode memory */
330 xorl %eax, %eax
331
332 /* Read bits 8 - 15 of the cursor address */
333 movw $0x3d4, %dx
334 movb $0xe, %al
335 outb %al, %dx
336
337 movw $0x3d5, %dx
338 inb %dx, %al
339 shl $8, %ax
340
341 /* Read bits 0 - 7 of the cursor address */
342 movw $0x3d4, %dx
343 movb $0xf, %al
344 outb %al, %dx
345
346 movw $0x3d5, %dx
347 inb %dx, %al
348
349 /* Sanity check for the cursor on screen */
350 cmp $2000, %ax
351 jb pm_puts_cursor_ok
352
353 movw $1998, %ax
354
355 pm_puts_cursor_ok:
356
357 movw %ax, %bx
358 shl $1, %eax
359 addl %eax, %edi
360
361 pm_puts_ploop:
362 lodsb
363
364 cmp $0, %al
365 je pm_puts_ploop_end
366
367 movb $0x0a, %ah /* black background, light green foreground */
368 stosw
369
370 /* Sanity check for the cursor on the last line */
371 inc %bx
372 cmp $2000, %bx
373 jb pm_puts_ploop
374
375 /* Scroll the screen (24 rows) */
376 movl %esi, %edx
377 movl $0xb80a0, %esi
378 movl $0xb8000, %edi
379 movl $960, %ecx
380 rep movsl
381
382 /* Clear the 24th row */
383 xorl %eax, %eax
384 movl $40, %ecx
385 rep stosl
386
387 /* Go to row 24 */
388 movl %edx, %esi
389 movl $0xb8f00, %edi
390 movw $1920, %bx
391
392 jmp pm_puts_ploop
393 pm_puts_ploop_end:
394
395 /* Write bits 8 - 15 of the cursor address */
396 movw $0x3d4, %dx
397 movb $0xe, %al
398 outb %al, %dx
399
400 movw $0x3d5, %dx
401 movb %bh, %al
402 outb %al, %dx
403
404 /* Write bits 0 - 7 of the cursor address */
405 movw $0x3d4, %dx
406 movb $0xf, %al
407 outb %al, %dx
408
409 movw $0x3d5, %dx
410 movb %bl, %al
411 outb %al, %dx
412
413 popl %edi
414 popl %edx
415 popl %ecx
416 popl %ebx
417 popl %eax
418
419 ret
420
421.code64
422
423.macro long_status msg
424 pushq %rdi
425 movq \msg, %rdi
426 call early_puts
427 popq %rdi
428.endm
429
430start64:
431
432 /*
433 * Long mode.
434 */
435
436 movq $(PA2KA(START_STACK)), %rsp
437
438 /* Create the first stack frame */
439 pushq $0
440 movq %rsp, %rbp
441
442 long_status $status_long
443
444 /* Call amd64_pre_main(multiboot_eax, multiboot_ebx) */
445 movl multiboot_eax, %edi
446 movl multiboot_ebx, %esi
447
448#ifdef MEMORY_MODEL_large
449 movabsq $amd64_pre_main, %rax
450 callq *%rax
451#else
452 callq amd64_pre_main
453#endif
454
455 long_status $status_main
456
457 /* Call main_bsp() */
458#ifdef MEMORY_MODEL_large
459 movabsq $main_bsp, %rax
460 callq *%rax
461#else
462 callq main_bsp
463#endif
464
465 /* Not reached */
466 cli
467 hlt0:
468 hlt
469 jmp hlt0
470
471/** Print string to EGA display.
472 *
473 * Should be called from long mode (with paging enabled
474 * and stack established). This function is ABI compliant
475 * (without red-zone).
476 *
477 * If CONFIG_EGA is undefined or CONFIG_FB is defined
478 * then this function does nothing.
479 *
480 * @param %rdi Pointer to the NULL-terminated string
481 * to be printed.
482 *
483 */
484early_puts:
485
486#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
487
488 /* Prologue, save preserved registers */
489 pushq %rbp
490 movq %rsp, %rbp
491 pushq %rbx
492
493 movq %rdi, %rsi
494 movq $(PA2KA(0xb8000)), %rdi /* base of EGA text mode memory */
495 xorq %rax, %rax
496
497 /* Read bits 8 - 15 of the cursor address */
498 movw $0x3d4, %dx
499 movb $0xe, %al
500 outb %al, %dx
501
502 movw $0x3d5, %dx
503 inb %dx, %al
504 shl $8, %ax
505
506 /* Read bits 0 - 7 of the cursor address */
507 movw $0x3d4, %dx
508 movb $0xf, %al
509 outb %al, %dx
510
511 movw $0x3d5, %dx
512 inb %dx, %al
513
514 /* Sanity check for the cursor on screen */
515 cmp $2000, %ax
516 jb early_puts_cursor_ok
517
518 movw $1998, %ax
519
520 early_puts_cursor_ok:
521
522 movw %ax, %bx
523 shl $1, %rax
524 addq %rax, %rdi
525
526 early_puts_ploop:
527 lodsb
528
529 cmp $0, %al
530 je early_puts_ploop_end
531
532 movb $0x0e, %ah /* black background, yellow foreground */
533 stosw
534
535 /* Sanity check for the cursor on the last line */
536 inc %bx
537 cmp $2000, %bx
538 jb early_puts_ploop
539
540 /* Scroll the screen (24 rows) */
541 movq %rsi, %rdx
542 movq $(PA2KA(0xb80a0)), %rsi
543 movq $(PA2KA(0xb8000)), %rdi
544 movl $480, %ecx
545 rep movsq
546
547 /* Clear the 24th row */
548 xorl %eax, %eax
549 movl $20, %ecx
550 rep stosq
551
552 /* Go to row 24 */
553 movq %rdx, %rsi
554 movq $(PA2KA(0xb8f00)), %rdi
555 movw $1920, %bx
556
557 jmp early_puts_ploop
558 early_puts_ploop_end:
559
560 /* Write bits 8 - 15 of the cursor address */
561 movw $0x3d4, %dx
562 movb $0xe, %al
563 outb %al, %dx
564
565 movw $0x3d5, %dx
566 movb %bh, %al
567 outb %al, %dx
568
569 /* Write bits 0 - 7 of the cursor address */
570 movw $0x3d4, %dx
571 movb $0xf, %al
572 outb %al, %dx
573
574 movw $0x3d5, %dx
575 movb %bl, %al
576 outb %al, %dx
577
578 /* Epilogue, restore preserved registers */
579 popq %rbx
580 leave
581
582#endif
583
584 ret
585
586.section K_INI_PTLS, "aw", @progbits
587
588/** Generate initial page table contents.
589 *
590 * @param cnt Number of entries to generate. Must be multiple of 8.
591 * @param g Number of GB that will be added to the mapping.
592 *
593 */
594.macro ptl2gen cnt g
595 .if \cnt
596 ptl2gen "\cnt - 8" \g
597 .quad ((\cnt - 8) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
598 .quad ((\cnt - 7) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
599 .quad ((\cnt - 6) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
600 .quad ((\cnt - 5) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
601 .quad ((\cnt - 4) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
602 .quad ((\cnt - 3) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
603 .quad ((\cnt - 2) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
604 .quad ((\cnt - 1) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
605 .endif
606.endm
607
608/* Page table for pages in the 1st gigabyte. */
609.align 4096
610ptl_2_0g:
611 ptl2gen 512 0
612
613/* Page table for pages in the 2nd gigabyte. */
614.align 4096
615ptl_2_1g:
616 ptl2gen 512 1
617
618/* Page table for pages in the 3rd gigabyte. */
619.align 4096
620ptl_2_2g:
621 ptl2gen 512 2
622
623/* Page table for pages in the 4th gigabyte. */
624.align 4096
625ptl_2_3g:
626 ptl2gen 512 3
627
628/* Page table for pages in the 5th gigabyte. */
629.align 4096
630ptl_2_4g:
631 ptl2gen 512 4
632
633/* Page table for pages in the 6th gigabyte. */
634.align 4096
635ptl_2_5g:
636 ptl2gen 512 5
637
638/* Page table for pages in the 7th gigabyte. */
639.align 4096
640ptl_2_6g:
641 ptl2gen 512 6
642
643/* Page table for pages in the 8th gigabyte. */
644.align 4096
645ptl_2_7g:
646 ptl2gen 512 7
647
648#ifdef MEMORY_MODEL_kernel
649.align 4096
650ptl_1:
651 /* Identity mapping for [0; 8G) */
652 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
653 .quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
654 .quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
655 .quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
656 .quad ptl_2_4g + (PTL_WRITABLE | PTL_PRESENT)
657 .quad ptl_2_5g + (PTL_WRITABLE | PTL_PRESENT)
658 .quad ptl_2_6g + (PTL_WRITABLE | PTL_PRESENT)
659 .quad ptl_2_7g + (PTL_WRITABLE | PTL_PRESENT)
660 .fill 502, 8, 0
661 /* Mapping of [0; 2G) at -2G */
662 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
663 .quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
664
665.align 4096
666SYMBOL(ptl_0)
667 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
668 .fill 510, 8, 0
669 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
670#endif
671
672#ifdef MEMORY_MODEL_large
673.align 4096
674ptl_1:
675 /* Identity mapping for [0; 8G) */
676 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
677 .quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
678 .quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
679 .quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
680 .quad ptl_2_4g + (PTL_WRITABLE | PTL_PRESENT)
681 .quad ptl_2_5g + (PTL_WRITABLE | PTL_PRESENT)
682 .quad ptl_2_6g + (PTL_WRITABLE | PTL_PRESENT)
683 .quad ptl_2_7g + (PTL_WRITABLE | PTL_PRESENT)
684 .fill 504, 8, 0
685
686.align 4096
687SYMBOL(ptl_0)
688 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
689 .fill 255, 8, 0
690 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
691 .fill 255, 8, 0
692#endif
693
694.section K_DATA_START, "aw", @progbits
695
696SYMBOL(bootstrap_idtr)
697 .word 0
698 .long 0
699
700SYMBOL(bootstrap_gdtr)
701 .word GDT_SELECTOR(GDT_ITEMS)
702 .long KA2PA(gdt)
703
704SYMBOL(multiboot_eax)
705 .long 0
706
707SYMBOL(multiboot_ebx)
708 .long 0
709
710err_extended_cpuid:
711 .asciz "Error: Extended CPUID not supported -- CPU is not 64-bit. System halted."
712err_long_mode:
713 .asciz "Error: 64-bit long mode not supported. System halted."
714err_noexecute:
715 .asciz "Error: No-execute pages not supported. System halted."
716err_fx:
717 .asciz "Error: FXSAVE/FXRESTORE instructions not supported. System halted."
718err_sse2:
719 .asciz "Error: SSE2 instructions not supported. System halted."
720
721status_prot:
722 .asciz "[prot] "
723status_multiboot_cmdline:
724 .asciz "[multiboot_cmdline] "
725status_prot2:
726 .asciz "[prot2] "
727status_long:
728 .asciz "[long] "
729status_main:
730 .asciz "[main] "
Note: See TracBrowser for help on using the repository browser.