МиМ. Защищенный режим x86
История организации памяти: http://www.uic.unn.ru/~kavs2/ZIP/AsmOS/OS/5.html
В микропроцессоре 8086 было четыре 16-разрядных сегментных регистра:
- CS — сегментный регистр кода;
- DS — сегментный регистр данных;
- ES — сегментный регистр дополнительных данных;
- SS — сегментный регистр стека.
Начиная с микропроцессора 80386, сегментных регистров стало шесть, но их разрядность не изменилась. «Новичками» стали два сегментных регистра дополнительных данных — FS и GS.
Общие правила использования сегментных регистров процессором таковы:
- для выборки кода команды всегда используется сегментный регистр CS;
- при обращении к стеку (смещение формируется с использованием регистров SP/ESP/RSP или BP/EBP/RBP) всегда используется сегментный регистр SS;
- в строковых операциях при обращении к операнду-приёмнику (смещение в регистре DI/EDI/RDI) применяется сегментный регистр ES;
- во всех остальных случаях, если не используется префикс замены сегмента, доступ к памяти осуществляется с использованием сегментного регистра DrS. При наличии префикса замены сегмента вместо DS используется указанный префиксом сегментный регистр.
В реальном режиме содержимое каждого сегментного регистра представляет собой номер параграфа — 16-байтового участка памяти, выровненного на границу 16 байт.
В защищённом режиме каждый сегментный регистр делится на три части, как показано на рисунке:

