Прыжок ассемблера в защищенном режиме с помощью GDT
В настоящее время я играю с x86 Assember, чтобы улучшить свои навыки программирования на низком уровне. В настоящее время я сталкиваюсь с небольшой проблемой со схемой адресации в 32-битном защищенном режиме.
Ситуация следующая:
У меня есть программа, загруженная в 0x7e0, которая переключает процессор в защищенный режим и переходит на соответствующую метку в коде:
[...]
code to switch CPU in Protected Mode
[...]
jmp ProtectedMode
[...]
bits 32
ProtectedMode:
.halt:
hlt
jmp .halt
Пока это работает абсолютно нормально. «Jmp ProtectedMode» работает без явного перехода в дальний угол, чтобы очистить очередь предварительной выборки - поскольку эта программа загружается со смещением 0 (org 0 в начале) - в результате чего сегмент кода указывает на правильное местоположение.
Моя текущая проблема заключается в том, что в метке «ProtectedMode» я хочу перейти к другой программе, которая загружается с 0x8000 (я проверил это с помощью дампа памяти, функция загрузки работала правильно, и программа загружена правильно в 0x8000) ,
Поскольку ЦП теперь находится в ProtectedMode, а не в RealMode, схема адресации отличается. ProtectedMode использует селекторы дескрипторов для поиска базового адреса и предела в таблице дескрипторов, чтобы добавить заданное смещение и получить физический адрес (как я понял). Следовательно, необходимо было установить GDT перед входом в ProtectedMode.
Моя выглядит так:
%ifndef __GDT_INC_INCLUDED__
%define __GDT_INC_INCLUDED__
;*********************************
;* Global Descriptor Table (GDT) *
;*********************************
NULL_DESC:
dd 0 ; null descriptor
dd 0
CODE_DESC:
dw 0xFFFF ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
DATA_DESC:
dw 0xFFFF ; data descriptor
dw 0 ; limit low
db 0 ; base low
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
gdtr:
Limit dw 24 ; length of GDT
Base dd NULL_DESC ; base of GDT
%endif ;__GDT_INC_INCLUDED__
и загружается в регистр GDT через
lgdt [gdtr]
До сих пор я не понял, как мне теперь перейти на физический адрес 0x8000 в ProtectedMode с помощью GDT?
Моими первыми мыслями было выбрать дескриптор кода (CODE_DESC), который должен указывать на 0x7e00 (если загружена текущая программа) и использовать смещение, необходимое для достижения 0x8000 (512 байт), в результате чего получилась инструкция перехода:
jmp CODE_DESC:0x200
Но это не работает.
jmp 0x7e0:0x200
тоже не работает ...
Ты хоть представляешь, что мне здесь не хватает? Может быть, я не понял чего-то существенного в схеме адресации 32-битного защищенного режима и использовании GDT.
[РЕДАКТИРОВАТЬ] Полный код:
bits 16
org 0 ; loaded with offset 0000 (phys addr: 0x7e00)
jmp Start
Start:
xor ax, ax
mov ax, cs
mov ds, ax ; update data segment
cli ; clear interrupts
lgdt [gdtr] ; load GDT from GDTR (see gdt_32.inc)
call OpenA20Gate ; open the A20 gate
call EnablePMode ; jumps to ProtectedMode
;******************
;* Opens A20 Gate *
;******************
OpenA20Gate:
in al, 0x93 ; switch A20 gate via fast A20 port 92
or al, 2 ; set A20 Gate bit 1
and al, ~1 ; clear INIT_NOW bit
out 0x92, al
ret
;**************************
;* Enables Protected Mode *
;**************************
EnablePMode:
mov eax, cr0
or eax, 1
mov cr0, eax
jmp ProtectedMode ; this works (jumps to label and halts)
;jmp (CODE_DESC-NULL_DESC):ProtectedMode ; => does not work
;jmp 08h:ProtectedMode , => does not work
;***************
;* data fields *
;* &includes *
;***************
%include "gdt_32.inc"
;******************
;* Protected Mode *
;******************
bits 32
ProtectedMode:
;here I want to jump to physical addr 0x8000 (elf64 asm program)
.halt:
hlt
jmp .halt