Wait for DRQ in status register to transition low before reading
[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
83         ### Poll status register while controller busy.
84         movl $0x1f7, %edx
85 1:      inb %dx, %al
86         testb $0x80, %al
87         jnz 1b
88
89         ### Read a single sector.
90         movl $0x1f2, %edx
91         movb $1, %al
92         outb %al, %dx
93
94         ### Sector number to write in low 28 bits.
95         ### LBA mode, device 0 in top 4 bits.
96         movl %ebx, %eax
97         andl $0x0fffffff, %eax
98         orl $0xe0000000, %eax
99
100         ### Dump %eax to ports 0x1f3...0x1f6.
101         movl $4, %ecx
102 2:      incw %dx
103         outb %al, %dx
104         shrl $8, %eax
105         loop 2b
106
107         ### READ command to command register.
108         incw %dx
109         movb $0x20, %al
110         outb %al, %dx
111
112         ### Poll status register while controller busy.
113 1:      inb %dx, %al
114         testb $0x80, %al
115         jnz 1b
116
117         ### Poll status register until data ready.
118 1:      inb %dx, %al
119         testb $0x08, %al
120         jz 1b
121
122         ### Transfer sector.
123         movl $512 / 4, %ecx
124         movl $0x1f0, %edx
125         rep insl
126
127         ### Next sector.
128         incl %ebx
129         cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
130         jnz read_sector
131
132 ##### Create temporary PDE and PTE and set page directory pointer
133 ##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages.
134
135         movl $0x10000, %edi
136         movl %edi, %cr3
137         subl %eax, %eax
138         movl $0x400, %ecx
139         rep stosl
140         movl $0x11000 | PG_U | PG_W | PG_P, %eax
141         movl %eax, 0x10000
142         movl %eax, 0x10c00
143         movl $PG_U | PG_W | PG_P, %eax
144         movl $0x400, %ecx
145 1:      stosl
146         addl $0x1000, %eax
147         loop 1b
148
149 ##### Enable paging.
150
151         movl %cr0, %eax
152         orl $CR0_PG, %eax
153         movl %eax, %cr0
154         jmp 1f
155 1:
156         
157 ##### Jump to kernel entry point.
158
159         movl $0xc0007c00, %esp
160         movl $0xc0100000, %eax
161         jmp *%eax
162
163 ##### GDT
164
165 gdt:
166         .quad 0x0000000000000000        # null seg
167         .quad 0x00cf9a000000ffff        # code seg
168         .quad 0x00cf92000000ffff        # data seg
169         
170 gdtdesc:
171         .word   0x17                    # sizeof (gdt) - 1
172         .long   gdt                     # address gdt
173
174 ##### Arrive here on error
175 panic:  jmp panic
176
177 ##### Memory size in 4 kB pages.
178         .org 0x200 - 8
179 ram_pages:
180         .long 0
181
182 ##### Boot-sector signature for BIOS inspection.
183         .org 0x200 - 2
184         .word 0xaa55