Converted ata read/write functions to work with bytes rather than words.
[movitz-core.git] / losp / x86-pc / ata.lisp
blob0d4b2f60c0372c54dddc2662129ba7cbd2cb5e4c
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 ;;;; --------------------------------------------------------------------------
11 ;;;; Package Setup
12 ;;;; --------------------------------------------------------------------------
13 (require :x86-pc/package)
14 (provide :x86-pc/ata)
16 (in-package muerte.x86-pc)
19 ;;;; --------------------------------------------------------------------------
20 ;;;; Constants
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 ;;;; --------------------------------------------------------------------------
41 ;;;; Functions
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+)
48 :unsigned-byte8))))
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)
53 command))
55 (defun ata-lba-read-write-common (ata-controller drive-number block-address)
56 ;; send a null
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)
68 -8))
69 ;; send the next 8 bits
70 (setf (io-port (+ ata-controller +ata-offset-lba3+) :unsigned-byte8)
71 (ash (logand block-address #xFF0000)
72 -16))
73 ;; send the last 4 bits and some magic bits
74 (setf (io-port (+ ata-controller +ata-offset-drive-head+) :unsigned-byte8)
75 (logand
76 (logior (ash (logand block-address #xF000000)
77 -24)
78 #xE0 ;; magic
79 (ash drive-number 4))
80 #x0F)))
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)
86 ;; send read command
87 (ata-send-command ata-controller +ata-command-read+)
88 ;; wait for the drive
89 (ata-busy-wait ata-controller)
90 ;; read the data
91 (loop for position from 0 to 255
92 for data = (io-port (+ ata-controller +ata-offset-data+)
93 :unsigned-byte16)
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)))))