assemblyx86protected-mode

Changing to protected mode causes triple fault


I have been having an issue whereby after long jumping to protected mode, seemingly when setting up the ss register, a triple fault is caused. My code:

switch-to-32bit.asm

[org 0x7c00]
[bits 16]
switch_to_32bit:
    cli
    lgdt [gdt_descriptor]
    mov eax, cr0
    or eax, 0x1 ; protected mode
    mov cr0, eax
    jmp CODE_SEG:init_32bit ; far jump

[bits 32]
init_32bit:
    mov ax, DATA_SEG ; 0x1000
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000 ; setup stack
    mov esp, ebp

    call BEGIN_32BIT

gdt.asm

gdt_start:
    dq 0x0

gdt_code:
    dw 0xffff ; segment length
    dw 0x0 ; segment base
    db 0x0 ; segment base
    db 10011010b ; flags 
    db 11001111b ; flags
    db 0x0 ; segment base

gdt_data:
    dw 0xffff ; segment length
    dw 0x0 ; segment base
    db 0x0 ; segment base
    db 10011010b ; flags 
    db 11001111b ; flags
    db 0x0 ; segment base

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1
    dd gdt_start

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

When running this with bochs, a lot of debugging lines come into the console, as seen here: Debug log

Does anyone know why setting the ss register causes this issue? Or maybe if the issue is deeper (I see SS.mode = 16 bit)? Thanks.


Solution

  • You have an incorrect flag on your data segment descriptor: 10011010b should be 10010010b. Bit 3 should be 0 to indicate a data segment.

    When you mov a value into a segment register, it checks it for validity. It's valid (though not desirable) to move a (readable) code segment descriptor into DS, as long as you don't try to write to the segment. It's not, however, valid to move that descriptor into SS, so that's the instruction that's faulting. You're probably getting a #GP(0x10) exception, which is cascading into a triple fault.