x86: Fixes bug in pml callbacks
[akaros.git] / kern / arch / x86 / boot / boot.S
1 #include <arch/mmu.h>
2         
3 .set PROT_MODE_CSEG,0x8         # code segment selector
4 .set PROT_MODE_DSEG,0x10        # data segment selector
5 .set CR0_PE_ON,0x1              # protected mode enable flag
6         
7 ###############################################################################
8 # ENTRY POINT   
9 #   This code should be stored in the first sector of the hard disk.
10 #   After the BIOS initializes the hardware on startup or system reset,
11 #   it loads this code at physical address 0x7c00 - 0x7d00 (512 bytes).
12 #   Then the BIOS jumps to the beginning of it, address 0x7c00,
13 #   while running in 16-bit real-mode (8086 compatibility mode).
14 #   The Code Segment register (CS) is initially zero on entry.
15 #       
16 # This code switches into 32-bit protected mode so that all of
17 # memory can accessed, then calls into C.
18 ###############################################################################
19         
20 .globl start                                    # Entry point   
21 start:          .code16                         # This runs in real mode
22                 cli                             # Disable interrupts
23                 cld                             # String operations increment
24
25                 # Set up the important data segment registers (DS, ES, SS).
26                 xorw    %ax,%ax                 # Segment number zero
27                 movw    %ax,%ds                 # -> Data Segment
28                 movw    %ax,%es                 # -> Extra Segment
29                 movw    %ax,%ss                 # -> Stack Segment
30
31                 # Set up the stack pointer, growing downward from 0x7c00.
32                 movw    $start,%sp              # Stack Pointer
33         
34 # Enable A20:
35 #   For fascinating historical reasons (related to the fact that
36 #   the earliest 8086-based PCs could only address 1MB of physical memory
37 #   and subsequent 80286-based PCs wanted to retain maximum compatibility),
38 #   physical address line 20 is tied to low when the machine boots.
39 #   Obviously this a bit of a drag for us, especially when trying to
40 #   address memory above 1MB.  This code undoes this.
41         
42 seta20.1:       inb     $0x64,%al               # Get status
43                 testb   $0x2,%al                # Busy?
44                 jnz     seta20.1                # Yes
45                 movb    $0xd1,%al               # Command: Write
46                 outb    %al,$0x64               #  output port
47 seta20.2:       inb     $0x64,%al               # Get status
48                 testb   $0x2,%al                # Busy?
49                 jnz     seta20.2                # Yes
50                 movb    $0xdf,%al               # Enable
51                 outb    %al,$0x60               #  A20
52
53 # Switch from real to protected mode:
54 #   Up until now, there's been no protection, so we've gotten along perfectly
55 #   well without explicitly telling the processor how to translate addresses.
56 #   When we switch to protected mode, this is no longer true!
57 #   We need at least to set up some "segments" that tell the processor it's
58 #   OK to run code at any address, or write to any address.
59 #   The 'gdt' and 'gdtdesc' tables below define these segments.
60 #   This code loads them into the processor.
61 #   We need this setup to ensure the transition to protected mode is smooth.
62
63 real_to_prot:   cli                     # Don't allow interrupts: mandatory,
64                                         # since we didn't set up an interrupt
65                                         # descriptor table for handling them
66                 lgdt    gdtdesc         # load GDT: mandatory in protected mode
67                 movl    %cr0, %eax      # Turn on protected mode
68                 orl     $CR0_PE_ON, %eax
69                 movl    %eax, %cr0
70
71                 # CPU magic: jump to relocation, flush prefetch queue, and
72                 # reload %cs.  Has the effect of just jmp to the next
73                 # instruction, but simultaneously loads CS with
74                 # $PROT_MODE_CSEG.
75                 ljmp    $PROT_MODE_CSEG, $protcseg
76         
77                 # we've switched to 32-bit protected mode; tell the assembler
78                 # to generate code for that mode
79 protcseg:       .code32
80                 # Set up the protected-mode data segment registers
81                 movw    $PROT_MODE_DSEG, %ax    # Our data segment selector
82                 movw    %ax, %ds                # -> DS: Data Segment
83                 movw    %ax, %es                # -> ES: Extra Segment
84                 movw    %ax, %fs                # -> FS
85                 movw    %ax, %gs                # -> GS
86                 movw    %ax, %ss                # -> SS: Stack Segment
87         
88                 call cmain                      # finish the boot load from C.
89                                                 # cmain() should not return
90 spin:           jmp spin                        # ..but in case it does, spin
91         
92                 .p2align 2                      # force 4 byte alignment
93 gdt:            SEG_NULL                                # null seg
94                 SEG(STA_X|STA_R, 0x0, 0xffffffff)       # code seg
95                 SEG(STA_W, 0x0, 0xffffffff)             # data seg
96         
97 gdtdesc:        .word   0x17                    # sizeof(gdt) - 1
98                 .long   gdt                     # address gdt