Disabling interrupts on HDD

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Disabling interrupts on HDD

Post by Mikae »

Hello all.

Shame on me, but I was confused working with nIEN bit of device control register. The following simple piece of code works perfect on VMWare, but doesn't disable interrupts on a real hardware.

Code: Select all

 mov dword [0x76 * 4], .hndlr

 mov al, 0x0
 mov dx, 0x1F6
 out dx, al

 mov dx, 0x3F6
 mov al, 0x2
 out dx, al

 mov dx, 0x1F7
 mov al, 0xEC
 out dx, al

 jmp $

.hndlr:
 mov ax, 0xB800
 mov es, ax
 mov word [es:0x0], 0x730
 iret
When I execute it on VMWare everything is Ok. But when I tried to execute it on real hardware, I see '0' character, signaling that the interrupt has occured.

What is the problem?..

TIA,
Mikae.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Heres what i would try, first do a
CLI ;Clear interrupts
Then check second bit of the status register (DRDY) isn't 1, the device isn't
ready, so keep looping until it is.
Then run your code, also i have seen code that users 10 instead of 2 here ?

Code: Select all

mov dx, 0x3F6 
 mov al, 0x2 ;<****HERE***
 out dx, al 


Then at the end do not forget to
STI
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Post by Mikae »

I tried to wait for DRDY (there is nothing about it in standard), but interrupts still arrive.

Code: Select all

org 0x7C00

 xor ax, ax
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, 0x7C00

 cli

 mov ax, 0xB800
 mov es, ax

 mov dword [0x76 * 4], .hndlr

 mov al, 0x0
 mov dx, 0x1F6
 out dx, al

 mov dx, 0x177
.wait_DRDY:
 in al, dx
 test al, 0x40
 mov word [es:0x2], 0x731
 jz .wait_DRDY
 mov word [es:0x2], 0x720

 mov dx, 0x3F6
 mov al, 0x2
 out dx, al

 mov dx, 0x1F7
 mov al, 0xEC
 out dx, al

 sti

 jmp $

.hndlr:
 mov ax, 0xB800
 mov es, ax
 mov word [es:0x0], 0x730
 iret
also i have seen code that users 10 instead of 2 here ?
10 (binary) stands for 2, so I am sure about it. I have to set second bit of device control to 1.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Mikae wrote:
also i have seen code that users 10 instead of 2 here ?
10 (binary) stands for 2, so I am sure about it. I have to set second bit of device control to 1.
But i have seen some code examples set it to 10 dec or 1010 bin, why i do not know, but you can try it.
Last edited by Dex on Mon Dec 17, 2007 10:43 am, edited 1 time in total.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Well according to T13 documentations, if you clear the nIEN bit, the IDE Controller will not send the Interrupts to the CPU. HOWEVER, you will get pending interrupts. You HAVE to read the (alternate) Status Register every time you issue a command to clear any pending interrupts. I had lots of troubles with nIEN and interrupts and I found that my problem was that I was not clearing pending interrupts. Now in all of my HDD libraries and etc I have something like this:

Code: Select all

    .NegateINTRQ:
      LEA     EDX , [EBX + IDE_PORT_OFFSET_STATUS]
      IN      AL , DX
      TIMES   0x04 NOP
      MOV     EDX , IDEC_PORT_ALTERNATESTATUS
      IN      AL , DX
      TIMES   0x04 NOP
I am reading both the Status and the Alternate Status Register to make sure the INTRQ signal is negated.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Post by Mikae »

Well, I thought that when I set nIEN any pending interrupts are cleared. Anyway pending interrupts should be cleared when I write command register (I do so in my code). I tried to read both status and alternate status registers before I set nIEN flag. The situation is the same: I have an interrupt after writing IDENTIFY_DEVICE command. Now, the code looks like this:

Code: Select all

org 0x7C00

 xor ax, ax
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, 0x7C00

 cli

 mov ax, 0xB800
 mov es, ax

 mov dword [0x76 * 4], .hndlr

;Select device
 mov al, 0x0
 mov dx, 0x1F6
 out dx, al

;Wait DRDY
 mov dx, 0x1F7
.wait_DRDY:
 in al, dx
 test al, 0x40
 mov word [es:0x2], 0x731
 jz .wait_DRDY
 mov word [es:0x2], 0x720

;Read status register
 mov dx, 0x1F7
 in al, dx
 nop
 nop
 nop
 nop

;Read alternate status register
 mov dx, 0x3F6
 in al, dx
 nop
 nop
 nop
 nop

;Set nIEN
 mov al, 0x2
 out dx, al

;Send IDENTIFY_DEVICE for test
 mov dx, 0x1F7
 mov al, 0xEC
 out dx, al

 sti

 jmp $

.hndlr:
 mov ax, 0xB800
 mov es, ax
 mov word [es:0x0], 0x730
 iret 
Any ideas?..
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

I wish I could help on this, but I start my OS out with stubbed disk IRQ handlers -- my singletasking driver only uses BSY/DRQ and the regular status register -- any IRQs are ignored. I couldn't care less if the IRQ handlers get called or not, until I'm all the way into multitasking mode, and the proper multitasking disk driver gets loaded into the IDT. So I never touch the nIEN bit at all. And it sounds like a pain in the @$$, anyway, so I'm glad. :wink:
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Post by Mikae »

Well, it seems to me that I have to go this way too: just use stub 'dummy' procedure to handle interrupt.

