Page 1 of 1

Bound Range Exceeded Exception on jmp [solved]

Posted: Sun May 04, 2008 7:06 am
by Stevo14
So, I'm back to trying to get "shutting down" to work in my kernel. I'm using the guide here->http://www.osdever.net/tutorials/pm.php in order to switch back to real mode to call the APM functions. The second step says to do a far jump to a 16 bit code segment. I have created a 16bit code segment in my GDT at offset 0x18 and I have loaded the 16bit shutdown code so that the code starts at 0x2000. When I try to jump to the code, however, I get this weird "Bound Range Exceeded" exception. I have read the Intel manuals and, as far as I can tell, this exception can only be thrown by a BOUNDS instruction. I have never used the BOUNDS instruction so I guess it is being inserted by NASM. If anyone could shed some light on this it would be greatly appreciated.

Posted: Sun May 04, 2008 10:32 am
by Dex
Does this help, its fasm code written for DexOS by smiddy:

Code: Select all

PowerDown:

    call DisableAllIRQs       
    mov al,11h
    out 020h,al
    out 0A0h,al

    mov al,08h
    out 021h,al

    mov al,070h
    out 0A1h,al

    mov al,4
    out 021h,al

    mov al,2
    out 0A1h,al

    mov al,1
    out 021h,al
    out 0A1h,al
    jmp 28h:RealModePowerDown

use16

PowerManagmentVersion dw 0
NoPowerManagment      db 'No power management functionality',10,13,0
ErrorMessage          db 'Power management error',10,13,0
WrongVersion          db 'Need APM version 1.1 or better',10,13,0

RealModePowerDown:

    mov ax,30h
    mov ds,ax
    mov ss,ax
    nop

    mov bx,[RealModeCS]
    push bx
    lea bx,[DoPowerDownRealMode]
    push bx

    mov eax,cr0
    and al,0xFE
    mov cr0,eax

    retf

DoPowerDownRealMode:

    mov ax,cs                               ; Save CS to AX
    mov ds,ax                               ; Put DS to CS
    mov ax,[StackSegment]                   ; Save original stack segment to AX
    mov ss,ax                               ; Replace original stack segment
    mov ax,[StackPointer]                   ; Save the stack pointer to AX
    movzx esp,ax                            ; and Replace original stack pointer (force 16 bit)
    nop                                     ; Take a CPU clock tick
    mov es,ax                               ; Update ES with AX
    mov fs,ax                               ; Update FS with AX
    mov gs,ax                               ; Update GS with AX

    ;;;;;;;;;;;;;;;;;;;;;;;
    ;; Load real mode IDTR
    ;;;;;;;;;;;;;;;;;;;;;;;

    lidt [RIDTR]                            ; Load original IVT from 0000:0000
    push cs                                 ; Put CS on stack
    pop ds                                  ; Put CS from stack to DS
    push ds                                 ; Save DS to the stack
    pop es                                  ; Update ES with DS from stack

    mov al,0                                ; Re-enable realmode IVT by turning on all IRQs
    out 0A1h,al                             ; Updates lower 7 IRQs
    out 021h,al                             ; Updates upper 8 IRQs
    sti                                     ; Re-enable interrupts

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Now to do the real mode interrupt
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

   mov ax,5300h                     ; See if APM available
   mov bx,0                         ; device = BIOS
   int 15h
   mov si,NoPowerManagment
   jc .Error
   cmp ax,101h                      ; See if version 1.1 or greater
   mov dx,WrongVersion
   jc .Error
   mov [PowerManagmentVersion],ax
   mov ax,5301h                     ; Do a real mode connection
   mov bx,0                         ; device = BIOS
   int 15h
   jnc .NoConnectionError
   cmp ah,2                         ; Pass if already connected
   mov si,ErrorMessage              ; else error
   jnz .Error

