Page 1 of 1

problem with a basic ide hard disk driver

Posted: Tue Apr 06, 2010 6:04 am
by vikassingh
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
#---------------------------------------------------------------

Re: problem with a basic ide hard disk driver

Posted: Tue Apr 06, 2010 7:55 am
by IanSeyler

Code: Select all

wait_for_results:

xor %eax, %eax # clear the accumulator
mov $IDE_ALT_STATUS, %dx # alternate status port
Shouldn't $IDE_ALT_STATUS be $IDE_COMMAND (or $IDE_STATUS)?

My read sector code looks like this (It's not complete but it does the job):

Code: Select all

	inc dx			; 0x01F7 - Command Port
	mov al, 0x20		; Read sector(s). 0x24 if LBA48
	out dx, al

readsectors_wait:		; VERIFY THIS
	in al, dx
	test al, 8		; This means the sector buffer requires servicing.
	jz readsectors_wait	; Don't continue until the sector buffer is ready.

Re: problem with a basic ide hard disk driver

Posted: Tue Apr 06, 2010 9:52 am
by bewing
Reading the Alternate Status Port is perfectly acceptable. The code posted above should work.
The most likely source of the problem is in your interrupt handler. So it would be wise to post your code for IRQ14. Reading the regular status port does not clear an interrupt that has already happened. (It only prevents one from happening in the first place.)

And when you post code like this, you need to surround it with code tags. Please look at the button row above the message text entry window, here, for a button that says "Code".