Прыжок ассемблера в защищенном режиме с помощью 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

Ответы на вопрос(2)

Ваш ответ на вопрос