Why does my subroutine crash when called from an ISR?

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.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

I've got a subroutine which, when called normally, executes fine and does not crash, but when I call it from an ISR, the system has some fault or another (not sure which kind, but it causes the machine to reset itself).

The subroutine is called "beep":

Code: Select all

beep:
	inb al, #0x0061
	or al, #0x03
	outb #0x0061, al
	mov cx, #0xFFFF
	mov dx, #0x0FFF
	mov bx, #0x0000
	loopba:
	mov ax, #0x0000
	loopaa:
	inc ax
	cmp ax, cx
	jne loopaa
	inc bx
	cmp bx, dx
	jne loopba
	inb al, #0x0061
	and al, #0xFC
	out #0x0061, al
	ret
When called from this ISR, the machine completes the beep (as in, the beep is continued for the same duration so it is not crashing part of the way through the beep) and then immediately resets itself:

Code: Select all

	call #0x0008:#beep+0x00007C00
	push ax
	mov al, #0x20
	outb 0x20, al
	pop ax
	iretd
This is in protected mode, without paging. The segments and addresses are all correct, as the "beep" subroutine is executed. I should maybe check if the crash is before the subroutine returns or after (back in the ISR), however I do not have time to check that now so will report back if/when I do.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Why does my subroutine crash when called from an ISR?

Post by kzinti »

To which IRQ are you hooking your ISR? Some processor interrupts will push a status code that you will need to pop before executing iretq.

Also, you aren't saving any registers and trashing a bunch of them...
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Why does my subroutine crash when called from an ISR?

Post by Brendan »

Hi,

The main reason this crashes is because you're using a "far call" (which pushes "return CS:EIP" on the stack) and then a "near ret" (which only pops a "return EIP" from the stack). This leaves a spare "return CS" to be left on the stack, which causes the IRETD to fail. Either change the call from "call #0x0008:#beep+0x00007C00" to "call #beep+0x00007C00"; or change the return from "ret" to "retf".

Also note that kiznit is correct - there are at least 2 more reasons why this could/would cause a crash.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

@kiznit: The ISR is hooked to the keyboard interrupt. Furthermore, if I remove the call to the subroutine, the ISR is (I assume) called when I press a key but does not do anything - the machine does not reset then. Thus the problem is not with returning from the ISR. Also the trashing of registers is currently not a problem, as I have the processor sitting in an inifinite jmp loop for now while I debug the ISR. Thus the value of the registers does not matter.

@Brenden: I use the same calling style from "normal" code and there is no problem. Furthermore, I just tested calling the subroutine twice before returning from the ISR and it beeps twice as it should. Thus the problem is not with the subroutine in any way, because it is able to return and be re-called without a crash.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Post by onlyonemac »

I just tried changing the ret to a retf and now it beeps twice when I press a key, does not reset, but does not beep if I then press another key. (To me this sounds like I am not acknowledging the interrupt correctly, but I was sure that I was.) I also don't understand why the calls were returnning properly even with the "wrong" ret statement, but causing the ISR to crash. In that case, i would have expected the machine to crash on returnning from the subroutine, not somewhere in the ISR.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Why does my subroutine crash when called from an ISR?

Post by iansjack »

Brendan explained why the "ret" call would return successfully but the subsequent "iret" wouldn't; the stack is left misaligned. A second subroutine call increases the misalignment, but will still return OK. It is only when the enclosing interrupt routine tries to return that the problem becomes apparent.
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Why does my subroutine crash when called from an ISR?

Post by Octocontrabass »

onlyonemac wrote:I also don't understand why the calls were returnning properly even with the "wrong" ret statement, but causing the ISR to crash. In that case, i would have expected the machine to crash on returnning from the subroutine, not somewhere in the ISR.
The interrupt pushes CS, then IP.

Stack: [ return CS ][ return IP ]

Your CALLF pushes CS, then IP.

Stack: [ return CS ][ return IP ][ ISR CS ][ ISR IP ]

Your RETN pops IP.

Stack: [ return CS ][ return IP ][ ISR CS ]

Your IRET pops the ISR CS into IP, and the return IP into CS. The return IP is not a valid code segment, so it crashes.


It probably works elsewhere because you never try to pop anything from the stack after calling the subroutine.

Why are you using CALLF anyway?
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

