1 ;;;; Movitz ATA Hard Drive Driver
2 ;;;; --------------------------------------------------------------------------
3 ;;;; [23 Feb 2008] Martin Bealby
4 ;;;; Read / write sector functions converted to work with lists of bytes
5 ;;;; [25 Oct 2007] Martin Bealby
6 ;;;; Rewritten from scratch based on http://www.osdever.net/tutorials/lba.php
7 ;;;; --------------------------------------------------------------------------
10 ;;;; --------------------------------------------------------------------------
12 ;;;; --------------------------------------------------------------------------
13 (require :x86-pc
/package
)
16 (in-package muerte.x86-pc
)
19 ;;;; --------------------------------------------------------------------------
21 ;;;; --------------------------------------------------------------------------
22 (defconstant +ata-controller0
+ #x1F0
)
23 (defconstant +ata-controller1
+ #x170
)
25 (defconstant +ata-offset-data
+ 0)
26 (defconstant +ata-offset-error-precomp
+ 1)
27 (defconstant +ata-offset-sector-count
+ 2)
28 (defconstant +ata-offset-lba1
+ 3)
29 (defconstant +ata-offset-lba2
+ 4)
30 (defconstant +ata-offset-lba3
+ 5)
31 (defconstant +ata-offset-drive-head
+ 6)
32 (defconstant +ata-offset-status-command
+ 7)
35 (defconstant +ata-command-read
+ #x20
)
36 (defconstant +ata-command-write
+ #x30
)
37 (defconstant +ata-bitflag-busy
+ 7)
40 ;;;; --------------------------------------------------------------------------
42 ;;;; --------------------------------------------------------------------------
43 (defun ata-busy-wait (ata-controller)
44 "ATA Driver busy spin loop."
45 (loop while
(logbitp +ata-bitflag-busy
+
46 (io-port (+ ata-controller
47 +ata-offset-status-command
+)
50 (defun ata-send-command (ata-controller command
)
51 "Send a command to an IDE controller."
52 (setf (io-port (+ ata-controller
+ata-offset-status-command
+) :unsigned-byte8
)
55 (defun ata-lba-read-write-common (ata-controller drive-number block-address
)
57 (setf (io-port (+ ata-controller
58 +ata-offset-error-precomp
+) :unsigned-byte8
) 0)
59 ;; send a sector count
60 (setf (io-port (+ ata-controller
61 +ata-offset-sector-count
+):unsigned-byte8
) 1)
62 ;; send the lowest 8 bits of the lba
63 (setf (io-port (+ ata-controller
+ata-offset-lba1
+) :unsigned-byte8
)
64 (logand block-address
#xFF
))
65 ;; send the next 8 bits
66 (setf (io-port (+ ata-controller
+ata-offset-lba2
+) :unsigned-byte8
)
67 (ash (logand block-address
#xFF00
)
69 ;; send the next 8 bits
70 (setf (io-port (+ ata-controller
+ata-offset-lba3
+) :unsigned-byte8
)
71 (ash (logand block-address
#xFF0000
)
73 ;; send the last 4 bits and some magic bits
74 (setf (io-port (+ ata-controller
+ata-offset-drive-head
+) :unsigned-byte8
)
76 (logior (ash (logand block-address
#xF000000
)
82 (defun ata-lba-read-sector (ata-controller drive-number block-address
)
83 "Reads a specified sector of data from the disk."
84 ;; Call common initialisation
85 (ata-lba-read-write-common ata-controller drive-number block-address
)
87 (ata-send-command ata-controller
+ata-command-read
+)
89 (ata-busy-wait ata-controller
)
91 (loop for position from
0 to
255
92 for data
= (io-port (+ ata-controller
+ata-offset-data
+)
94 collect
(logand #x00FF data
)
95 collect
(ash (logand #xFF00 data
) -
8)))
98 (defun ata-lba-write-sector (ata-controller drive-number block-address data
)
99 "Writes data to a sector of the disk."
100 ;; data must be a list of 512 unsigned-byte8's
101 ;; based upon ata-lba-read-sector-above
102 (ata-lba-read-write-common ata-controller drive-number block-address
)
103 (ata-send-command ata-controller
+ata-command-write
+)
104 (ata-busy-wait ata-controller
)
105 (loop for position from
0 to
511 by
2
106 do
(setf (io-port (+ ata-controller
+ata-offset-data
+) :unsigned-byte16
)
107 (+ (ash (nth position data
) 8)
108 (nth (+ 1 position
) data
)))))