source: mainline/kernel/arch/amd64/src/boot/boot.S@ 5d8d71e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d8d71e was 5d8d71e, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Move multiboot parsing to genarch/*/multiboot and adapt it for use with both ia32 and amd64. Multiboot info parsing now supported on amd64, too.

  • Property mode set to 100644
File size: 12.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 <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
179 # arch_pre_main(grub_eax, grub_ebx)
180 xorq %rdi, %rdi
181 movl grub_eax, %edi
182 xorq %rsi, %rsi
183 movl grub_ebx, %esi
184 call arch_pre_main
185
186 call main_bsp
187
188 # Not reached.
189
190 cli
191 hlt
192
193#ifdef CONFIG_FB
194.code32
195vesa_init:
196 jmp $gdtselector(VESA_INIT_DES), $vesa_init_real - vesa_init
197
198.code16
199vesa_init_real:
200
201 mov %cr0, %eax
202 and $~1, %eax
203 mov %eax, %cr0
204
205 jmp $VESA_INIT_SEGMENT, $vesa_init_real2 - vesa_init
206
207vesa_init_real2:
208
209 mov $VESA_INIT_SEGMENT, %bx
210
211 mov %bx, %es
212 mov %bx, %fs
213 mov %bx, %gs
214 mov %bx, %ds
215 mov %bx, %ss
216
217 movl $0x0000fffc, %esp
218 movl $0x0000fffc, %ebp
219
220#define VESA_INFO_SIZE 1024
221
222#define VESA_MODE_ATTRIBUTES_OFFSET 0
223#define VESA_MODE_LIST_PTR_OFFSET 14
224#define VESA_MODE_SCANLINE_OFFSET 16
225#define VESA_MODE_WIDTH_OFFSET 18
226#define VESA_MODE_HEIGHT_OFFSET 20
227#define VESA_MODE_BPP_OFFSET 25
228#define VESA_MODE_PHADDR_OFFSET 40
229
230#define VESA_END_OF_MODES 0xffff
231
232#define VESA_OK 0x4f
233
234#define VESA_GET_INFO 0x4f00
235#define VESA_GET_MODE_INFO 0x4f01
236#define VESA_SET_MODE 0x4f02
237#define VESA_SET_PALETTE 0x4f09
238
239#define CONFIG_VESA_BPP_a 255
240
241#if CONFIG_VESA_BPP == 24
242#define CONFIG_VESA_BPP_VARIANT 32
243#endif
244
245 mov $VESA_GET_INFO, %ax
246 mov $e_vesa_init - vesa_init, %di
247 push %di
248 int $0x10
249
250 pop %di
251 cmp $VESA_OK, %al
252 jnz 0f
253
254 mov 2 + VESA_MODE_LIST_PTR_OFFSET(%di), %si
255 mov %si, %gs
256 mov VESA_MODE_LIST_PTR_OFFSET(%di), %si
257
258 add $VESA_INFO_SIZE, %di
259
2601:# Try next mode
261 mov %gs:(%si), %cx
262 cmp $VESA_END_OF_MODES, %cx
263 jz 0f
264
265 inc %si
266 inc %si
267 push %cx
268 push %di
269 push %si
270 mov $VESA_GET_MODE_INFO, %ax
271 int $0x10
272
273 pop %si
274 pop %di
275 pop %cx
276 cmp $VESA_OK, %al
277 jnz 0f
278
279 mov $CONFIG_VESA_WIDTH, %ax
280 cmp VESA_MODE_WIDTH_OFFSET(%di), %ax
281 jnz 1b
282
283 mov $CONFIG_VESA_HEIGHT, %ax
284 cmp VESA_MODE_HEIGHT_OFFSET(%di), %ax
285 jnz 1b
286
287 mov $CONFIG_VESA_BPP, %al
288 cmp VESA_MODE_BPP_OFFSET(%di), %al
289
290#ifdef CONFIG_VESA_BPP_VARIANT
291 jz 2f
292
293 mov $CONFIG_VESA_BPP_VARIANT, %al
294 cmp VESA_MODE_BPP_OFFSET(%di), %al
295#endif
296 jnz 1b
297
2982:
299
300 mov %cx, %bx
301 or $0xc000, %bx
302 push %di
303 mov $VESA_SET_MODE, %ax
304 int $0x10
305
306 pop %di
307 cmp $VESA_OK, %al
308 jnz 0f
309
310#if CONFIG_VESA_BPP == 8
311
312 # Set 3:2:3 VGA palette
313
314 mov VESA_MODE_ATTRIBUTES_OFFSET(%di), %ax
315 push %di
316 mov $vga323 - vesa_init, %di
317 mov $0x100, %ecx
318
319 bt $5, %ax # Test if VGA compatible registers are present
320 jnc vga_compat
321
322 # Try VESA routine to set palette
323
324 mov $VESA_SET_PALETTE, %ax
325 xor %bl, %bl
326 xor %dx, %dx
327 int $0x10
328
329 cmp $0x00, %ah
330 je vga_not_compat
331
332 vga_compat:
333
334 # Try VGA registers to set palette
335
336 movw $0x3c6, %dx # Set palette mask
337 movb $0xff, %al
338 outb %al, %dx
339
340 movw $0x3c8, %dx # First index to set
341 xor %al, %al
342 outb %al, %dx
343
344 movw $0x3c9, %dx # Data port
345 vga_loop:
346 movb %es:2(%di), %al
347 outb %al, %dx
348
349 movb %es:1(%di), %al
350 outb %al, %dx
351
352 movb %es:(%di), %al
353 outb %al, %dx
354
355 addw $4, %di
356 loop vga_loop
357
358 vga_not_compat:
359
360 pop %di
361
362#endif
363
364 mov VESA_MODE_PHADDR_OFFSET(%di), %esi
365 mov VESA_MODE_WIDTH_OFFSET(%di), %ax
366 shl $16, %eax
367 mov VESA_MODE_HEIGHT_OFFSET(%di), %ax
368 mov VESA_MODE_BPP_OFFSET(%di), %bl
369 xor %bh, %bh
370 shl $16, %ebx
371 mov VESA_MODE_SCANLINE_OFFSET(%di), %bx
372 mov %eax, %edi
373
3748:
375
376 mov %cr0, %eax
377 or $1, %eax
378 mov %eax, %cr0
379
380 jmp 9f
3819:
382
383 ljmpl $gdtselector(KTEXT32_DES), $(vesa_init_protect - vesa_init + VESA_INIT_SEGMENT << 4)
384
3850:# No prefered mode found
386 mov $0x111, %cx
387 push %di
388 push %cx
389 mov $VESA_GET_MODE_INFO, %ax
390 int $0x10
391
392 pop %cx
393 pop %di
394 cmp $VESA_OK, %al
395 jnz 1f
396 jz 2b # Force relative jump
397
3981:
399 mov $0x0003, %ax
400 int $0x10
401 mov $0xffffffff, %edi # EGA text mode used, because of problems with VESA
402 xor %ax, %ax
403 jz 8b # Force relative jump
404
405vga323:
406#include "vga323.pal"
407
408.code32
409vesa_init_protect:
410 movw $gdtselector(KDATA_DES), %cx
411 movw %cx, %es
412 movw %cx, %ds # kernel data + stack
413 movw %cx, %ss
414 # Simics seems to remove hidden part of GS on entering user mode
415 # when _visible_ part of GS does not point to user-mode segment
416 movw $gdtselector(UDATA_DES), %cx
417 movw %cx, %fs
418 movw %cx, %gs
419
420 movl $START_STACK, %esp # initialize stack pointer
421
422 jmpl $gdtselector(KTEXT32_DES), $vesa_meeting_point
423
424.align 4
425e_vesa_init:
426#endif
427
428# Print string from %esi to EGA display (in red) and halt
429error_halt:
430 movl $0xb8000, %edi # base of EGA text mode memory
431 xorl %eax, %eax
432
433 movw $0x3d4, %dx # read bits 8 - 15 of the cursor address
434 movb $0xe, %al
435 outb %al, %dx
436
437 movw $0x3d5, %dx
438 inb %dx, %al
439 shl $8, %ax
440
441 movw $0x3d4, %dx # read bits 0 - 7 of the cursor address
442 movb $0xf, %al
443 outb %al, %dx
444
445 movw $0x3d5, %dx
446 inb %dx, %al
447
448 cmp $1920, %ax
449 jbe cursor_ok
450 movw $1920, %ax # sanity check for the cursor on the last line
451 cursor_ok:
452
453 movw %ax, %bx
454 shl $1, %eax
455 addl %eax, %edi
456
457 movw $0x0c00, %ax # black background, light red foreground
458
459 ploop:
460 lodsb
461 cmp $0, %al
462 je ploop_end
463 stosw
464 inc %bx
465 jmp ploop
466 ploop_end:
467
468 movw $0x3d4, %dx # write bits 8 - 15 of the cursor address
469 movb $0xe, %al
470 outb %al, %dx
471
472 movw $0x3d5, %dx
473 movb %bh, %al
474 outb %al, %dx
475
476 movw $0x3d4, %dx # write bits 0 - 7 of the cursor address
477 movb $0xf, %al
478 outb %al, %dx
479
480 movw $0x3d5, %dx
481 movb %bl, %al
482 outb %al, %dx
483
484 cli
485 hlt
486
487
488.section K_INI_PTLS, "aw", @progbits
489
490#
491# Macro for generating initial page table contents.
492# @param cnt Number of entries to generat. Must be multiple of 8.
493# @param g Number of GB that will be added to the mapping.
494#
495.macro ptl2gen cnt g
496.if \cnt
497 ptl2gen "\cnt - 8" \g
498 .quad ((\cnt - 8) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
499 .quad ((\cnt - 7) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
500 .quad ((\cnt - 6) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
501 .quad ((\cnt - 5) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
502 .quad ((\cnt - 4) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
503 .quad ((\cnt - 3) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
504 .quad ((\cnt - 2) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
505 .quad ((\cnt - 1) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
506.endif
507.endm
508
509# Page table for pages in the first gigabyte.
510.align 4096
511.global ptl_2_0g
512ptl_2_0g:
513 ptl2gen 512 0
514
515# Page table for pages in the second gigabyte.
516.align 4096
517.global ptl_2_1g
518ptl_2_1g:
519 ptl2gen 512 1
520
521# Page table for pages in the third gigabyte.
522.align 4096
523.global ptl_2_2g
524ptl_2_2g:
525 ptl2gen 512 2
526
527# Page table for pages in the fourth gigabyte.
528.align 4096
529.global ptl_2_3g
530ptl_2_3g:
531 ptl2gen 512 3
532
533.align 4096
534.global ptl_1
535ptl_1:
536 # Identity mapping for [0; 4G)
537 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
538 .quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
539 .quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
540 .quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
541 .fill 506, 8, 0
542 # Mapping of [0; 1G) at -2G
543 .quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
544 .fill 1, 8, 0
545
546.align 4096
547.global ptl_0
548ptl_0:
549 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
550 .fill 255,8,0
551 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
552 .fill 254,8,0
553 .quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
554
555.section K_DATA_START, "aw", @progbits
556
557.global bootstrap_gdtr
558bootstrap_gdtr:
559 .word gdtselector(GDT_ITEMS)
560 .long KA2PA(gdt)
561
562grub_eax:
563 .long 0
564
565grub_ebx:
566 .long 0
567
568extended_cpuid_msg:
569 .asciz "Extended CPUID not supported. System halted."
570long_mode_msg:
571 .asciz "64 bit long mode not supported. System halted."
572noexecute_msg:
573 .asciz "No-execute pages not supported. System halted."
574fx_msg:
575 .asciz "FXSAVE/FXRESTORE instructions not supported. System halted."
576sse2_msg:
577 .asciz "SSE2 instructions not supported. System halted."
Note: See TracBrowser for help on using the repository browser.