* remove "\r" nonsense
[mascara-docs.git] / amd64 / bareMetalOS-0.5.3 / os / drivers / hdd.asm
blobaee2095795f7a9256bdb98aebc0bf0947cae3477
1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
5 ; Hard Drive Functions
6 ; =============================================================================
8 align 16
9 db 'DEBUG: HDD '
10 align 16
13 ; NOTE: These functions use LBA28. Maximum visible drive size is 128GiB
14 ; LBA48 would be needed to access sectors over 128GiB (up to 128PiB)
15 ; These functions are hard coded to access the Primary Master HDD
18 ; -----------------------------------------------------------------------------
19 ; readsectors -- Read sectors on the hard drive
20 ; IN: RAX = starting sector to read
21 ; RCX = number of sectors to read (1 - 256)
22 ; RDI = memory location to store sectors
23 ; OUT: RAX = RAX + number of sectors that were read
24 ; RCX = number of sectors that were read (0 on error)
25 ; RDI = RDI + (number of sectors * 512)
26 ; All other registers preserved
27 readsectors:
28 push rdx
29 push rcx
30 push rbx
31 push rax
33 push rcx ; Save RCX for use in the read loop
34 mov rbx, rcx ; Store number of sectors to read
35 cmp rcx, 256
36 jg readsectors_fail ; Over 256? Fail!
37 jne readsectors_skip ; Not 256? No need to modify CL
38 xor rcx, rcx ; 0 translates to 256
39 readsectors_skip:
41 push rax ; Save RAX since we are about to overwrite it
42 mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0
43 mov al, cl ; Read CL sectors
44 out dx, al
45 pop rax ; Restore RAX which is our sector number
46 inc dx ; 0x01F3 - LBA Low Port 7:0
47 out dx, al
48 inc dx ; 0x01F4 - LBA Mid Port 15:8
49 shr rax, 8
50 out dx, al
51 inc dx ; 0x01F5 - LBA High Port 23:16
52 shr rax, 8
53 out dx, al
54 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)
55 shr rax, 8
56 and al, 00001111b ; Clear bits 4-7 just to be safe
57 or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master)
58 out dx, al
59 inc dx ; 0x01F7 - Command Port
60 mov al, 0x20 ; Read sector(s). 0x24 if LBA48
61 out dx, al
63 mov rcx, 4
64 readsectors_wait:
65 in al, dx ; Read status from 0x01F7
66 test al, 0x80 ; BSY flag set?
67 jne readsectors_retry
68 test al, 0x08 ; DRQ set?
69 jne readsectors_dataready
70 readsectors_retry:
71 dec rcx
72 jg readsectors_wait
73 readsectors_nextsector:
74 in al, dx ; Read status from 0x01F7
75 test al, 0x80 ; BSY flag set?
76 jne readsectors_nextsector
77 test al, 0x21 ; ERR or DF set?
78 jne readsectors_fail
80 readsectors_dataready:
81 sub dx, 7 ; Data port (0x1F0)
82 mov rcx, 256 ; Read
83 rep insw ; Copy a 512 byte sector to RDI
84 add dx, 7 ; Set DX back to status register (0x01F7)
85 in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ
86 in al, dx
87 in al, dx
88 in al, dx
90 dec rbx ; RBX is the "sectors to read" counter
91 cmp rbx, 0
92 jne readsectors_nextsector
94 pop rcx
95 pop rax
96 pop rbx
97 add rax, rcx
98 pop rcx
99 pop rdx
102 readsectors_fail:
103 pop rcx
104 pop rax
105 pop rbx
106 pop rcx
107 pop rdx
108 xor rcx, rcx ; Set RCX to 0 since nothing was read
110 ; -----------------------------------------------------------------------------
113 ; -----------------------------------------------------------------------------
114 ; writesectors -- Write sectors on the hard drive
115 ; IN: RAX = starting sector to write
116 ; RCX = number of sectors to write (1 - 256)
117 ; RSI = memory location of sectors
118 ; OUT: RAX = RAX + number of sectors that were written
119 ; RCX = number of sectors that were written (0 on error)
120 ; RSI = RSI + (number of sectors * 512)
121 ; All other registers preserved
122 writesectors:
123 push rdx
124 push rcx
125 push rbx
126 push rax
128 push rcx ; Save RCX for use in the write loop
129 mov rbx, rcx ; Store number of sectors to write
130 cmp rcx, 256
131 jg writesectors_fail ; Over 256? Fail!
132 jne writesectors_skip ; Not 256? No need to modify CL
133 xor rcx, rcx ; 0 translates to 256
134 writesectors_skip:
136 push rax ; Save RAX since we are about to overwrite it
137 mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0
138 mov al, cl ; Write CL sectors
139 out dx, al
140 pop rax ; Restore RAX which is our sector number
141 inc dx ; 0x01F3 - LBA Low Port 7:0
142 out dx, al
143 inc dx ; 0x01F4 - LBA Mid Port 15:8
144 shr rax, 8
145 out dx, al
146 inc dx ; 0x01F5 - LBA High Port 23:16
147 shr rax, 8
148 out dx, al
149 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)
150 shr rax, 8 ; Bits 7 and 5 are obsolete in LBA mode so set to 0
151 and al, 00001111b ; Clear bits 4-7 just to be safe
152 or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master)
153 out dx, al
154 inc dx ; 0x01F7 - Command Port
155 mov al, 0x30 ; Write sector(s). 0x34 if LBA48
156 out dx, al
158 mov rcx, 4
159 writesectors_wait:
160 in al, dx ; Read status from 0x01F7
161 test al, 0x80 ; BSY flag set?
162 jne writesectors_retry
163 test al, 0x08 ; DRQ set?
164 jne writesectors_dataready
165 writesectors_retry:
166 dec rcx
167 jg writesectors_wait
168 writesectors_nextsector:
169 in al, dx ; Read status from 0x01F7
170 test al, 0x80 ; BSY flag set?
171 jne writesectors_nextsector
172 test al, 0x21 ; ERR or DF set?
173 jne writesectors_fail
175 writesectors_dataready:
176 sub dx, 7 ; Data port (0x01F0)
177 mov rcx, 256 ; Write 256 words (512 bytes)
178 writesectors_nextword:
179 outsw ; Cannot use rep as a small delay is needed between each out
180 sub rcx, 1
181 cmp rcx, 0
182 jne writesectors_nextword
183 add dx, 7 ; Set DX back to Command / Status Register (0x01F7)
184 mov al, 0xE7 ; Cache Flush command
185 out dx, al
186 in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ
187 in al, dx
188 in al, dx
189 in al, dx
191 dec rbx ; RBX is the "sectors to write" counter
192 cmp rbx, 0
193 jne writesectors_nextsector
195 pop rcx
196 pop rax
197 pop rbx
198 add rax, rcx
199 pop rcx
200 pop rdx
203 writesectors_fail:
204 pop rcx
205 pop rax
206 pop rbx
207 pop rcx
208 pop rdx
209 xor rcx, rcx ; Set RCX to 0 since nothing was written
211 ; -----------------------------------------------------------------------------
214 ; =============================================================================
215 ; EOF