Page 1 of 1

Am I in protected mode yet?

Posted: Thu Jul 07, 2011 1:49 pm
by rspencer
Hi,

I am fairly new to the level of programming required for osdev and was wondering if I am missing something stupid in the following problem:
I am following many different tutorials and am always getting stuck at one point: protected mode.
My code currently reads as follows (an extract):

Code: Select all

cli
mov	al, 2	; set bit 2 (enable a20)
out  0x92, al
call InstallGDT
jmp 0x1000 : Stage3
Stage3:		
  mov  eax, cr0			; set bit 0 in CR0-go to pmode
  or  eax, 1
  mov  cr0, eax
  hlt
This runs fine on Bochs. However I am wondering about the following:
1) That jump statement. I am told by numerous sources that it should be jmp 0x08 for my GDT and ds. However implementing this results in a triple fault. (I am loaded at 0x10000)
2) The order of my commands. Should I be jumping before setting cr0 or after? Jumping after gave a fault. Also, when should I enable A20?
3) Am I actually in pmode by the hlt statement???

I understand if you get impatient with my questions which may have obvious solutions but I have trawled the web and consulted tutorials 'till I was blue in the face. Everything they suggested ran into triple faults when I ran it. This suggests another alternative. Is there anything I need to know about setting up bochs that may help?

Any help would be much appreciated.
Thanks.

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 1:56 pm
by AJ
Hi and Welcome,
rspencer wrote:1) That jump statement. I am told by numerous sources that it should be jmp 0x08 for my GDT and ds. However implementing this results in a triple fault. (I am loaded at 0x10000)
This is because of:
rspencer wrote:2) The order of my commands. Should I be jumping before setting cr0 or after? Jumping after gave a fault. Also, when should I enable A20?
You need to set the protected mode bit before the jump. You have not entered PMode until you have jumped, as it's the far jump that makes CS point to a GDT offset rather than a real mode segment.
3) Am I actually in pmode by the hlt statement???
No :)

