Triple error when switching to 64-bit long

The following code, moving from 32-bit protected mode (with A20 support) to 64-bit long mode, seems to give me problems. I have 1GiB card identification pages from 0x00000000 to 0x3fffffff; enable PAE; enable long bit in EFER MSR; install gdt; enable paging; and then execute the simulated FAR JMP for my 64-bit entry point:

lea eax, [PML4]
mov cr3, eax

mov eax, cr4
or eax, 100000b
mov cr4, eax

mov ecx, 0xc0000080
rdmsr
or eax, 100000000b
wrmsr

mov eax, cr0
mov ebx, 0x1
shl ebx, 31
or eax, ebx
mov cr0, eax

call gdt64_install
push 8
push longmode
retf ;<===================== faults here

The program triple crashes in BOCHS when executing a command RETF, but does not seem to return any errors. If I type info tabbefore this jump, I get:

0x00000000-0x3fffffff -> 0x000000000000-0x00003fffffff

It seems to me that paging works. This is the conclusion sreg:

es:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
    Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9b00, dl=0x0000ffff, valid=1
    Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
    Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
    Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
    Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x0000000000008252, limit=0x1f
idtr:base=0x0000000000000000, limit=0x3ff

My GDT entry:

gdt64_install:
    lgdt[GDT_addr]
    ret


    GDT_addr:
    dw (GDT64_end - GDT64) - 1
    dd GDT64

    GDT64:
    dd 0, 0

    dd 0xffff  ; segment limit
    dd 0xef9a00

    dd 0xffff  ; segment limit
    dd 0xef9200

    dd 0, 0
    GDT64_end:

The structure of my page table using PML4 and PDP is defined as:

align 4096 ;;align to 4 KB
    PML4:
        dq 0 or 1b or 10b or PDP;;preset bit, r/w bit
        dq 511 dup(PDP or 10b)
    PDP:
        dq 0 or 1b or 10000000b ;;dq zero, because we map memory from start so 0x0000, present bit
        ;;PDPE.PS to indicate 1gb pages
        dq 511 dup(10000000b)

Any ideas why this could be a triple mistake?

Github

+4
1

, GDT, , 32-. 64- 64- . OSDev wiki GDT, :

enter image description here

enter image description here

, 64- :

x86-64

  • 'L' ( 21, 'Sz') x86-64
  • "Sz" ( 22) 0, "L" , Sz = 1, L = 1 ( , )

Intel GDT 8 . 64- 0. GDT 64- , dd GDT64 . , GDT, :

    GDT_addr:
        dw (GDT64_end - GDT64) - 1
        dq GDT64                     ; Use quadword so we can use this GDT table
                                     ;     from 64-bit mode if necessary

align 8                              ; Intel suggests GDT should be 8 byte aligned

    GDT64:                           ; Global Descriptor Table (64-bit).

    ; 64-bit descriptors should set all limit and base to 0
    ; NULL Descriptor
        dw 0                         ; Limit (low).
        dw 0                         ; Base (low).
        db 0                         ; Base (middle)
        db 0                         ; Access.
        db 0                         ; Flags.
        db 0                         ; Base (high).

    ; 64-bit Code descriptor
        dw 0                         ; Limit (low).
        dw 0                         ; Base (low).
        db 0                         ; Base (middle)
        db 10011010b                 ; Access (present/exec/read).
        db 00100000b                 ; Flags 64-bit descriptor
        db 0                         ; Base (high).

    ; 64-bit Data descriptor    
        dw 0                         ; Limit (low).
        dw 0                         ; Base (low).
        db 0                         ; Base (middle)
        db 10010010b                 ; Access (present/read&write).
        db 00100000b                 ; Flags 64-bit descriptor.
        db 0                         ; Base (high).
    GDT64_end:

64- :

push 8
push longmode
retf

, FASM NASM, FAR JMP, 32 - :

jmp 0x08:longmode

FAR JMP 64- , AMD64 JMP mem16: 64. PUSH/RETF . FAR JMP 64- .


. , . exread.inc :

SECTOREAD equ 20

, , 13976. 28 (512 * 28 = 14336). 20 . , , , , .


, Makefile:

qrun: deploy_all
    qemu-system-i386 kernel.bin

64- QEMU, qemu-system-x86_64 not qemu-system-i386. :

qrun: deploy_all
    qemu-system-x86_64 -fda floppy.bin -no-shutdown -no-reboot -d int

-no-shutdown -no-reboot -d int . , QEMU . -d int , .

+2

Source: https://habr.com/ru/post/1674921/


All Articles