Бит TI в этом случае указывает, какая таблица дескрипторов должна использоваться: нуль соответствует таблице глобальных дескрипторов (GDT), единица — таблице локальных дескрипторов (LDT).
Поле Index является номером (индексом) дескриптора в таблице дескрипторов; этот дескриптор используется при вычислении линейного адреса.
Наконец, поле RPL является запрошенным уровнем привилегий, используемым для контроля прав доступа программы к сегменту.
Источник информации: https://osdev.fandom.com/ru/wiki/%D0%A1%D0%B5%D0%B3%D0%BC%D0%B5%D0%BD%D1%82%D0%BD%D1%8B%D0%B5_%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D1%8B
Таблицы дескрипторов
В процессорах Intel одновременно в системе может существовать две дескрипторных таблицы: Глобальная (Global descriptor table или GDT) и Локальная (Local descriptor table или LDT).
GDT существует в единственном экземпляре. Адрес и предел GDT хранятся в специальном системном регистре (GDTR) в 48 бит длиной (6 байт).
LDT может быть индивидуальная для каждой задачи, или общая для системы, или же ее вообще может не быть. Адрес и размер LDT определяется в GDT, для обращения к LDT в процессоре существует специальный регистр (LDTR), но в отличии от GDTR он имеет размер 16 бит и содержит в себе селектор из GDT.
Дескрипторы сегментов.
Дескрипторные таблицы состоят из записей по 64 бита (8 байт) в каждой. Формат дескриптора таков:
| 7 | 6 | 5 | 4 |
| Базовый адрес 31-24 | Предел 19-16 | Права доступа | Базовый адрес 23-16 |
| 3 | 2 | 1 | 0 |
| Базовый адрес 15-0 | Предел 15-0 | ||
Сразу бросается в глаза очень странная организация дескриптора, но это связано с совместимостью с процессором i286, формат дескриптора в котором был таков:
| 7 | 6 | 5 | 4 |
| Зарезервировано | Права доступа | Базовый адрес 23-16 | |
| 3 | 2 | 1 | 0 |
| Базовый адрес 15-0 | Предел 15-0 | ||
Что же содержится в дескрипторе:
Базовый адрес - 32 бита (24 бита для i286). Определяет линейный адрес памяти, с которого начинается сегмент. В отличие от реального режима этот адрес может быть указан с точностью до байта.
Предел - 20 бит (16 бит для i286). Определяет размер сегмента (максимальный адрес, по которому может быть произведено обращение, это справедливо не всегда). 20-битное поле может показаться не очень то большим для 32-х битного процессора, но это не так. Оно не всегда показывает размер в байтах.
Байт прав доступа:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| P | DPL | S | Type | A | |||
Бит P (present) - Указывает на присутствие сегмента в памяти. обращение к отсутствующему сегменту вызывает особый случай не присутствия сегмента в памяти.
Двух битное поле DPL определяет уровень привилегий сегмента. Про Уровни привилегий мы поговорим чуть позже.
Бит S (Segment)- Будучи установленным в 1, определяет сегмент памяти, к которому может быть получен доступ на чтение (запись) или выполнение.
Три бита Type - в зависимости от бита S определяет либо возможности чтения/записи, выполнения сегмента или определяет тип системных данных, хранимых в селекторе. Подробнее это выглядит так:
Если бит S установлен в 1, о поле Type делится на биты:
| 2 | 1 | 0 |
| 1 - код | Подчиненный сегмент кода | Допустимо считывание |
| 0 - данные | Расширяется вниз | Допустима запись |
Если сегмент расширяется вниз (это используется для стековых сегментов) то поле предела показывает адрес, выше которого допустима запись. ниже запись недопустима и вызовет нарушение пределов сегмента.
Бит А (Accessed) устанавливается в 1, если к сегменту производилось обращение.
Если бит S установлен в 0, то в сегменте находится служебная информация определяемая полем Typе и битом A.
| TYPE | A | Описание |
| 000 | 1 | TSS для i286 |
| 001 | 0 | LDT |
| 001 | 1 | Занятый TSS для i286 |
| 010 | 0 | Шлюз вызова i286 |
| 010 | 1 | Шлюз задачи |
| 011 | 0 | Шлюз прерывания i286 |
| 011 | 1 | Шлюз исключения i286 |
| 100 | 1 | TSS для i386 |
| 101 | 1 | Занятый TSS i386 |
| 110 | 0 | Шлюз вызова i386 |
| 111 | 0 | Шлюз прерывания i386 |
| 111 | 1 | Шлюз ловушки i386 |
Остальные комбинации либо недопустимы, либо зарезервированы.
TSS - это сегмент состояния задачи (Task state segment).
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| G | D | 0 | U | Предел 19-16 | |||
Шестой байт дескриптора, помимо старших бит предела, содержит в себе несколько битовых полей.
Бит G (Granularity) - определяет размер элементов, в которых измеряется предел. если 0 - предел в байтах, если 1 - размер в страницах.
Бит D (Default size) - размер операндов в сегменте. Если 0 - 16 бит. если 1 - 32 бита.
Бит U (User) - доступен для пользователя (вернее для программиста операционной системы)
Источник информации: http://www.uic.unn.ru/~kavs2/ZIP/AsmOS/OS/5.html
Пример программы
org 0x7c00
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
lgdt [gdt_descriptor]
mov eax, cr0
or al, 1
mov cr0, eax
jmp 08h:init_pm
use32
init_pm:
mov ax, 10h ; 00010 0 00 Сегмент №2 (gdt_data), кольцо защиты 0
mov ds, ax
mov es, ax
; Адрес видеопамяти для текстового режима
mov edi, 0xB8000
mov esi, msg1
mov ah, 0x07 ; Атрибут: серый текст на черном фоне
.loop1:
lodsb ; Загрузить байт из [esi] в al
test al, al ; Проверка на конец строки (0)
jz .done
mov [edi], ax ; Записать символ и атрибут в видеопамять
add edi, 2
jmp .loop1
.done:
jmp $
msg1 db 'HELLO', 0
; Таблица GDT
gdt_start:
dq 0
gdt_code:
dw 0FFFFh, 0, 9A00h, 00CFh
gdt_data:
dw 0FFFFh, 0, 9200h, 00CFh
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
times 510-($-$$) db 0
dw 0xAA55
Разберем запись
gdt_code:
dw 0FFFFh, 0, 9A00h, 00CFh
| 7 | 6 | 5 | 4 |
| Базовый адрес 31-24: 00h | Предел 19-16: CFh 11001111 | Права доступа: 9Ah 1 00 1 101 0 | Базовый адрес 23-16: 00h |
| 3 | 2 | 1 | 0 |
| Базовый адрес 15-0: 0 | Предел 15-0: 0FFFFh | ||
Права доступа: 9Ah = 1 00 1 101 0
|
1 4433_3e6b96-4c> |
P (present) 4433_46ca71-7b> |
сегмент находится в памяти 4433_5022ba-59> |
|
00 4433_904256-55> |
DPL 4433_84087e-2c> |
уровень привилегий сегмента 4433_faae79-18> |
|
1 4433_c9e457-0f> |
S (Segment) 4433_5c3bc4-c9> |
может быть получен доступ на чтение (запись) или выполнение 4433_94ee60-84> |
|
101 4433_a55f42-87> |
Type 4433_2732da-f9> |
1 код, 0 - неподчинённый сегмент, 1 - допустимо считывание 4433_a88ed3-a0> |
|
0 4433_534f74-b2> |
А (Accessed) 4433_b4e2b2-29> |
к сегменту обращение не производилось 4433_160df7-f8> |
- -
- Разберем запись
gdt_data:
dw 0FFFFh, 0, 9200h, 00CFh
| 7 | 6 | 5 | 4 |
| Базовый адрес 31-24: 00h | Предел 19-16: CFh 11001111 | Права доступа: 92h 1 00 1 001 0 | Базовый адрес 23-16: 00h |
| 3 | 2 | 1 | 0 |
| Базовый адрес 15-0: 0 | Предел 15-0: 0FFFFh | ||
Права доступа: 9Ah = 1 00 1 101 0
|
1 4433_4fa522-e3> |
P (present) 4433_8a5649-e5> |
сегмент находится в памяти 4433_63cd91-30> |
|
00 4433_ab65eb-5c> |
DPL 4433_0f173b-a6> |
уровень привилегий сегмента 4433_7d64c7-e6> |
|
1 4433_55c50e-37> |
S (Segment) 4433_e63385-c2> |
может быть получен доступ на чтение (запись) или выполнение 4433_953419-46> |
|
001 4433_52fb13-63> |
Type 4433_28d4a6-20> |
0 - данные, 0 - не расширяется вниз, 1 - допустима запись 4433_16286f-9d> |
|
0 4433_d19b08-fc> |
А (Accessed) 4433_e42dcc-a3> |
к сегменту обращение не производилось 4433_a91ed3-d5> |