But, may be it is a problem of my HDD only? Could someone to run this code on a real hardware, to check, if interrupt is asserted? The code, for now, look like this:

Code: Select all

org 0x7C00

 xor ax, ax
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, 0x7C00

 cli

 mov ax, 0xB800
 mov es, ax

 mov dword [0x76 * 4], .hndlr

 mov al, 0x0
 mov dx, 0x1F6
 out dx, al

 mov dx, 0x1F7
.wait_DRDY:
 in al, dx
 test al, 0x40
 mov word [es:0x2], 0x731
 jz .wait_DRDY
 mov word [es:0x2], 0x720

 mov dx, 0x1F7
 in al, dx
 nop
 nop
 nop
 nop

 mov dx, 0x3F6
 in al, dx
 nop
 nop
 nop
 nop

 mov al, 0x2
 out dx, al

 mov dx, 0x1F7
 mov al, 0xEC
 out dx, al

 sti

 jmp $

.hndlr:
 mov ax, 0xB800
 mov es, ax
 mov word [es:0x0], 0x730
 iret

times 510 - ($ - $$) db 0xFF
dw 0xAA55
and should be compiled with FASM. If interrupt occurs, it prints '0' character in top-left cell of screen.

TIA,
Mikae.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

I have run a modded ver of your code in MiniDos

Code: Select all

org 100h

 mov ax, 0xB800
 mov es, ax
;;;;;; code added;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	push  ds			    ; Save DS
	cli				    ; Turn off int's
	xor   ax,ax			    ;
	mov   ds,ax			    ; 0 DS
	mov   word [ds:0x76*4],.hndlr	    ; load int vecter with hndlr	 address
	mov   word [ds:0x76*4+2],cs	    ; + CS
	sti				    ; Turn on int's
	pop   ds			    ; restore DS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


 mov al, 0x0
 mov dx, 0x1F6
 out dx, al

 mov dx, 0x1F7
.wait_DRDY:
 in al, dx
 test al, 0x40
 mov word [es:0x2], 0x731
 jz .wait_DRDY
 mov word [es:0x2], 0x720

 mov dx, 0x1F7
 in al, dx
 nop
 nop
 nop
 nop

 mov dx, 0x3F6
 in al, dx
 nop
 nop
 nop
 nop

 mov al, 2
 out dx, al

 mov dx, 0x1F7
 mov al, 0xEC
 out dx, al



 xor  ax,ax
 int  16h
 ret

.hndlr:
 mov ax, 0xB800
 mov es, ax
 mov word [es:0x0], 0x730
 mov al,0x20
 out 0xa0,al
 out 0x20,al				       ; quiet screaming irq chip.
 iret
I get 0 printed with both 2 and 0, but with the 2 i only get 0 printed once, So it is turn irq off, but there must be a pending IRQ that needs clearing.
User avatar
mathematician
Member
Member
Posts: 437
Joined: Fri Dec 15, 2006 5:26 pm
Location: Church Stretton Uk

Post by mathematician »

Could you let the IDE controller generate its interrupts, and then mask them in the PIC?
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Post by Mikae »

Dex
I get 0 printed with both 2 and 0, but with the 2 i only get 0 printed once
What do you mean, speaking '2' and '0'? If character '0' is printed at top-left cell of screen, it means, that interrupt has occured.

mathematician
Yes, sure I can mask HDD's interrupt on PIC. But, the first, I want to understand, is there something wrong with my device or my code, and the second -- I need to initialize PIC every time I want to turn off interrupt, and that is undesireble.
Mikae
Member
Member
Posts: 94
Joined: Sun Jul 30, 2006 1:08 pm

Post by Mikae »

After some investigations I've found out:

1. This is not problem of my device only, at least one more device behave itself this way.
2. Interrupt occurs when I write nIEN bit to device control register.

Any ideas?..
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Mikae wrote:Dex
I get 0 printed with both 2 and 0, but with the 2 i only get 0 printed once
What do you mean, speaking '2' and '0'? If character '0' is printed at top-left cell of screen, it means, that interrupt has occured.
If i run the above code with 2 here:

Code: Select all

mov al, 2
 out dx, al
I get a 0 printed, but it only prints the first time i run it, as i can re-run the program from the command line of MiniDos, (my simple dos clone OS).

But if i put 0 here:

Code: Select all

mov al, 0
 out dx, al
It will print 0 every time i run it.
This means your code is WORKING, but it has a interrupt pending, you need to clear it.
[EDIT]After more test, just by writing to this bit it fire the interrupt, so you will alway get one last interrupt after turning it off.
And it does the same on 10 PC's i have tested it on, so its nothing to do with your controler.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

Heh. Jeez. Turning the disk interrupts off fires an interrupt? Now there's something I'm gonna have to write into the wiki.
User avatar
Masterkiller
Member
Member
Posts: 153
Joined: Sat May 05, 2007 6:20 pm

Post by Masterkiller »

Code: Select all

76543210 bits
00001SI0
S - Software Reset
I - Interrupt Enable

You are writing to a port 00000010b, istead of MOV try OR-ing the AL and then write to 0x03F6.
If you set I bit INTRQ become high-impedance (not 0, nor 1). So it is possible the CPU handle this as '1' (Interrupt Request) because of changing its status (impuls). The next time device tells the Controller to interrupt, INTRQ remain high-impedance.
Post Reply