Процессоры Intel 80386, 80486 и Pentium с точки зрения рассматриваемых в данном разделе вопросов имеют аналогичные средства, поэтому для краткости в тексте используется термин "процессор i386", хотя вся информация этого раздела в равной степени относится к трем моделям процессоров фирмы Intel.
Процессор i386 имеет два режима работы - реальный (real mode) и защищенный (protected mode). В реальном режиме процессор i386 работает как быстрый процессор 8086 с несколько расширенным набором команд. В защищенном режиме процессор i386 может использовать все механизмы 32-х разрядной организации памяти, в том числе механизмы поддержки виртуальной памяти и механизмы переключения задач. Кроме этого, в защищенном режиме для каждой задачи процессор i386 может эмулировать 86 и 286 процессоры, которые в этом случае называются виртуальными процессорами. Таким образом, при многозадачной работе в защищенном режиме процессор i386 работает как несколько виртуальных процессоров, имеющих общую память. В отличие от реального режима, режим виртуального процессора i86, который называется в этом случае режимом V86, поддерживает страничную организацию памяти и средства многозадачности. Поэтому задачи, выполняющиеся в режиме V86, используют те же средства межзадачной защиты и защиты ОС от пользовательских задач, что и задачи, работающие в защищенном режиме i386. Однако максимальный размер виртуального адресного пространства составляет 1 Мб, как и у процессора i86.
Переключение процессора i386 из реального режима в защищенный и обратно осуществляется просто путем выполнения команды MOV, которая изменяет бит режима в одном из управляющих регистров процессора. Переход процессора в режим V86 происходит похожим образом путем изменения значения определенного бита в другом регистре процессора.
Физическое адресное пространство процессора i386 составляет 4 Гбайта, что определяется 32-разрядной шиной адреса. Физическая память является линейной с адресами от 00000000 до FFFFFFFF в шестнадцатеричном представлении. Виртуальный адрес, используемый в программе, представляет собой пару - номер сегмента и смещение внутри сегмента. Смещение хранится в соответствующем поле команды, а номер сегмента - в одном из шести сегментных регистров процессора (CS, SS, DS, ES, FS или GS), каждый из которых является 16-битным. Средства сегментации образуют верхний уровень средств управления виртуальной памятью процессора i386, а средства страничной организации - нижний уровень. Средства страничной организации могут быть как включены, так и выключены (за счет установки определенного бита в управляющем регистре процессора), и в зависимости от этого изменяется смысл преобразования виртуального адреса, которое выполняют средства сегментации. Сначала рассмотрим случай работы средств сегментации при отключенном механизме управления страницами.
Рис. 2.19. Поддержка сегментов
На рисунке 2.19 показано виртуальное адресное пространство процессора i386 при отключенном механизме управления страницами. 32-битное смещение определяет размер виртуального сегмента в 232=4 Гбайта, а количество сегментов определяется размером поля, отведенного в сегментном регистре под номер сегмента. На рисунке 2.20,а показана структура данных в сегментном регистре. Эта структура называется селектором, так как предназначена для выбора дескриптора определенного сегмента из таблиц дескрипторов сегментов. Дескриптор сегмента описывает все характеристики сегмента, необходимые для проверки правильности доступа к нему и нахождения его в физическом адресном пространстве. Процессор i386 поддерживает две таблицы дескрипторов сегментов - глобальную (Global Descriptor Table, GDT) и локальную (Local Descriptor Table, LDT). Глобальная таблица предназначена для описания сегментов операционной системы и сегментов межзадачного взаимодействия, то есть сегментов, которые в принципе могут использоваться всеми процессами, а локальная таблица - для сегментов отдельных задач. Таблица GDT одна, а таблиц LDT должно быть столько, сколько в системе выполняется задач. При этом активной в каждый момент времени может быть только одна из таблиц LDT.
Рис. 2.20. Форматы селектора и дескрипторов данных и кода:
а - формат селектора; б - формат регистра GDTR;
в - формат дескриптора сегмента данных или кода
Из рисунка 2.20 видно, что селектор состоит из трех полей - 13-битного поля индекса (номера сегмента) в таблицах GDT и LDT, 1-битного поля - указателя типа используемой таблицы дескрипторов и двухбитного поля текущих прав доступа задачи - CPL. Разрядность поля индекса определяет максимальное число глобальных и локальных сегментов задачи - по 8K (213) сегментов каждого типа, всего 16 K. С учетом максимального размера сегмента - 4 Гбайта - каждая задача при чисто сегментной организации виртуальной памяти работает в виртуальном адресном пространстве в 64 Тбайта.
Теперь проследим, как виртуальное пространство отображается на физическое пространство размером в 4 Гбайта при чисто сегментном механизме отображения. Итак, когда задаче необходимо получить доступ к ячейке физической памяти, то для выбора дескриптора виртуального сегмента используется значение селектора из соответствующего (в зависимости от команды и стадии ее выполнения - выборка кода команды или данных) сегментного регистра процессора. Значение поля типа таблицы указывает на то, какую таблицу нужно использовать - GDT или LDT. Рассмотрим сначала случай использования таблицы GDT. Для хранения таблиц GDT и LDT используется оперативная память (использование быстрой ассоциативной памяти процессора для хранения элементов этих таблиц рассмотрим позже). Для того, чтобы процессор смог найти в физической памяти таблицу GDT, ее полный 32-битный физический адрес (адрес начала таблицы), а также размер (поле в 16 бит) хранятся в специальном регистре процессора GDTR (рисунок 2.20, б). Каждый дескриптор в таблицах GDT и LDT имеет размер 8 байт, поэтому максимальный размер этих таблиц - 64 К (8(8 К дескрипторов). Для извлечения нужного дескриптора из таблицы процессор складывает базовый адрес таблицы GDT из регистра GDTR со сдвинутым на 3 разряда влево (умножение на 8, в соответствии с числом байтов в элементе таблицы GDT) значением поля индекса из сегментного регистра и получает физический линейный адрес нужного дескриптора в физической памяти. Таблица GDT постоянно присутствует в физической памяти, поэтому процессор извлекает по этому адресу нужный дескриптор сегмента и помещает его во внутренний (программно недоступный) регистр процессора. (Таких регистров шесть и каждый из них соответствует определенному сегментному регистру, что значительно ускоряет работу процессора).
Дескриптор виртуального сегмента (рисунок 2.20,в) состоит из нескольких полей, основными из которых являются поле базы - базового 32-разрядного физического адреса начала сегмента, поле размера сегмента и поле прав доступа к сегменту - DPL (Descriptor Privilege Level). Сначала процессор определяет правильность адреса, сравнивая смещение и размер сегмента (в случае выхода за границы сегмента происходит прерывание типа исключение - exсeption). Потом процессор проверяет права доступа задачи к данному сегменту, сравнивая значения полей CPL селектора и DPL дескриптора сегмента. В процессоре i386 мандатный способ определения прав доступа (называемый также механизмом колец защиты), при котором имеется несколько уровней прав доступа, и объекты какого-либо уровня имеют доступ ко всем объектам равного уровня или более низких уровней, но не имеет доступа к объектам более высоких уровней. В процессоре i386 существует четыре уровня прав доступа - от 0-го, который является самым высоким, до 3-го - самого низкого. Очевидно, что операционная система может использовать механизм уровней защиты по своему усмотрению. Однако предполагается, что нулевой уровень будет использован для ядра операционной системы, а третий уровень - для прикладных программ, промежуточные уровни - для утилит и подсистем операционной системы, менее привилегированных, чем ядро.
Таким образом, доступ к виртуальному сегменту считается законным, если уровень прав селектора CPL выше или равен уровню прав сегмента DPL (CPL ( DPL). При нарушении прав доступа происходит прерывание, как и в случае несоблюдения границ сегмента. Далее проверяется наличие сегмента в физической памяти по значению бита P дескриптора, и если сегмент отсутствует в физической памяти, то происходит прерывание. При наличии сегмента в памяти вычисляется физический линейный адрес путем сложения базы сегмента и смещения и производится доступ к элементу физической памяти по этому адресу.
В случае, когда селектор указывает на таблицу LDT, виртуальный адрес преобразуется в физический аналогичным образом, но для доступа к самой таблице LDT добавляется еще один этап, так как в процессоре регистр LDTR указывает на размещение таблицы LDT не прямо, а косвенно. Сам регистр LDTR имеет размер 16 бит и содержит селектор дескриптора таблицы GDT, который описывает расположение этой таблицы в физической памяти. Поэтому при доступе к элементу физической памяти через таблицу LDT происходит двукратное преобразование виртуального адреса в физический, причем оба раза по описанной выше схеме. Сначала по значению селектора LDTR определяется физический адрес дескриптора из таблицы GDT, описывающего начало расположения таблицы LDT в физической памяти, а затем с помощью селектора задачи вычисляется смещение в таблице LDT и определяется физический адрес нужного дескриптора. Далее процесс аналогичен преобразованию виртуального адреса с помощью таблицы GDT.