Page 1 of 1
Interrupt not working properly
Posted: Sat Nov 04, 2006 3:24 am
by nitinjavakid
Code: Select all
;storing previous interrupt address
mov ax,0
mov ds,ax
mov ax,[ds:08h*4]
mov [previpaddress], ax
mov ax, [ds:08h*4 + 2]
mov [prevcsaddress], ax
;putting in new interrupt address
mov ax,0
mov ds,ax
mov word [ds:08h*4], temp
mov word [ds:08h*4 + 2],0x07c0
temp:
cli
mov ax, 0x07c0
mov ds, ax
mov es, ax ; used by int 0x10 13h
mov ax, 0x00
mov ss, ax
mov sp, 0x9c00
push DWORD msg ; pushing the address of msg
call _print
sub sp,2
push DWORD msg1
call _print
sub sp,2
sti
mov cs,[prevcsaddress]
jmp [previpaddress]
_print:
push bp
mov bp, sp
mov si, [bp+4]
mov ah,0x0e
mov bh,0
mov cx,1
loopprint:
lodsb
cmp al,00
je exitprint
int 0x10
jmp loopprint
exitprint:
pop bp
ret
msg db 'Welcome to the world of amazing things.',13,10,0
msg1 db 'I feel great pleasure in providing you with nothing',0
prevcsaddress dw 0
previpaddress dw 0
Actually, I want to execute the temp: part again and again continuously. So, I thought interrupt 08h which is a timer interrupt would do it continuously. But this thing is getting executed only twice:( Not continuously. Any suggestions?
Re: Interrupt not working properly
Posted: Sat Nov 04, 2006 4:58 am
by Brendan
Hi,
nitinjavakid wrote:Actually, I want to execute the temp: part again and again continuously. So, I thought interrupt 08h which is a timer interrupt would do it continuously. But this thing is getting executed only twice:( Not continuously. Any suggestions?
To be honest, I'm surprised it worked at all - your IRQ handler trashes registers in use by anything it interrupts. It also looks like you're getting your segments mixed up, assuming DS is normally equal to CS (DS can't be 0x0000 and 0x7C00 at the same time), which it should be unless you're using a really messed up linker script.
When the IRQ handler calls "print" it pushes 4 bytes and then pops 2 bytes. There's also no need to disable and then re-enable IRQs (the CPU does this automatically anyway).
The IRQ handler can't assume that the direction flag is set or cleared, so instructions like "lodsb" might go backwards (decrement SI instead of incrementing it). The code for "print" doesn't need a stack frame either, and it's a waste of time pushing it's arguments on the stack. I also like to write functions (like print) so they don't trash registers either - it makes it much easier to maintain the code.
Lastly, I have no idea how the assembler allowed something like "
mov cs,[prevcsaddress]" to assemble.
Code: Select all
;storing previous interrupt address
mov ax,0
mov ds,ax
mov ax,[ds:08h*4]
mov [cs:prevaddress], ax
mov ax, [ds:08h*4 + 2]
mov [cs:prevaddress + 2], ax
;putting in new interrupt address
; mov ax,0 <- not needed
; mov ds,ax <- not needed
mov word [ds:08h*4], temp
mov word [ds:08h*4 + 2],0x07c0
Code: Select all
;IRQ handler
temp:
push si
mov si,msg
call _print
mov si,msg1
call _print
pop si
jmp far [cs:prevaddress]
;Print the string at CS:SI
_print:
pusha
cld ; <- needed for "lodsb"
mov ah,0x0e
mov bh,0
loopprint:
cs lodsb ;Use CS segment override to avoid messing with segment registers
cmp al,00
je exitprint
int 0x10
jmp loopprint
exitprint:
popa
ret
msg db 'Welcome to the world of amazing things.',13,10,0
msg1 db 'I feel great pleasure in providing you with nothing',0
prevaddress dw 0,0
BTW I'd recommend using CS = DS = 0, and then putting "org 0x7C00" at the start of your boot loader (it makes things easier to figure out).
Cheers,
Brendan
Posted: Sat Nov 04, 2006 6:11 am
by nitinjavakid
But the code still doesnt work. I tried the new one. It still shows the message only one time.
Can gs be used while jumping?
Posted: Sun Nov 05, 2006 3:39 am
by nitinjavakid
come people! plzzzz help me! I am a complete newbie to os development.
Well actually a newbie to assembly as well
Posted: Sun Nov 05, 2006 4:04 am
by B.E
I think you should ether use GRUB and skip the boot loader part, or learn assembly(ie. tackle little things before tackling a giant).
One thing to note if temp is a ISR, then i should return with a iret not a just a ret
Posted: Sun Nov 05, 2006 4:58 am
by Brendan
Hi,
B.E wrote:One thing to note if temp is a ISR, then i should return with a iret not a just a ret
For "interrupt chaining" in real mode, the new IRQ handler jumps to the old IRQ hander in a way that the old IRQ still runs, and doesn't know the difference - that's why there's no EOI and no IRET...
@nitinjavakid: I can't see anything wrong that I didn't mention previously - is it possible to see all of your source?
Cheers,
Brendan
Posted: Sun Nov 05, 2006 7:40 am
by nitinjavakid
Code: Select all
;storing previous interrupt address
mov ax,0
mov ds,ax
mov word ax,[ds:08h*4]
mov word [previpaddress], ax
mov word ax, [ds:08h*4 + 2]
mov word [prevcsaddress], ax
;putting in new interrupt address
mov word [ds:08h*4], temp
mov word [ds:08h*4 + 2],0x07c0
temp:
cli
mov ax, 0x07c0
mov ds, ax
mov es, ax ; used by int 0x10 13h
mov ax, 0x00
mov ss, ax
mov sp, 0x9F00
push si
mov si, msg ; pushing the address of msg
call _print
mov si,msg1
call _print
pop si
sti
mov word gs,[prevcsaddress]
jmp far [gs:previpaddress]
_print:
pusha
cld
mov ah,0x0e
mov bh,0
mov cx,1
loopprint:
lodsb
cmp al,00
je exitprint
int 0x10
jmp loopprint
exitprint:
popa
ret
msg db 'Welcome to the world of amazing things.',13,10,0
msg1 db 'Damn',13,10,0
prevcsaddress dw 0
previpaddress dw 0
This is all i have written. Is there any limitations of es,gs,fs etc. I mean why cant they be used for indirect addressing in jmp instruction.
I think you should ether use GRUB and skip the boot loader part, or learn assembly(ie. tackle little things before tackling a giant).
Please name a good book on assembly using NASM.
Posted: Sun Nov 05, 2006 9:17 am
by Dex
First you need to disable ints, like this, from MiniDOS and try "CS" instead of 0x07c0.
Code: Select all
Installints:
push ds ; Save DS
cli ; Turn off int's
xor ax,ax
mov ds,ax ; 0 DS
mov word [ds:20h*4],int20 ; load int vecter with int20h address
mov word [ds:20h*4+2],cs ; + CS
mov word [ds:21h*4],int21 ; load int vecter with int21h address
mov word [ds:21h*4+2],cs ; + CS
sti ; Turn on int's
pop ds ; restore DS
ret ; Return
Also do not go to old timer, why are you saving old address when your rebooting.
Uses "iret" at end of your function.
Put this at end of function
Code: Select all
mov al, 0x20
out 0x20,al ; quiet screaming irq chip.
you should not use theres "cli" or "sti" in IRQ function as thats whats this, is for iret.
Posted: Sun Nov 05, 2006 10:41 am
by Brendan
Hi,
You need to tell the assembler where in memory your code starts and initialise a stack at the start of your code (NOT within the IRQ handler, which should use the interrupted code's stack).
You also need to give the CPU something to do in-between IRQs. The CLI/STI is still not needed.
It may have been a good idea to re-read my last post - your new code makes most of the mistakes I mentioned earlier (like not saving/restoring registers used by the IRQ handler).
Code: Select all
org 0x7C00
xor ax,ax
mov ds,ax
cli
mov ss,ax
mov sp,stackTop
sti
;storing previous interrupt address
mov word ax,[08h*4]
mov word [prevaddress], ax
mov word ax, [08h*4 + 2]
mov word [prevaddress+2], ax
;putting in new interrupt address
cli ; <- Dex was right about this!
mov word [08h*4], temp
mov word [08h*4 + 2],0
sti
;Lock up (nothing else to do while waiting for IRQs).
jmp $
;IRQ handler
temp:
push si
mov si,msg
call _print
mov si,msg1
call _print
pop si
jmp far [cs:prevaddress]
;Print the string at CS:SI
_print:
pusha
cld ; <- needed for "lodsb"
mov ah,0x0e
mov bh,0
loopprint:
cs lodsb ;Use CS segment override to avoid messing with segment registers
cmp al,00
je exitprint
int 0x10
jmp loopprint
exitprint:
popa
ret
section .data
msg db 'Welcome to the world of amazing things.',13,10,0
msg1 db 'Damn',13,10,0
align 4
section .bss
prevaddress resd 1
stack: resb 1024 ;1 KB stack space
stackTop:
section .text
This is all i have written. Is there any limitations of es,gs,fs etc. I mean why cant they be used for indirect addressing in jmp instruction.
First, any register you use in the IRQ handler must be saved and restored, but you can't restore anything
after the jump.
Secondly, "jmp far [gs:previpaddress]" will load CS:IP from the 2 words at [gs:previpaddress], it will not load CS with GS.
I'm also a little worried what you're intent is - using video functions within any IRQ handler is a bad idea.
Cheers,
Brendan
Posted: Sun Nov 05, 2006 11:44 am
by nitinjavakid
Splendid! Nice explaination. Also, one more thing,
mov ss,ax
in this statement, can ss be initialized to stack: ? If yes, what will be the effect on the overall program? Damn I have many doubts in my mind. Hope you dont mind it.
Regards,
Nitin
Posted: Sun Nov 05, 2006 12:38 pm
by JAAman
you must always initialize the stack first, rather than leave it at an unknown location:
the combination of:
mov SS, [reg16/32]
mov SP, [imm16/reg16]
will define where in memory your stack is located, and where 'push', 'pop', 'call', and interupts get/put the information, it is important that you place the stack out of the way where it will not overwrite anything, nor be overwritten by anything
remember the stack grows downwards (and is decremented before write) , so within the SS segment, SP should be initialized to the address 1 higher than the highest address you want it to use)
Posted: Sun Nov 05, 2006 1:18 pm
by nitinjavakid
Splendid! Great Help!
This forum rocks!!!
Posted: Sun Nov 05, 2006 11:24 pm
by nitinjavakid
Secondly, "jmp far [gs:previpaddress]" will load CS:IP from the 2 words at [gs:previpaddress], it will not load CS with GS.
So, suppose if we have address of a segment stored in some register say fs and the offset stored in another register say bx, then how can we jump to that particular location?
The JMP r/m forms execute a near jump (within the same segment), loading the destination address out of memory or out of a register. The keyword NEAR may be specified, for clarity, in these forms, but is not necessary. Again, operand size can be overridden using JMP WORD mem or JMP DWORD mem.
This is what the nasm manual tells. So I guess through register only jump within the present segment can be done? Am I right?
Posted: Mon Nov 06, 2006 1:47 am
by Brendan
Hi,
nitinjavakid wrote:Secondly, "jmp far [gs:previpaddress]" will load CS:IP from the 2 words at [gs:previpaddress], it will not load CS with GS.
So, suppose if we have address of a segment stored in some register say fs and the offset stored in another register say bx, then how can we jump to that particular location?
Basically, CS and IP must be loaded at the
same time - otherwise you end up executing code at the new CS and old IP (or at the old CS and the new IP).
To do this you need to have the new CS and IP at the same place. This means either storing them in memory somewhere and doing a "jmp far [indirect]" or pushing them on the stack and doing a "retf".
nitinjavakid wrote:The JMP r/m forms execute a near jump (within the same segment), loading the destination address out of memory or out of a register. The keyword NEAR may be specified, for clarity, in these forms, but is not necessary. Again, operand size can be overridden using JMP WORD mem or JMP DWORD mem.
This is what the nasm manual tells. So I guess through register only jump within the present segment can be done? Am I right?
Yes.
For your purposes (jumping to a previous IRQ handler) using any register won't work anyway, because you need to restore all registers to how they were before your IRQ handler started before doing the jump.
Cheers,
Brendan
Posted: Mon Nov 06, 2006 6:00 am
by nitinjavakid
Thanks again!