Семинар 02. - chrislvt/OS GitHub Wiki
Прееход в защищенный режим.
Установить флаг PE не достаточно чтобы прейти в защищенный режим - нужно провести некоторые приготовления. Программам нужны некоторые ресурсы, чтобы они могли исполняться - это может быть память, процессорное время, регистры процессора, порты ввода/вывода.
Нас будет интересовать память(адресация). В реальном режиме были только сегмент и смещение. Адрес = сегмент*16 + смещение - получаем линейный физический адрес. Доступное адресное пространство - 1 МБ.
В защищенном же режиме есть поддержка виртуальной памяти, в том числе и на аппаратном уровне.
Управление памятью, сегментами в защищенном режиме.
Для того, чтобы использовать память, нам ее нужно сначала выделить и описать. В системе есть специальные таблицы для упарвления памятью.
- GDT - глобальная таблица дескрипторов
- IDT - таблица дескрипторов прерываний
- LDT - локальная таблица дескрипторов
Регистры системных адресов - чтобы поддерживать эти таблицы.
Напрямую эти регистры недотупны - есть специальные команды чтобы загружать или выгружать их, эти команды привилегированные. (Lgdt)
- GDTR
- IDTК(аналогично)
- LDTR -16-битный, в нем хранится селектор
- TR (task register - регистр задач) - тоже хранится селектор, 16-битный
Системные таблицы
Глобальная таблица дескрипторов
GDT состоит из 8-байтных записей - дескрипторов.
Первая запись всегда должна быть заполнена нулями и не используется.
Далее следуют дескрипторы сегментов. На начло таблицы указывает GDT. Обращение к записям в этой таблице.
Есть селекторы - внутри себя содержат номер записи в таблице(индекс), по нему получем запись в ней - то есть дескриптор.
Формат селектора.
Селектор занимает байты начиная с 3 и до 15 в старшей части. Так как размер дескриптора 8 байт, то минимальный селектор должен тоже быть 8 - мы через первые три бита домножаем селектор на 8(добавляем три разряда в двоичной).
01 000 -> 8 (первый селектор)
10 000 -> 16 (второй селектор)
...
0 и 1 бит - RPL(request privilege level) отвечают за уровни привилегий - их всего 4, используются порцессором при проверке возможности доступа к сегментам.
2 бит - определяет к какой таблице идет обращение(1- к локальной или 0 - к глобальной)
Формат дескриптора
Поскольку у регистров доступны младшие части, это показывает что старшие компьютеры поддерживают реальный режим аппаратно - основаная идея Intel - обратная совместимость.
Возникает вопрос - сколько разрядов в шине адреса в реальном режиме? 20
Это максимально возможный объем который мы можем адресовать в реальном режиме - 1 МБ памяти.
Первые 2 байта - limit (только 16 разрядов), а шина 20-разрядная - нам не хватает 4 разрядов.
Следующие два байта - base_low
Четвертый байт - base_middle
И последний байт - base_high
Таким образом мы имеем базовый линейный адрес - можем адресовать начало сегмента.
Отдельно рассмотрим байты атрибутов.
В первом байте находятся недостоющие 4 бита для размера сегмента(в сумме теперь 20 разрядов). Но в защищенном режиме максимально адресуемая память - 4Гб. Дело в том, чтоесли установлен старший бит первого атрибута G - бит гранулярности - то память меряется в страницах по 4 Кб (1Мб * 4Кб = 4Гб), если он сброшен - то в байтах.
Бит А - доступ к сегменту (access), устанавливается автоматически.
Биты 5-6 - DPL - descriptor privilege level - уровень привилегий этого дескриптора от 0 до 3.
Бит S - бит system (0 - системный объект, 1 - обычный сегмент).
Бит P - present - бит присутствия, представлен ли сегмент в памяти (выгружен ли из внешней в оперативную).
Бит D - digit - определяет разрядность сегмента (1 - 32-разрядный, 0 - 16-разрядный).
Типы сегментов
Если третий бит 0 - то сегмент данных либо стека, если 1 - кода.
Для второго бита:
Если сегмент даных или стека:
- 0 - данных
- 1 - стека
Если кода - то это бит подчинения:
- 0 - подчиненный(связан с каким-то другиим сегментом)
- 1 - обычный
Для третьего бита:
Если сегмент данных или стека:
- 0 - модификация запрещена
- 1 - разрешена
Если кода:
- 0 - чтение запрещено
- 1 - разрешено чтение
Выборка команд - считывание из памяти и загрузка в регистры процессора.
Локальные таблицы дескрипторов.
Ипользуются процессами - они могут там хранить свои сегменты и обращаться к ним вместо того чтобы хранить это в глобальной таблице.
Начинается с нулевого дескриптора.
Формат дескрипторов абсолютно такой же.
В LDTR хранится селектор дескриптора глобальной таблицы, по этому смещению хранится дескриптор сегмента LDT. То есть у нас локальная таблица дескрипторов находится в сегменте, который уже должен быть выделен в GDT.
GDT размещается в защищенной области памяти, к которой имеет доступ только ядро операционной системы.
Регистр LDTR может загружаться при переключении между задачами и у каждой задачи может быть своя локальная таблица дескрипторов.
Таким образом мы берем из GDT базовый линейный адрес и получаем начало таблицы LDT.
Например мы загрузили в DS селектор из LDT, то процессору нужно сначала найти сегмент где хранится LDT, получить ее базовый линейный адрес и уже тогда к нему прибавить смещение из селектора. Получим снова базовый линейный адрес, к кторому прибавляем смещение - получаем соответствующий линейный адрес.
LDT может быть столько в памяти, сколько существует задач(многопроцессность).