Не могу перейти с 16-битного на 32-битный режим

Я пытаюсь создать простой загрузчик, который загружает мое ядро ​​​​в 32-битном режиме. Прочитал много статей и форумов и пишет бутсектор 512 байт и потом загрузчик stage2. На этапе 2 я могу загрузить gdt, A20, защищенный режим. но когда я перехожу в 32-битный режим, он не работает в qemu. Я много раз проверял свой код с разными документами. Теперь я не знаю, есть ли в моих кодах ошибка или qemu работает плохо. Все мои коды в загрузчике stage2:(мой ассемблер NASM)

bits 16
org 0x0
;-----------------------------------
jmp short main
; give the descriptor offsets names
%define NULL_DESC 0
%define CODE_DESC 0x8
%define DATA_DESC 0x10
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;---------------main---------------
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
main:
;------------------------------------setup segments and stack
cli     
;set up our segment registers to point to the segment in which we were         loaded – 2000    
mov ax, 2000h
mov ds, ax
mov es, ax
;setup stack in 9000
mov ax, 0x9000                  ; stack begins at 0x9000-0xffff
mov ss, ax
mov sp, 0xFFFF
sti                             ; Restore interrupts
cld                             ; The default direction for string operations will be 'up' - incrementing address in RAM
;------------------------------------install gdt
call InstallGDT
;------------------------------------enable A20 line
cli
push ax
mov al, 0xdd    ; send enable a20 address line command to controller
out 0x64, al
pop ax
;mov ax, 0x2401
;int 0x15
;mov ax, 0x3
;int 0x10
;------------------------------------enter to protected mode
cli
mov eax, cr0
or eax,0x1
mov cr0, eax
jmp CODE_DESC:BEGIN_PROTECTED_MODE

;------------------------------------halt the system
;cli
jmp $
;hlt


InstallGDT:
cli                             ; clear interrupts
pusha                           ; save registers
lgdt    [gdt_descriptor]        ; load GDT into GDTR
sti                             ; enable interrupts
popa                            ; restore registers
;-----------------------------------------------
gdt_data: 
dd 0                            ; null descriptor
dd 0 
; gdt code:             ; code descriptor
dw 0FFFFh           ; limit low
dw 0                ; base low
db 0                ; base middle
db 10011010b        ; access
db 11001111b        ; granularity
db 0                ; base high
; gdt data:             ; data descriptor
dw 0FFFFh           ; limit low (Same as code)10:56 AM 7/8/2007
dw 0                ; base low
db 0                ; base middle
db 10010010b        ; access
db 11001111b        ; granularity
db 0                ; base high
end_of_gdt:

; GDT descriptor
gdt_descriptor:
dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
dd gdt_data                     ; base of GDT
;******************************************************
;   ENTRY POINT FOR 32 bits mode
;******************************************************
bits 32
BEGIN_PROTECTED_MODE:               ; after the switch we will get here
;Set registers  
  mov ax,DATA_DESC  
  mov ds, ax
  mov es, ax
 ;mov fs, ax
 ;mov gs, ax
 mov ss, ax
 mov esp,0x90000                    ; stack begins from 90000h
    ;cli
    ;hlt
;print a string
 mov esi,MSG_PROT_MODE
 mov ebx,0xb8000
.loop:
  lodsb
  or al,al
  jz halt
  or eax,0x0100
  mov word [ebx], ax
  add ebx,2
  jmp .loop
halt:
  cli
  hlt

MSG_PROT_MODE db "Loaded 32-bit protected mode", 0

person madkne    schedule 19.06.2018    source источник
comment
Во-первых, базовый адрес в вашем gdt_desciptor должен быть линейным адресом. Я предполагаю, что из кода вы загрузили код по адресу 0x2000:0x0000. Это представляет физический адрес 0x20000. Вам нужно будет добавить 0x20000 к gdt_data, чтобы получить правильный линейный адрес. Ваш дальний переход в защищенный режим также должен учитывать тот факт, что BEGIN_PROTECTED_MODE относится к базовому адресу 0x20000, поэтому вам нужно будет добавить 0x20000 к BEGIN_PROTECTED_MODE, чтобы получить 32-битный линейный адрес для перехода.   -  person Michael Petch    schedule 19.06.2018
comment
@DavidHoelzer: у него есть инструкция CLI перед включением защищенного режима (4 строки, прежде чем он выполняет FAR JMP для CODE_DESC:BEGIN_PROTECTED_MODE. Его код защищенного режима не включает его повторно.   -  person Michael Petch    schedule 19.06.2018
comment
Я смотрел на функцию InstallGDT, а потом перестал смотреть. @MichaelPetch Плохо.   -  person David Hoelzer    schedule 19.06.2018
comment
извините ‹code›ret ; Готово!‹/код› неверный. этот код был в другом файле и забыл его удалить.   -  person madkne    schedule 20.06.2018
comment
Спасибо за предложения, но я изучаю эти предложения и не получаю ответа.   -  person madkne    schedule 20.06.2018
comment
Я не вижу смысла в удалении ret и попадании выполнения в данные в GDT. Почему вы внесли эту правку в свой вопрос? Теперь в вашем коде обнаружена очевидная ошибка еще до того, как она достигнет jmp far. Пошаговый код в отладчике (например, внутри BOCHS или с заглушкой QEMU gdb)   -  person Peter Cordes    schedule 20.06.2018