Добрый день, уважаемые читатели! Сегодня почитаем теорию о том, что такое таблица дескрипторов и из чего состоит каждый дескриптор. Ниже представлен перевод части 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.

Таблица дескрипторов (GDT) - понимание сути - дескриптор

Некоторые пояснения к картинке:

ПометкаОписание
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 Это даст возможность записывать данные в сегмент, иначе он будет доступен только для чтения

Теперь, когда мы увидели реальную конфигурацию двух сегментов, исследуя большинство возможных параметров дескриптора, становится ясно, что защищенный режим предоставляет большую гибкость в разделении памяти чем режим реальных адресов

На этом пока закончим. Также можно перечитать статью: Бит, байт, адресация, она связана с текущей. Вскоре мы реализуем таблицу дескрипторов на практике. До встречи!

Картинки найдены на просторах интернета.

Статья в Яндекс.Дзен