* mikeOS 16 bit and amd64 baremetal
[mascara-docs.git] / amd64 / pure64-0.5.0 / src / init_hdd.asm
blob26214967b83816172de56610d3aa2c10db541756
1 ; =============================================================================
2 ; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
5 ; INIT HDD
6 ; =============================================================================
8 ; The code below only utilizes the Master drive on the Primary ATA Bus.
9 ; Port IO is hard-coded to Primary : 0x01F0 - 0x01F7, 0x03F6
10 ; Secondary Bus would be 0x0170 - 0x0177, 0x0376
12 hdd_setup:
13 ; Probe for PATA hard drive
14 mov dx, 0x01F0
15 mov [ata_base], dx
16 add dx, 7 ; Primary ATA Regular Status Byte
17 in al, dx
18 cmp al, 0xFF ; Check for "float" value
19 je hdd_setup_try_sata ; No drive detected
20 test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set?
21 jne hdd_setup_err_read
22 jmp hdd_setup_load_sector
24 ; Probe for a hard drive controller
25 hdd_setup_try_sata:
26 xor ebx, ebx
27 xor ecx, ecx
28 findcontroller:
29 cmp bx, 256 ; Search up to 256 buses
30 je hdd_setup_err_drive ; No drive detected
31 cmp cl, 32 ; Up to 32 devices per bus
32 jne findcontroller_1
33 add bx, 1
34 xor ecx, ecx
35 findcontroller_1:
36 mov dl, 2 ; We want the Class/Device code
37 call os_pci_read_reg
38 add cl, 1
39 shr rax, 16
40 cmp ax, 0x0106 ; Mass storage device, SATA
41 jne findcontroller
42 sub cl, 1
43 mov dl, 9
44 call os_pci_read_reg ; BAR5 (AHCI Base Address Register)
45 mov [sata_base], eax
46 call os_debug_dump_eax
47 call os_print_newline
48 mov rsi, rax
49 lodsd
50 call os_debug_dump_eax
51 call os_print_newline
52 bt rax, 18
53 jnc legacy_mode_ok
54 push rsi
55 mov rsi, no_sata_legacy
56 call os_print_string
57 pop rsi
58 jmp $
59 legacy_mode_ok:
60 mov rdi, rsi
61 lodsd
62 call os_debug_dump_eax
63 call os_print_newline
64 xor eax, eax
65 stosd
67 ;jmp $
69 mov dl, 4 ; BAR0
70 call os_pci_read_reg
71 and ax, 0xFFFC ; AX now holds the Base IO Address (clear the low 2 bits)
72 ; call os_debug_dump_eax
73 mov dx, ax
74 mov [ata_base], dx
75 in al, dx
76 cmp al, 0xFF ; Check for "float" value
77 je hdd_setup_err_drive ; No drive detected
78 test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set?
79 jne hdd_setup_err_read
81 ; Read first sector of HDD into memory
82 hdd_setup_load_sector:
83 xor rax, rax ; We want sector 0
84 mov rdi, hdbuffer
85 push rdi
86 mov rcx, 1 ; Read one sector
87 call readsectors
88 pop rdi
89 cmp rcx, 0
90 je hdd_setup_err_read
92 cmp byte [cfg_mbr], 0x01 ; Did we boot from a MBR drive
93 jne hdd_setup_no_mbr ; If not then we already have the correct sector
95 ; Grab the partition offset value for the first partition
96 mov eax, [rdi+0x01C6]
97 mov [fat16_PartitionOffset], eax
99 ; Read the first sector of the first partition
100 mov rdi, hdbuffer
101 push rdi
102 mov rcx, 1
103 call readsectors
104 pop rdi
105 cmp rcx, 0
106 je hdd_setup_err_read
108 hdd_setup_no_mbr:
109 ; Get the values we need to start using fat16
110 mov ax, [rdi+0x0b]
111 mov [fat16_BytesPerSector], ax ; This will probably be 512
112 mov al, [rdi+0x0d]
113 mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB)
114 mov ax, [rdi+0x0e]
115 mov [fat16_ReservedSectors], ax
116 mov [fat16_FatStart], eax
117 mov al, [rdi+0x10]
118 mov [fat16_Fats], al ; This will probably be 2
119 mov ax, [rdi+0x11]
120 mov [fat16_RootDirEnts], ax
121 mov ax, [rdi+0x16]
122 mov [fat16_SectorsPerFat], ax
124 ; Find out how many sectors are on the disk
125 xor eax, eax
126 mov ax, [rdi+0x13]
127 cmp ax, 0x0000
128 jne lessthan65536sectors
129 mov eax, [rdi+0x20]
130 lessthan65536sectors:
131 mov [fat16_TotalSectors], eax
133 ; Calculate the size in MiB
134 xor rax, rax
135 mov eax, [fat16_TotalSectors]
136 mov [hd1_maxlba], rax
137 shr rax, 11 ; rax = rax * 512 / 1048576
138 mov [hd1_size], eax ; in mebibytes (MiB)
140 ; Create a string of the harddrive size
141 mov rdi, hdtempstring
142 call os_int_to_string
144 xor rax, rax
145 xor rbx, rbx
146 mov ax, [fat16_SectorsPerFat]
147 shl ax, 1 ; quick multiply by two
148 add ax, [fat16_ReservedSectors]
149 mov [fat16_RootStart], eax
150 mov bx, [fat16_RootDirEnts]
151 shr ebx, 4 ; bx = (bx * 32) / 512
152 add ebx, eax ; BX now holds the datastart sector number
153 mov [fat16_DataStart], ebx
157 hdd_setup_err_drive:
158 mov rsi, hdd_setup_no_drive
159 call os_print_string
160 jmp exception_gate_halt
162 hdd_setup_err_read:
163 mov rsi, hdd_setup_read_error
164 call os_print_string
165 jmp exception_gate_halt
167 ; -----------------------------------------------------------------------------
168 ; readsectors -- Read sectors on the hard drive
169 ; IN: RAX = starting sector to read
170 ; RCX = number of sectors to read (1 - 256)
171 ; RDI = memory location to store sectors
172 ; OUT: RAX = RAX + number of sectors that were read
173 ; RCX = number of sectors that were read (0 on error)
174 ; RDI = RDI + (number of sectors * 512)
175 ; All other registers preserved
176 readsectors:
177 push rdx
178 push rcx
179 push rbx
180 push rax
182 push rcx ; Save RCX for use in the read loop
183 mov rbx, rcx ; Store number of sectors to read
184 cmp rcx, 0
185 je readsectors_fail ; Try to read nothing? Fail!
186 cmp rcx, 256
187 jg readsectors_fail ; Over 256? Fail!
188 jne readsectors_skip ; Not 256? No need to modify CL
189 xor rcx, rcx ; 0 translates to 256
190 readsectors_skip:
192 push rax ; Save RAX since we are about to overwrite it
193 mov dx, [ata_base]
194 ;mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0
195 add dx, 2
196 mov al, cl ; Read CL sectors
197 out dx, al
198 pop rax ; Restore RAX which is our sector number
199 inc dx ; 0x01F3 - LBA Low Port 7:0
200 out dx, al
201 inc dx ; 0x01F4 - LBA Mid Port 15:8
202 shr rax, 8
203 out dx, al
204 inc dx ; 0x01F5 - LBA High Port 23:16
205 shr rax, 8
206 out dx, al
207 inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24)
208 shr rax, 8
209 and al, 00001111b ; Clear bits 4-7 just to be safe
210 or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master)
211 out dx, al
212 inc dx ; 0x01F7 - Command Port
213 mov al, 0x20 ; Read sector(s). 0x24 if LBA48
214 out dx, al
216 mov rcx, 4
217 readsectors_wait:
218 in al, dx ; Read status from 0x01F7
219 test al, 0x80 ; BSY flag set?
220 jne readsectors_retry
221 test al, 0x08 ; DRQ set?
222 jne readsectors_dataready
223 readsectors_retry:
224 dec rcx
225 jg readsectors_wait
226 readsectors_nextsector:
227 in al, dx ; Read status from 0x01F7
228 test al, 0x80 ; BSY flag set?
229 jne readsectors_nextsector
230 test al, 0x21 ; ERR or DF set?
231 jne readsectors_fail
233 readsectors_dataready:
234 sub dx, 7 ; Data port (0x1F0)
235 mov rcx, 256 ; Read
236 rep insw ; Copy a 512 byte sector to RDI
237 add dx, 7 ; Set DX back to status register (0x01F7)
238 in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ
239 in al, dx
240 in al, dx
241 in al, dx
243 dec rbx ; RBX is the "sectors to read" counter
244 cmp rbx, 0
245 jne readsectors_nextsector
247 test al, 0x21 ; ERR or DF set?
248 jne readsectors_fail
250 pop rcx
251 pop rax
252 pop rbx
253 add rax, rcx
254 pop rcx
255 pop rdx
258 readsectors_fail:
259 pop rcx
260 pop rax
261 pop rbx
262 pop rcx
263 pop rdx
264 xor rcx, rcx ; Set RCX to 0 since nothing was read
266 ; -----------------------------------------------------------------------------
268 no_sata_legacy: db "SATA Controller only suppports native mode!", 13, 0
270 ; =============================================================================
271 ; EOF