1 | #include "asm.h" |
2 | #include "memlayout.h" |
3 | #include "mmu.h" |
4 | |
5 | # Start the first CPU: switch to 32-bit protected mode, jump into C. |
6 | # The BIOS loads this code from the first sector of the hard disk into |
7 | # memory at physical address 0x7c00 and starts executing in real mode |
8 | # with %cs=0 %ip=7c00. |
9 | |
10 | .code16 # Assemble for 16-bit mode |
11 | .globl start |
12 | start: |
13 | cli # BIOS enabled interrupts; disable |
14 | |
15 | # Zero data segment registers DS, ES, and SS. |
16 | xorw %ax,%ax # Set %ax to zero |
17 | movw %ax,%ds # -> Data Segment |
18 | movw %ax,%es # -> Extra Segment |
19 | movw %ax,%ss # -> Stack Segment |
20 | |
21 | # Physical address line A20 is tied to zero so that the first PCs |
22 | # with 2 MB would run software that assumed 1 MB. Undo that. |
23 | seta20.1: |
24 | inb $0x64,%al # Wait for not busy |
25 | testb $0x2,%al |
26 | jnz seta20.1 |
27 | |
28 | movb $0xd1,%al # 0xd1 -> port 0x64 |
29 | outb %al,$0x64 |
30 | |
31 | seta20.2: |
32 | inb $0x64,%al # Wait for not busy |
33 | testb $0x2,%al |
34 | jnz seta20.2 |
35 | |
36 | movb $0xdf,%al # 0xdf -> port 0x60 |
37 | outb %al,$0x60 |
38 | |
39 | # Switch from real to protected mode. Use a bootstrap GDT that makes |
40 | # virtual addresses map directly to physical addresses so that the |
41 | # effective memory map doesn't change during the transition. |
42 | lgdt gdtdesc |
43 | movl %cr0, %eax |
44 | orl $CR0_PE, %eax |
45 | movl %eax, %cr0 |
46 | |
47 | //PAGEBREAK! |
48 | # Complete the transition to 32-bit protected mode by using a long jmp |
49 | # to reload %cs and %eip. The segment descriptors are set up with no |
50 | # translation, so that the mapping is still the identity mapping. |
51 | ljmp $(SEG_KCODE<<3), $start32 |
52 | |
53 | .code32 # Tell assembler to generate 32-bit code now. |
54 | start32: |
55 | # Set up the protected-mode data segment registers |
56 | movw $(SEG_KDATA<<3), %ax # Our data segment selector |
57 | movw %ax, %ds # -> DS: Data Segment |
58 | movw %ax, %es # -> ES: Extra Segment |
59 | movw %ax, %ss # -> SS: Stack Segment |
60 | movw $0, %ax # Zero segments not ready for use |
61 | movw %ax, %fs # -> FS |
62 | movw %ax, %gs # -> GS |
63 | |
64 | # Set up the stack pointer and call into C. |
65 | movl $start, %esp |
66 | call bootmain |
67 | |
68 | # If bootmain returns (it shouldn't), trigger a Bochs |
69 | # breakpoint if running under Bochs, then loop. |
70 | movw $0x8a00, %ax # 0x8a00 -> port 0x8a00 |
71 | movw %ax, %dx |
72 | outw %ax, %dx |
73 | movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a00 |
74 | outw %ax, %dx |
75 | spin: |
76 | jmp spin |
77 | |
78 | # Bootstrap GDT |
79 | .p2align 2 # force 4 byte alignment |
80 | gdt: |
81 | SEG_NULLASM # null seg |
82 | SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg |
83 | SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg |
84 | |
85 | gdtdesc: |
86 | .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1 |
87 | .long gdt # address gdt |
88 | |
89 | |