source: mainline/kernel/arch/ia32/src/boot/boot.S@ ad12b5ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ad12b5ea was fb45c7b, checked in by Martin Sucha <sucha14@…>, 14 years ago

Call PSE variant of map_kernel on AP.
This fixes boot on ia32 with SMP enabled.

  • Property mode set to 100644
File size: 13.9 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/boot/memmap.h>
33#include <arch/mm/page.h>
34#include <arch/pm.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 GRUB arguments */
95 movl %eax, grub_eax
96 movl %ebx, grub_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(grub_eax, grub_ebx) */
138 pushl grub_ebx
139 pushl grub_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 */
198map_kernel_non_pse:
199 /* Paging features */
200 movl %cr4, %ecx
201 andl $(~(1 << 5)), %ecx /* PAE off */
202 movl %ecx, %cr4
203
204 call calc_kernel_end
205 call find_mem_for_pt
206
207 mov kernel_end, %esi
208 mov free_area, %ecx
209
210 cmpl %esi, %ecx
211 jbe use_kernel_end
212
213 mov %ecx, %esi
214
215 /* Align address down to 4k */
216 andl $(~4095), %esi
217
218 use_kernel_end:
219
220 /* Align address to 4k */
221 addl $4095, %esi
222 andl $(~4095), %esi
223
224 /* Allocate space for page tables */
225 movl %esi, pt_loc
226 movl $ballocs, %edi
227 andl $0x7fffffff, %edi
228
229 movl %esi, (%edi)
230 addl $4, %edi
231 movl $(2 * 1024 * 1024), (%edi)
232
233 /* Fill page tables */
234 xorl %ecx, %ecx
235 xorl %ebx, %ebx
236
237 floop_pt:
238 movl $((1 << 1) | (1 << 0)), %eax
239 orl %ebx, %eax
240 movl %eax, (%esi, %ecx, 4)
241 addl $(4 * 1024), %ebx
242
243 incl %ecx
244 cmpl $(512 * 1024), %ecx
245
246 jl floop_pt
247
248 /* Fill page directory */
249 movl $(page_directory + 0), %esi
250 movl $(page_directory + 2048), %edi
251 xorl %ecx, %ecx
252 movl pt_loc, %ebx
253
254 floop:
255 movl $((1 << 1) | (1 << 0)), %eax
256 orl %ebx, %eax
257
258 /* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
259 movl %eax, (%esi, %ecx, 4)
260
261 /* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
262 movl %eax, (%edi, %ecx, 4)
263 addl $(4 * 1024), %ebx
264
265 incl %ecx
266 cmpl $512, %ecx
267
268 jl floop
269
270 movl %esi, %cr3
271
272 movl %cr0, %ebx
273 orl $(1 << 31), %ebx /* paging on */
274 movl %ebx, %cr0
275
276 ret
277
278/** Calculate unmapped address of the end of the kernel. */
279calc_kernel_end:
280 movl $hardcoded_load_address, %edi
281 andl $0x7fffffff, %edi
282 movl (%edi), %esi
283 andl $0x7fffffff, %esi
284
285 movl $hardcoded_ktext_size, %edi
286 andl $0x7fffffff, %edi
287 addl (%edi), %esi
288 andl $0x7fffffff, %esi
289
290 movl $hardcoded_kdata_size, %edi
291 andl $0x7fffffff, %edi
292 addl (%edi), %esi
293 andl $0x7fffffff, %esi
294 movl %esi, kernel_end
295
296 ret
297
298/** Find free 2M (+4k for alignment) region where to store page tables */
299find_mem_for_pt:
300 /* Check if multiboot info is present */
301 cmpl $MULTIBOOT_LOADER_MAGIC, grub_eax
302 je check_multiboot_map
303
304 ret
305
306 check_multiboot_map:
307
308 /* Copy address of the multiboot info to ebx */
309 movl grub_ebx, %ebx
310
311 /* Check if memory map flag is present */
312 movl (%ebx), %edx
313 andl $(1 << 6), %edx
314 jnz use_multiboot_map
315
316 ret
317
318 use_multiboot_map:
319
320 /* Copy address of the memory map to edx */
321 movl 48(%ebx), %edx
322 movl %edx, %ecx
323
324 addl 44(%ebx), %ecx
325
326 /* Find a free region at least 2M in size */
327 check_memmap_loop:
328
329 /* Is this a free region? */
330 cmp $1, 20(%edx)
331 jnz next_region
332
333 /* Check size */
334 cmp $0, 16(%edx)
335 jnz next_region
336
337 cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
338 jbe next_region
339
340 cmp $0, 8(%edx)
341 jz found_region
342
343 next_region:
344
345 cmp %ecx, %edx
346 jbe next_region_do
347
348 ret
349
350 next_region_do:
351
352 addl (%edx), %edx
353 addl $4, %edx
354 jmp check_memmap_loop
355
356 found_region:
357
358 /* Use end of the found region */
359 mov 4(%edx), %ecx
360 add 12(%edx), %ecx
361 sub $(2 * 1024 * 1024), %ecx
362 mov %ecx, free_area
363
364 ret
365
366/** Print string to EGA display (in light red) and halt.
367 *
368 * Should be executed from 32 bit protected mode with paging
369 * turned off. Stack is not required. This routine is used even
370 * if CONFIG_EGA is not enabled. Since we are going to halt the
371 * CPU anyway, it is always better to at least try to print
372 * some hints.
373 *
374 * @param %esi NULL-terminated string to print.
375 *
376 */
377pm_error_halt:
378 movl $0xb8000, %edi /* base of EGA text mode memory */
379 xorl %eax, %eax
380
381 /* Read bits 8 - 15 of the cursor address */
382 movw $0x3d4, %dx
383 movb $0xe, %al
384 outb %al, %dx
385
386 movw $0x3d5, %dx
387 inb %dx, %al
388 shl $8, %ax
389
390 /* Read bits 0 - 7 of the cursor address */
391 movw $0x3d4, %dx
392 movb $0xf, %al
393 outb %al, %dx
394
395 movw $0x3d5, %dx
396 inb %dx, %al
397
398 /* Sanity check for the cursor on screen */
399 cmp $2000, %ax
400 jb err_cursor_ok
401
402 movw $1998, %ax
403
404 err_cursor_ok:
405
406 movw %ax, %bx
407 shl $1, %eax
408 addl %eax, %edi
409
410 err_ploop:
411 lodsb
412
413 cmp $0, %al
414 je err_ploop_end
415
416 movb $0x0c, %ah /* black background, light red foreground */
417 stosw
418
419 /* Sanity check for the cursor on the last line */
420 inc %bx
421 cmp $2000, %bx
422 jb err_ploop
423
424 /* Scroll the screen (24 rows) */
425 movl %esi, %edx
426 movl $0xb80a0, %esi
427 movl $0xb8000, %edi
428 movl $960, %ecx
429 rep movsl
430
431 /* Clear the 24th row */
432 xorl %eax, %eax
433 movl $40, %ecx
434 rep stosl
435
436 /* Go to row 24 */
437 movl %edx, %esi
438 movl $0xb8f00, %edi
439 movw $1920, %bx
440
441 jmp err_ploop
442 err_ploop_end:
443
444 /* Write bits 8 - 15 of the cursor address */
445 movw $0x3d4, %dx
446 movb $0xe, %al
447 outb %al, %dx
448
449 movw $0x3d5, %dx
450 movb %bh, %al
451 outb %al, %dx
452
453 /* Write bits 0 - 7 of the cursor address */
454 movw $0x3d4, %dx
455 movb $0xf, %al
456 outb %al, %dx
457
458 movw $0x3d5, %dx
459 movb %bl, %al
460 outb %al, %dx
461
462 cli
463 hlt1:
464 hlt
465 jmp hlt1
466
467/** Print string to EGA display (in light green).
468 *
469 * Should be called from 32 bit protected mode with paging
470 * turned off. A stack space of at least 24 bytes is required,
471 * but the function does not establish a stack frame.
472 *
473 * Macros such as pm_status take care that this function
474 * is used only when CONFIG_EGA is enabled.
475 *
476 * @param %esi NULL-terminated string to print.
477 *
478 */
479pm_early_puts:
480 pushl %eax
481 pushl %ebx
482 pushl %ecx
483 pushl %edx
484 pushl %edi
485
486 movl $0xb8000, %edi /* base of EGA text mode memory */
487 xorl %eax, %eax
488
489 /* Read bits 8 - 15 of the cursor address */
490 movw $0x3d4, %dx
491 movb $0xe, %al
492 outb %al, %dx
493
494 movw $0x3d5, %dx
495 inb %dx, %al
496 shl $8, %ax
497
498 /* Read bits 0 - 7 of the cursor address */
499 movw $0x3d4, %dx
500 movb $0xf, %al
501 outb %al, %dx
502
503 movw $0x3d5, %dx
504 inb %dx, %al
505
506 /* Sanity check for the cursor on screen */
507 cmp $2000, %ax
508 jb pm_puts_cursor_ok
509
510 movw $1998, %ax
511
512 pm_puts_cursor_ok:
513
514 movw %ax, %bx
515 shl $1, %eax
516 addl %eax, %edi
517
518 pm_puts_ploop:
519 lodsb
520
521 cmp $0, %al
522 je pm_puts_ploop_end
523
524 movb $0x0a, %ah /* black background, light green foreground */
525 stosw
526
527 /* Sanity check for the cursor on the last line */
528 inc %bx
529 cmp $2000, %bx
530 jb pm_puts_ploop
531
532 /* Scroll the screen (24 rows) */
533 movl %esi, %edx
534 movl $0xb80a0, %esi
535 movl $0xb8000, %edi
536 movl $960, %ecx
537 rep movsl
538
539 /* Clear the 24th row */
540 xorl %eax, %eax
541 movl $40, %ecx
542 rep stosl
543
544 /* Go to row 24 */
545 movl %edx, %esi
546 movl $0xb8f00, %edi
547 movw $1920, %bx
548
549 jmp pm_puts_ploop
550 pm_puts_ploop_end:
551
552 /* Write bits 8 - 15 of the cursor address */
553 movw $0x3d4, %dx
554 movb $0xe, %al
555 outb %al, %dx
556
557 movw $0x3d5, %dx
558 movb %bh, %al
559 outb %al, %dx
560
561 /* Write bits 0 - 7 of the cursor address */
562 movw $0x3d4, %dx
563 movb $0xf, %al
564 outb %al, %dx
565
566 movw $0x3d5, %dx
567 movb %bl, %al
568 outb %al, %dx
569
570 popl %edi
571 popl %edx
572 popl %ecx
573 popl %ebx
574 popl %eax
575
576 ret
577
578/** Print string to EGA display.
579 *
580 * Should be called from 32 bit protected mode (with paging
581 * enabled and stack established). This function is ABI compliant.
582 *
583 * If CONFIG_EGA is undefined or CONFIG_FB is defined
584 * then this function does nothing.
585 *
586 * @param %ebp+0x08 NULL-terminated string to print.
587 *
588 */
589early_puts:
590
591#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
592
593 /* Prologue, save preserved registers */
594 pushl %ebp
595 movl %esp, %ebp
596 pushl %ebx
597 pushl %esi
598 pushl %edi
599
600 movl 0x08(%ebp), %esi
601 movl $(PA2KA(0xb8000)), %edi /* base of EGA text mode memory */
602 xorl %eax, %eax
603
604 /* Read bits 8 - 15 of the cursor address */
605 movw $0x3d4, %dx
606 movb $0xe, %al
607 outb %al, %dx
608
609 movw $0x3d5, %dx
610 inb %dx, %al
611 shl $8, %ax
612
613 /* Read bits 0 - 7 of the cursor address */
614 movw $0x3d4, %dx
615 movb $0xf, %al
616 outb %al, %dx
617
618 movw $0x3d5, %dx
619 inb %dx, %al
620
621 /* Sanity check for the cursor on screen */
622 cmp $2000, %ax
623 jb early_puts_cursor_ok
624
625 movw $1998, %ax
626
627 early_puts_cursor_ok:
628
629 movw %ax, %bx
630 shl $1, %eax
631 addl %eax, %edi
632
633 early_puts_ploop:
634 lodsb
635
636 cmp $0, %al
637 je early_puts_ploop_end
638
639 movb $0x0e, %ah /* black background, yellow foreground */
640 stosw
641
642 /* Sanity check for the cursor on the last line */
643 inc %bx
644 cmp $2000, %bx
645 jb early_puts_ploop
646
647 /* Scroll the screen (24 rows) */
648 movl %esi, %edx
649 movl $(PA2KA(0xb80a0)), %esi
650 movl $(PA2KA(0xb8000)), %edi
651 movl $960, %ecx
652 rep movsl
653
654 /* Clear the 24th row */
655 xorl %eax, %eax
656 movl $40, %ecx
657 rep stosl
658
659 /* Go to row 24 */
660 movl %edx, %esi
661 movl $(PA2KA(0xb8f00)), %edi
662 movw $1920, %bx
663
664 jmp early_puts_ploop
665 early_puts_ploop_end:
666
667 /* Write bits 8 - 15 of the cursor address */
668 movw $0x3d4, %dx
669 movb $0xe, %al
670 outb %al, %dx
671
672 movw $0x3d5, %dx
673 movb %bh, %al
674 outb %al, %dx
675
676 /* Write bits 0 - 7 of the cursor address */
677 movw $0x3d4, %dx
678 movb $0xf, %al
679 outb %al, %dx
680
681 movw $0x3d5, %dx
682 movb %bl, %al
683 outb %al, %dx
684
685 /* Epilogue, restore preserved registers */
686 popl %edi
687 popl %esi
688 popl %ebx
689 leave
690
691#endif
692
693 ret
694
695#include "vesa_real.inc"
696
697.section K_DATA_START, "aw", @progbits
698
699.align 4096
700page_directory:
701 .space 4096, 0
702
703bootstrap_gdtr:
704 .word GDT_SELECTOR(GDT_ITEMS)
705 .long KA2PA(gdt)
706
707grub_eax:
708 .long 0
709grub_ebx:
710 .long 0
711
712pt_loc:
713 .long 0
714kernel_end:
715 .long 0
716free_area:
717 .long 0
718
719status_prot:
720 .asciz "[prot] "
721status_pse:
722 .asciz "[pse] "
723status_non_pse:
724 .asciz "[non_pse] "
725status_vesa_copy:
726 .asciz "[vesa_copy] "
727status_grub_cmdline:
728 .asciz "[grub_cmdline] "
729status_vesa_real:
730 .asciz "[vesa_real] "
731status_prot2:
732 .asciz "[prot2] "
733status_prot3:
734 .asciz "[prot3] "
735status_main:
736 .asciz "[main] "
Note: See TracBrowser for help on using the repository browser.