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

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

resurrect the original PSE page mapping code and use it if PSE is available
(otherwise use the non-PSE variant as a last resort)

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/*
2 * Copyright (c) 2001 Jakub Jermar
3 * Copyright (c) 2005 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <arch/boot/boot.h>
31#include <arch/boot/memmap.h>
32#include <arch/mm/page.h>
33#include <arch/pm.h>
34#include <arch/cpuid.h>
35
36#define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE)
37
38.section K_TEXT_START, "ax"
39
40.code32
41
42.macro pm_error msg
43 movl \msg, %esi
44 jmp pm_error_halt
45.endm
46
47.macro pm_status msg
48#ifdef CONFIG_EGA
49 pushl %esi
50 movl \msg, %esi
51 call pm_early_puts
52 popl %esi
53#endif
54.endm
55
56.macro pm2_status msg
57 pushl \msg
58 call early_puts
59.endm
60
61.align 4
62.global multiboot_image_start
63multiboot_header:
64 .long MULTIBOOT_HEADER_MAGIC
65 .long MULTIBOOT_HEADER_FLAGS
66 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* checksum */
67 .long multiboot_header
68 .long unmapped_ktext_start
69 .long 0
70 .long 0
71 .long multiboot_image_start
72
73multiboot_image_start:
74 cld
75
76 /* Initialize stack pointer */
77 movl $START_STACK, %esp
78
79 /* Initialize Global Descriptor Table register */
80 lgdtl bootstrap_gdtr
81
82 /* Kernel data + stack */
83 movw $GDT_SELECTOR(KDATA_DES), %cx
84 movw %cx, %es
85 movw %cx, %fs
86 movw %cx, %gs
87 movw %cx, %ds
88 movw %cx, %ss
89
90 jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
91 multiboot_meeting_point:
92
93 /* Save GRUB arguments */
94 movl %eax, grub_eax
95 movl %ebx, grub_ebx
96
97 pm_status $status_prot
98
99#include "vesa_prot.inc"
100
101#ifndef PROCESSOR_i486
102
103 pm_status $status_prot2
104
105 movl $(INTEL_CPUID_LEVEL), %eax
106 cpuid
107 cmp $0x0, %eax /* any function > 0? */
108 jbe pse_unsupported
109
110 movl $(INTEL_CPUID_STANDARD), %eax
111 cpuid
112 bt $(INTEL_PSE), %edx
113 jnc pse_unsupported
114
115 /* Map kernel and turn paging on */
116 pm_status $status_pse
117 call map_kernel_pse
118 jmp stack_init
119
120#endif /* PROCESSOR_i486 */
121
122 pse_unsupported:
123
124 /* Map kernel and turn paging on */
125 pm_status $status_non_pse
126 call map_kernel
127
128 stack_init:
129
130 /* Create the first stack frame */
131 pushl $0
132 movl %esp, %ebp
133
134 pm2_status $status_prot3
135
136 /* Call arch_pre_main(grub_eax, grub_ebx) */
137 pushl grub_ebx
138 pushl grub_eax
139 call arch_pre_main
140
141 pm2_status $status_main
142
143 /* Call main_bsp() */
144 call main_bsp
145
146 /* Not reached */
147 cli
148 hlt0:
149 hlt
150 jmp hlt0
151
152/** Setup mapping for the kernel (PSE variant)
153 *
154 * Setup mapping for both the unmapped and mapped sections
155 * of the kernel. For simplicity, we map the entire 4G space.
156 *
157 */
158.global map_kernel_pse
159map_kernel_pse:
160 /* Paging features */
161 movl %cr4, %ecx
162 orl $(1 << 4), %ecx /* PSE on */
163 andl $(~(1 << 5)), %ecx /* PAE off */
164 movl %ecx, %cr4
165
166 movl $(page_directory + 0), %esi
167 movl $(page_directory + 2048), %edi
168 xorl %ecx, %ecx
169 xorl %ebx, %ebx
170
171 floop_pse:
172 movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax
173 orl %ebx, %eax
174 /* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
175 movl %eax, (%esi, %ecx, 4)
176 /* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
177 movl %eax, (%edi, %ecx, 4)
178 addl $(4 * 1024 * 1024), %ebx
179
180 incl %ecx
181 cmpl $512, %ecx
182 jl floop_pse
183
184 movl %esi, %cr3
185
186 movl %cr0, %ebx
187 orl $(1 << 31), %ebx /* paging on */
188 movl %ebx, %cr0
189 ret
190
191/** Setup mapping for the kernel (non-PSE variant).
192 *
193 * Setup mapping for both the unmapped and mapped sections
194 * of the kernel. For simplicity, we map the entire 4G space.
195 *
196 */
197.global map_kernel
198map_kernel:
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.