pmode switch doesn't work correctly

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.
Post Reply
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

pmode switch doesn't work correctly

Post by sevobal »

Hi,
I've written a real-mode OS with a console so the user can give commands to it. The bootsector of the flopp disk just loads sector 1 - 19 to the position 0X1000:0x0000 and jumps to it to execute the OS. This works perfectly. Now if the user enters 'PM' at the console the system shut switch to protected mode. But this doesn't work and I don't why. Maybe I've missed something :(

Here is my code:

Code: Select all

; Code is now at 0x1000x0x0000

; Here is some code of my real-mode is.

; User enters 'PM'

        jmp kernel_pmode:

; Here are also some functions of my real-mode OS



; Let's try to switch
kernel_pmode:

    jmp p_start
   
gdt:

gdt_null:
    dd 0x00
    dd 0x00

gdt_code:
    dw 0xFFFF        ; Size of 65535
    dw 0x00
    db 0x1000        ;Because code is at 0x1000:0x0000
    db 10011010b    ;segment is in memory, priority 0, executable and readable
    db 11001111b    ;4096 KB, 80386 segment
    db 0x00

gdt_data:
    dw 0xFFFF        ; Size of 65535
    dw 0x00
    db 0x1000        ;Because code is at 0x1000:0x0000
    db 10010010b    ;segment is in memory, priority 0, writeable and readable
    db 11001111b    ;4096 KB, 80386 segment
    db 0x00

gdt_end:

GDT32:
    Limit    dw gdt_end - gdt - 1    ;limit (size)
    BaseAdr    dd gdt
   
p_start:
    lgdt [GDT32]
   
    cli
   
    mov eax, 000000011h
    mov cr0, eax
   
    ; "FAR-JMP"
    db 0eah
    dw now_in_prot
    dw 0x08
   
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 32-Bit protected mode
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
now_in_prot:

    jmp $
User avatar
ManOfSteel
Member
Member
Posts: 60
Joined: Tue Feb 01, 2005 12:00 am

Post by ManOfSteel »

You load it with int 13h at 0X1000:0x0000, but are you sure your above code is actually running there? What's your org xxxx value?
For example, if you have org 0 you would have to adjust all your memory references so they point to 0X1000:0x0000 or else you'd be running code (or even data) contained elsewhere instead of your PM code.

Also, when switching to PM without paging, you usually only have to set the PE bit on (i.e. bit 0):

Code: Select all

mov eax, cr0
or al,1
mov cr0,eax
And bit 4 tells you if there's a coprocessor or not.
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

My bootloader has org 0x7c20, but my kernel didn't has any org xxxx. So I tried org 0x1000, but now the kernel doesn't work correctly. Any other possibilities for org xxxx or something else?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

You do know what "org" does? Or are you just guessing / doing trial & error?
Every good solution is obvious once you've found it.
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

org sets the start adresse of the actual segment in which org is placed. If org isn't set the program starts at 0.

I think this should be correct.
iammisc
Member
Member
Posts: 269
Joined: Thu Nov 09, 2006 6:23 pm

Post by iammisc »

doesn't the limit come *after* the base address in the gdt pointer?
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

And where,s the use32 or [BITS 32], just before the now_in_prot label ?.
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

Okay guys here we go again:

I modified this code a little bit and now I've this one. The PC stands for about 5 seconds in pmode or trying to switch into, but then restarts again.

Code: Select all

jmp p_start
   
gdt:

gdt_null:
    dd 0x00
    dd 0x00

gdt_code:
    dw 0xFFFF        ; Size of 65535
    dw 0x00
    db 0x10         ;Because code is at 0x1000:0x0000
    db 10011010b    ;segment is in memory, priority 0, executable and readable
    db 11001111b    ;4096 KB, 80386 segment
    db 0x10

gdt_data:
    dw 0xFFFF        ; Size of 65535
    dw 0x00
    db 0x10         ;Because code is at 0x1000:0x0000
    db 10010010b    ;segment is in memory, priority 0, writeable and readable
    db 11001111b    ;4096 KB, 80386 segment
    db 0x00

gdt_end:

GDT32:
    Limit		dw 3 * 8
    BaseAdr		dd gdt + 0x10000
   
p_start:
	mov ax,cs
    and eax,0FFFFh
    shl eax,4
    add ax,p_start

    mov word [gdt_code+2],ax
    shr eax,16
    mov byte [gdt_code+4],al
    
    mov ax,cs
    and eax,0FFFFh
    shl eax,4
    add ax,p_start

    mov word [gdt_data+2],ax
    shr eax,16
    mov byte [gdt_data+4],al
                
    lgdt [GDT32]
   
    cli
   
    mov eax, cr0
	or al,1
	mov cr0,eax
   
    ; "FAR-JMP"
    db 0eah
    dw now_in_prot
    dw 0x08
   
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 32-Bit protected mode
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
now_in_prot:

	jmp $
User avatar
ManOfSteel
Member
Member
Posts: 60
Joined: Tue Feb 01, 2005 12:00 am

Post by ManOfSteel »

@iammisc:
doesn't the limit come *after* the base address in the gdt pointer?
No, the limit is 0-15 and the base is 16-47 (or 16-79).


@sevobal:
My bootloader has org 0x7c20
0x7c20?
org sets the start adresse of the actual segment in which org is placed.
org xxxx sets the address where the rest of your code is expected to be running, i.e. it adds xxxx to every memory reference in your code. Keep in mind it doesn't actually move anything.
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

Sorry my bootloader is of course at 7c00.
I tried to debug with bochs and get this:

Code: Select all

00200832996i[CPU0 ] BxError: instruction with opcode=0xff
00200832996i[CPU0 ] mod was c0, nnn was 7, rm was 7
00200832996i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)
00200832996i[CPU0 ] protected mode
00200832996i[CPU0 ] CS.d_b = 32 bit
00200832996i[CPU0 ] SS.d_b = 16 bit
00200832996i[CPU0 ] EFER   = 0x00000000
00200832996i[CPU0 ] | RAX=0000000000000011  RBX=0000000000000001
00200832996i[CPU0 ] | RCX=0000000000000607  RDX=0000000000000e00
00200832996i[CPU0 ] | RSP=000000000000fffc  RBP=0000000000000000
00200832996i[CPU0 ] | RSI=00000000ffff0849  RDI=0000000000080000
00200832996i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00200832996i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00200832996i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00200832996i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00200832996i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00200832996i[CPU0 ] | SEG selector     base    limit G D
00200832996i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00200832996i[CPU0 ] |  CS:0008( 0001| 0|  0) 10010aac 000fffff 1 1
00200832996i[CPU0 ] |  DS:1000( 0005| 0|  0) 00010000 0000ffff 0 0
00200832996i[CPU0 ] |  SS:9000( 0005| 0|  0) 00090000 0000ffff 0 0
00200832996i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00200832996i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00200832996i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00200832996i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00200832996i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00200832996i[CPU0 ] | RIP=0000000000000af1 (0000000000000af1)
00200832996i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
00200832996i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00200832996i[CPU0 ] >> (invalid)  : FFFF
00200832996e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Could this be usefull for someone here?
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

