Code: Select all
;----------------------------------------------------------;
; Read number of sectors from HDD to the ;
; memory ;
; Input: ;
; EAX=LBA address to read data from ;
; EBX=Memory address to read data to ;
; CH=Which drive to use (0x0 master,0x1 slave) ;
; CL=Number of sectors to read ;
;----------------------------------------------------------;
ata_read:
pushad
push ebp
mov ebp,esp
sub esp,12
; Save the input values
mov DWORD [ebp-4],eax ;This is the LBA address
mov DWORD [ebp-8],ebx ;Memory to store the data
shl ecx,16 ;This will zero the high word of ECX
shr ecx,16
mov DWORD [ebp-12],ecx ;The drive to use and number of sectors to read
; Try the MSB of the status register(BUSY)
; and loop if the bit is set
mov dx,0x1f7
.loop1:
in al,dx
bt ax,7
jc .loop1
cli
; Try bit 6(Device ready) and loop if the bit is 0
mov dx,0x1f7
.loop2:
in al,dx
bt ax,6
jnc .loop2
; The following code will read from HDD to memory
mov eax,[ebp-12]
mov dx,0x1f2
out dx,al ;Set the # of sectors to read
mov eax,[ebp-4] ;EAX=LBA address
call lba2chs ;Calculate CHS translation.ECX=Sector
mov eax,ecx
mov dx,0x1f3
out dx,al ;Set the starting sector sector
mov eax,[ebp-4] ;EAX=LBA address
call lba2chs ;Calculate CHS translation.EAX=Cylinder
mov dx,0x1f4
out dx,al ;Set the low cylinder port
mov dx,0x1f5
shr ax,8 ;Move AH->AL.Now AL=cylinder high
out dx,al ;Set the high cylinder port
mov eax,[ebp-4] ;EAX=LBA address
call lba2chs ;Calculate the CHS translation.EBX=head
mov eax,[ebp-12] ;Store the drive wanted in AH
mov al,bl ;Store the head number in AL
shl ah,4 ;Move the dreive head bit 4 positions left
or al,0xa0 ;Set the reserved flags
or al,ah ;Set the drive bit
mov dx,0x1f6
out dx,al ;Set the Head/Drive register
mov dx,0x1f7
mov al,0x20
out dx,al ;Set the 0x20 command(Read sector with retry)
.loop3:
in al,dx
bt ax,3
jnc .loop3
mov eax,[ebp-12]
shl eax,24 ;This set to zero all except the # of sectors to read
shr eax,24 ;AX=number of sectors to read
mov cx,512 ;CX=number of bytes in a sector
mul cx ;DX:AX=AX*CX.This tell us how many bytes to read
shl eax,16 ;MSW of the EAX now hold the AX
mov ax,dx ;AX=DX
rol eax,16 ;Now EAX=DX:AX the result from the multiplication
mov ebx,4 ;When divide EAX of 4 then we will know how many DWORDs
xor edx,edx ;we need to read from the HDD port
div ebx ;EAX=(EDX:EAX)/EBX
mov ecx,eax
mov edi,[ebp-8] ;This is the destination of the read sector
mov dx,0x1f0 ;This is the data port
cld
rep insd
add esp,12
pop ebp
popad
ret
;----------------------------------------------------------;
; Convert LBA to CHS. ;
; Input: ;
; EAX=LBA address ;
; Output: ;
; EAX=Cylinder, EBX=Head, ECX= Sector ;
;----------------------------------------------------------;
lba2chs:
push ebp
mov ebp,esp
sub esp,4
mov ebx,PHed*PSec ;Cylinder=LBA/(PHed*PSec)
xor edx,edx ;This is needed for the DIV instruction
div ebx ;EAX=quotient(Cylinder) EDX=reminder
mov [ebp-4],eax ;Save the Cylinder
mov eax,edx ;EAX=temp variable
xor edx,edx ;Needed for the DIV instruction
mov ebx,PSec ;EBX is divider
div ebx ;EAX=quotient(Head) EDX=reminder(Sector)
mov ebx,eax ;EBX=EAX(Head)
mov ecx,edx ;ECX=EDX(Sector)+1
inc ecx
mov eax,[ebp-4] ;EAX=[EBP-4] which is the Cylinder
mov esp,ebp
pop ebp
ret
PCyl equ 20
PHed equ 16
PSec equ 63