.NoConnectionError:

   mov ax,530eh                     ; Enable latest version of APM
   mov bx,0                         ; device = BIOS
   mov cx,[PowerManagmentVersion]   ; version
   int 15h
   mov si,ErrorMessage
   jc .Error
   mov ax,530dh                     ; Now engage and enable CPU management
   mov bx,1                         ; device = all
   mov cx,1                         ; enable
   int 15h
   mov si,ErrorMessage
   jc .Error
   mov ax,530fh
   mov bx,1                         ; device = ALL
   mov cx,1                         ; enable
   int 15h
   mov si,ErrorMessage
   jc .Error
   mov ax,5307h                     ; Do the power down
   mov bx,1                         ; device = ALL
   mov cx,3                         ; mode = OFF
   int 15h                          ; shutdown CPU
   mov si,ErrorMessage

.Error:

   call PrintString
   jmp CheckCodeSegment             ; Change this to the DOS check for EXIT or REBOOT
;   ret

Use32                               ; No expected return


Re: Bound Range Exceeded Exception on jmp

Posted: Sun May 04, 2008 2:41 pm
by Combuster
Stevo14 wrote:I have never used the BOUNDS instruction so I guess it is being inserted by NASM.
You too, young padawan, must learn not to blame the compiler.


You're probably executing somewhere in the data area. Have you at least tried using bochs' debugger?

Re: Bound Range Exceeded Exception on jmp

Posted: Sun May 04, 2008 3:33 pm
by Stevo14
Combuster wrote:
Stevo14 wrote:I have never used the BOUNDS instruction so I guess it is being inserted by NASM.
You too, young padawan, must learn not to blame the compiler.
Yea, sorry. That was just my first instinct. I will continue to learn. :)
Combuster wrote: You're probably executing somewhere in the data area. Have you at least tried using bochs' debugger?
No, I have not. I had endless problems trying to compile a version with debugging enabled, so I just stuck with the default package.

@Dex: If I'm following the code correctly, it doesn't use a jmp command to set the code segment but rather pushes the code segment and address onto the stack and then simulates a return. Is there any specific reason for this?

Re: Bound Range Exceeded Exception on jmp

Posted: Sun May 04, 2008 9:26 pm
by Dex
Stevo14 wrote:
@Dex: If I'm following the code correctly, it doesn't use a jmp command to set the code segment but rather pushes the code segment and address onto the stack and then simulates a return. Is there any specific reason for this?
Its just one of the instructions that change the CS register like:
jmp (far)
retf
iret

I have written many demos, one that demos go to and from real mode to pmode, for vesa mode switching, it may help you, with your problem.
http://www.dex4u.com/demos/VesaDemo.zip

Re: Bound Range Exceeded Exception on jmp

Posted: Mon May 05, 2008 7:16 am
by Stevo14
I feel like a total idiot.... I forgot to tell Bochs to load the shutdown code as a module so I was, in fact, trying to jump into some random garbage instead of my code... :roll:
Dex wrote: I have written many demos, one that demos go to and from real mode to pmode, for vesa mode switching, it may help you, with your problem.
http://www.dex4u.com/demos/VesaDemo.zip
Thanks for that link. After realizing my stupid mistake I used your demo to help me get into real mode. Now I'm back to where I was last time, getting interrupts to work. I have loaded the Ivt using the lidt instruction (like in the demo) but whenever I invoke an interrupt (int 0x10 for example) it seems to jump off into some random piece of memory.

Here are the relevant portions of code:

Code: Select all

;***********************************************************;
;*************         Protected Mode         **************;
;***********************************************************;
use32
exit_pmode:
		
	cli				;make sure interrupts are disabled

	;clear all registers
	xor eax,eax
	xor ebx,ebx
	xor ecx,ecx
	xor edx,edx

	xor esp,esp
	xor ebp,ebp

	xor esi,esi
	xor edi,edi	

	;point the processor to the real mode gdt
	lgdt [gdtr]

	;load the real mode data segments
	mov   ax,0x10

	mov   ds,ax

	mov   ss,ax
	mov   es,ax
	mov   fs,ax
	mov   gs,ax

	nop

	;load the real mode code segment
	jmp 0x08:exit_pmode2

