Семинар 02. - chrislvt/OS GitHub Wiki

Прееход в защищенный режим.

Установить флаг PE не достаточно чтобы прейти в защищенный режим - нужно провести некоторые приготовления. Программам нужны некоторые ресурсы, чтобы они могли исполняться - это может быть память, процессорное время, регистры процессора, порты ввода/вывода.

Нас будет интересовать память(адресация). В реальном режиме были только сегмент и смещение. Адрес = сегмент*16 + смещение - получаем линейный физический адрес. Доступное адресное пространство - 1 МБ.

В защищенном же режиме есть поддержка виртуальной памяти, в том числе и на аппаратном уровне.

Управление памятью, сегментами в защищенном режиме.

Для того, чтобы использовать память, нам ее нужно сначала выделить и описать. В системе есть специальные таблицы для упарвления памятью.

  • GDT - глобальная таблица дескрипторов
  • IDT - таблица дескрипторов прерываний
  • LDT - локальная таблица дескрипторов

Регистры системных адресов - чтобы поддерживать эти таблицы.

Напрямую эти регистры недотупны - есть специальные команды чтобы загружать или выгружать их, эти команды привилегированные. (Lgdt)

  • GDTR
  • IDTК(аналогично)
  • LDTR -16-битный, в нем хранится селектор
  • TR (task register - регистр задач) - тоже хранится селектор, 16-битный

Системные таблицы

Глобальная таблица дескрипторов

GDT состоит из 8-байтных записей - дескрипторов.

photo_2020-10-18 19 38 03

Первая запись всегда должна быть заполнена нулями и не используется.

Далее следуют дескрипторы сегментов. На начло таблицы указывает GDT. Обращение к записям в этой таблице.

Есть селекторы - внутри себя содержат номер записи в таблице(индекс), по нему получем запись в ней - то есть дескриптор.

Формат селектора.

photo_2020-10-18 19 48 29

Селектор занимает байты начиная с 3 и до 15 в старшей части. Так как размер дескриптора 8 байт, то минимальный селектор должен тоже быть 8 - мы через первые три бита домножаем селектор на 8(добавляем три разряда в двоичной).

01 000 -> 8 (первый селектор)

10 000 -> 16 (второй селектор)

...

0 и 1 бит - RPL(request privilege level) отвечают за уровни привилегий - их всего 4, используются порцессором при проверке возможности доступа к сегментам.

2 бит - определяет к какой таблице идет обращение(1- к локальной или 0 - к глобальной)

Формат дескриптора

photo_2020-10-18 19 47 21

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

Возникает вопрос - сколько разрядов в шине адреса в реальном режиме? 20

Это максимально возможный объем который мы можем адресовать в реальном режиме - 1 МБ памяти.

Первые 2 байта - limit (только 16 разрядов), а шина 20-разрядная - нам не хватает 4 разрядов.

Следующие два байта - base_low

Четвертый байт - base_middle

И последний байт - base_high

Таким образом мы имеем базовый линейный адрес - можем адресовать начало сегмента.

Отдельно рассмотрим байты атрибутов.

photo_2020-10-18 19 42 09 photo_2020-10-18 19 46 00

В первом байте находятся недостоющие 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 - разрешено чтение

Выборка команд - считывание из памяти и загрузка в регистры процессора.

Локальные таблицы дескрипторов.

Ипользуются процессами - они могут там хранить свои сегменты и обращаться к ним вместо того чтобы хранить это в глобальной таблице.

Начинается с нулевого дескриптора.

photo_2020-10-18 19 44 57

Формат дескрипторов абсолютно такой же.

В LDTR хранится селектор дескриптора глобальной таблицы, по этому смещению хранится дескриптор сегмента LDT. То есть у нас локальная таблица дескрипторов находится в сегменте, который уже должен быть выделен в GDT.

GDT размещается в защищенной области памяти, к которой имеет доступ только ядро операционной системы.

Регистр LDTR может загружаться при переключении между задачами и у каждой задачи может быть своя локальная таблица дескрипторов.

Таким образом мы берем из GDT базовый линейный адрес и получаем начало таблицы LDT.

Например мы загрузили в DS селектор из LDT, то процессору нужно сначала найти сегмент где хранится LDT, получить ее базовый линейный адрес и уже тогда к нему прибавить смещение из селектора. Получим снова базовый линейный адрес, к кторому прибавляем смещение - получаем соответствующий линейный адрес.

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