looks like the base of your CS is really wrong. why do you have a base anyway. It is way safer to just use zero. Further more you are in protected mode now so set DS en SS also to the correct value 0x10 in your case.
Author of COBOS
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

I correct ds and ss:

Code: Select all

...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 32-Bit protected mode
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
now_in_prot:

	mov ax,0x10		; Segmentregister laden
	mov ds,ax
	mov ss,ax
		
	jmp $
But where should I correct the wrong cs? (And then why I'm not needing a base for it?)
User avatar
ManOfSteel
Member
Member
Posts: 60
Joined: Tue Feb 01, 2005 12:00 am

Post by ManOfSteel »

You must add the address (10000h) to all your memory references (including "dw now_in_prot"), but this may be a problem in 16bit code so I suggest you divide all your addresses by 16 (eg: 1000h->100h, 10000h->1000h).

You indeed have to set ds and ss, but that not what's causingthe tripple fault anyway.
sevobal
Member
Member
Posts: 63
Joined: Sun Oct 22, 2006 7:11 am

Post by sevobal »

At this point I would like to thank you for your patience.

Now I'm getting this:

Code: Select all

00797242979e[CPU0 ] jump_protected: call gate.p == 0
00797242979e[CPU0 ] fetch_raw_descriptor: GDT: index (f007)1e00 > limit (18)
00797242979i[CPU0 ] protected mode
00797242979i[CPU0 ] CS.d_b = 16 bit
00797242979i[CPU0 ] SS.d_b = 16 bit
00797242979i[CPU0 ] EFER   = 0x00000000
00797242979i[CPU0 ] | RAX=0000000000000011  RBX=0000000000000001
00797242979i[CPU0 ] | RCX=0000000000000607  RDX=0000000000000e00
00797242979i[CPU0 ] | RSP=000000000000fffc  RBP=0000000000000000
00797242979i[CPU0 ] | RSI=00000000ffff0849  RDI=0000000000080000
00797242979i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00797242979i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00797242979i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00797242979i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00797242979i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00797242979i[CPU0 ] | SEG selector     base    limit G D
00797242979i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00797242979i[CPU0 ] |  CS:1000( 0004| 0|  0) 00010000 0000ffff 0 0
00797242979i[CPU0 ] |  DS:1000( 0005| 0|  0) 00010000 0000ffff 0 0
00797242979i[CPU0 ] |  SS:9000( 0005| 0|  0) 00090000 0000ffff 0 0
00797242979i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00797242979i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00797242979i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00797242979i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00797242979i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00797242979i[CPU0 ] | RIP=0000000000000aba (0000000000000aba)
00797242979i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
00797242979i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00797242979i[CPU0 ] >> jmp far 0008:0abf : EABF0A0800
00797242979e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
I think it's a problem with the far-jmp or is there something more?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

You have yet another org xxx related issue

Code: Select all

p_start:
   mov ax,cs
    and eax,0FFFFh
    shl eax,4
    add ax,p_start 
your code is assembled to the start of the file while you try to modify the GDT to make the offset relative to some point halfway into the file.

Other than that, you get an error that you are calling a call gate, which is something not present in your GDT. That means it either got corrupted or that you are looking at something that isn't the GDT
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply