source: mainline/kernel/arch/amd64/src/boot/boot.S@ 19077a5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 19077a5 was 19077a5, checked in by Jakub Jermar <jakub@…>, 18 years ago

Grow the initial identity mapping from 64M to 4G.
We should not allocate GDT's from above 4G or the amd64 will occassionally
triple-fault again.

  • Property mode set to 100644
File size: 14.4 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 <arch/boot/boot.h>
32#include <arch/boot/memmap.h>
33#include <arch/mm/page.h>
34#include <arch/mm/ptl.h>
35#include <arch/pm.h>
36#include <arch/cpu.h>
37#include <arch/cpuid.h>
38
39#define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE)
40
41.section K_TEXT_START, "ax"
42
43.code32
44.align 4
45.global multiboot_image_start
46multiboot_header:
47 .long MULTIBOOT_HEADER_MAGIC
48 .long MULTIBOOT_HEADER_FLAGS
49 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) # checksum
50 .long multiboot_header
51 .long unmapped_ktext_start
52 .long 0
53 .long 0
54 .long multiboot_image_start
55
56multiboot_image_start:
57 movl $START_STACK, %esp # initialize stack pointer
58 lgdtl bootstrap_gdtr # initialize Global Descriptor Table register
59
60 movw $gdtselector(KDATA_DES), %cx
61 movw %cx, %es
62 movw %cx, %ds # kernel data + stack
63 movw %cx, %ss
64 # Simics seems to remove hidden part of GS on entering user mode
65 # when _visible_ part of GS does not point to user-mode segment
66 movw $gdtselector(UDATA_DES), %cx
67 movw %cx, %fs
68 movw %cx, %gs
69
70 jmpl $gdtselector(KTEXT32_DES), $multiboot_meeting_point
71 multiboot_meeting_point:
72
73 movl %eax, grub_eax # save parameters from GRUB
74 movl %ebx, grub_ebx
75
76 # Protected 32-bit. We want to reuse the code-seg descriptor,
77 # the Default operand size must not be 1 when entering long mode
78
79 movl $(INTEL_CPUID_EXTENDED), %eax
80 cpuid
81 cmp $(INTEL_CPUID_EXTENDED), %eax
82 ja extended_cpuid_supported
83
84 movl $extended_cpuid_msg, %esi
85 jmp error_halt
86
87 extended_cpuid_supported:
88
89 movl $(AMD_CPUID_EXTENDED), %eax
90 cpuid
91 bt $(AMD_EXT_LONG_MODE), %edx
92 jc long_mode_supported
93
94 movl $long_mode_msg, %esi
95 jmp error_halt
96
97 long_mode_supported:
98
99 bt $(AMD_EXT_NOEXECUTE), %edx
100 jc noexecute_supported
101
102 movl $noexecute_msg, %esi
103 jmp error_halt
104
105 noexecute_supported:
106
107 movl $(INTEL_CPUID_STANDARD), %eax
108 cpuid
109 bt $(INTEL_FXSAVE), %edx
110 jc fx_supported
111
112 movl $fx_msg, %esi
113 jmp error_halt
114
115 fx_supported:
116
117 bt $(INTEL_SSE2), %edx
118 jc sse2_supported
119
120 movl $sse2_msg, %esi
121 jmp error_halt
122
123 sse2_supported:
124
125#ifdef CONFIG_FB
126 mov $vesa_init, %esi
127 mov $VESA_INIT_SEGMENT << 4, %edi
128 mov $e_vesa_init - vesa_init, %ecx
129 cld
130 rep movsb
131
132 mov $VESA_INIT_SEGMENT << 4, %edi
133 jmpl *%edi
134
135 vesa_meeting_point:
136
137 mov %esi, KA2PA(vesa_ph_addr)
138 mov %di, KA2PA(vesa_height)
139 shr $16, %edi
140 mov %di, KA2PA(vesa_width)
141 mov %bx, KA2PA(vesa_scanline)
142 shr $16, %ebx
143 mov %bx, KA2PA(vesa_bpp)
144#endif
145
146 # Enable 64-bit page translation entries - CR4.PAE = 1.
147 # Paging is not enabled until after long mode is enabled
148
149 movl %cr4, %eax
150 btsl $5, %eax
151 movl %eax, %cr4
152
153 # Set up paging tables
154
155 leal ptl_0, %eax
156 movl %eax, %cr3
157
158 # Enable long mode
159
160 movl $EFER_MSR_NUM, %ecx # EFER MSR number
161 rdmsr # Read EFER
162 btsl $AMD_LME_FLAG, %eax # Set LME = 1
163 wrmsr # Write EFER
164
165 # Enable paging to activate long mode (set CR0.PG = 1)
166
167 movl %cr0, %eax
168 btsl $31, %eax
169 movl %eax, %cr0
170
171 # At this point we are in compatibility mode
172
173 jmpl $gdtselector(KTEXT_DES), $start64
174
175.code64
176start64:
177 movq $(PA2KA(START_STACK)), %rsp
178 movl grub_eax, %eax
179 movl grub_ebx, %ebx
180
181 cmpl $MULTIBOOT_LOADER_MAGIC, %eax # compare GRUB signature
182 je valid_boot
183
184 xorl %ecx, %ecx # no memory size or map available
185 movl %ecx, e801memorysize
186 movl %ecx, e820counter
187
188 jmp invalid_boot
189
190 valid_boot:
191
192 movl (%ebx), %eax # ebx = physical address of struct multiboot_info
193
194 bt $0, %eax # mbi->flags[0] (mem_lower, mem_upper valid)
195 jc mem_valid
196
197 xorl %ecx, %ecx
198 jmp mem_invalid
199
200 mem_valid:
201 movl 4(%ebx), %ecx # mbi->mem_lower
202 addl 8(%ebx), %ecx # mbi->mem_upper
203
204 mem_invalid:
205 movl %ecx, e801memorysize
206
207 bt $3, %eax # mbi->flags[3] (mods_count, mods_addr valid)
208 jc mods_valid
209
210 xorq %rcx, %rcx
211 movq %rcx, init
212 jmp mods_end
213
214 mods_valid:
215
216 xorq %rcx, %rcx
217 movl 20(%ebx), %ecx # mbi->mods_count
218 movq %rcx, init
219
220 cmpl $0, %ecx
221 je mods_end
222
223 movl 24(%ebx), %esi # mbi->mods_addr
224 movq $init, %rdi
225
226 mods_loop:
227
228 xorq %rdx, %rdx
229 movl 0(%esi), %edx # mods->mod_start
230 movq $0xffff800000000000, %r10
231 addq %r10, %rdx
232 movq %rdx, 8(%rdi)
233
234 xorq %rdx, %rdx
235 movl 4(%esi), %edx
236 subl 0(%esi), %edx # mods->mod_end - mods->mod_start
237 movq %rdx, 16(%rdi)
238
239 addl $16, %esi
240 addq $16, %rdi
241
242 loop mods_loop
243
244 mods_end:
245
246 bt $6, %eax # mbi->flags[6] (mmap_length, mmap_addr valid)
247 jc mmap_valid
248
249 xorl %edx, %edx
250 jmp mmap_invalid
251
252 mmap_valid:
253 movl 44(%ebx), %ecx # mbi->mmap_length
254 movl 48(%ebx), %esi # mbi->mmap_addr
255 movq $e820table, %rdi
256 xorl %edx, %edx
257
258 mmap_loop:
259 cmpl $0, %ecx
260 jle mmap_end
261
262 movl 4(%esi), %eax # mmap->base_addr_low
263 movl %eax, (%rdi)
264
265 movl 8(%esi), %eax # mmap->base_addr_high
266 movl %eax, 4(%rdi)
267
268 movl 12(%esi), %eax # mmap->length_low
269 movl %eax, 8(%rdi)
270
271 movl 16(%esi), %eax # mmap->length_high
272 movl %eax, 12(%rdi)
273
274 movl 20(%esi), %eax # mmap->type
275 movl %eax, 16(%rdi)
276
277 movl (%esi), %eax # mmap->size
278 addl $0x4, %eax
279 addl %eax, %esi
280 subl %eax, %ecx
281 addq $MEMMAP_E820_RECORD_SIZE, %rdi
282 incl %edx
283 jmp mmap_loop
284
285 mmap_end:
286
287 mmap_invalid:
288 movl %edx, e820counter
289
290 invalid_boot:
291
292#ifdef CONFIG_SMP
293
294 # copy AP bootstrap routines below 1 MB
295
296 movq $BOOT_OFFSET, %rsi
297 movq $AP_BOOT_OFFSET, %rdi
298 movq $_hardcoded_unmapped_size, %rcx
299 cld
300 rep movsb
301
302#endif
303
304 call main_bsp # never returns
305
306 cli
307 hlt
308
309#ifdef CONFIG_FB
310.code32
311vesa_init:
312 jmp $gdtselector(VESA_INIT_DES), $vesa_init_real - vesa_init
313
314.code16
315vesa_init_real:
316
317 mov %cr0, %eax
318 and $~1, %eax
319 mov %eax, %cr0
320
321 jmp $VESA_INIT_SEGMENT, $vesa_init_real2 - vesa_init
322
323vesa_init_real2:
324
325 mov $VESA_INIT_SEGMENT, %bx
326
327 mov %bx, %es
328 mov %bx, %fs
329 mov %bx, %gs
330 mov %bx, %ds
331 mov %bx, %ss
332
333 movl $0x0000fffc, %esp
334 movl $0x0000fffc, %ebp
335
336#define VESA_INFO_SIZE 1024
337
338#define VESA_MODE_ATTRIBUTES_OFFSET 0
339#define VESA_MODE_LIST_PTR_OFFSET 14
340#define VESA_MODE_SCANLINE_OFFSET 16
341#define VESA_MODE_WIDTH_OFFSET 18
342#define VESA_MODE_HEIGHT_OFFSET 20
343#define VESA_MODE_BPP_OFFSET 25
344#define VESA_MODE_PHADDR_OFFSET 40
345
346#define VESA_END_OF_MODES 0xffff
347
348#define VESA_OK 0x4f
349
350#define VESA_GET_INFO 0x4f00
351#define VESA_GET_MODE_INFO 0x4f01
352#define VESA_SET_MODE 0x4f02
353#define VESA_SET_PALETTE 0x4f09
354
355#define CONFIG_VESA_BPP_a 255
356
357#if CONFIG_VESA_BPP == 24
358#define CONFIG_VESA_BPP_VARIANT 32
359#endif
360
361 mov $VESA_GET_INFO, %ax
362 mov $e_vesa_init - vesa_init, %di
363 push %di
364 int $0x10
365
366 pop %di
367 cmp $VESA_OK, %al
368 jnz 0f
369
370 mov 2 + VESA_MODE_LIST_PTR_OFFSET(%di), %si
371 mov %si, %gs
372 mov VESA_MODE_LIST_PTR_OFFSET(%di), %si
373
374 add $VESA_INFO_SIZE, %di
375
3761:# Try next mode
377 mov %gs:(%si), %cx
378 cmp $VESA_END_OF_MODES, %cx
379 jz 0f
380
381 inc %si
382 inc %si
383 push %cx
384 push %di
385 push %si
386 mov $VESA_GET_MODE_INFO, %ax
387 int $0x10
388
389 pop %si
390 pop %di
391 pop %cx
392 cmp $VESA_OK, %al
393 jnz 0f
394
395 mov $CONFIG_VESA_WIDTH, %ax
396 cmp VESA_MODE_WIDTH_OFFSET(%di), %ax
397 jnz 1b
398
399 mov $CONFIG_VESA_HEIGHT, %ax
400 cmp VESA_MODE_HEIGHT_OFFSET(%di), %ax
401 jnz 1b
402
403 mov $CONFIG_VESA_BPP, %al
404 cmp VESA_MODE_BPP_OFFSET(%di), %al
405
406#ifdef CONFIG_VESA_BPP_VARIANT
407 jz 2f
408
409 mov $CONFIG_VESA_BPP_VARIANT, %al
410 cmp VESA_MODE_BPP_OFFSET(%di), %al
411#endif
412 jnz 1b
413
4142:
415
416 mov %cx, %bx
417 or $0xc000, %bx
418 push %di
419 mov $VESA_SET_MODE, %ax
420 int $0x10
421
422 pop %di
423 cmp $VESA_OK, %al
424 jnz 0f
425
426#if CONFIG_VESA_BPP == 8
427
428 # Set 3:2:3 VGA palette
429
430 mov VESA_MODE_ATTRIBUTES_OFFSET(%di), %ax
431 push %di
432 mov $vga323 - vesa_init, %di
433 mov $0x100, %ecx
434
435 bt $5, %ax # Test if VGA compatible registers are present
436 jnc vga_compat
437
438 # Try VESA routine to set palette
439
440 mov $VESA_SET_PALETTE, %ax
441 xor %bl, %bl
442 xor %dx, %dx
443 int $0x10
444
445 jmp vga_not_compat
446
447 vga_compat:
448
449 # Try VGA registers to set palette
450
451 movw $0x3c6, %dx # Set palette mask
452 movb $0xff, %al
453 outb %al, %dx
454
455 movw $0x3c8, %dx # First index to set
456 xor %al, %al
457 outb %al, %dx
458
459 movw $0x3c9, %dx # Data port
460 vga_loop:
461 movb %es:2(%di), %al
462 outb %al, %dx
463
464 movb %es:1(%di), %al
465 outb %al, %dx
466
467 movb %es:(%di), %al
468 outb %al, %dx
469
470 addw $4, %di
471 loop vga_loop
472
473 vga_not_compat:
474
475 pop %di
476
477#endif
478
479 mov VESA_MODE_PHADDR_OFFSET(%di), %esi
480 mov VESA_MODE_WIDTH_OFFSET(%di), %ax
481 shl $16, %eax
482 mov VESA_MODE_HEIGHT_OFFSET(%di), %ax
483 mov VESA_MODE_BPP_OFFSET(%di), %bl
484 xor %bh, %bh
485 shl $16, %ebx
486 mov VESA_MODE_SCANLINE_OFFSET(%di), %bx
487 mov %eax, %edi
488
4898:
490
491 mov %cr0, %eax
492 or $1, %eax
493 mov %eax, %cr0
494
495 jmp 9f
4969:
497
498 ljmpl $gdtselector(KTEXT32_DES), $(vesa_init_protect - vesa_init + VESA_INIT_SEGMENT << 4)
499
5000:# No prefered mode found
501 mov $0x111, %cx
502 push %di
503 push %cx
504 mov $VESA_GET_MODE_INFO, %ax
505 int $0x10
506
507 pop %cx
508 pop %di
509 cmp $VESA_OK, %al
510 jnz 1f
511 jz 2b # Force relative jump
512
5131:
514 mov $0x0003, %ax
515 int $0x10
516 mov $0xffffffff, %edi # EGA text mode used, because of problems with VESA
517 xor %ax, %ax
518 jz 8b # Force relative jump
519
520vga323:
521#include "vga323.pal"
522
523.code32
524vesa_init_protect:
525 movw $gdtselector(KDATA_DES), %cx
526 movw %cx, %es
527 movw %cx, %ds # kernel data + stack
528 movw %cx, %ss
529 # Simics seems to remove hidden part of GS on entering user mode
530 # when _visible_ part of GS does not point to user-mode segment
531 movw $gdtselector(UDATA_DES), %cx
532 movw %cx, %fs
533 movw %cx, %gs
534
535 movl $START_STACK, %esp # initialize stack pointer
536
537 jmpl $gdtselector(KTEXT32_DES), $vesa_meeting_point
538
539.align 4
540e_vesa_init:
541#endif
542
543# Print string from %esi to EGA display (in red) and halt
544error_halt:
545 movl $0xb8000, %edi # base of EGA text mode memory
546 xorl %eax, %eax
547
548 movw $0x3d4, %dx # read bits 8 - 15 of the cursor address
549 movb $0xe, %al
550 outb %al, %dx
551
552 movw $0x3d5, %dx
553 inb %dx, %al
554 shl $8, %ax
555
556 movw $0x3d4, %dx # read bits 0 - 7 of the cursor address
557 movb $0xf, %al
558 outb %al, %dx
559
560 movw $0x3d5, %dx
561 inb %dx, %al
562
563 cmp $1920, %ax
564 jbe cursor_ok
565 movw $1920, %ax # sanity check for the cursor on the last line
566 cursor_ok:
567
568 movw %ax, %bx
569 shl $1, %eax
570 addl %eax, %edi
571
572 movw $0x0c00, %ax # black background, light red foreground
573 cld
574
575 ploop:
576 lodsb
577 cmp $0, %al
578 je ploop_end
579 stosw
580 inc %bx
581 jmp ploop
582 ploop_end:
583
584 movw $0x3d4, %dx # write bits 8 - 15 of the cursor address
585 movb $0xe, %al
586 outb %al, %dx
587
588 movw $0x3d5, %dx
589 movb %bh, %al
590 outb %al, %dx
591
592 movw $0x3d4, %dx # write bits 0 - 7 of the cursor address
593 movb $0xf, %al
594 outb %al, %dx
595
596 movw $0x3d5, %dx
597 movb %bl, %al
598 outb %al, %dx
599
600 cli
601 hlt
602
603
604.section K_INI_PTLS, "aw", @progbits
605
606#
607# Macro for generating initial page table contents.
608# @param cnt Number of entries to generat. Must be multiple of 8.
609# @param g Number of GB that will be added to the mapping.
610#
611.macro ptl2gen cnt g
612.if \cnt
613 ptl2gen "\cnt - 8" \g
614 .quad ((\cnt - 8) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
615 .quad ((\cnt - 7) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
616 .quad ((\cnt - 6) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
617 .quad ((\cnt - 5) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
618 .quad ((\cnt - 4) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
619 .quad ((\cnt - 3) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
620 .quad ((\cnt - 2) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
621 .quad ((\cnt - 1) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
622.endif
623.endm
624
625# Page table for pages in the first gigabyte.
626.align 4096
627.global ptl_2_0g
628ptl_2_0g:
629 ptl2gen 512 0
630
631# Page table for pages in the second gigabyte.
632.align 4096
633.global ptl_2_1g
634ptl_2_1g:
635 ptl2gen 512 1
636
637# Page table for pages in the third gigabyte.
638.align 4096
639.global ptl_2_2g
640ptl_2_2g:
641 ptl2gen 512 2
642
643# Page table for pages in the fourth gigabyte.
644.align 4096
645.global ptl_2_3g
646ptl_2_3g:
647 ptl2gen 512 3
648
649.align 4096
650.global ptl_1
651ptl_1:
652 # Identity mapping for [0; 4G)
653 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
654 .quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
655 .quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
656 .quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
657 .fill 506, 8, 0
658 # Mapping of [0; 1G) at -2G
659 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
660 .fill 1, 8, 0
661
662.align 4096
663.global ptl_0
664ptl_0:
665 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
666 .fill 255,8,0
667 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
668 .fill 254,8,0
669 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
670
671.section K_DATA_START, "aw", @progbits
672
673.global bootstrap_gdtr
674bootstrap_gdtr:
675 .word gdtselector(GDT_ITEMS)
676 .long KA2PA(gdt)
677
678grub_eax:
679 .long 0
680
681grub_ebx:
682 .long 0
683
684extended_cpuid_msg:
685 .asciz "Extended CPUID not supported. System halted."
686long_mode_msg:
687 .asciz "64 bit long mode not supported. System halted."
688noexecute_msg:
689 .asciz "No-execute pages not supported. System halted."
690fx_msg:
691 .asciz "FXSAVE/FXRESTORE instructions not supported. System halted."
692sse2_msg:
693 .asciz "SSE2 instructions not supported. System halted."
Note: See TracBrowser for help on using the repository browser.