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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dc41772 was dc41772, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Revert "Remove dead code" - needs more work

This reverts commit 9a791eb9411b32c4c733f382971ad899794149b1.

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