exit_pmode2:
	;disable protection (go into real mode)
	mov   eax,cr0

	and   al,0xFE

	mov   cr0,eax


;***********************************************************;
;*************        Start Real Mode         **************;
;***********************************************************;
use16
init_real_mode:

	;realmode segments
	mov   ax,0x00

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

	mov	ax,rm_stack_bottom
	mov   ss,ax

	;point the processor to the real mode interrupt table
	lidt [idtr]

	;load the realmode stack
	mov ax,rm_stack_top
	mov sp,ax
	mov ax,0x0000
	mov bp,ax

	sti	;re enable interrupts

and the declarations at the end of the code:

Code: Select all

rm_stack_bottom:
	resb 0x1000
rm_stack_top:

idtr:
	dw 0xFFFF			;idt limit
	dd 0x00000000		;idt base

gdtr:	
	dw gdt_end - gdt - 1		   ; GDT limit
	dd gdt				   ; (GDT base gets set above)

gdt:					   ; Address for the gdt 
	dw 0				   ; limit 15:0    (0h) Null Segment
	dw 0				   ; base 15:0
	db 0				   ; base 23:16
	db 0				   ; type
	db 0				   ; limit 19:16, flags
	db 0				   ; base 31:24

real_code_1:				   ; (20h) Real mode code segment
       dw 0xFFFF
       dw 0						 
       db 0
       db 10011010b						  
       db 0						  
       db 0

real_data_1:				   ; (28h) Real mode data segment
       dw 0xFFFF
       dw 0						  
       db 0
       db 10010010b						  
       db 0						  
       db 0
gdt_end:				   ; Used to calculate the size of the GDT
EDIT: More specifically, it seems things go wrong when the processor tries to return from an interrupt. A good example is using int 10 to print a character. The character is printed fine but after it is printed it starts running off into unknown memory.

Posted: Mon May 05, 2008 12:29 pm
by Dex
Here things to watch:
1. do you remap pic on entering pmode ?, as these may need setting back.
2. In the demo and my OS, i set addressing identical in realmode and protected mode, by setting the base of the code and data descriptors to DS * 16.
If not you have to do this each time you switch to realmode from pmode and use pointers etc.

3. Is the realmode stack below 1MB ?.

Are you sure this is right

Code: Select all

	jmp 0x08:exit_pmode2
8h does not seem right, also you first go from pmode to 16bit pmode, than realmode

Here some well commented code that may help, nasm this time

Posted: Mon May 05, 2008 4:29 pm
by Stevo14
Dex wrote:Here things to watch:
1. do you remap pic on entering pmode ?, as these may need setting back.
Yes, I do but I didn't think about remapping it back. This seems like a likely culprit. I will look into it.
Dex wrote: 2. In the demo and my OS, i set addressing identical in realmode and protected mode, by setting the base of the code and data descriptors to DS * 16.
If not you have to do this each time you switch to realmode from pmode and use pointers etc.
I'm not exactly sure what you mean by this. In my OS the segments for pmode have a base of 0x00 and a limit of 4GB. I change this though by loading the 16bit pmode gdt.
Dex wrote: 3. Is the realmode stack below 1MB ?.
Yes. It actually comes right after the code at about 0x2000. It has a size of 0x1000 (and it grows downward).
Dex wrote: Are you sure this is right

Code: Select all

	jmp 0x08:exit_pmode2
8h does not seem right, also you first go from pmode to 16bit pmode, than realmode
0x08 is the offset in the new gdt to the 16bit code selector.
Dex wrote: Here some well commented code that may help, nasm this time
Thanks again. Well commented sample code is much appreciated. :)

Posted: Mon May 05, 2008 4:54 pm
by Stevo14
Hey, It works now! My mistake was rather simple. I wasn't properly setting the real mode code segment. All I did was add

Code: Select all

;realmode code segment
jmp 0x00:rmode
and it worked! I can post the full code if someone wants it. It has also been committed to the goglecode repository if someone wants to get it that way.

Many thanks to all who helped me. :)