source: mainline/kernel/arch/amd64/src/boot/boot.S@ 0d5a50c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0d5a50c was 53634f9, checked in by Martin Decky <martin@…>, 17 years ago

make RANDI a generic macro

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