source: mainline/kernel/arch/ia32/src/boot/multiboot.S@ 306f0de

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 306f0de was 1f5c9c96, checked in by Martin Decky <martin@…>, 14 years ago

implement multiboot v2 specification and use it in GRUB for UEFI

  • improve multiboot v1 code, move defines to a common location
  • rename VESA framebuffer stuff to generic "boot framebuffer"
  • small collateral changes
  • Property mode set to 100644
File size: 14.0 KB
Line 
1/*
2 * Copyright (c) 2001 Jakub Jermar
3 * Copyright (c) 2005 Martin Decky
4 * Copyright (c) 2011 Martin Sucha
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/mm/page.h>
33#include <arch/pm.h>
34#include <genarch/multiboot/multiboot.h>
35#include <arch/cpuid.h>
36
37#define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE)
38
39.section K_TEXT_START, "ax"
40
41.code32
42
43.macro pm_error msg
44 movl \msg, %esi
45 jmp pm_error_halt
46.endm
47
48.macro pm_status msg
49#ifdef CONFIG_EGA
50 pushl %esi
51 movl \msg, %esi
52 call pm_early_puts
53 popl %esi
54#endif
55.endm
56
57.macro pm2_status msg
58 pushl \msg
59 call early_puts
60.endm
61
62.align 4
63.global multiboot_image_start
64multiboot_header:
65 .long MULTIBOOT_HEADER_MAGIC
66 .long MULTIBOOT_HEADER_FLAGS
67 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* checksum */
68 .long multiboot_header
69 .long unmapped_ktext_start
70 .long 0
71 .long 0
72 .long multiboot_image_start
73
74multiboot_image_start:
75 cld
76
77 /* Initialize stack pointer */
78 movl $START_STACK, %esp
79
80 /* Initialize Global Descriptor Table register */
81 lgdtl bootstrap_gdtr
82
83 /* Kernel data + stack */
84 movw $GDT_SELECTOR(KDATA_DES), %cx
85 movw %cx, %es
86 movw %cx, %fs
87 movw %cx, %gs
88 movw %cx, %ds
89 movw %cx, %ss
90
91 jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
92 multiboot_meeting_point:
93
94 /* Save multiboot arguments */
95 movl %eax, multiboot_eax
96 movl %ebx, multiboot_ebx
97
98 pm_status $status_prot
99
100#include "vesa_prot.inc"
101
102#ifndef PROCESSOR_i486
103
104 pm_status $status_prot2
105
106 movl $(INTEL_CPUID_LEVEL), %eax
107 cpuid
108 cmp $0x0, %eax /* any function > 0? */
109 jbe pse_unsupported
110
111 movl $(INTEL_CPUID_STANDARD), %eax
112 cpuid
113 bt $(INTEL_PSE), %edx
114 jnc pse_unsupported
115
116 /* Map kernel and turn paging on */
117 pm_status $status_pse
118 call map_kernel_pse
119 jmp stack_init
120
121#endif /* PROCESSOR_i486 */
122
123 pse_unsupported:
124
125 /* Map kernel and turn paging on */
126 pm_status $status_non_pse
127 call map_kernel_non_pse
128
129 stack_init:
130
131 /* Create the first stack frame */
132 pushl $0
133 movl %esp, %ebp
134
135 pm2_status $status_prot3
136
137 /* Call arch_pre_main(multiboot_eax, multiboot_ebx) */
138 pushl multiboot_ebx
139 pushl multiboot_eax
140 call arch_pre_main
141
142 pm2_status $status_main
143
144 /* Call main_bsp() */
145 call main_bsp
146
147 /* Not reached */
148 cli
149 hlt0:
150 hlt
151 jmp hlt0
152
153/** Setup mapping for the kernel (PSE variant)
154 *
155 * Setup mapping for both the unmapped and mapped sections
156 * of the kernel. For simplicity, we map the entire 4G space.
157 *
158 */
159.global map_kernel_pse
160map_kernel_pse:
161 /* Paging features */
162 movl %cr4, %ecx
163 orl $(1 << 4), %ecx /* PSE on */
164 andl $(~(1 << 5)), %ecx /* PAE off */
165 movl %ecx, %cr4
166
167 movl $(page_directory + 0), %esi
168 movl $(page_directory + 2048), %edi
169 xorl %ecx, %ecx
170 xorl %ebx, %ebx
171
172 floop_pse:
173 movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax
174 orl %ebx, %eax
175 /* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
176 movl %eax, (%esi, %ecx, 4)
177 /* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
178 movl %eax, (%edi, %ecx, 4)
179 addl $(4 * 1024 * 1024), %ebx
180
181 incl %ecx
182 cmpl $512, %ecx
183 jl floop_pse
184
185 movl %esi, %cr3
186
187 movl %cr0, %ebx
188 orl $(1 << 31), %ebx /* paging on */
189 movl %ebx, %cr0
190 ret
191
192/** Setup mapping for the kernel (non-PSE variant).
193 *
194 * Setup mapping for both the unmapped and mapped sections
195 * of the kernel. For simplicity, we map the entire 4G space.
196 *
197 */
198.global map_kernel_non_pse
199map_kernel_non_pse:
200 /* Paging features */
201 movl %cr4, %ecx
202 andl $(~(1 << 5)), %ecx /* PAE off */
203 movl %ecx, %cr4
204
205 call calc_kernel_end
206 call find_mem_for_pt
207
208 mov kernel_end, %esi
209 mov free_area, %ecx
210
211 cmpl %esi, %ecx
212 jbe use_kernel_end
213
214 mov %ecx, %esi
215
216 /* Align address down to 4k */
217 andl $(~4095), %esi
218
219 use_kernel_end:
220
221 /* Align address to 4k */
222 addl $4095, %esi
223 andl $(~4095), %esi
224
225 /* Allocate space for page tables */
226 movl %esi, pt_loc
227 movl $ballocs, %edi
228 andl $0x7fffffff, %edi
229
230 movl %esi, (%edi)
231 addl $4, %edi
232 movl $(2 * 1024 * 1024), (%edi)
233
234 /* Fill page tables */
235 xorl %ecx, %ecx
236 xorl %ebx, %ebx
237
238 floop_pt:
239 movl $((1 << 1) | (1 << 0)), %eax
240 orl %ebx, %eax
241 movl %eax, (%esi, %ecx, 4)
242 addl $(4 * 1024), %ebx
243
244 incl %ecx
245 cmpl $(512 * 1024), %ecx
246
247 jl floop_pt
248
249 /* Fill page directory */
250 movl $(page_directory + 0), %esi
251 movl $(page_directory + 2048), %edi
252 xorl %ecx, %ecx
253 movl pt_loc, %ebx
254
255 floop:
256 movl $((1 << 1) | (1 << 0)), %eax
257 orl %ebx, %eax
258
259 /* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
260 movl %eax, (%esi, %ecx, 4)
261
262 /* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
263 movl %eax, (%edi, %ecx, 4)
264 addl $(4 * 1024), %ebx
265
266 incl %ecx
267 cmpl $512, %ecx
268
269 jl floop
270
271 movl %esi, %cr3
272
273 movl %cr0, %ebx
274 orl $(1 << 31), %ebx /* paging on */
275 movl %ebx, %cr0
276
277 ret
278
279/** Calculate unmapped address of the end of the kernel. */
280calc_kernel_end:
281 movl $hardcoded_load_address, %edi
282 andl $0x7fffffff, %edi
283 movl (%edi), %esi
284 andl $0x7fffffff, %esi
285
286 movl $hardcoded_ktext_size, %edi
287 andl $0x7fffffff, %edi
288 addl (%edi), %esi
289 andl $0x7fffffff, %esi
290
291 movl $hardcoded_kdata_size, %edi
292 andl $0x7fffffff, %edi
293 addl (%edi), %esi
294 andl $0x7fffffff, %esi
295 movl %esi, kernel_end
296
297 ret
298
299/** Find free 2M (+4k for alignment) region where to store page tables */
300find_mem_for_pt:
301 /* Check if multiboot info is present */
302 cmpl $MULTIBOOT_LOADER_MAGIC, multiboot_eax
303 je check_multiboot_map
304
305 ret
306
307 check_multiboot_map:
308
309 /* Copy address of the multiboot info to ebx */
310 movl multiboot_ebx, %ebx
311
312 /* Check if memory map flag is present */
313 movl (%ebx), %edx
314 andl $(1 << 6), %edx
315 jnz use_multiboot_map
316
317 ret
318
319 use_multiboot_map:
320
321 /* Copy address of the memory map to edx */
322 movl 48(%ebx), %edx
323 movl %edx, %ecx
324
325 addl 44(%ebx), %ecx
326
327 /* Find a free region at least 2M in size */
328 check_memmap_loop:
329
330 /* Is this a free region? */
331 cmp $1, 20(%edx)
332 jnz next_region
333
334 /* Check size */
335 cmp $0, 16(%edx)
336 jnz next_region
337
338 cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
339 jbe next_region
340
341 cmp $0, 8(%edx)
342 jz found_region
343
344 next_region:
345
346 cmp %ecx, %edx
347 jbe next_region_do
348
349 ret
350
351 next_region_do:
352
353 addl (%edx), %edx
354 addl $4, %edx
355 jmp check_memmap_loop
356
357 found_region:
358
359 /* Use end of the found region */
360 mov 4(%edx), %ecx
361 add 12(%edx), %ecx
362 sub $(2 * 1024 * 1024), %ecx
363 mov %ecx, free_area
364
365 ret
366
367/** Print string to EGA display (in light red) and halt.
368 *
369 * Should be executed from 32 bit protected mode with paging
370 * turned off. Stack is not required. This routine is used even
371 * if CONFIG_EGA is not enabled. Since we are going to halt the
372 * CPU anyway, it is always better to at least try to print
373 * some hints.
374 *
375 * @param %esi NULL-terminated string to print.
376 *
377 */
378pm_error_halt:
379 movl $0xb8000, %edi /* base of EGA text mode memory */
380 xorl %eax, %eax
381
382 /* Read bits 8 - 15 of the cursor address */
383 movw $0x3d4, %dx
384 movb $0xe, %al
385 outb %al, %dx
386
387 movw $0x3d5, %dx
388 inb %dx, %al
389 shl $8, %ax
390
391 /* Read bits 0 - 7 of the cursor address */
392 movw $0x3d4, %dx
393 movb $0xf, %al
394 outb %al, %dx
395
396 movw $0x3d5, %dx
397 inb %dx, %al
398
399 /* Sanity check for the cursor on screen */
400 cmp $2000, %ax
401 jb err_cursor_ok
402
403 movw $1998, %ax
404
405 err_cursor_ok:
406
407 movw %ax, %bx
408 shl $1, %eax
409 addl %eax, %edi
410
411 err_ploop:
412 lodsb
413
414 cmp $0, %al
415 je err_ploop_end
416
417 movb $0x0c, %ah /* black background, light red foreground */
418 stosw
419
420 /* Sanity check for the cursor on the last line */
421 inc %bx
422 cmp $2000, %bx
423 jb err_ploop
424
425 /* Scroll the screen (24 rows) */
426 movl %esi, %edx
427 movl $0xb80a0, %esi
428 movl $0xb8000, %edi
429 movl $960, %ecx
430 rep movsl
431
432 /* Clear the 24th row */
433 xorl %eax, %eax
434 movl $40, %ecx
435 rep stosl
436
437 /* Go to row 24 */
438 movl %edx, %esi
439 movl $0xb8f00, %edi
440 movw $1920, %bx
441
442 jmp err_ploop
443 err_ploop_end:
444
445 /* Write bits 8 - 15 of the cursor address */
446 movw $0x3d4, %dx
447 movb $0xe, %al
448 outb %al, %dx
449
450 movw $0x3d5, %dx
451 movb %bh, %al
452 outb %al, %dx
453
454 /* Write bits 0 - 7 of the cursor address */
455 movw $0x3d4, %dx
456 movb $0xf, %al
457 outb %al, %dx
458
459 movw $0x3d5, %dx
460 movb %bl, %al
461 outb %al, %dx
462
463 cli
464 hlt1:
465 hlt
466 jmp hlt1
467
468/** Print string to EGA display (in light green).
469 *
470 * Should be called from 32 bit protected mode with paging
471 * turned off. A stack space of at least 24 bytes is required,
472 * but the function does not establish a stack frame.
473 *
474 * Macros such as pm_status take care that this function
475 * is used only when CONFIG_EGA is enabled.
476 *
477 * @param %esi NULL-terminated string to print.
478 *
479 */
480pm_early_puts:
481 pushl %eax
482 pushl %ebx
483 pushl %ecx
484 pushl %edx
485 pushl %edi
486
487 movl $0xb8000, %edi /* base of EGA text mode memory */
488 xorl %eax, %eax
489
490 /* Read bits 8 - 15 of the cursor address */
491 movw $0x3d4, %dx
492 movb $0xe, %al
493 outb %al, %dx
494
495 movw $0x3d5, %dx
496 inb %dx, %al
497 shl $8, %ax
498
499 /* Read bits 0 - 7 of the cursor address */
500 movw $0x3d4, %dx
501 movb $0xf, %al
502 outb %al, %dx
503
504 movw $0x3d5, %dx
505 inb %dx, %al
506
507 /* Sanity check for the cursor on screen */
508 cmp $2000, %ax
509 jb pm_puts_cursor_ok
510
511 movw $1998, %ax
512
513 pm_puts_cursor_ok:
514
515 movw %ax, %bx
516 shl $1, %eax
517 addl %eax, %edi
518
519 pm_puts_ploop:
520 lodsb
521
522 cmp $0, %al
523 je pm_puts_ploop_end
524
525 movb $0x0a, %ah /* black background, light green foreground */
526 stosw
527
528 /* Sanity check for the cursor on the last line */
529 inc %bx
530 cmp $2000, %bx
531 jb pm_puts_ploop
532
533 /* Scroll the screen (24 rows) */
534 movl %esi, %edx
535 movl $0xb80a0, %esi
536 movl $0xb8000, %edi
537 movl $960, %ecx
538 rep movsl
539
540 /* Clear the 24th row */
541 xorl %eax, %eax
542 movl $40, %ecx
543 rep stosl
544
545 /* Go to row 24 */
546 movl %edx, %esi
547 movl $0xb8f00, %edi
548 movw $1920, %bx
549
550 jmp pm_puts_ploop
551 pm_puts_ploop_end:
552
553 /* Write bits 8 - 15 of the cursor address */
554 movw $0x3d4, %dx
555 movb $0xe, %al
556 outb %al, %dx
557
558 movw $0x3d5, %dx
559 movb %bh, %al
560 outb %al, %dx
561
562 /* Write bits 0 - 7 of the cursor address */
563 movw $0x3d4, %dx
564 movb $0xf, %al
565 outb %al, %dx
566
567 movw $0x3d5, %dx
568 movb %bl, %al
569 outb %al, %dx
570
571 popl %edi
572 popl %edx
573 popl %ecx
574 popl %ebx
575 popl %eax
576
577 ret
578
579/** Print string to EGA display.
580 *
581 * Should be called from 32 bit protected mode (with paging
582 * enabled and stack established). This function is ABI compliant.
583 *
584 * If CONFIG_EGA is undefined or CONFIG_FB is defined
585 * then this function does nothing.
586 *
587 * @param %ebp+0x08 NULL-terminated string to print.
588 *
589 */
590early_puts:
591
592#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
593
594 /* Prologue, save preserved registers */
595 pushl %ebp
596 movl %esp, %ebp
597 pushl %ebx
598 pushl %esi
599 pushl %edi
600
601 movl 0x08(%ebp), %esi
602 movl $(PA2KA(0xb8000)), %edi /* base of EGA text mode memory */
603 xorl %eax, %eax
604
605 /* Read bits 8 - 15 of the cursor address */
606 movw $0x3d4, %dx
607 movb $0xe, %al
608 outb %al, %dx
609
610 movw $0x3d5, %dx
611 inb %dx, %al
612 shl $8, %ax
613
614 /* Read bits 0 - 7 of the cursor address */
615 movw $0x3d4, %dx
616 movb $0xf, %al
617 outb %al, %dx
618
619 movw $0x3d5, %dx
620 inb %dx, %al
621
622 /* Sanity check for the cursor on screen */
623 cmp $2000, %ax
624 jb early_puts_cursor_ok
625
626 movw $1998, %ax
627
628 early_puts_cursor_ok:
629
630 movw %ax, %bx
631 shl $1, %eax
632 addl %eax, %edi
633
634 early_puts_ploop:
635 lodsb
636
637 cmp $0, %al
638 je early_puts_ploop_end
639
640 movb $0x0e, %ah /* black background, yellow foreground */
641 stosw
642
643 /* Sanity check for the cursor on the last line */
644 inc %bx
645 cmp $2000, %bx
646 jb early_puts_ploop
647
648 /* Scroll the screen (24 rows) */
649 movl %esi, %edx
650 movl $(PA2KA(0xb80a0)), %esi
651 movl $(PA2KA(0xb8000)), %edi
652 movl $960, %ecx
653 rep movsl
654
655 /* Clear the 24th row */
656 xorl %eax, %eax
657 movl $40, %ecx
658 rep stosl
659
660 /* Go to row 24 */
661 movl %edx, %esi
662 movl $(PA2KA(0xb8f00)), %edi
663 movw $1920, %bx
664
665 jmp early_puts_ploop
666 early_puts_ploop_end:
667
668 /* Write bits 8 - 15 of the cursor address */
669 movw $0x3d4, %dx
670 movb $0xe, %al
671 outb %al, %dx
672
673 movw $0x3d5, %dx
674 movb %bh, %al
675 outb %al, %dx
676
677 /* Write bits 0 - 7 of the cursor address */
678 movw $0x3d4, %dx
679 movb $0xf, %al
680 outb %al, %dx
681
682 movw $0x3d5, %dx
683 movb %bl, %al
684 outb %al, %dx
685
686 /* Epilogue, restore preserved registers */
687 popl %edi
688 popl %esi
689 popl %ebx
690 leave
691
692#endif
693
694 ret
695
696#include "vesa_real.inc"
697
698.section K_DATA_START, "aw", @progbits
699
700.align 4096
701page_directory:
702 .space 4096, 0
703
704.global bootstrap_gdtr
705bootstrap_gdtr:
706 .word GDT_SELECTOR(GDT_ITEMS)
707 .long KA2PA(gdt)
708
709.global multiboot_eax
710multiboot_eax:
711 .long 0
712
713.global multiboot_ebx
714multiboot_ebx:
715 .long 0
716
717pt_loc:
718 .long 0
719kernel_end:
720 .long 0
721free_area:
722 .long 0
723
724status_prot:
725 .asciz "[prot] "
726status_pse:
727 .asciz "[pse] "
728status_non_pse:
729 .asciz "[non_pse] "
730status_vesa_copy:
731 .asciz "[vesa_copy] "
732status_multiboot_cmdline:
733 .asciz "[multiboot_cmdline] "
734status_vesa_real:
735 .asciz "[vesa_real] "
736status_prot2:
737 .asciz "[prot2] "
738status_prot3:
739 .asciz "[prot3] "
740status_main:
741 .asciz "[main] "
Note: See TracBrowser for help on using the repository browser.