Change to deal with crappy GAS bug.
[pintos-anon] / src / threads / loader.S
1 /* This file is derived from source code used in MIT's 6.828
2    course.  The original copyright notice is reproduced in full
3    below. */
4
5 /*
6  * Copyright (C) 1997 Massachusetts Institute of Technology 
7  *
8  * This software is being provided by the copyright holders under the
9  * following license. By obtaining, using and/or copying this software,
10  * you agree that you have read, understood, and will comply with the
11  * following terms and conditions:
12  *
13  * Permission to use, copy, modify, distribute, and sell this software
14  * and its documentation for any purpose and without fee or royalty is
15  * hereby granted, provided that the full text of this NOTICE appears on
16  * ALL copies of the software and documentation or portions thereof,
17  * including modifications, that you make.
18  *
19  * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
20  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
21  * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
22  * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
23  * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
24  * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
25  * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
26  * DOCUMENTATION.
27  *
28  * The name and trademarks of copyright holders may NOT be used in
29  * advertising or publicity pertaining to the software without specific,
30  * written prior permission. Title to copyright in this software and any
31  * associated documentation will at all times remain with copyright
32  * holders. See the file AUTHORS which should have accompanied this software
33  * for a list of all copyright holders.
34  *
35  * This file may be derived from previously copyrighted software. This
36  * copyright applies only to those changes made by the copyright
37  * holders listed in the AUTHORS file. The rest of this file is covered by
38  * the copyright notices, if any, listed below.
39  */
40
41 #include "threads/loader.h"
42         
43         .intel_syntax noprefix
44         
45 #### Kernel loader.
46
47 #### This code should be stored in the first sector of the hard disk.
48 #### When the BIOS runs, it loads this code at physical address
49 #### 0x7c00-0x7e00 (512 bytes).  Then it jumps to the beginning of it,
50 #### in real mode.  This code switches into protected mode (32-bit
51 #### mode) so that all of memory can accessed, loads the kernel into
52 #### memory, and jumps to the first byte of the kernel, where start.S
53 #### is linked.
54         
55 /* Flags in control register 0. */
56 #define CR0_PE 0x00000001      /* Protection Enable. */
57 #define CR0_EM 0x00000004      /* (Floating-point) Emulation. */
58 #define CR0_PG 0x80000000      /* Paging. */
59 #define CR0_WP 0x00010000      /* Write-Protect enable in kernel mode. */
60
61 # Code runs in real mode, which is a 16-bit segment.
62
63 .globl start
64 start:
65         .code16
66
67 # Disable interrupts.
68 # String instructions go upward.
69
70         cli
71         cld
72
73 # Set up data segments.
74
75         sub ax, ax
76         mov es, ax
77         mov ds, ax
78
79 # Set up stack segment.
80 # Stack grows downward starting from us.
81 # We don't ever use the stack so this is strictly speaking
82 # unnecessary.
83
84         mov ss, ax
85         mov sp, 0x7c00
86         
87 #### Enable A20.  Address line 20 is tied to low when the machine
88 #### boots, which prevents addressing memory about 1 MB.  This code
89 #### fixes it.
90         
91 # Poll status register while busy.
92
93 1:      in al, 0x64
94         test al, 0x2
95         jnz 1b
96
97 # Send command for writing output port.
98
99         mov al, 0xd1
100         outb 0x64, al
101
102 # Poll status register while busy.
103
104 1:      in al, 0x64
105         test al, 0x2
106         jnz 1b
107
108 # Enable A20 line.
109
110         mov al, 0xdf
111         out 0x60, al
112
113 #### Get memory size, via interrupt 15h function 88h, which returns CF
114 #### clear if successful, with AX = (kB of physical memory) - 1024.
115 #### This only works for memory sizes <= 65 MB, which should be fine
116 #### for our purposes.  We cap memory at 64 MB because that's all we
117 #### prepare page tables for, below.
118         
119         mov ah, 0x88
120         int 0x15
121         jc panic
122         add eax, 1024           # Total kB memory
123         cmp eax, 0x10000        # Cap at 64 MB
124         jbe 1f
125         mov eax, 0x10000
126 1:      shr eax, 2              # Total 4 kB pages
127         mov ram_pages, eax 
128         
129 #### Create temporary page directory and page table and set page
130 #### directory base register.
131
132 # Create page directory at 64 kB and fill with zeroes.
133         mov ax, 0x1000
134         mov es, ax
135         sub eax, eax
136         sub edi, edi
137         mov ecx, 0x400
138         rep stosd
139
140 # Add PDEs to point to PTEs for the first 64 MB of RAM.
141 # Also add identical PDEs starting at LOADER_PHYS_BASE.
142 # See [IA32-v3] section 3.7.6 for a description of the bits in eax.
143
144 # A bug in some versions of GAS prevents us from using the straightforward
145 #       mov es:[di + LOADER_PHYS_BASE / 1024 / 1024], eax
146 # so we calculate the displacement in bx instead.
147
148         mov eax, 0x11007
149         mov ecx, 0x11
150         sub di, di
151         mov ebx, LOADER_PHYS_BASE
152         shr ebx, 20
153 1:      mov es:[di], eax
154         mov es:[bx + di], eax 
155         add di, 4
156         add eax, 0x1000
157         loop 1b
158
159 # Set up one-to-map linear to physical map for the first 64 MB of RAM.
160 # See [IA32-v3] section 3.7.6 for a description of the bits in eax.
161
162         mov ax, 0x1100
163         mov es, ax
164         mov eax, 0x7
165         mov cx, 0x4000
166         sub di, di
167 1:      mov es:[di], eax 
168         add di, 4 
169         add eax, 0x1000
170         loop 1b
171
172 # Set page directory base register.
173
174         mov eax, 0x10000
175         mov cr3, eax
176         
177 #### Switch to protected mode.
178
179 # Then we point the GDTR to our GDT.  Protected mode requires a GDT.
180 # We need a data32 prefix to ensure that all 32 bits of the GDT
181 # descriptor are loaded (default is to load only 24 bits).
182
183         data32 lgdt gdtdesc
184
185 # Then we turn on the following bits in CR0:
186 #    PE (Protect Enable): this turns on protected mode.
187 #    PG (Paging): turns on paging.
188 #    WP (Write Protect): if unset, ring 0 code ignores
189 #       write-protect bits in page tables (!).
190 #    EM (Emulation): forces floating-point instructions to trap.
191 #       We don't support floating point. 
192         
193         mov eax, cr0
194         or eax, CR0_PE + CR0_PG + CR0_WP + CR0_EM
195         mov cr0, eax
196         
197 # We're now in protected mode in a 16-bit segment.  The CPU still has
198 # the real-mode code segment cached in cs's segment descriptor.  We
199 # need to reload cs, and the easiest way is to use a far jump.
200 # Because we're not in a 32-bit segment the data32 prefix is needed to
201 # jump to a 32-bit offset.
202
203         data32 ljmp SEL_KCSEG, 1f + LOADER_PHYS_BASE
204
205 # We're now in protected mode in a 32-bit segment.
206
207         .code32
208
209 # Reload all the other segment registers and the stack pointer to
210 # point into our new GDT.
211
212 1:      mov ax, SEL_KDSEG
213         mov ds, ax              
214         mov es, ax              
215         mov fs, ax              
216         mov gs, ax              
217         mov ss, ax
218         mov esp, LOADER_PHYS_BASE + 0x30000
219
220 #### Load kernel starting at physical address LOADER_KERN_BASE by
221 #### frobbing the IDE controller directly.
222
223         mov ebx, 1
224         mov edi, LOADER_KERN_BASE + LOADER_PHYS_BASE
225 read_sector:
226
227 # Poll status register while controller busy.
228
229         mov edx, 0x1f7
230 1:      in al, dx
231         test al, 0x80
232         jnz 1b
233
234 # Read a single sector.
235
236         mov edx, 0x1f2
237         mov al, 1 
238         out dx, al
239
240 # Sector number to write in low 28 bits.
241 # LBA mode, device 0 in top 4 bits.
242
243         mov eax, ebx
244         and eax, 0x0fffffff
245         or eax, 0xe0000000
246
247 # Dump eax to ports 0x1f3...0x1f6.
248
249         mov ecx, 4
250 1:      inc dx
251         out dx, al
252         shr eax, 8
253         loop 1b
254
255 # READ command to command register.
256
257         inc dx
258         mov al, 0x20
259         out dx, al
260
261 # Poll status register while controller busy.
262
263 1:      in al, dx
264         test al, 0x80
265         jnz 1b
266
267 # Poll status register until data ready.
268
269 1:      in al, dx
270         test al, 0x08
271         jz 1b
272
273 # Transfer sector.
274
275         mov ecx, 256
276         mov edx, 0x1f0
277         rep insw
278
279 # Next sector.
280
281         inc ebx
282         cmp ebx, KERNEL_LOAD_PAGES*8 + 1
283         jnz read_sector
284
285 #### Jump to kernel entry point.
286
287         mov eax, LOADER_PHYS_BASE + LOADER_KERN_BASE
288         call eax
289         jmp panic
290
291 #### GDT
292
293 gdt:
294         .quad 0x0000000000000000        # null seg
295         .quad 0x00cf9a000000ffff        # code seg
296         .quad 0x00cf92000000ffff        # data seg
297         
298 gdtdesc:
299         .word   0x17                    # sizeof (gdt) - 1
300         .long   gdt + LOADER_PHYS_BASE  # address gdt
301
302 #### Fatal error.
303 #### Print panicmsg (with help from the BIOS) and spin.
304
305 panic:  .code16                 # We only panic in real mode.
306         mov si, offset panicmsg
307         mov ah, 0xe
308         sub bh, bh
309 1:      lodsb
310         test al, al
311 2:      jz 2b                   # Spin.
312         int 0x10
313         jmp 1b
314
315 panicmsg:
316         .ascii "Loader panic!\r\n"
317         .byte 0
318
319 #### Memory size in 4 kB pages.
320         .org LOADER_RAM_PAGES - LOADER_BASE
321 ram_pages:
322         .long 0
323
324 #### Command-line arguments inserted by another utility.
325 #### The loader doesn't use these, but we note their
326 #### location here for easy reference.
327         .org LOADER_CMD_LINE - LOADER_BASE
328 cmd_line:
329         .fill 0x80, 1, 0
330
331 #### Boot-sector signature for BIOS inspection.
332         .org LOADER_BIOS_SIG - LOADER_BASE
333         .word 0xaa55