ATA read/write sectors: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(9 intermediate revisions by 6 users not shown)
Line 4:
 
==Read in CHS mode==
Accessing disk using CHS (cylinder,head,sector) indexes seem to be kinda old type but is the base for LBA access. The following NASM long-mode subroutine reads CH sectors to memory address indicated by RDI register.
<sourcesyntaxhighlight lang="asm">
;=============================================================================
; ATA read sectors (CHS mode, also called HTS mode, HTS=head+track+sector)
; Max head index is 15, giving 16 possible heads
; Max cylinder index can be a very large number (up to 65535)
Line 77:
popfq
ret
</syntaxhighlight>
</source>
 
==Read in LBA mode==
{{stub}}
<syntaxhighlight lang="asm">
;=============================================================================
; ATA read sectors (LBA mode)
;
; @param EAX Logical Block Address of sector
; @param CL Number of sectors to read
; @param RDI The address of buffer to put data obtained from disk
;
; @return None
;=============================================================================
ata_lba_read:
pushfq
and rax, 0x0FFFFFFF
push rax
push rbx
push rcx
push rdx
push rdi
 
mov rbx, rax ; Save LBA in RBX
mov edx, 0x01F6 ; Port to send drive and bit 24 - 27 of LBA
shr eax, 24 ; Get bit 24 - 27 in al
or al, 11100000b ; Set bit 6 in al for LBA mode
out dx, al
 
mov edx, 0x01F2 ; Port to send number of sectors
mov al, cl ; Get number of sectors from CL
out dx, al
mov edx, 0x1F3 ; Port to send bit 0 - 7 of LBA
mov eax, ebx ; Get LBA from EBX
out dx, al
 
mov edx, 0x1F4 ; Port to send bit 8 - 15 of LBA
mov eax, ebx ; Get LBA from EBX
shr eax, 8 ; Get bit 8 - 15 in AL
out dx, al
 
 
mov edx, 0x1F5 ; Port to send bit 16 - 23 of LBA
mov eax, ebx ; Get LBA from EBX
shr eax, 16 ; Get bit 16 - 23 in AL
out dx, al
 
mov edx, 0x1F7 ; Command port
mov al, 0x20 ; Read with retry.
out dx, al
 
.still_going: in al, dx
test al, 8 ; the sector buffer requires servicing.
jz .still_going ; until the sector buffer is ready.
 
mov rax, 256 ; to read 256 words = 1 sector
xor bx, bx
mov bl, cl ; read CL sectors
mul bx
mov rcx, rax ; RCX is counter for INSW
mov rdx, 0x1F0 ; Data port, in and out
rep insw ; in to [RDI]
 
pop rdi
pop rdx
pop rcx
pop rbx
pop rax
popfq
ret
</syntaxhighlight>
 
=ATA write sectors=
 
A write is mostly equivalent to performing a read operation. The only changes needed are a change in command (0x30 for chs write), and the direction of the data, which is written (rep outsw from *SI) to the data port rather than read (rep insw to *DI).
==Write in CHS mode==
As noted by Dex (aka 'qark') in this [http://forum.osdev.org/viewtopic.php?f=1&t=12268 forum topic], the only difference to ata_chs_read is 30h is sent to command register instead of 20h, and using OUTSW instead of INSW, and of course from [RSI] instead of to [RDI]. So code for ata_chs_write can be obtained this way.
 
<syntaxhighlight lang="asm">
==Write in LBA mode==
;=============================================================================
Similar to 'read in LBA mode'.
; ATA write sectors (LBA mode)
;
; @param EAX Logical Block Address of sector
; @param CL Number of sectors to write
; @param RDI The address of data to write to the disk
;
; @return None
;=============================================================================
 
ata_lba_write:
pushfq
and rax, 0x0FFFFFFF
push rax
push rbx
push rcx
push rdx
push rdi
mov rbx, rax ; Save LBA in RBX
 
mov edx, 0x01F6 ; Port to send drive and bit 24 - 27 of LBA
shr eax, 24 ; Get bit 24 - 27 in al
or al, 11100000b ; Set bit 6 in al for LBA mode
out dx, al
 
mov edx, 0x01F2 ; Port to send number of sectors
mov al, cl ; Get number of sectors from CL
out dx, al
 
mov edx, 0x1F3 ; Port to send bit 0 - 7 of LBA
mov eax, ebx ; Get LBA from EBX
out dx, al
 
mov edx, 0x1F4 ; Port to send bit 8 - 15 of LBA
mov eax, ebx ; Get LBA from EBX
shr eax, 8 ; Get bit 8 - 15 in AL
out dx, al
 
 
mov edx, 0x1F5 ; Port to send bit 16 - 23 of LBA
mov eax, ebx ; Get LBA from EBX
shr eax, 16 ; Get bit 16 - 23 in AL
out dx, al
 
mov edx, 0x1F7 ; Command port
mov al, 0x30 ; Write with retry.
out dx, al
 
.still_going: in al, dx
test al, 8 ; the sector buffer requires servicing.
jz .still_going ; until the sector buffer is ready.
 
mov rax, 256 ; to read 256 words = 1 sector
xor bx, bx
mov bl, cl ; write CL sectors
mul bx
mov rcx, rax ; RCX is counter for OUTSW
mov rdx, 0x1F0 ; Data port, in and out
mov rsi, rdi
rep outsw ; out
 
pop rdi
pop rdx
pop rcx
pop rbx
pop rax
popfq
ret
</syntaxhighlight>
 
=See also=
* [http://forum.osdev.org/viewtopic.php?t=12268 Read/write disk sectors by Dex]
* [http://wiki.osdev.org/[ATA_PIO_Mode |ATA PIO Modemode]]
* [[ATA]]
* [http://wiki.osdev.org/ATA ATA/IDE]
 
[[Category:ATA]]