Текст лекции. Процессор аппаратно контролирует доступ программ к любому адресу в оперативной памяти

Процессор аппаратно контролирует доступ программ к любому адресу в оперативной памяти. При работе в защищенном режиме адресное пространство процессора делится на

- глобальное – общее для всех задач,

- локальное – отдельное для каждой задачи.

Для получения доступа целевой адрес, к которому хочет получить доступ программа, должен быть описан для программы. Это означает, что участок физической памяти, содержащий нужный адрес, должен быть описан с помощью некоторого дескриптора сегмента, который помещается в одну из трех таблиц дескрипторов. Локализация этих таблиц осуществляется с использованием одного из системных регистров:

- gdtr (Global Descriptor Table Register – регистр таблицы глобальных дескрипторов), имеет размер 48 бит (6 байтов) и содержит 32-битный (биты 16-47) базовый адрес глобальной таблицы дескрипторов GDT и 16-битное (биты 0-15) значение предела, представляющее собой размер в байтах GDT,

- ldtr (Local Descriptor Table Register – регистр таблицы локальных дескрипторов), имеет размер 16 бит и содержит селектор дескриптора локальной таблицы дескрипторов LDT, являющийся указателем на дескриптор в таблице глобальных дескрипторов GDT, который и описывает сегмент, содержащий локальную таблицу дескрипторов LDT,

- idtr (Interrupt Descriptor Table Register – регистр таблицы дескрипторов прерываний), имеет размер 48 бит (6 байтов) и содержит 32-битный (биты 16-47) базовый адрес таблицы дескрипторов прерываний IDT и 16-битное (биты 0-15) значение предела, представляющее собой размер в байтах IDT.

Кроме того, в процессоре имеется 16-битный регистр задачи tr (Task Register), который, как и ldtr содержит селектор, то есть, указатель на дескриптор в таблице GDT. Этот дескриптор описывает текущий сегмент состояния задачи TSS (Task State Segment). Такой сегмент создается для каждой задачи в системе, имеет жестко регламентированную структуру и содержит контекст (текущее состояние) задачи. Основное назначение TSS – сохранять текущее состояние задачи в момент переключения на другую задачу.

Программе, которая желает использовать данный участок памяти, должен быть сообщен указатель на соответствующий дескриптор в одной из таблиц дескрипторов GDT или LDT. Указатель на дескриптор сегмента в одной из таблиц GDT или LDT, в зависимости от функционального назначения описываемого дескриптором участка памяти (сегмента), помещается в один из шести сегментных регистров. Таким образом, в защищенном режиме меняется роль сегментных регистров. Они теперь содержат не адрес, а селектор или индекс в таблице дескрипторов сегментов. Само же назначение сегментных регистров остается неизменным – они по-прежнему указывают на сегменты команд, данных и стека, однако механизмы, используемые при этом, меняются. 14/10/14

Структура дескриптора сегмента показана на рисунке 1.5. Поля дескриптора, указанные на рисунке 1.5, подробно описаны в таблице 1.2.

При взгляде на рисунок 1.5, может возникнуть ряд вопросов. Первый из них – почему поля, определяющие размер сегмента, не расположены непрерывно, а разбиты на несколько непонятных фрагментов? Ответ прост. Все определяется необходимостью соблюдения совместимости с младшими моделями процессоров.

Впервые защищенный режим появился в процессоре i286. Он имел 24-разрядную адресную шину (мог адресовать до 16 Мбайт оперативной памяти) и оперировал с сегментами, размером, не превышающим 64 Кбайт (для размера сегмента использовались 16 разрядов).

Рисунок 1.5 – Структура дескриптора сегмента

После появления полностью 32-разрядного процессора i386 появилась необходимость в увеличении размера соответствующих полей. Однако из соображений все той же совместимости формат существующего дескриптора не изменили, а просто добавили недостающие поля в дополнительных байтах. Внутри процессора эти поля непрерывны, и неудобства ему не доставляют. Программистам же приходится иметь дело с фрагментированными полями.

Второй вопрос такой: как при поле размера сегмента всего в 20 разрядов (адресуемое пространство – 1 Мбайт) размер описываемого сегмента может достигать 4 Гбайт? Все дело в поле гранулярности G. Если это битовое поле имеет значение «0», то размер сегмента в поле обозначается в байтах, и не может превышать 1 Мбайта. Если же G = 1, то размер сегмента выражается в страницах. Так как размер страницы составляет 4 Кбайта, то 1 М страниц по 4 Кбайта составляет в сумме 4 Гбайта.

