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