@octocontrabass: Thanks for the explanation. So essentially it doesn't matter, if I just call and return, call and return, etc. that it is returnning wrong because the CS doesn't actually change. But I get it now. The reason why I'm using a far call is because I'm still trying to figure out how to get my assembler to do an absolute near call, not a relative near call, because it does a relative call not to the address specified but rather jumping by the value specified, interpreting the address as an offset, resulting in the wrong address being executed.

The real question now though is why it works once, but not again.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Why does my subroutine crash when called from an ISR?

Post by iansjack »

You're not reading the keycode from the keyboard controller. Until you do that you will get no further interrupts from it.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

LOL yeah I think I knew that at one time.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Why does my subroutine crash when called from an ISR?

Post by Octocontrabass »

onlyonemac wrote:The reason why I'm using a far call is because I'm still trying to figure out how to get my assembler to do an absolute near call, not a relative near call, because it does a relative call not to the address specified but rather jumping by the value specified, interpreting the address as an offset, resulting in the wrong address being executed.
Your linker should be smart enough to generate the correct offset for a near CALL. What assembler/linker are you using?
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

According to http://x86.renejeschke.de/html/file_mod ... id_26.html, there doesn't seem to be a way to do an absolute near call.
Opcode Mnemonic Description
E8 cw CALL rel16 Call near, relative, displacement relative to next instruction
E8 cd CALL rel32 Call near, relative, displacement relative to next instruction
FF /2 CALL r/m16 Call near, absolute indirect, address given in r/m16
FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32
9A cd CALL ptr16:16 Call far, absolute, address given in operand
9A cp CALL ptr16:32 Call far, absolute, address given in operand
FF /3 CALL m16:16 Call far, absolute indirect, address given in m16:16
FF /3 CALL m16:32 Call far, absolute indirect, address given in m16:32
The only options are a relative near call, or an indirect absolute near call, or an absolute far call. This means that my functions which are at static addresses such that they can be called from any code even if it does not know the offset of the address need to use far calls (and thus far returns).
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Why does my subroutine crash when called from an ISR?

Post by Octocontrabass »

onlyonemac wrote:indirect absolute near call
That's still absolute. "Indirect" just means the destination address comes from a register or memory location instead of the operand.
onlyonemac wrote:This means that my functions which are at static addresses such that they can be called from any code even if it does not know the offset of the address need to use far calls (and thus far returns).
It sounds like you're writing position-independent code. You should look up some examples for an idea of how to make it work without far calls.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Why does my subroutine crash when called from an ISR?

Post by onlyonemac »

Octocontrabass wrote:Your linker should be smart enough to generate the correct offset for a near CALL. What assembler/linker are you using?
I'm using as86. Don't know about linkers - told it to make a raw binary. I don't think there's a linker involved. The problem is that I tell the assembler "ORG 0" even though the code's executing at 0x7C00, otherwise I get a file that's got 31744 zeros at the front. Thus when I give it an address to jump to, I have to add 0x7C00 to the address - unfortunately it interprets it that I want to add 0x7C00 to the offset. Besides, the point is not if it's doing a near or a far call; the point is that I need to call an absolute address.
Octocontrabass wrote:That's still absolute. "Indirect" just means the destination address comes from a register or memory location instead of the operand.
Yeah I know that, but I don't want to waste memory/registers with having to specify an address. It's easier to just keep all absolute calls as far calls.
Octocontrabass wrote:It sounds like you're writing position-independent code. You should look up some examples for an idea of how to make it work without far calls.
No it's not position-independent code. It's a few low-level utility routines (such as "beep") which need to be located at known addresses such that they can be called from anywhere wihtout having to calculate an offset. Thus I can call them simply by calling their address - except that that's proving more complicated than it should be.

I think I'll just stick with the far calls.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Why does my subroutine crash when called from an ISR?

Post by iansjack »

onlyonemac wrote:
Octocontrabass wrote:That's still absolute. "Indirect" just means the destination address comes from a register or memory location instead of the operand.
Yeah I know that, but I don't want to waste memory/registers with having to specify an address. It's easier to just keep all absolute calls as far calls
You are wasting more memory by making far calls than if you used indirect near calls.

The real answer real is to use a proper assembler/linker so that you can make all calls relative and save even more memory.
Post Reply