Добрый день, уважаемые читатели! Сегодня почитаем теорию о том, что такое таблица дескрипторов и из чего состоит каждый дескриптор. Ниже представлен перевод части 4 главы статьи: Написание простой операционной системы с нуля. Я старался переводить ближе к тексту. Надеюсь что получилось. Начнем!
Основная концепция GDT в том, что это базис для всех операций в защищенном режиме. Важно осознать это до того, как мы углубимся в детали. Напомним что основная причина сегментной адресации в 16-битном режиме реальных адресов — это дать доступ программисту к памяти большей (хотя и незначительно по современным стандартам), чем могло позволить 16-битное смещение. В качестве примера предположим, что программист хотел поместить значение из регистра ax по адресу 0x4fe56. Без использования сегментной адресации лучшее что он смог бы сделать:
mov [0xffff], ax
что значительно не дотягивает до требуемого адреса. Используя сегментную адресацию, задача становится выполнимой:
mov bx , 0x4000 mov es , bx mov [es:0xfe56], ax
Реализация сегментации
Хотя основная идея сегментирования памяти и использования смещения внутри сегментов для достижения конкретного адреса осталась неизменной, путь реализации в защищенном режиме полностью изменен. Эти изменения внесены для большей гибкости решения. Переключив процессор в 32-битный защищенный режим, процесс с помощью которого преобразуют логические адреса (т.е. комбинацию сегментного регистра и смещения) в физические адреса совершенно отличается. Вместо того чтобы умножать значение сегментного регистра на 16 и прибавлять к результату смещение, оно становится индексом определенного дескриптора сегмента в таблице дескрипторов (GDT). Дескриптор сегмента состоит из определенной структуры данных размером в 8 байт. Вот свойства сегмента защищенного режима:
Название свойства | Размер | Описание |
Базовый адрес | 32 бита | Определяет, где начинается сегмент в физической памяти |
Лимит сегмента | 20 бит | Размер сегмента |
Флаги | 12 бит | Свойства сегмента. (Уровень привилегий, только для записи и т.п.) |
На картинке ниже представлена актуальная структура сегментного дескриптора. Обратите внимание как, просто чтобы добавить путаницы, фрагментируется базовый адрес и лимит сегмента во всей структуре. К примеру, младшие 16 бит идут в первых двух байтах, а старшие 4 бита в начале 7-го байта. Возможно, это было сделано в шутку или, что более вероятно, имеет исторические корни. А может быть на такой вид дескриптора повлиял аппаратный дизайн процессора.
Мы не будем касаться деталей всех возможных конфигураций дескриптора сегмента. Полная информация дана в Руководстве разработчика Intel. Мы изучим то, что потребуется для запуска нашего кода в 32-битном защищенном режиме.
Базовая плоская модель
Простейшая применяемая конфигурация сегментного регистра описана Intel как базовая плоская модель. В соответствии с ней определены два перекрывающихся сегмента, которые охватывают полностью 4 GB адресуемой памяти. Один сегмент предназначен для кода, а другой — для данных. Тот факт что в модели сегменты пересекаются означает, что не только никаких попыток защитить один сегмент от другого нет, но и также нет попыток использовать функции подкачки для виртуальной памяти. Это плата за простоту на раннем этапе. К тому же проще можно будет изменить сегментные дескрипторы, перейдя на язык более высокого уровня.
Вдобавок, кроме сегмента кода и сегмента данных процессор требует чтобы первая запись таблицы дескрипторов (GDT) была специально неверный нулевой дескриптор, состоящий из 8 нулевых байтов. Нулевой дескриптор является простым механизмом для ловли ошибок когда мы забываем сформировать конкретный сегментный регистр прежде получения доступа к адресу. Например некоторые сегментные регистры установлены в 0x0, а мы не установили в них подходящие значения после перехода в защищенный режим. Если выполнена попытка обращения по адресу с нулевым дескриптором, то CPU выбросит исключение, являющееся по существу прерыванием. Поэтому не стоит его путать с концепцией исключений в языках высокого уровня, вроде Java.
Некоторые пояснения к картинке:
Пометка | Описание |
LIMIT | Лимит сегмента |
BASE | Базовый адрес |
TYPE | Тип сегмента |
S | Тип дескриптора (0 =системный; 1=код или данные) |
DPL | Уровень привилегий дескриптора |
P | Сегмент присутствует |
AVL | Доступность для использования системным ПО |
D/B | Размер операций по умолчанию (0=16-битный сегмент; 1=32-битный сегмент) |
G | Размерность: 1= 4К, 0 = 1 байт |
Сегмент кода
Наш сегмент кода будет иметь следующую конфигурацию:
- Base: 0x0
- Limit: 0xfffff
- P: 1, то есть сегмент присутствует в памяти (используется в виртуальной памяти)
- DPL: 0, это наиболее высокий уровень привилегий
- S: 1, код или данные
- TYPE:
- Code: 1 это сегмент кода
- Conforming: 0, это означает что сегмент с более низким уровнем привилегий не может вызвать код в этом сегменте (это ключ к защите памяти)
- Readable: 1, 1 если для чтения, 0 только для исполнения. Такая конфигурация типа позволит нам читать константы, определенные в коде.
- Accessed: 0 Это часто используется для отладки, так как процессор устанавливает бит, когда обращается к сегменту.
- Другие флаги
- Granularity: 1, установленный бит означает что наш лимит умножается на 4 К, то есть наше значение лимита 0xfffff позволит охватить 4 гигабайта памяти
- 32-bit default: 1, так наш сегмент будет содержать 32-битный код, а при использовании 0 — 16-битный. Это фактически устанавливает размер блока данных по умолчанию для операций
- 64-bit code segment: 0, не используется в 32-битном процессоре
- AVL: 0, Этот бит можно установить для наших собственных целей, например для отладки, но не будем этого делать
Сегмент данных
Так как мы используем простую плоскую модель с перекрывающимися сегментами кода и данных, то дескриптор для данных будет практически идентичен первому дескриптору, за исключением некоторых флагов:
- S: 0 для данных
- TYPE:
- Code: 0
- Writable: 1 Это даст возможность записывать данные в сегмент, иначе он будет доступен только для чтения
Теперь, когда мы увидели реальную конфигурацию двух сегментов, исследуя большинство возможных параметров дескриптора, становится ясно, что защищенный режим предоставляет большую гибкость в разделении памяти чем режим реальных адресов
На этом пока закончим. Также можно перечитать статью: Бит, байт, адресация, она связана с текущей. Вскоре мы реализуем таблицу дескрипторов на практике. До встречи!
Картинки найдены на просторах интернета.