assemblyx86gnu-assemblermemory-segmentationprotected-mode

Protected mode, setting segment registers


I'm recently playing with gnu-assembler in simple os development. I'm using code below to switch CPU to protected mode. In order to do this I set GDT as follow and performed far jump to given label wit 0x08 as GDT offset (to set CS). CPU did not reset itself after jmp, but none of mov instructions were executed correctly after jumping to leaveToKernel. The reason why Im saying that mov failed to set DS and SS is this qemu print (info registers):

EAX=00000000 EBX=00105fd8 ECX=000003eb EDX=000b8000
ESI=00010000 EDI=00000000 EBP=00105fc0 ESP=00105fc0
EIP=0083ec44 EFL=00200002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00100000 02710fff 00c09a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]

Can someone help me understand and explain this behaviour? Thanks in advance

The code used to switch CPU to p-mode(GAS syntax):

.equ NULL_DESCRIPTOR,  0x0000000000000000

.equ CODE0,          0x00C09A1000002710
.equ DATA0,          0x00C09210010007D0
.equ PLACE_HLD1,     0x0000000000000000
.equ PLACE_HLD2,     0x0000000000000000
.section .data
     GDT:
        .quad NULL_DESCRIPTOR
        .quad CODE_P0
        .quad DATA_P0
        .quad PLACE_HLD1
        .quad PLACE_HLD2
    _GDT:
        .word 24
        .long GDT
.section .text
.global setProtectedMode
.type setProtectedMode, @function
setProtectedMode:
    push %ebp
    mov %esp,%ebp

    cli
    lgdt _GDT
    mov %cr0, %eax
    or $1, %eax
    mov %eax, %cr0
    jmp $0x08 ,$leaveToKernel
    leaveToKernel:
    xor %eax, %eax
    mov $0x10, %ax
    mov %ax, %ss
    mov %ax, %ds
    hlt
leave    
ret

Solution

  • Apparently your CS base is not zero so I say you are not jumping to the proper place. It's not usual to have non-zero CS base, I assume you did want 0, but set up the GDT entry wrong. Fix it :)