Таблица 1.2 – Значение полей дескриптора сегмента

Номер байта Количество битов в поле Символическое обозначение Значение поля
0…1   limit_1 Младшие биты (0…15) 20-разрядного поля размера сегмента, определяемого в единицах, соответствующих значению поля гранулярности G
2…4   base_1 Биты 0…23 32-разрядной базы сегмента. Она определяет значение линейного адреса начала сегмента в памяти
    AR Байт, поля которого определяют права доступа к сегменту (таблица 1.3)
  0…3 limit_2 Старшие биты (16…19) 20-разрядного предела сегмента
    U Бит пользователя (User). Не имеет специального назначения, может использоваться по усмотрению программиста
    0 – бит не используется
    D Бит разрядности операндов и адресов: 0 – в программе используются 16-разрядные операнды и режимы 16-разрядной адресации, 1 – в программе используются 32-разрядные операнды и режимы 32-разрядной адресации
    G Бит гранулярности: 0 – размер сегмента равен значению поля limit в байтах, 1 – размер сегмента равен значению поля limit в страницах
    base_2 Биты 24-31 32-разрядной базы сегмента

Таблица 1.3 – Байт AR дескриптора сегмента

Номер бита в байте AR Символическое обозначение Значение поля
  A Бит доступа (Accessed) к сегменту. Устанавливается аппаратно при обращении к сегменту

Таблица 1.3 (продолжение)

Номер бита в байте AR Символическое обозначение Значение поля
  R Для сегментов кода – это бит доступа по чтению (Readable). определяет, возможно ли чтение из сегмента кода при осуществлении замены префикса сегмента: 0 – чтение из сегмента запрещено, 1 – чтение из сегмента разрешено
  W Для сегмента данных – это бит записи: 0 – модификация данных в сегменте запрещена, 1 – модификация данных в сегменте разрешена
  C Для сегмента кода – это бит подчинения (Conforming): 0 – обычный сегмент кода, 1 – подчиненный сегмент кода
  ED Для многозадачного режима определяет особенности смены значения текущего уровня привилегий. Для сегментов данных – это бит расширения вниз (Expand Down), служит для различения сегментов стека и данных, а также определяет трактовку поля limit: 0 – сегмент данных, 1 – сегмент стека
  I Бит предназначения (Intending): 0 – сегмент данных или стека, 1 – сегмент кода
  S Если S = 1 – это бит сегмента (Segment). Для любых сегментов в памяти равен 1. Назначение и порядок использования сегмента уточняется битами C и R. Если S = 0 – это бит системный (System). Такое состояние бита S говорит о том, что данный дескриптор описывает специальный системный объект, который может и не быть сегментом в памяти
5…6 dpl Поле уровня привилегий сегмента (Descriptor Privilege Level). Содержит численное значение в диапазоне от) до 3 привилегированности сегмента, описываемого данным дескриптором
  P Бит присутствия (Present): 0 – сегмента нет в оперативной памяти в данный момент, 1 – сегмент находится в данный момент в оперативной памяти В дескрипторах сегментов, отсутствующих в оперативной памяти (Р = 0), для процессора действителен только байт управления доступом. Остальные байты могут использоваться операционной системой по своему усмотрению. (В частности, они могут использоваться для указания места сегмента на внешних носителях.)

В представленной выше таблице биты, входящие в поля типа, рассмотрены по отдельности. Часто для их совместной интерпретации рассматривают комбинации этих битов в целом. В таблице 1.4 показаны некоторые комбинации этих битов.

Таблица 1.4 – Типичные комбинации в поле типа сегмента

Комбинации битов в поле type_seg   Назначение сегмента
  Сегмент данных только для чтения
  Сегмент данных с разрешение чтения и записи
  Не определено
  Сегмент стека с разрешение чтения и записи
  Сегмент кода с разрешение только выполнения
  Сегмент кода с разрешением выполнения и чтения из него
  Подчиненный сегмент кода с разрешением выполнения
  Подчиненный сегмент кода с разрешением выполнения и чтения из него

