[n00b] Triple faults in pmode...

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
Heulanith
Posts: 4
Joined: Sun Sep 17, 2006 4:39 am

[n00b] Triple faults in pmode...

Post by Heulanith »

Hi, I've read ALOT of tutorials and such about setting up the GDT and PMODE.... However I keep getting triple faults whatever I do...
Well.. Here's my bootloader (TASM syntax):

Code: Select all


.model tiny
.code
.8086

_start:
	cli			; Disable IRQ until stack is ready
	mov ax,07C0h		; Set up ds
	mov ds,ax
	xor ax,ax		; Set up our stack
	mov ss,ax
	mov sp,4500h
	sti			; IRQ on, Real-Mode stack

	mov si,00000000d
	mov bx,0800h		; ES = dest.seg.
	mov es,bx
	xor bx,bx		; BX = dest.offs.
	mov ah,2		; Read function
	mov ch,0		; Cylinder/Track
	mov cl,2		; Start sector
	mov al,3		; Sectors to read (per call)
	mov dh,0		; Head number
	mov dl,0		; Drive number of floppy drive to read from
	int 13h			; Read!

	cmp byte ptr [es:0000],0E9h
	je jcode
	cmp byte ptr [es:0000],0EBh
	je jcode
_error:	mov ax,0013h
	int 10h
	lea bp,error_msg	; Error message
	mov cx,5		; Message is 5 characters long
	mov bx,0Ch		; Intesified red (BL), Page 0 (BH)
	mov dx,0000h		; Line 00h, Column 00h
	mov ax,1301h		; BIOS Textout function
	push ds			; BIOS Textout function needs ES:BP
	pop es
	int 10h			; Call BIOS print function
clear:	jmp clear		; Freeze
jcode:	db 0EAh, 00h		; jmp 0800h:0000h
	db 00h, 00h
	db 08h

error_msg	db	'ERROR'

	ORG 510
	db 55h, 0AAh

end
And here's my test-gdt_and_pmode-kernel (NASM syntax):

Code: Select all

[BITS 16]
[ORG 0x0000]

jmp @@start
@@start:
	cli
	lgdt [cs:gdt_desc]	; load the gdt
	mov eax,cr0		; move to protected mode
	inc ax
	mov cr0,eax

	jmp 08:clear_pipe

[BITS 32]
clear_pipe:

	mov ax,16
	mov ds,ax
	mov ss,ax
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov esp,090000h

	mov byte [ds:0B8000h],'P'
	mov byte [ds:0B8000h],07h

hang:
	jmp hang

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GDT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 4Gb limit                                                            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

gdt:
gdt_null:
	dd 0
	dd 0
gdt_code:
	dw 0FFFFh	; limit_low
	dw 0		; base_low
	db 0		; base_middle
	db 10011010b	; 
	db 11001111b	; 
	db 0		; base_high
gdt_data:
	dw 0FFFFh	; limit_low
	dw 0		; base_low
	db 0		; base_middle
	db 10010010b	; 
	db 11001111b	; 
	db 0		; base_high
gdt_end:
gdt_desc:
	dw gdt_end - gdt - 1
	dd gdt
I don't think the bootloader is the problem because my print-some-text test worked...

- Robin
User avatar
hailstorm
Member
Member
Posts: 110
Joined: Wed Nov 02, 2005 12:00 am
Location: The Netherlands

Post by hailstorm »

Hi Heulanith.

It's probably your gdt pointer. Although the offset of the gdt is used as base address, you didn't add the segment part to the base! The lgdt command interprets the base as if there are no segments. So you have to think in a way of flat memory . In your code you use real mode segment 0x800. You have to add 0x8000 (0x800 * 16) to your gdt base and then it should work.

Greetz.

Code: Select all

gdt_desc: 
   dw gdt_end - gdt - 1 
   dd gdt + 0x8000
Heulanith
Posts: 4
Joined: Sun Sep 17, 2006 4:39 am

Post by Heulanith »

Thanks for the reply!

I tried what you said but it didn't work. The code enters pmode but then I get a triple fault, as before. :oops:
User avatar
gaf
Member
Member
Posts: 349
Joined: Thu Oct 21, 2004 11:00 pm
Location: Munich, Germany

Post by gaf »

Hello Heulanith
as you set the orign of your nasm kernel to zero, all symbols are relative to the rmode code-segment (0x0800:0x0000). The switch to pmode however reloads the code-segment and sets its base to zero as defined in the gdt. Symbols like clear_pipe are then no longer interpreted as 0x0800:00XX but as 0x0000:00XX, which is of course out side of your kernel. As the lgdt instruction works with physical addresses it is too affected by this problem, so that the gdt probably never was loaded.

