Дальний прыжок в GDT в загрузчике

flush_gdt:
    lgdt [gdtr]
    jmp 0x08:complete_flush

complete_flush:
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ret

Я не могу понять, что делает этот код. flush_gdt ярлык хорошо, тогда lgdt [gdtr] загружает 48-bit указатель в gdtr зарегистрироваться и после этого от jmp 0x08:complet_flush,

Что делает инструкция JMP? и тогда почему мы перемещаем 0x10 в топор, а затем в другие регистры

1 ответ

Решение

x86 поддерживает две схемы виртуальной памяти ( об этом читайте здесь):

  • Сегментация должна выполняться с использованием таблицы сегментов GDT.
  • пейджинг, необязательно, управляется с помощью таблицы страниц, PDT.

Большинство операционных систем хотят использовать пейджинг и не хотят сегментации, но это должно и не может быть просто отключено.

Так что хитрость заключается в том, чтобы отключить его эффект, поскольку его там не было. Обычно это можно сделать, создав 4 дескриптора больших перекрывающихся сегментов (кроме нулевого сегмента):

  • индекс сегмента 0: дескриптор нулевого сегмента
  • Сегментный индекс 1: дескриптор сегмента кода для привилегированного режима (ядра)
  • Сегментный индекс 2: дескриптор сегмента данных для привилегированного режима (ядра)
  • индекс сегмента 3: дескриптор сегмента кода для непривилегированного (пользовательского) режима
  • Сегментный индекс 4: дескриптор сегмента данных для непривилегированного (пользовательского) режима

все эти сегменты начинаются с 0x00000000 вплоть до 0xffffffffТаким образом, в итоге вы получите перекрывающиеся большие сегменты с привилегированным кодом и данными, а также непривилегированный код и данные одновременно. Это должно открыть виртуальную память и отключить эффект сегментации.

Процессор использует селекторы сегментов (регистры сегментов cs, ds, ss...), чтобы узнать правильный сегмент (еще раз, сегментация должна).

Каждый селектор сегмента имеет размер 16 бит и имеет следующую компоновку ( источник):

  • Первые два бита указывают, что уровень привилегий x86 поддерживает 4 уровня, но только два из них фактически используются (00 самый высокий и 11 самый низкий).

  • Третий бит указывает на то, что таблицу следует использовать, в основном 0ГДТ.

  • Остальные 13 битов указывают на индекс сегмента.

Если вы интерпретировали 0x08 который загружен в cs, это будет в двоичном виде:

0000000000001     0         00
index 1 (code)   GDT    privileged

и 0x10 который загружен в ds, ss,...:

0000000000010     0         00
index 2 (data)   GDT    privileged

Если вы читаете селекторы сегментов любой программы пользовательского режима, вы должны увидеть, что cs значение 27 (0x1b) что значит:

0000000000011     0         11
index 3 (code)   GDT   non-privileged

и селекторы данных ds, ss,..., должен хранить 35 (0x23):

0000000000100     0         11
index 4 (data)   GDT   non-privileged

Селекторы сегментов данных (регистры), могут быть легко изменены с помощью простого mov инструкция, но cs не может быть использован с movтак что вы используете jmp 0x08:OFFSET загрузить конфигурации сегмента в селектор сегмента кода.

Другие вопросы по тегам