1 ;;;; Movitz ATA Hard Drive Driver
2 ;;;; --------------------------------------------------------------------------
3 ;;;; [13 Mar 2008] Martin Bealby
4 ;;;; Moved into muerte.x86-pc.ata package
5 ;;;; 'ata' prefix removed from function names
6 ;;;; [23 Feb 2008] Martin Bealby
7 ;;;; Partition reading and parsing functions added
8 ;;;; Read / write sector functions converted to work with lists of bytes
9 ;;;; [25 Oct 2007] Martin Bealby
10 ;;;; Rewritten from scratch based on http://www.osdever.net/tutorials/lba.php
11 ;;;; --------------------------------------------------------------------------
14 ;;;; --------------------------------------------------------------------------
16 ;;;; --------------------------------------------------------------------------
17 (require :x86-pc
/package
)
19 (defpackage muerte.x86-pc.ata
20 (:use muerte.cl muerte.lib muerte
)
21 (:export
#:read-partition-table
25 #:partition-start-offset
32 (in-package muerte.x86-pc.ata
)
35 ;;;; --------------------------------------------------------------------------
37 ;;;; --------------------------------------------------------------------------
38 (defconstant +controller0
+ #x1F0
)
39 (defconstant +controller1
+ #x170
)
41 (defconstant +offset-data
+ 0)
42 (defconstant +offset-error-precomp
+ 1)
43 (defconstant +offset-sector-count
+ 2)
44 (defconstant +offset-lba1
+ 3)
45 (defconstant +offset-lba2
+ 4)
46 (defconstant +offset-lba3
+ 5)
47 (defconstant +offset-drive-head
+ 6)
48 (defconstant +offset-status-command
+ 7)
51 (defconstant +command-read
+ #x20
)
52 (defconstant +command-write
+ #x30
)
53 (defconstant +bitflag-busy
+ 7)
56 (defparameter *partitions
* '((nil nil nil nil
) ; controller 1 disc 1
57 (nil nil nil nil
) ; controller 1 disc 2
58 (nil nil nil nil
) ; controller 2 disc 1
59 (nil nil nil nil
))) ; controller 2 disc 2
62 ;;;; --------------------------------------------------------------------------
64 ;;;; --------------------------------------------------------------------------
65 (defun busy-wait (controller)
66 "ATA Driver busy spin loop."
67 (loop while
(logbitp +bitflag-busy
+
68 (io-port (+ controller
69 +offset-status-command
+)
72 (defun send-command (controller command
)
73 "Send a command to an IDE controller."
74 (setf (io-port (+ controller
+offset-status-command
+) :unsigned-byte8
)
77 (defun lba-read-write-common (controller drive-number block-address
)
78 (if (= 0 block-address
)
79 (error "Sector zero is not a valid index for LBA addressing."))
81 (setf (io-port (+ controller
82 +offset-error-precomp
+) :unsigned-byte8
) 0)
83 ;; send a sector count
84 (setf (io-port (+ controller
85 +offset-sector-count
+):unsigned-byte8
) 1)
86 ;; send the lowest 8 bits of the lba
87 (setf (io-port (+ controller
+offset-lba1
+) :unsigned-byte8
)
88 (logand block-address
#xFF
))
89 ;; send the next 8 bits
90 (setf (io-port (+ controller
+offset-lba2
+) :unsigned-byte8
)
91 (ash (logand block-address
#xFF00
)
93 ;; send the next 8 bits
94 (setf (io-port (+ controller
+offset-lba3
+) :unsigned-byte8
)
95 (ash (logand block-address
#xFF0000
)
97 ;; send the last 4 bits and some magic bits
98 (setf (io-port (+ controller
+offset-drive-head
+) :unsigned-byte8
)
100 (logior (ash (logand block-address
#xF000000
)
103 (ash drive-number
4))
107 (defun lba-read-sector (controller drive-number block-address
)
108 "Reads a specified sector of data from the disk."
109 ;; Call common initialisation
110 (lba-read-write-common controller drive-number block-address
)
112 (send-command controller
+command-read
+)
113 ;; wait for the drive
114 (busy-wait controller
)
116 (loop for position from
0 to
255
117 for data
= (io-port (+ controller
+offset-data
+)
119 collect
(logand #x00FF data
)
120 collect
(ash (logand #xFF00 data
) -
8)))
123 (defun lba-write-sector (controller drive-number block-address data
)
124 "Writes data to a sector of the disk."
125 ;; data must be a list of 512 unsigned-byte8's
126 ;; based upon lba-read-sector-above
127 (lba-read-write-common controller drive-number block-address
)
128 (send-command controller
+command-write
+)
129 (busy-wait controller
)
130 (loop for position from
0 to
511 by
2
131 do
(setf (io-port (+ controller
+offset-data
+) :unsigned-byte16
)
132 (+ (ash (nth position data
) 8)
133 (nth (+ 1 position
) data
)))))
136 ;;;; --------------------------------------------------------------------------
137 ;;;; Partition Functions
138 ;;;; --------------------------------------------------------------------------
139 (defun read-partition-table (controller drive-number
)
140 "Reads and stores the partition table from the specified disk."
141 (cond ((> controller
1) ; assume 2 controllers for now
142 (error "Invalid controller number.")))
143 (cond ((> drive-number
1) ; assume 2 drives per controller for now
144 (error "Invalid driver number.")))
147 (cond ((= 0 controller
)
148 (lba-read-sector +controller0
+ drive-number
1))
150 (lba-read-sector +controller1
+ drive-number
1)))))
151 (setf (nth (+ controller drive-number
) *partitions
*)
152 (list (loop for offset from
446 to
461
153 collect
(nth offset sector
))
154 (loop for offset from
462 to
477
155 collect
(nth offset sector
))
156 (loop for offset from
478 to
493
157 collect
(nth offset sector
))
158 (loop for offset from
494 to
509
159 collect
(nth offset sector
))))))
161 (defun get-partition-data (controller drive-number partition
)
162 "Returns the partition data for the specified controller and drive from the local cache.
163 The data can be supplied to:
166 partition-start-offset
168 (cond ((> controller
1) ; assume 2 controllers for now
169 (error "Invalid controller number.")))
170 (cond ((> drive-number
1) ; assume 2 drives per controller for now
171 (error "Invalid driver number.")))
172 (cond ((> partition
3) ; max 4 partitions per drive (no extended partitions for now)
173 (error "Invalid partition number.")))
175 (nth (+ controller drive-number
) *partitions
*)))
177 (defun partition-active-p (partition-data)
178 "Returns the state of the active flag for the partition."
179 (cond ((= #x80
(nth 0 partition-data
))
183 (defun partition-type (partition-data)
184 "Returns the partition type for the partition."
185 (let ((id (nth 4 partition-data
)))
213 (defun partition-start-offset (partition-data)
214 "Returns the starting offset (LBA) for the partition."
215 (+ (nth 8 partition-data
)
216 (ash (nth 9 partition-data
)
218 (ash (nth 10 partition-data
)
220 (ash (nth 11 partition-data
)
223 (defun partition-size (partition-data)
224 "Returns the size of the partition."
225 (+ (nth 12 partition-data
)
226 (ash (nth 13 partition-data
)
228 (ash (nth 14 partition-data
)
230 (ash (nth 15 partition-data
)