讀取ATA十分的麻煩,要了解ATA的各個暫存器的IO Port和使用方法。詳情可以參考這篇文章的介紹。https://wiki.osdev.org/ATA_PIO_Mode
利用這篇文章中,28bit PIO提供的方法,我們就要寫一個讀取硬碟的函式。
首先,我們要了解LBA的硬碟定址。
在古老年代的CHS定址法,是利用磁頭、磁柱、磁區這些物理構造來定位的,不過,對於大的硬碟沒辦法處裡,而且計算起來很麻煩(我覺得),所以改用LBA會比較好。LBA主要有28bits和48bits這兩種,因為我們用28bits就很夠了,所以我們在Boot Loader這裡暫時就用28bits的LBA。LBA定址方式十分易懂,就是從第零個磁區開始,0,1,2,3,4,5...。
依照文章開頭提到的參考資料,我們的步驟是:
- 把0xE0和LBA的最高4位元進行位元或計算,輸出到0x1F6端口。
- 將要讀取的磁區數量,輸出到0x1F2端口
- 將LBA最低8位輸出到0x1F3端口,以上的8位輸出到0x1F4,再上面8位輸出到0x1F5
- 輸出0x20(讀取磁區)到0x1F7端口
- 等待一小小段時間,然後用0x1F7的DRQ位元來確認是否讀取好了
- 逐一讀取位元(512Bytes)到目的地
- 重複到第5個步驟
所以照著這個方法,我們寫出了一段程式。注意,我們依照OSDev裡面的建議,利用連續讀取五次來製造一個Delay時間。
# ===============================================================================
# readATA
# ebx = LBA 28 bits
# ecx = sectors to read count
# edi = position to put
# ===============================================================================
readATA:
pushl %edx
movw $0x1F6, %dx
movl %ebx, %eax
shrl $24, %eax
orb $0xE0, %al
outb %al, %dx
movw $0x1F2, %dx
movb %cl, %al
outb %al, %dx
movw $0x1F3, %dx
movl %ebx, %eax
outb %al, %dx
movw $0x1F4, %dx
shrl $8, %eax
outb %al, %dx
movw $0x1F5, %dx
shrl $8, %eax
outb %al, %dx
movw $0x1F7, %dx
movb $0x20, %al
outb %al, %dx
.wait_ready:
inb %dx, %al
inb %dx, %al
inb %dx, %al
inb %dx, %al
inb %dx, %al
test $0x80, %al # BSY bit
jnz .wait_ready
test $0x1, %al # ERR bit
jnz .wait_ready
test $0x20, %al # DF bit
jnz .wait_ready
test $0x8, %al # DRQ bit
jz .wait_ready
# ecx * 512 / 2 = ecx * 256 = ecx << 8
movl %ecx, %eax
movl $256, %ecx
movw $0x1F0, %dx
rep insw
movl %eax, %ecx
movw $0x1F7, %dx
loop .wait_ready
popl %edx
ret
到目前為止的程式長這樣:https://github.com/TNPLR/nos/tree/0.9
0.9版的readATA函式有問題!!!
請自行用文章中或GitHub的這個函式取代0.9版本裡面的。
👉【幫我們一個忙!】👈
👋如果您喜歡這篇文章,請在下方按5個Like!
❤您的支持是我們最大的動力!
您只要登入帳號(Facebook、Google),在下方按5個Like,我們就會收到來自LikeCoin基金會的贊助。
您只需要支持我們,完全不會花到錢!