Как видно из содержимого поля типа в байте AR, возможны два принципиально разных вида сегментов: данных и кода. Сегмент стека является разновидностью сегмента данных, но с особой трактовкой поля размера сегмента. Это объясняется спецификой использования стека (он растет в направлении от старших адресов памяти к младшим). Ясно, что поле типа ограничивает использование объявленных сегментов. В частности, программные сегменты не могут быть модифицированы без применения специальных мер. Доступ к сегменту данных также может быть ограничен только чтением.

Системные сегменты предназначены для хранения локальных таблиц дескрипторов LDT и состояния задач TSS (Task State Segment). Их дескрипторы определяют базовый адрес, лимит сегмента (1 – 64 Кбайт), права доступа (чтение, чтение/запись, только исполнение кода, исполнение/чтение) и присутствие сегмента в физической памяти (рисунок 1.6)

Рисунок 1.6 – Дескриптор системных сегментов

Бит AVL доступен для использования операционной системой. В байте управления доступом у этих дескрипторов бит Р определяет действительность (Р = 1) или недействительность (Р = 0) содержимого сегмента. Поле DPL в системных сегментах используется только в дескрипторах состояния задач. В дескрипторах локальных таблиц это поле не используется, так как обращение к локальным дескрипторам возможно только по привилегированным командам. Поле Type_seg (1 – 3, 9 – В) определяет тип сегмента:

o 0,8 – недопустимые значения,

o 1 – доступный сегмент состояния задачи 80286,

o 2 – таблица локальных дескрипторов LDT,

o 3 – занятый сегмент состояния задачи 80286,

o 9 – доступный сегмент состояния задачи 386+,

o А – не определено,

o В – занятый сегмент состояния задачи 386+.

Непосредственная межсегментная передача управления (командами JMP, CALL, INT, RET, IRET) возможна только к сегментам кода с тем же уровнем привилегий, либо к подчиненным сегментам, уровень которых выше, CPL – Current Privilege Level (при этом CPL не изменяется). Для переходов с изменением уровня привилегий используются вентили (Gate), называемые также шлюзами. Для каждого способа косвенной межсегментной передачи управления имеются соответствующие вентили. Их использование позволяет процессору автоматически осуществлять контроль защиты. Вентили вызова (Call Gates) используются для вызова процедур со сменой уровня привилегий. Вентили задач (Task Gates) используются для переключения задач. Вентили прерываний (Interrupt Gates) и ловушек (Trap Gates) определяют процедуры обслуживания прерываний.

Вентили вызова позволяют автоматически копировать заданное число слов из старого стека в новый. Вентили прерываний отличаются от вентилей ловушек только тем, что они запрещают прерывания (сбрасывают флаг IF), а вентили ловушек – нет. Для каждого типа вентилей используются соответствующие дескрипторы вентилей (Gate Descriptors). Формат дескрипторов вентилей приведен на рисунке 1.7.

В байте управления доступом у этих дескрипторов бит Р определяет действительность (Р = 1) или недействительность (Р = 0) содержимого сегмента. Поле DPL задает уровень привилегий. Поле type_seg определяет тип вентиля:

o 4 – вентиль вызова 80286 (Call Gate),

o 5 – вентиль задачи 80286 (Task Gate),

o 6 – вентиль прерывания 80286 (Interrupt Gate),

o 7 – вентиль ловушки 80286 (Trap Gate),

o C – вентиль вызова 386+ (Call Gate),

o D – вентиль задачи 386+ (Task Gate),

o E – вентиль прерывания 386+ (Interrupt Gate),

o F – вентиль ловушки 386+ (Trap Gate).

Рисунок 1.7 – Формат дескрипторов вентилей

Поле Word Count используется только в вентилях вызова и определяет количество слов из стека вызывающего процесса, автоматически копируемых в стек вызываемой процедуры. Для сегментов 80286 слова 16-битные, для 386+ – 32-битные.

Поле Destination Selector для вентилей вызова, прерываний и ловушек задает селектор целевого сегмента кода, а для вентиля задачи – селектор целевого TSS.

Поле Destination Segment задает смещение (адрес) точки входа в целевом сегменте.

При использовании вентилей может возникнуть исключение #GP, которое означает, что селектор указывает на некорректный тип дескриптора. При попытке использования недействительного вентиля (Р = 0) возникает исключение #NP (см. раздел 1.4).



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: