Make tests public. Rewrite most tests. Add tests.
[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         cli                     # BIOS might have enabled interrupts
123         add eax, 1024           # Total kB memory
124         cmp eax, 0x10000        # Cap at 64 MB
125         jbe 1f
126         mov eax, 0x10000
127 1:      shr eax, 2              # Total 4 kB pages
128         mov ram_pgs, eax 
129         
130 #### Create temporary page directory and page table and set page
131 #### directory base register.
132
133 # Create page directory at 64 kB and fill with zeroes.
134         mov ax, 0x1000
135         mov es, ax
136         sub eax, eax
137         sub edi, edi
138         mov ecx, 0x400
139         rep stosd
140
141 # Add PDEs to point to PTEs for the first 64 MB of RAM.
142 # Also add identical PDEs starting at LOADER_PHYS_BASE.
143 # See [IA32-v3] section 3.7.6 for a description of the bits in eax.
144
145 # A bug in some versions of GAS prevents us from using the straightforward
146 #       mov es:[di + LOADER_PHYS_BASE / 1024 / 1024], eax
147 # so we calculate the displacement in bx instead.
148
149         mov eax, 0x11007
150         mov ecx, 0x11
151         sub di, di
152         mov ebx, LOADER_PHYS_BASE
153         shr ebx, 20
154 1:      mov es:[di], eax
155         mov es:[bx + di], eax 
156         add di, 4
157         add eax, 0x1000
158         loop 1b
159
160 # Set up one-to-map linear to physical map for the first 64 MB of RAM.
161 # See [IA32-v3] section 3.7.6 for a description of the bits in eax.
162
163         mov ax, 0x1100
164         mov es, ax
165         mov eax, 0x7
166         mov cx, 0x4000
167         sub di, di
168 1:      mov es:[di], eax 
169         add di, 4 
170         add eax, 0x1000
171         loop 1b
172
173 # Set page directory base register.
174
175         mov eax, 0x10000
176         mov cr3, eax
177         
178 #### Switch to protected mode.
179
180 # Then we point the GDTR to our GDT.  Protected mode requires a GDT.
181 # We need a data32 prefix to ensure that all 32 bits of the GDT
182 # descriptor are loaded (default is to load only 24 bits).
183
184         data32 lgdt gdtdesc
185
186 # Then we turn on the following bits in CR0:
187 #    PE (Protect Enable): this turns on protected mode.
188 #    PG (Paging): turns on paging.
189 #    WP (Write Protect): if unset, ring 0 code ignores
190 #       write-protect bits in page tables (!).
191 #    EM (Emulation): forces floating-point instructions to trap.
192 #       We don't support floating point. 
193         
194         mov eax, cr0
195         or eax, CR0_PE + CR0_PG + CR0_WP + CR0_EM
196         mov cr0, eax
197         
198 # We're now in protected mode in a 16-bit segment.  The CPU still has
199 # the real-mode code segment cached in cs's segment descriptor.  We
200 # need to reload cs, and the easiest way is to use a far jump.
201 # Because we're not in a 32-bit segment the data32 prefix is needed to
202 # jump to a 32-bit offset.
203
204         data32 ljmp SEL_KCSEG, 1f + LOADER_PHYS_BASE
205
206 # We're now in protected mode in a 32-bit segment.
207
208         .code32
209
210 # Reload all the other segment registers and the stack pointer to
211 # point into our new GDT.
212
213 1:      mov ax, SEL_KDSEG
214         mov ds, ax              
215         mov es, ax              
216         mov fs, ax              
217         mov gs, ax              
218         mov ss, ax
219         mov esp, LOADER_PHYS_BASE + 0x30000
220
221 #### Load kernel starting at physical address LOADER_KERN_BASE by
222 #### frobbing the IDE controller directly.
223
224         mov ebx, 1
225         mov edi, LOADER_KERN_BASE + LOADER_PHYS_BASE
226 read_sector:
227
228 # Poll status register while controller busy.
229
230         mov edx, 0x1f7
231 1:      in al, dx
232         test al, 0x80
233         jnz 1b
234
235 # Read a single sector.
236
237         mov edx, 0x1f2
238         mov al, 1 
239         out dx, al
240
241 # Sector number to write in low 28 bits.
242 # LBA mode, device 0 in top 4 bits.
243
244         mov eax, ebx
245         and eax, 0x0fffffff
246         or eax, 0xe0000000
247
248 # Dump eax to ports 0x1f3...0x1f6.
249
250         mov ecx, 4
251 1:      inc dx
252         out dx, al
253         shr eax, 8
254         loop 1b
255
256 # READ command to command register.
257
258         inc dx
259         mov al, 0x20
260         out dx, al
261
262 # Poll status register while controller busy.
263
264 1:      in al, dx
265         test al, 0x80
266         jnz 1b
267
268 # Poll status register until data ready.
269
270 1:      in al, dx
271         test al, 0x08
272         jz 1b
273
274 # Transfer sector.
275
276         mov ecx, 256
277         mov edx, 0x1f0
278         rep insw
279
280 # Next sector.
281
282         inc ebx
283         cmp ebx, KERNEL_LOAD_PAGES*8 + 1
284         jnz read_sector
285
286 #### Jump to kernel entry point.
287
288         mov eax, LOADER_PHYS_BASE + LOADER_KERN_BASE
289         call eax
290         jmp panic
291
292 #### GDT
293
294 gdt:
295         .quad 0x0000000000000000        # null seg
296         .quad 0x00cf9a000000ffff        # code seg
297         .quad 0x00cf92000000ffff        # data seg
298         
299 gdtdesc:
300         .word   0x17                    # sizeof (gdt) - 1
301         .long   gdt + LOADER_PHYS_BASE  # address gdt
302
303 #### Fatal error.
304 #### Print panicmsg (with help from the BIOS) and spin.
305
306 panic:  .code16                 # We only panic in real mode.
307         mov si, offset panic_message
308         mov ah, 0xe
309         sub bh, bh
310 1:      lodsb
311         test al, al
312 2:      jz 2b                   # Spin.
313         int 0x10
314         jmp 1b
315
316 panic_message:
317         .ascii "Panic!"
318         .byte 0
319
320 #### Physical memory size in 4 kB pages.
321 #### This is initialized by the loader and read by the kernel.
322         .org LOADER_RAM_PGS - LOADER_BASE
323 ram_pgs:
324         .long 0
325
326 #### Command-line arguments and their count.
327 #### This is written by the `pintos' utility and read by the kernel.
328 #### The loader itself does not do anything with the command line.
329         .org LOADER_ARG_CNT - LOADER_BASE
330 arg_cnt:        
331         .long 0
332         .org LOADER_ARGS - LOADER_BASE
333 args:           
334         .fill 0x80, 1, 0
335
336 #### Boot-sector signature.
337 #### The BIOS checks that this is set properly.
338         .org LOADER_SIG - LOADER_BASE
339         .word 0xaa55