You should then be able to load the various segment registers and hlt with no triple fault (provided you don't re-enable interrupts until you have loaded a valid PMode IDT.

Cheers,
Adam
[edit: BTW, enable A20 before going to PMode - on computers that still pay any attention to A20, you will otherwise find that you can only access alternate megabyte ranges of memory otherwise]

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 1:59 pm
by rspencer
Ok, my code now reads:

Code: Select all

cli
mov	al, 2	; set bit 2 (enable a20)
out	0x92, al


call InstallGDT

 	mov		eax, cr0			; set bit 0 in CR0-go to pmode
	or		eax, 1
	mov		cr0, eax
	jmp 0x8: Stage3

Stage3:		

	hlt
But this too triple faults :(. (The same story if I say jmp 0x1000: Stage3)

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 2:06 pm
by xenos
Could you post the code in InstallGDT and the contents of your GDT?

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 2:08 pm
by rspencer
My whole code is:

Code: Select all

[org 0x0000]
[bits 16]
mov si,letter
call ptstr
mov ax,0x0E61
int 10h
;
mov ax,0x0E62
int 10h

cli
mov	al, 2	; set bit 2 (enable a20)
out	0x92, al


call InstallGDT

 	mov		eax, cr0			; set bit 0 in CR0-go to pmode
	or		eax, 1
	mov		cr0, eax
	jmp 0x8: Stage3

Stage3:		

	hlt



	mov		ax, 0x10		; set data segments to data selector (0x10)
	mov		ds, ax
	mov		ss, ax
	mov		es, ax
	mov		esp, 90000h
;---------------------------------------------------------------------------------
ptstr:                      ; Prints a null terminated string, starting at [es:si]
	pusha

.go:
  lodsb                     ; Load Byte
  or al, al                 ; Compare to 0
  jz .rt                    ; If null, return
  
  mov ah,0x0E
  int 0x10
	jmp .go 
.rt:
	popa
  ret                       ; Return

InstallGDT:
 
	cli				; clear interrupts
	mov ax,0x00
	mov ds,ax
	lgdt 	[toc]			; load GDT into GDTR
			; enable interrupts
	ret				; All done!
 
;*******************************************
; Global Descriptor Table (GDT)
;*******************************************
 
gdt_data: 
	dd 0 				; null descriptor
	dd 0 
 
; gdt code:				; code descriptor
	dw 0FFFFh 			; limit low
	dw 0 				; base low
	db 0 				; base middle
	db 10011010b 			; access
	db 11001111b 			; granularity
	db 0 				; base high
 
; gdt data:				; data descriptor
	dw 0FFFFh 			; limit low (Same as code)
	dw 0 				; base low
	db 0 				; base middle
	db 10010010b 			; access
	db 11001111b 			; granularity
	db 0				; base high
 
end_of_gdt:
toc: 
	dw end_of_gdt - gdt_data - 1 	; limit (Size of GDT)
	dd gdt_data 			; base of GDT




letter db 13,10,'Welcome',13,10,0
[edit: some of the code after the hlt is redundant]

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 2:39 pm
by DavidCooper
rspencer wrote:

Code: Select all

[org 0x0000]
[bits 16]
mov si,letter
call ptstr
mov ax,0x0E61
int 10h
;
mov ax,0x0E62
int 10h
Please comment your code properly. It looks as if it prints "Welcome" to the screen, followed by "ab" on the line below, but you should say so. Should I take it that the "a" and "b" are appearing for a moment before the crash, or does it happen to quickly for you to tell?

Code: Select all

cli
mov	al, 2	; set bit 2 (enable a20)
out	0x92, al
That's the fast way to enable the A20, but it doesn't work on all machines. I don't know if it can cause a crash if you do that on a machine that doesn't support it, but you can find out by printing to the screen again afterwards, just so long as you follow that with a delay loop big enough to show it up before a following crash.

Your GDT looks fine, but I'm not an assembler programmer and can't tell if you're loading it correctly - I'd need to see the raw machine code, but I'm sure someone else will tell you if there's something wrong with it.

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 3:48 pm
by Velko
I highly doubt, your code is actually loaded at address 0, but you are assuming so [-X

Code: Select all

[org 0x0000]
.
.
InstallGDT:
   cli            ; clear interrupts
   mov ax,0x00
   mov ds,ax
   lgdt    [toc]         ; load GDT into GDTR
If your ptstr works, you need not to modify DS at all. If not - load your DS register with value of CS.

Also, your GDT pointer is wrong:

Code: Select all

toc:
   dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
   dd gdt_data          ; base of GDT
Value of base should contain linear (not segment-relative) address to gdt_data. You may want to calculate linear address at runtime and then put it there.

Re: Am I in protected mode yet?

Posted: Thu Jul 07, 2011 5:08 pm
by Combuster
The same problem goes again for the jump in protected mode: The start of the file has been given address 0. Stage3 becomes relative to the start of the file, and not relative to the start of actual memory.
3) Am I actually in pmode by the hlt statement???
No :)
Actually, you are in 16-bit protected mode. Protected mode makes that all segments are treated as indexes into the GDT (hence, you need 0x8 for the jump instead of 0). You are not however in the mode most people mean when they say "protected mode", which implies 32-bit mode and requires some more setup after setting "protected mode enable" in CR0.

Re: Am I in protected mode yet?

Posted: Fri Jul 08, 2011 4:24 am
by rspencer
Thank you one and all for your comments and suggestions.
However, I am still having trouble, having fixed all the problems you mentioned.
My code reads as follows (I changed a lot):

Code: Select all

[org 0x500]								;I KNOW I am loaded at 0x500 (bootloader
													;put me there)
[bits 16]
st:												;Program start
	push cs									;Set up ds to cs
	pop ds

	mov si,letter-st				;Print out the welcome message
	call ptstr

	cli											;Clear interrupts to be alone 
	mov	al, 2								; set bit 2 (enable a20)
	out	0x92, al
	
	mov ax,0x0E62						;Print letter 'b' to test no crash at a20
	int 10h

  LGDT  [toc]							;Load our GDT


 	mov		eax, cr0					; set bit 0 in CR0-go to pmode
	or		eax, 1
	mov		cr0, eax
	
	jmp 0x8: Stage3		;Jump to set up

Stage3:
[bits 32]		
	hlt
	
[bits 16]  								;Get back into 16 bits for the rest of 
													;the funtions

;---------------------------------------------------------------------------------
ptstr:                      ; Prints a null terminated string, starting at [es:si]
	pusha

.go:
  lodsb                     ; Load Byte
  or al, al                 ; Compare to 0
  jz .rt                    ; If null, return
  
  mov ah,0x0E								; Print
  int 0x10
	jmp .go 
.rt:
	popa
  ret                       ; Return

;*******************************************
; Global Descriptor Table (GDT)
;*******************************************
gdt_data: 
	dd 0 				; null descriptor
	dd 0 
 
; gdt code:				; code descriptor
	dw 0FFFFh 			; limit low
	dw 0 				; base low
	db 0 				; base middle
	db 10011010b 			; access
	db 11001111b 			; granularity
	db 0 				; base high
 
; gdt data:				; data descriptor
	dw 0FFFFh 			; limit low (Same as code)
	dw 0 				; base low
	db 0 				; base middle
	db 10010010b 			; access
	db 11001111b 			; granularity
	db 0				; base high
 
end_of_gdt:
toc: 
	dw end_of_gdt-gdt_data-1	    ; limit (Size of GDT)
Pointer:
	dd gdt_data		; base of GDT  The Org command sets it correctly

letter db 13,10,'Welcome',13,10,0
I know that I am loaded at 0x500, so the gdt pointer should be right shouldn't it? I checked the machine code and it looks correct: 5d 05 (should it be least sig. first?). Thus I don't think it is the gdt that is giving the error. I do see the letter 'b' before it crashes, so it is not the A20 and I have narrowed it down (again) to that jmp.

As far as I can see, the jmp should work as the ord at the top should add 0x500 to Stage3 so once again I am at a bit of a loss.

Re: Am I in protected mode yet?

Posted: Fri Jul 08, 2011 4:50 am
by Combuster
The only undocumented thing is that your code still assumes CS=DS=0, which means your bootloader must end with a jmp far 0x0000:0x0500. I tested the code based on that assumption and the switch to protected mode worked for me, which means your code probably does something different.

I did find some other issues though:

Code: Select all

  lodsb                     ; Load Byte
ES undefined

Code: Select all

  mov si,letter-st            ;Print out the welcome message
Why changing the offset relative to CS into the offset relative to the start of the file? The org directive also takes care of this address.

With regards to the original issue, please post your bootloader if above comments do not fix the problem.

Re: Am I in protected mode yet?

Posted: Fri Jul 08, 2011 5:56 am
by rspencer
Ah, thank you.
It turned out that a combination of defining ES and changing my last line of the bootloader from:

Code: Select all

jmp 0x0050 : 0x0000
to

Code: Select all

jmp 0x0000 : 0x0000
got rid of the problem (slap on wrist for messing up that jump).
Thanks again all for your comments and suggestions.

Re: Am I in protected mode yet?

Posted: Sat Jul 09, 2011 6:13 am
by DLBuunk
rspencer wrote:

Code: Select all

jmp 0x0000 : 0x0000
Erm, i suppose you mean:

Code: Select all

jmp 0x0000 : 0x0500
As you are executing the IVT right now...

Re: Am I in protected mode yet?

Posted: Sat Jul 09, 2011 10:16 am
by rspencer
Yes, my mistake. Sorry.