Page 1 of 1

[solved] Invalid jmp inside of an interrupt - real mode x86

Posted: Sun Feb 14, 2010 7:21 pm
by Lithorien
I'm working on a real mode OS, and currently working on getting interrupts hooked into the IVT. I've hooked the interrupts correctly and they work (mostly), but I've hit on a strange bug that I can't seem to track down.

When I call my OS' interrupt for getting a string from the keyboard, it works fine - until I type in a control character that I handle (enter or backspace - things like tab that I ignore work fine). Half the time I get junk characters printed to the screen, and half the time Bochs bombs out with a "LOCK prefix unallowed" issue. When I traced the execution, it appears that my jmp isn't pointing to the right address, but I can't figure out why that's happening.

Here's the code for my interrupt:

Code: Select all

Int32h:
	cli
	pusha
	
	cmp ah,0x0
	je .0
	
	jmp .done
	
	.0:
		xor cx,cx						; cx = Buffer count
	
		.cmd_loop:
			mov ah,0x1
			int 16h
			jz .cmd_loop
			
			mov ah,0
			int 16h
			
			cmp al,0x8					; 0x8 = Backspace
			je .backspace
			
			cmp al,0xD					; 0xD = CR
			je .end
			
			.store_buf:
				cmp cx,256
				je .cmd_loop
				
				mov ah,0x1
				int 31h
			
				stosb
				inc cx
				jmp .cmd_loop
				
			.backspace:
				cmp cx,0				; Beginning of string
				je .cmd_loop
				
				dec di
				mov BYTE [di],0
				dec cx
				
				mov ah,0x1
				int 31h
				
				mov al,' '
				mov ah,0x1
				int 31h
				
				mov al,0x08
				mov ah,0x1
				int 31h
				
				jmp .cmd_loop
			
			.end:
				mov al,0				; Null terminator
				stosb
				jmp .done
	
	.done:
		popa
		sti
		iret
Any help is appreciated. Thank you very much!

Edit: Ints 30 and 31 are also handled by my OS. If the code for those would help, please let me know and I'll add it to this post. Thanks!

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Sun Feb 14, 2010 10:30 pm
by Artlav
Which jmp's doesn't seem to work?
What looks wrong in the code is that i don't see where di is being initialized to a meaningful value. If it is not, the character is written into a random memory location, potentially - jmp command or so.

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 2:20 am
by qw
Are you sure the direction flag is clear?

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 4:06 am
by xenos
You could also enable memory tracing in Bochs, or set a memory watchpoint, just to see whether the jmp instruction gets overwritten at some point. Something similar once happened to me when I was using real mode the last time...

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 7:21 am
by jal
Artlav wrote:What looks wrong in the code is that i don't see where di is being initialized to a meaningful value.
Neither is es, so the stosb will fail as well. Come to think of it, neither is ds, so the interrupt routine will trash the calling program's data segment. I don't want to start insulting, but this is all basic stuff. Please...


JAL

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 7:49 am
by Lithorien
jal wrote:
Artlav wrote:What looks wrong in the code is that i don't see where di is being initialized to a meaningful value.
Neither is es, so the stosb will fail as well. Come to think of it, neither is ds, so the interrupt routine will trash the calling program's data segment. I don't want to start insulting, but this is all basic stuff. Please...


JAL
My segments are set in my kernel (which is loaded at 0:0x500, my stack points to 0:0x700)

Code: Select all

xor ax,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax

mov ss,ax
mov sp,0x700
And di is being set in the calling code - Buffer is defined as 'Buffer times 256 db 0', so I have a 256-byte buffer established already:

Code: Select all

mov di,Buffer
mov ah,0x0
int 32h
The jumps that are failing are the "je .backspace" and "je .end" jumps.
Hobbes wrote:Are you sure the direction flag is clear?
According to Bochs, df is clear.

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 8:08 am
by DednDave
you may need to save and restore DI and CX across the earlier INT's as well
that includes INT 16h and your INT 31h's
BIOS INT 16h probably doesn't mess with CX or DI
but, better safe than sorry
some machines out there may have crappy BIOS - lol

Code: Select all

         .backspace:
            cmp cx,0            ; Beginning of string
            je .cmd_loop
            
            dec di
;;;;            mov BYTE [di],0 ;no need to 0 this byte - it will be overwritten
            dec cx
            
            mov ah,0x1
            push di             ;save di - not sure, but you may need to save/restore ES as well
            push cx             ;save cx
            int 31h
            
            mov al,' '
            mov ah,0x1
            int 31h
            
            mov al,0x08
            mov ah,0x1
            int 31h
            pop cx              ;restore cx
            pop di              ;restore di
            
            jmp .cmd_loop
         
         .end:
            mov al,0            ; Null terminator
            stosb
;;;;            jmp .done       ;unnecessary branch
   
   .done:
      popa
      sti
      iret

Re: Invalid jmp inside of an interrupt - real mode x86 ASM

Posted: Mon Feb 15, 2010 8:34 am
by Lithorien
It's fixed, as far as I can tell.

When I moved my stack from 0x700 to 0x1000, the problems ceased. I think that I was trampling over existing code when the stack grew too large and so my jmp was getting modified-in-place. (I need to suck it up and move my stack to a memory location far above the kernel, I guess.)

Thank you all for your help - it's very appreciated.