problem with a basic ide hard disk driver
Posted: Tue Apr 06, 2010 6:04 am
hello everybody
i was trying to code a basic IDE hard disk driver. which would read a sector from harddisk and copy to a buffer.
but when i ran it, it turned out to be stuck in an infinite loop.
to figure out where it was stuck i put some printing command
it gave 3 output of message1. which shows in is stuck in wait_for_result function. i tried to figure out the error but couldn't can any body help, please.
#------------------------------------------------------------------
.section .data
.equ IDE_CMD_BLOCK, 0x01F0 # IDE command-block port
.equ IDE_CTL_BLOCK, 0x03F4 # IDE control-block port
.equ DMA_CTL_BLOCK, 0xFEA0 # DMA control-block port
.equ IDE_DATA, IDE_CMD_BLOCK+0
.equ IDE_FEATURES, IDE_CMD_BLOCK+1
.equ IDE_ERROR, IDE_CMD_BLOCK+1
.equ IDE_COUNT, IDE_CMD_BLOCK+2
.equ IDE_LBA_LOW, IDE_CMD_BLOCK+3
.equ IDE_LBA_MID, IDE_CMD_BLOCK+4
.equ IDE_LBA_HIGH, IDE_CMD_BLOCK+5
.equ IDE_DEVICE, IDE_CMD_BLOCK+6
.equ IDE_STATUS, IDE_CMD_BLOCK+7
.equ IDE_COMMAND, IDE_CMD_BLOCK+7
.equ IDE_ALT_STATUS, 0x03F6
.equ IDE_CONTROL, 0x03f6
#------------------------------------------------------------------
.section .text
.globl _hddriver
_hddriver:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
call device_selection
call _message1
call write_parameters
call _message1
call initiate_command
call _message1
call wait_for_results
call _message1
call read_sector_data
call _message1
movl %ebp, %esp
popl %ebp
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
ide_status: .short 0 # for controller status
sector_lba: .int DISK_LBA,1 # location to read from
.equ NUM_BLOCKS, 2 # count sectors to read
#------------------------------------------------------------------
device_selection:
# await controller-status: BSY==0 and DRQ==0
mov $IDE_STATUS, %dx # port-address into DX
xor %cx, %cx # load timeout counter
spin1: in %dx, %al # input current status
test $0x88, %al # BSY==0 and DRQ==0?
loopnz spin1 # no, continue testing
# write to Drive/Head register to select device
mov $IDE_DEVICE, %dx # port-address into DX
mov $0xE0, %al # use LBA=1, Drive=0
out %al, %dx # output to controller
mov $IDE_STATUS, %dx # port-address into DX
xor %cx, %cx # load timeout counter
spin2: in %dx, %al # input current status
test $0x88, %al # BSY==0 and DRQ==0?
loopnz spin2 # no, continue testing
ret
#------------------------------------------------------------------
write_parameters:
mov $IDE_COUNT, %dx # port for Sector-Count
mov $NUM_BLOCKS, %al # how many disk-sectors
out %al, %dx # output register-value
mov $IDE_LBA_LOW, %dx # port for LBA[7..0]
mov sector_lba+0, %al # value of low byte
out %al, %dx # output register-value
mov $IDE_LBA_MID, %dx # port for LBA[15..8]
mov sector_lba+1, %al # value of mid byte
out %al, %dx # output register-value
mov $IDE_LBA_HIGH, %dx # port for LBA[23..16]
mov sector_lba+2, %al # value of high byte
out %al, %dx # output register-value
mov $IDE_DEVICE, %dx # port for LBA[27..24]
mov sector_lba+3, %al # value of high nybble
and $0x0F, %al # isolate nybble bits
or $0xE0, %al # specify LBA, Drive 0
out %al, %dx # output register-value
ret
#------------------------------------------------------------------
initiate_command:
mov $IDE_COMMAND, %dx # port for command byte
mov $0x20, %al # 'Read Sector' command
out %al, %dx # output register-value
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
wait_for_results:
xor %eax, %eax # clear the accumulator
mov $IDE_ALT_STATUS, %dx # alternate status port
xor %ecx, %ecx # setup timeout counter
spin3: in %dx, %al # input current status
test $0x80, %al # check: BSY==1?
loopnz spin3 # yes, continue checking
call _message2
test $0x08, %al # check: DRQ==0?
loopz spin3 # no, continue checking
call _message2
test $0x01, %al # any errors indicated?
jz noerr # no, transfer the data
mov $IDE_ERROR, %dx # else select error-port
in %dx, %al # input error settings
shl $8, %ax # and shift them to AH
noerr:
mov $IDE_STATUS, %dx # select status port
in %dx, %al # and clear interrupt
mov %ax, ide_status # save status w/error
call _message2
ret
#------------------------------------------------------------------
read_sector_data:
testw $0xFF01, ide_status # any errors recorded?
jnz failed # yes, don't take risk
call _message2
movl 8(%ebp), %edi # point ES:DI to region
cld # do forward processing
call _message2
nxblk:
mov $IDE_DATA, %dx # port-address for data
mov $256, %cx # CX = words-per-sector
rep insw # input data into arena
call _message2
ret
failed:
call _message3
#---------------------------------------------------------------
i was trying to code a basic IDE hard disk driver. which would read a sector from harddisk and copy to a buffer.
but when i ran it, it turned out to be stuck in an infinite loop.
to figure out where it was stuck i put some printing command
it gave 3 output of message1. which shows in is stuck in wait_for_result function. i tried to figure out the error but couldn't can any body help, please.
#------------------------------------------------------------------
.section .data
.equ IDE_CMD_BLOCK, 0x01F0 # IDE command-block port
.equ IDE_CTL_BLOCK, 0x03F4 # IDE control-block port
.equ DMA_CTL_BLOCK, 0xFEA0 # DMA control-block port
.equ IDE_DATA, IDE_CMD_BLOCK+0
.equ IDE_FEATURES, IDE_CMD_BLOCK+1
.equ IDE_ERROR, IDE_CMD_BLOCK+1
.equ IDE_COUNT, IDE_CMD_BLOCK+2
.equ IDE_LBA_LOW, IDE_CMD_BLOCK+3
.equ IDE_LBA_MID, IDE_CMD_BLOCK+4
.equ IDE_LBA_HIGH, IDE_CMD_BLOCK+5
.equ IDE_DEVICE, IDE_CMD_BLOCK+6
.equ IDE_STATUS, IDE_CMD_BLOCK+7
.equ IDE_COMMAND, IDE_CMD_BLOCK+7
.equ IDE_ALT_STATUS, 0x03F6
.equ IDE_CONTROL, 0x03f6
#------------------------------------------------------------------
.section .text
.globl _hddriver
_hddriver:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
call device_selection
call _message1
call write_parameters
call _message1
call initiate_command
call _message1
call wait_for_results
call _message1
call read_sector_data
call _message1
movl %ebp, %esp
popl %ebp
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
ide_status: .short 0 # for controller status
sector_lba: .int DISK_LBA,1 # location to read from
.equ NUM_BLOCKS, 2 # count sectors to read
#------------------------------------------------------------------
device_selection:
# await controller-status: BSY==0 and DRQ==0
mov $IDE_STATUS, %dx # port-address into DX
xor %cx, %cx # load timeout counter
spin1: in %dx, %al # input current status
test $0x88, %al # BSY==0 and DRQ==0?
loopnz spin1 # no, continue testing
# write to Drive/Head register to select device
mov $IDE_DEVICE, %dx # port-address into DX
mov $0xE0, %al # use LBA=1, Drive=0
out %al, %dx # output to controller
mov $IDE_STATUS, %dx # port-address into DX
xor %cx, %cx # load timeout counter
spin2: in %dx, %al # input current status
test $0x88, %al # BSY==0 and DRQ==0?
loopnz spin2 # no, continue testing
ret
#------------------------------------------------------------------
write_parameters:
mov $IDE_COUNT, %dx # port for Sector-Count
mov $NUM_BLOCKS, %al # how many disk-sectors
out %al, %dx # output register-value
mov $IDE_LBA_LOW, %dx # port for LBA[7..0]
mov sector_lba+0, %al # value of low byte
out %al, %dx # output register-value
mov $IDE_LBA_MID, %dx # port for LBA[15..8]
mov sector_lba+1, %al # value of mid byte
out %al, %dx # output register-value
mov $IDE_LBA_HIGH, %dx # port for LBA[23..16]
mov sector_lba+2, %al # value of high byte
out %al, %dx # output register-value
mov $IDE_DEVICE, %dx # port for LBA[27..24]
mov sector_lba+3, %al # value of high nybble
and $0x0F, %al # isolate nybble bits
or $0xE0, %al # specify LBA, Drive 0
out %al, %dx # output register-value
ret
#------------------------------------------------------------------
initiate_command:
mov $IDE_COMMAND, %dx # port for command byte
mov $0x20, %al # 'Read Sector' command
out %al, %dx # output register-value
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
wait_for_results:
xor %eax, %eax # clear the accumulator
mov $IDE_ALT_STATUS, %dx # alternate status port
xor %ecx, %ecx # setup timeout counter
spin3: in %dx, %al # input current status
test $0x80, %al # check: BSY==1?
loopnz spin3 # yes, continue checking
call _message2
test $0x08, %al # check: DRQ==0?
loopz spin3 # no, continue checking
call _message2
test $0x01, %al # any errors indicated?
jz noerr # no, transfer the data
mov $IDE_ERROR, %dx # else select error-port
in %dx, %al # input error settings
shl $8, %ax # and shift them to AH
noerr:
mov $IDE_STATUS, %dx # select status port
in %dx, %al # and clear interrupt
mov %ax, ide_status # save status w/error
call _message2
ret
#------------------------------------------------------------------
read_sector_data:
testw $0xFF01, ide_status # any errors recorded?
jnz failed # yes, don't take risk
call _message2
movl 8(%ebp), %edi # point ES:DI to region
cld # do forward processing
call _message2
nxblk:
mov $IDE_DATA, %dx # port-address for data
mov $256, %cx # CX = words-per-sector
rep insw # input data into arena
call _message2
ret
failed:
call _message3
#---------------------------------------------------------------