Initial revision
[pintos-anon] / src / threads / loader.S
1 #include "mmu.h"
2         
3 ###################################################################################
4 # ENTRY POINT   
5 #   This code should be stored in the first sector of the hard disk.  When the  
6 #   BIOS runs, it loads this code at physical address 0x7c00 - 0x7e00 (512 bytes).
7 #   Then jumps to the beginning of it, in real-mode (BIOS runs in real mode).  
8 #       
9 # This code switches into protected mode (32-bit mode) so that all of
10 # memory can accessed, then calls into C.
11 ###################################################################################
12         
13 .globl start                            # Entry point   
14 start:  .code16                         # This runs in real mode
15         cli                             # Disable interrupts
16         cld                             # String ops inc
17         xorw %ax,%ax                    # Zero
18         movw %ax,%es                    # Address
19         movw %ax,%ds                    #  data
20         movw %ax,%ss                    # Set up
21         movw $start,%sp                 #  stack (grows down)
22         
23 #### Enable A20:
24 ####   Address line 20 is tied to low when the machine boots, 
25 ####   obviously this a bit of a drag, such as when trying to
26 ####   address memory above 1MB.  This code undoes this.
27         
28 1:      inb $0x64,%al           # Get status
29         testb $0x2,%al          # Busy?
30         jnz 1b                  # Yes
31         movb $0xd1,%al          # Command: Write
32         outb %al,$0x64          #  output port
33 2:      inb $0x64,%al           # Get status
34         testb $0x2,%al          # Busy?
35         jnz 2b                  # Yes
36         movb $0xdf,%al          # Enable
37         outb %al,$0x60          #  A20
38
39 #### Get memory size, via interrupt 15h function 88h.
40 #### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
41 #### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
42         
43         movb    $0x88,%ah
44         int     $0x15
45         jc      panic                   # Carry flag set on error
46         addl    $1024,%eax              # Total kB
47         shrl    $2,%eax                 # Total 4 kB pages
48         movl    %eax, ram_pages
49         
50 #### switch from real to protected mode 
51 ####     The segments in GDT allow all of physical memory to be accessed.
52 ####     Furthermore, the segments have base addresses of 0, so that the
53 ####     segment translation is a NOP, ie. virtual addresses are identical to
54 ####     their physical addresses.  With this setup, it appears to this code
55 ####     that it is running directly on physical memory.
56         
57         cli                     # Mandatory since we dont set up an IDT
58         lgdt gdtdesc            # load GDT -- mandatory in protected mode
59         movl %cr0, %eax         # turn on protected mode
60         orl $CR0_PE, %eax       # 
61         movl %eax, %cr0         # 
62         ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs
63         ### Has the effect of just jmp to the next instruction, but simultaneous
64         ### loads CS with $PROT_MODE_CSEG.
65         ljmp $SEL_KCSEG, $protcseg
66         
67 #### We are in protected mode in a 32-bit segment (hence the .code32)
68 protcseg:
69         .code32
70         movw $SEL_KDSEG, %ax    # set up data segment registers
71         movw %ax, %ds           
72         movw %ax, %es           
73         movw %ax, %fs           
74         movw %ax, %gs           
75         movw %ax, %ss
76
77 #### Load kernel at 1 MB by frobbing the IDE controller directly.
78
79         movl $1, %ebx
80         movl $0x100000, %edi
81 read_sector:            
82         movl $0x1f7, %edx
83 1:      inb %dx, %al
84         testb $0x80, %al
85         jnz 1b
86         
87         movl $0x1f2, %edx
88         movb $1, %al
89         outb %al, %dx
90
91         movl %ebx, %eax
92         andl $0x0fffffff, %eax
93         orl $0xe0000000, %eax
94
95         movl $4, %ecx
96 2:      incl %edx
97         outb %al, %dx
98         shrl $8, %eax
99         loop 2b
100
101         incw %dx
102         movb $0x20, %al
103         outb %al, %dx
104         
105 1:      inb %dx, %al
106         testb $0x80, %al
107         jnz 1b
108
109         movl $512 / 4, %ecx
110         movl $0x1f0, %edx
111         rep insl
112
113         incl %ebx
114         cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
115         jnz read_sector
116
117 ##### Create temporary PDE and PTE and set page directory pointer
118 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
119
120         movl $0x10000, %edi
121         movl %edi, %cr3
122         subl %eax, %eax
123         movl $0x400, %ecx
124         rep stosl
125         movl $0x11000 | PG_U | PG_W | PG_P, %eax
126         movl %eax, 0x10000
127         movl %eax, 0x10c00
128         movl $PG_U | PG_W | PG_P, %eax
129         movl $0x400, %ecx
130 1:      stosl
131         addl $0x1000, %eax
132         loop 1b
133
134 ##### Enable paging.
135
136         movl %cr0, %eax
137         orl $CR0_PG, %eax
138         movl %eax, %cr0
139         jmp 1f
140 1:
141         
142 ##### Jump to kernel entry point.
143
144         movl $0xc0007c00, %esp
145         movl $0xc0100000, %eax
146         jmp *%eax
147
148 ##### GDT
149
150 gdt:
151         .quad 0x0000000000000000        # null seg
152         .quad 0x00cf9a000000ffff        # code seg
153         .quad 0x00cf92000000ffff        # data seg
154         
155 gdtdesc:
156         .word   0x17                    # sizeof (gdt) - 1
157         .long   gdt                     # address gdt
158
159 ##### Arrive here on error
160 panic:  jmp panic
161
162 ##### Memory size in 4 kB pages.
163         .org 0x200 - 8
164 ram_pages:
165         .long 0
166
167 ##### Boot-sector signature for BIOS inspection.
168         .org 0x200 - 2
169         .word 0xaa55