OS triple faults in protected mode

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
OnixIsThePewterGod
Posts: 3
Joined: Wed Oct 12, 2022 6:41 am

OS triple faults in protected mode

Post by OnixIsThePewterGod »

Hello,
I'm working on my own OS. I'm keeping what I can in the boot sector right now because I want to use that space. My OS seems to switch into protected mode and print strings just fine, but it triple faults after a few seconds. I looked in Bochs's output and see this directly after the booting message:

Code: Select all

00015041311e[CPU0  ] interrupt(): gate.type(9) != {5,6,7,14,15}
00015041311e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00015041311e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
...
00015041311i[CPU0  ] 0x000000000000ffb1>> (invalid) : F0CE
00015041311e[CPU0  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
The gate descriptor is from the IDT, which I have (purposefully) not set up yet. I only have the GDT set up, so I'm confused as to why this error is being caused. I can tell the first exception is a general protection fault, and I can't find anywhere in my code that may be causing it. :?

Here is my code (ignore the unused disk read function, I'm using that later):

Code: Select all

[org 0x7c00]
[bits 16]

%define ENDL 0x0D, 0x0A

start:
    jmp main

;
; Prints a string to the screen
; Params:
;   - ds:si points to string
;

main:
    ; setup data segments
    xor ax, ax
    mov es, ax
    mov ds, ax
    
    mov bp, 0x9000
    mov ss, ax
    mov sp, bp

    ; print hello world message
    mov si, string16
    call puts16

    mov ah, 0x0e
    mov al, 'J'
    int 0x10


EnterProtectedMode:
	call EnableA20
	cli
	lgdt [gdt_descriptor]
	mov eax, cr0
	or eax, 1
	mov cr0, eax
	jmp codeseg:StartProtectedMode

EnableA20:
	in al, 0x92
	or al, 2
	out 0x92, al
	ret

[bits 32]

StartProtectedMode:

	mov ax, dataseg
	mov ds, ax
	mov ss, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

        mov edx, 0xb8000 ; init edx w/ proper start location
	mov si, string32a
        call puts32
        mov si, string32b
        call puts32
        jmp $

[bits 16]

puts16:
    ; save registers we will modify
    pusha

    .puts16_loop:
       lodsb               ; loads next character in al
       or al, al           ; verify if next character is null?
       jz .puts16_done

       mov ah, 0x0E        ; call bios interrupt
       mov bh, 0           ; set page number to 0
       int 0x10

       jmp .puts16_loop
    .puts16_done:
       popa    
       ret

[bits 32]

puts32:
  pusha

  loop_puts32:
    lodsb
    cmp al, 0
    je done_puts32
    cmp al, 0dh
    je cr_puts32
    cmp al, 0ah
    je lf_puts32
    mov [edx], al
    add edx, 2
    jmp loop_puts32

  cr_puts32:
    and edx, 0xfff00
    jmp loop_puts32

  lf_puts32:
    add edx, 0xa0
    jmp loop_puts32

  done_puts32:
    pusha
    ret

[bits 16]

read_disk:
  xor ax, ax    ; make sure ds is set to 0
  mov ds, ax
  cld
  ; start putting in values:
  mov ah, 2h    ; int13h function 2
  mov al, 1    ; we want to read 1 sector
  mov ch, 0     ; from cylinder number 0
  mov cl, 2     ; the sector number 2 - second sector (starts from 1, not 0)
  mov dh, 0     ; head number 0
  xor bx, bx    
  mov es, bx    ; es should be 0
  mov bx, 7e00h ; 512bytes from origin address 7c00h
  int 13h
  jc disk_read_failed
  ret

disk_read_failed:
  mov si, DiskReadErrorString
  call puts16
  hlt


gdt_nulldesc:
	dd 0
	dd 0	
gdt_codedesc:
	dw 0xFFFF			; Limit
	dw 0x0000			; Base (low)
	db 0x00				; Base (medium)
	db 10011010b		; Flags
	db 11001111b		; Flags + Upper Limit
	db 0x00				; Base (high)
gdt_datadesc:
	dw 0xFFFF
	dw 0x0000
	db 0x00
	db 10010010b
	db 11001111b
	db 0x00

gdt_end:

gdt_descriptor:
	gdt_size: 
		dw gdt_end - gdt_nulldesc - 1
		dq gdt_nulldesc

codeseg equ gdt_codedesc - gdt_nulldesc
dataseg equ gdt_datadesc - gdt_nulldesc


string16: db 'Hello, 16-bit world!', ENDL, 0
string32a: db 'Hello, 32-bit world!', ENDL, 0
string32b: db 'Goodbye, cruel world!', 0
DiskReadErrorString: db 'Disk Read Failed',0


times 510-($-$$) db 0
dw 0AA55h
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: OS triple faults in protected mode

Post by iansjack »

In put32s you do a "pusha" just before the ret. So who knows where the routine returns to. Wherever, it is certain to eventually cause a GPF.

I suspect you meant this to be "popa".

BTW, do you need to save all registers in a routine that only uses eax and edx? And saving edx would be a mistake as you want its value to be changed by the routine.
OnixIsThePewterGod
Posts: 3
Joined: Wed Oct 12, 2022 6:41 am

Re: OS triple faults in protected mode

Post by OnixIsThePewterGod »

Oh thank you! :shock: I made a stupid mistake again... We all get confused on them. #-o

And another thing: Boch seems to be hung up running the image. I removed the pusha and popa and I just see a blank screen after a few seconds with the cursor near the bottom of the screen. What's wrong???
Just doing x86 assembly here
Octocontrabass
Member
Member
Posts: 5562
Joined: Mon Mar 25, 2013 7:01 pm

Re: OS triple faults in protected mode

Post by Octocontrabass »

What does your debugger say the CPU is doing when it gets stuck? (Bochs has a built-in debugger you can use, if you don't already have one.)
OnixIsThePewterGod
Posts: 3
Joined: Wed Oct 12, 2022 6:41 am

Re: OS triple faults in protected mode

Post by OnixIsThePewterGod »

I should have mentioned it runs fine on QEMU, just not on Bochs.
Just doing x86 assembly here
Post Reply