Work on loader to prepare for passing in a command line.
[pintos-anon] / src / threads / loader.S
1 #include "mmu.h"
2         
3 ##############################################################################
4 # Kernel loader.
5 #
6 # This code should be stored in the first sector of the hard disk.  When the  
7 # BIOS runs, it loads this code at physical address 0x7c00-0x7e00 (512 bytes).
8 # Then it jumps to the beginning of it, in real mode.  
9 # This code switches into protected mode (32-bit mode) so that all of
10 # memory can accessed, loads the kernel into memory, and jumps to the
11 # first byte of the kernel, where start.S is linked.
12 ##############################################################################
13         
14 .globl start                            # Entry point   
15 start:  .code16                         # This runs in real mode
16         cli                             # Disable interrupts
17         cld                             # String ops inc
18         xorw %ax,%ax                    # Zero
19         movw %ax,%es                    # Address
20         movw %ax,%ds                    #  data
21         movw %ax,%ss                    # Set up
22         movw $start,%sp                 #  stack (grows down)
23         
24 #### Enable A20:
25 ####   Address line 20 is tied to low when the machine boots, 
26 ####   obviously this a bit of a drag, such as when trying to
27 ####   address memory above 1MB.  This code undoes this.
28         
29 1:      inb $0x64,%al           # Get status
30         testb $0x2,%al          # Busy?
31         jnz 1b                  # Yes
32         movb $0xd1,%al          # Command: Write
33         outb %al,$0x64          #  output port
34 2:      inb $0x64,%al           # Get status
35         testb $0x2,%al          # Busy?
36         jnz 2b                  # Yes
37         movb $0xdf,%al          # Enable
38         outb %al,$0x60          #  A20
39
40 #### Get memory size, via interrupt 15h function 88h.
41 #### Returns CF clear if successful, with AX = (kB of physical memory) - 1024.
42 #### This only works for memory sizes <= 65 MB, which should be fine for our purposes.
43         
44         movb $0x88,%ah
45         int $0x15
46         jc panic                # Carry flag set on error
47 2:      addl $1024,%eax         # Total kB
48         shrl $2,%eax            # Total 4 kB pages
49         movl %eax, ram_pages
50         
51 #### switch from real to protected mode 
52 ####     The segments in GDT allow all of physical memory to be accessed.
53 ####     Furthermore, the segments have base addresses of 0, so that the
54 ####     segment translation is a NOP, ie. virtual addresses are identical to
55 ####     their physical addresses.  With this setup, it appears to this code
56 ####     that it is running directly on physical memory.
57         
58         cli                     # Mandatory since we dont set up an IDT
59         lgdt gdtdesc            # load GDT -- mandatory in protected mode
60         movl %cr0, %eax         # turn on protected mode
61         orl $CR0_PE, %eax       # 
62         movl %eax, %cr0         # 
63         ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs
64         ### Has the effect of just jmp to the next instruction, but simultaneous
65         ### loads CS with $PROT_MODE_CSEG.
66         ljmp $SEL_KCSEG, $protcseg
67         
68 #### We are in protected mode in a 32-bit segment (hence the .code32)
69 protcseg:
70         .code32
71         movw $SEL_KDSEG, %ax    # set up data segment registers
72         movw %ax, %ds           
73         movw %ax, %es           
74         movw %ax, %fs           
75         movw %ax, %gs           
76         movw %ax, %ss
77
78 #### Load kernel at 1 MB by frobbing the IDE controller directly.
79
80         movl $1, %ebx
81         movl $0x100000, %edi
82 read_sector:
83
84         ### Poll status register while controller busy.
85         movl $0x1f7, %edx
86 1:      inb %dx, %al
87         testb $0x80, %al
88         jnz 1b
89
90         ### Read a single sector.
91         movl $0x1f2, %edx
92         movb $1, %al
93         outb %al, %dx
94
95         ### Sector number to write in low 28 bits.
96         ### LBA mode, device 0 in top 4 bits.
97         movl %ebx, %eax
98         andl $0x0fffffff, %eax
99         orl $0xe0000000, %eax
100
101         ### Dump %eax to ports 0x1f3...0x1f6.
102         movl $4, %ecx
103 2:      incw %dx
104         outb %al, %dx
105         shrl $8, %eax
106         loop 2b
107
108         ### READ command to command register.
109         incw %dx
110         movb $0x20, %al
111         outb %al, %dx
112
113         ### Poll status register while controller busy.
114 1:      inb %dx, %al
115         testb $0x80, %al
116         jnz 1b
117
118         ### Poll status register until data ready.
119 1:      inb %dx, %al
120         testb $0x08, %al
121         jz 1b
122
123         ### Transfer sector.
124         movl $512 / 4, %ecx
125         movl $0x1f0, %edx
126         rep insl
127
128         ### Next sector.
129         incl %ebx
130         cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
131         jnz read_sector
132
133 ##### Create temporary PDE and PTE and set page directory pointer
134 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
135
136         movl $0x10000, %edi
137         movl %edi, %cr3
138         subl %eax, %eax
139         movl $0x400, %ecx
140         rep stosl
141         movl $0x11000 | PG_U | PG_W | PG_P, %eax
142         movl %eax, 0x10000
143         movl %eax, 0x10c00
144         movl $PG_U | PG_W | PG_P, %eax
145         movl $0x400, %ecx
146 1:      stosl
147         addl $0x1000, %eax
148         loop 1b
149
150 ##### Enable paging.
151
152         movl %cr0, %eax
153         orl $CR0_PG, %eax
154         movl %eax, %cr0
155         jmp 1f
156 1:
157
158 ##### Turn on EM bit in CR0, forcing most floating-point instructions
159 ##### to trap.  We don't support floating-point or MMX.
160
161         movl %cr0, %eax
162         orl $CR0_EM, %eax
163         movl %eax, %cr0
164         
165 ##### Jump to kernel entry point.
166
167         movl $0xc0007c00, %esp
168         movl $0xc0100000, %eax
169         jmp *%eax
170
171 ##### GDT
172
173 gdt:
174         .quad 0x0000000000000000        # null seg
175         .quad 0x00cf9a000000ffff        # code seg
176         .quad 0x00cf92000000ffff        # data seg
177         
178 gdtdesc:
179         .word   0x17                    # sizeof (gdt) - 1
180         .long   gdt                     # address gdt
181
182 ##### To panic, we print panicmsg (with help from the BIOS) and spin.
183 panic:  .code16                 # We only panic in real mode.
184         movw $panicmsg, %si
185         movb $0xe, %ah
186         xorb %bh, %bh
187 1:      lodsb
188         test %al, %al
189 2:      jz 2b                   # Spin.
190         int $0x10
191         jmp 1b
192
193 panicmsg:
194         .ascii "Loader panic!\r\n"
195         .byte 0
196
197 ##### Command-line arguments inserted by another utility.
198 ##### The loader doesn't use these, but we note their
199 ##### location here for easy reference.
200         .org 0x200 - 0x80
201 cmd_line:       
202
203 ##### Memory size in 4 kB pages.
204         .org 0x200 - 6
205 ram_pages:
206         .long 0
207
208 ##### Boot-sector signature for BIOS inspection.
209         .org 0x200 - 2
210         .word 0xaa55