Page 1 of 1

Far jump in assembly

Posted: Tue Nov 11, 2008 10:42 am
by thestew42
Alright, I know I'll probably get flamed for this but I'm having some trouble with far jumps. I understand how they work, but I'm having trouble actually implementing one. I'm writing part of a boot program that executes a far jump into 32 bit code after entering protected mode. The problem is that I have no idea what segment number to use. The code segment being used by the second stage boot program is 0x0050 and the label for the 32 bit code section is clear_pipe so I'm just doing this:

jmp 0x0050:clear_pipe

but bochs keeps giving me an error

3rd (13) exception with no resolution. I'll post the code with some modifications to shorten it.

Code: Select all

[BITS 16]      ;16 bit code generation
[ORG 0x0000]

START:
	;Adjust segments
	cli
	mov		ax, 0x0050
	mov 	es, ax
	mov     ds, ax
	mov     fs, ax
	mov     gs, ax
	
	;Print status message
	mov si, msgLoading
	call WriteMessage
	
	;Check for compatible processor
	call detect_cpu
	
	;Enable A20 Line
	call enableA20
	
	;Enter protected mode
	cli                     ; Disable interrupts, we want to be alone

    xor ax, ax
    mov ds, ax              ; Set DS-register to 0 - used by lgdt

    lgdt [gdt_desc]         ; Load the GDT descriptor

    mov eax, cr0            ; Copy the contents of CR0 into EAX
    or eax, 1               ; Set bit 0
    mov cr0, eax            ; Copy the contents of EAX into CR0

    ;Far jump to 32 bit code
    jmp 0x0050:clear_pipe

;********************Check CPU for 386 or higher************************
detect_cpu:
	;Omitted

;**********************Enable A20 Line*******************************
enableA20:
	;Omitted

;**********************Message Procedure*****************************
        ;Omitted

;*************************Protected Mode Code************************
[BITS 32]                       ; We now need 32-bit instructions
clear_pipe:
		jmp $
        mov ax, 10h             ; Save data segment identifyer
        mov ds, ax              ; Move a valid data segment into the data segment register
        mov ss, ax              ; Move a valid data segment into the stack segment register
        mov esp, 090000h        ; Move the stack pointer to 090000h

        mov byte [ds:0B8000h], 'P'      ; Move the ASCII-code of 'P' into first video memory
        mov byte [ds:0B8001h], 1Bh      ; Assign a color code

hang:
        jmp hang                ; Loop, self-jump

;**********************Global Descriptor Table***********************
        ;Omitted
Thanks for any help

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 10:50 am
by AJ
Hi,

It looks like you are confusing real mode and protected mode segments. Does the GDT entry at offset 0x50 even exist? Remember that you are already in PMode by the time you do that far jump, so you need to be using a PMode segment for the far jump.

Chances are that you want 0x08:clear_pipe, but I would need to see your GDT to confirm this. Also remember that LGDT uses DS while you are still in Real Mode, so DS needs to point to the correct real mode segment before you load your GDT.

If this fails, Bochs should give you some extended information about why you triple-faulted (probably a GPF). Any chance of seeing this extended info and register dump?

Cheers,
Adam

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 11:00 am
by thestew42
Wow. I didn't even realize that the segments would change, thanks for that information. I got this protected mode stuff from a tutorial that I read, and I was going to get the code working before I actually started to look into building the GDT. As a result, this GDT was just copied:

Code: Select all

;**********************Global Descriptor Table***********************
gdt:                    ; Address for the GDT

gdt_null:               ; Null Segment
        dd 0
        dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
        dw 0FFFFh
        dw 0
        db 0
        db 10011010b
        db 11001111b
        db 0

gdt_data:               ; Data segment, read/write, expand down
        dw 0FFFFh
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0

gdt_end:                ; Used to calculate the size of the GDT



gdt_desc:                       ; The GDT descriptor
        dw gdt_end - gdt - 1    ; Limit (size)
        dd gdt                  ; Address of the GDT
and here is the log

Code: Select all

00000004256i[BIOS ]  rombios.c,v 1.85.2.1 2003/01/16 21:58:42 cbothamy Exp $
00000330043i[KBD  ] reset-disable command received
00000506792e[HD   ] device set to 0 which does not exist
00000507085e[HD   ] device set to 1 which does not exist
00000618429e[CPU  ] jump_protected: dpl > CPL
00000618429p[CPU  ] >>PANIC<< exception(): 3rd (13) exception with no resolution
00000618429i[SYS  ] Last time is 1226422142
00000618429i[CPU  ] protected mode
00000618429i[CPU  ] CS.d_b = 16 bit
00000618429i[CPU  ] SS.d_b = 16 bit
00000618429i[CPU  ] | EAX=60000011  EBX=00000007  ECX=000b0004  EDX=00000fff
00000618429i[CPU  ] | ESP=0000fffb  EBP=00000000  ESI=000001b7  EDI=00000005
00000618429i[CPU  ] | IOPL=0 NV UP DI PL NZ NA PE NC
00000618429i[CPU  ] | SEG selector     base    limit G D
00000618429i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00000618429i[CPU  ] |  DS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000618429i[CPU  ] |  ES:0050( 0000| 0|  0) 00000500 0000ffff 0 0
00000618429i[CPU  ] |  FS:0050( 0000| 0|  0) 00000500 0000ffff 0 0
00000618429i[CPU  ] |  GS:0050( 0000| 0|  0) 00000500 0000ffff 0 0
00000618429i[CPU  ] |  SS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000618429i[CPU  ] |  CS:0050( 0000| 0|  0) 00000500 0000ffff 0 0
00000618429i[CPU  ] | EIP=0000002e (0000002e)
00000618429i[CPU  ] | CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
00000618429i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00000618429i[     ] restoring default signal behavior
00000618429i[CTRL ] quit_sim called with exit code 1
Thank you!

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 11:05 am
by AJ
Hi,

In real mode, you obtain a linear address by adding the segment * 0x10 to the offset, so:

0x1000:0x0002 == 0x10002 linear.

In protected mode, the segment is a selector in to the GDT and the offset becomes 32 bit. I have not checked every bit in your GDT, but you definitely need to use the selector 0x08. I'm not too sure why Bochs is complaining about the DPL, because the error should be that you have read beyond the limit of the GDT. This could be to do with DS being incorrect before the LGDT instruction and the CPU therefore loading an incorrect value in to GDTR.

[edit]Standard addition to this reply: Get the Intel Manuals :) [/edit]

Cheers,
Adam

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 11:34 am
by thestew42
Ok. Does that mean that all of the memory is one segment? It looks like that GDT only has two real entries.

Also, before I load the GDT, what do you mean by the data segment being set. What should it be set to? I believe that the code sets the ds register to 0x50 just like all of the other segment registers.

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 1:16 pm
by AJ
Hi,

Yes - that GDT places all potential 4GiB of memory in to a single segment (well - one segment for code and the other is used for data access, but both use the same memory space).

As for DS being set, the GDTR is loaded from DS:offset, so you need to verify that DS points where you want it to. If this isn't clear, you need to do some background reading from the intel manuals (and the wiki).

Cheers,
Adam

Re: Far jump in assembly

Posted: Tue Nov 11, 2008 1:34 pm
by Love4Boobies
Just so you're not confused: in this case you have a segment covering the whole memory, but it's not a must. It is a common architecture, though.