Дальний прыжок в 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
загрузить конфигурации сегмента в селектор сегмента кода.