Setting the origin to 0x8000 should fix the problem..
You have to add 0x8000 (0x800 * 16) to your gdt base and then it should work.
That should indeed fix the problem with the lgdt instruction, but the symbols will remain incorect in pmode. The (absolute) jump to pmode thus causes a crash.

regards,
gaf
Heulanith
Posts: 4
Joined: Sun Sep 17, 2006 4:39 am

Post by Heulanith »

Wow, thanks to both of you! :P

I don't get any triple faults now, my only problem now is that my kernel does never print a P on the screen.. I've done something wrong again.. :?

The "new" kernel code:

Code: Select all

[BITS 16]
[ORG 0x0000]

jmp @@start
@@start:
	cli
	push cs
	pop ds
	lgdt [gdt_desc]		; load the gdt
	mov eax,cr0		; move to protected mode
	inc ax
	mov cr0,eax

	jmp 08:clear_pipe

[BITS 32]
clear_pipe:

	mov ax,16
	mov ds,ax
	mov ss,ax
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov esp,090000h

	mov byte [ds:0B8000h],'P'
	mov byte [ds:0B8001h],07h

hang:
	jmp hang

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GDT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 4Gb limit                                                            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

gdt:
gdt_null:
	dd 0
	dd 0
gdt_code:
	dw 0FFFFh	; limit_low
	dw 08000h	; base_low
	db 0		; base_middle
	db 10011010b	; 
	db 11001111b	; 
	db 0		; base_high
gdt_data:
	dw 0FFFFh	; limit_low
	dw 08000h	; base_low
	db 0		; base_middle
	db 10010010b	; 
	db 11001111b	; 
	db 0		; base_high
gdt_end:
gdt_desc:
	dw gdt_end - gdt - 1
	dd gdt + 0x8000
	dw 0
User avatar
hailstorm
Member
Member
Posts: 110
Joined: Wed Nov 02, 2005 12:00 am
Location: The Netherlands

Post by hailstorm »

Gaf, you were totally right. Didn't see that one coming. :D

Heulantith: Be aware that since you have changed the offset of the data segment to 0x8000, the memory address [0xb8000] that you are writing to is in fact [0xb8000+0x8000].... Using 0xb0000 as address could do the trick...
Heulanith
Posts: 4
Joined: Sun Sep 17, 2006 4:39 am

Post by Heulanith »

Thanks!

I can now *happily* continue with my hobby OS! :P
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

exactly why can he not use a 0 base and use org xxxx?

edit:
that way will work, I just don't like non-zero bases because you have to subtract from any full memory address such as b8000 but also for things like dma...
User avatar
gaf
Member
Member
Posts: 349
Joined: Thu Oct 21, 2004 11:00 pm
Location: Munich, Germany

Post by gaf »

exactly why can he not use a 0 base and use org xxxx?
That's actually what I really meant to suggest. Probably it was just a bit ambiguous when I just proposed to change the origin:

Code: Select all

[BITS 16] 
[ORG 0x8000] 

jmp @@start 
@@start: 
   cli 
   push cs 
   pop ds 
   lgdt [gdt_desc]      ; load the gdt 
   mov eax,cr0      ; move to protected mode 
   inc ax 
   mov cr0,eax 

   jmp dword 08:clear_pipe 

[BITS 32] 
clear_pipe: 

   mov ax,16 
   mov ds,ax 
   mov ss,ax 
   mov es,ax 
   mov fs,ax 
   mov gs,ax 
   mov esp,090000h 

   mov byte [ds:0B8000h],'P' 
   mov byte [ds:0B8001h],07h 

hang: 
   jmp hang 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; GDT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; 4Gb limit                                                            ; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 

gdt: 
gdt_null: 
   dd 0 
   dd 0 
gdt_code: 
   dw 0FFFFh   ; limit_low 
   dw 0      ; base_low 
   db 0      ; base_middle 
   db 10011010b   ; 
   db 11001111b   ; 
   db 0      ; base_high 
gdt_data: 
   dw 0FFFFh   ; limit_low 
   dw 0      ; base_low 
   db 0      ; base_middle 
   db 10010010b   ; 
   db 11001111b   ; 
   db 0      ; base_high 
gdt_end: 
gdt_desc: 
   dw gdt_end - gdt - 1 
   dd gdt 
   dw 0
cheers,
gaf
Post Reply