- •2.1.2. Определение сегментов в процессоре с i486
- •2.1.3. Права доступа сегмента
- •2.1.4. Дескрипторные таблицы
- •2.1.5. Селекторы сегментов
- •2.1.6. Локальные дескрипторные таблицы
- •2.2. Страничная организация памяти
- •2.2.1. Структура страниц
- •2.2.2. Страничное преобразование адреса
- •2.2.4. Разрешение и запрещение страничного преобразования
- •2.2.6. Совместное действие
Сегментация памяти в процессоре 8086
В процессоре 8086 сегментация памяти реализована довольно простыми средствами. Под сегментом понимается блок смежных ячек памяти (в адресном пространстве 1Мбайт) с максимальным размером 64 Кбайт и начальным или базовым адресом, находящимся на 16-байтной границе (такая граница называется параграфом). Для обращения к памяти необходимо определить базу сегмента и 16-битное расстояние от базы, называемое смещением (offset) или относительным адресом. Базовые адреса четырех одновременно доступных программе сегментов находятся в сегментных регистрах кода CS, данных DS, стека SS и дополнительных данных ES. Каждый из них имеет длину 16 бит, но можно считать сегментный регистр 20-битным при формировании физического адреса(четыре младших бита базового адреса содержат нули). Таким образом, две 16-битных величины (указателя), соответствующие базовому адресу сегмента (с подразумеваемыми младшими нулями) и смещению, позволяют обращаться ко всему адресному пространству 1 Мбайт, как показано на рис. 2.1.
Рис.2.1.
Сегментация памяти в процессоре 8086
Отметим, что сегментные регистры содержат физические адреса памяти, т.е. значение в каждом сегментном регистре прямо указывает на границу параграфа в адресном пространстве 1 Мбайт. В защищенном режиме последующих процессоров значение в сегментном регистре не имеет прямой взаимосвязи с реальным адресом памяти.
Чтобы упростить обращения к памяти, за каждой командой закреплен сегментный регистр по умолчанию, который привлекается без специальных указаний. Так, команды всегда выбираются из сегмента кода (указателями служит пара CS:IP), все стековые операции выполняются в сегменте стека (SS:SP), данные (переменные) находятся в сегменте данных (база находится в регистре DS, а смещение, называемое эффективным адресом ЕА, определяется режимом адресации). Для обращения к другим сегментам перед командой помещается префикс замены сегмента. Например, команда MOV АХ,[100Н] загружает в регистр АХ слово из сегмента, базовый адрес которого находится в регистре DS, а смещение равно 100Н. Команда с префиксом замены сегмента MOV AX,ES:[100H] будет обращаться к дополнительному сегменту данных, базовый адрес которого находится в регистре ES.
Преобразование пары сегмент:смещение, называемой также логическим или виртуальным адресом, в физический адрес осуществляется довольно просто: содержимое сегментного регистра сдвигается влево на четыре бита (что эквивалентно умножению на 16), а затем суммируется со смещением. Если, например, регистр DS содержит 1234Н, а регистр SI содержит 5678Н, то физический адрес в команде MOV AX,[SI] будет равен
- (DS) * 16 + (SI) = 12340Н + 5678Н = 179В8Н
Отметим два обстоятельства, связанные с сегментацией памяти в процессоре 8086. Во-первых, преобразование логического адреса в физический всегда однозначно, т.е. каждому логическому адресу соответствует уникальный физический адрес. Однако обратное преобразование неоднозначно: каждому физическому адресу соответствуют 4К логических адресов. Поэтому во всех процессорах фирмы Intel манипуляции физическими адресами осуществляются довольно сложно. Во-вторых, в этом способе формирования физического адреса может возникнуть своеобразное переполнение. Пусть, например, регистр DS содержит 0FFFFH. Тогда в команде MOV АХ,[3000Н] физический адрес будет равен
(DS) * 16 + 3000Н = OFFFFOH + 3000Н = 102FF0H
В такой ситуации процессор просто отбрасывает старший 21-й бит адреса и выдает на шину адрес 02FF0H. Другими словами, здесь происходит так называемое «заворачивание» или «закругление» (wrap around) адреса: от адреса 0FFFFFH происходит переход к нулевому адресу. Заворачивание адреса приходится учитывать при работе процессора i486 в R- и V-режиме.
Простая сегментация памяти в процессоре 8086 обладает следующими особенностями, которые в известном смысле можно считать ее недостатками, усложняющими разработки мультизадачных систем.
Сегменты памяти, определяемые только одними сегментными регистрами, имеют всего два атрибута: начальный адрес, находящийся на границе параграфа, и максимальный размер 64 Кбайт. Никаких аппаратных средств контроля правильности использования сегментов нет. Размещение сегментов в памяти произвольно: сегменты могут частично или полностью перекрываться или не иметь общих частей. Программа может обращаться к любому сегменту для производства как считывания, так и записи данных, а также для выборки команд. В более общем плане, программа может обратиться по любому физическому адресу, а для защиты определенных областей памяти от несанкционированного доступа требуются внешние схемы.
Нет никаких препятствий для обращения даже к физически- несуществующей памяти. Когда программа выдает адрес несуществующей памяти, результат зависит только от особенностей схем дешифрирования адреса и управления внешней шиной: процессор может получить фиктивные данные, будет сформирован сигнал прерывания или система может просто зависнуть в ожидании данных, которые никогда не будут возвращены.
С учетом этих недостатков сегментация памяти сначала в процессоре 80286, а затем и в процессорах 80386 и далее была значительно усовершенствована. В этих процессорах имеются гибкие средства организации сегментов с большим числом атрибутов и эффективные механизмы контроля и защиты доступа к сегментам. Кроме того, «ниже» сегментации действует внутренний механизм страничной организации памяти, который позволяет еще более гибко управлять ресурсами памяти компьютера.
2.1.2. Определение сегментов в процессоре с i486
В той модели сегментации памяти, которая применяется в процессоре i486, невозможно представить всю определяющую сегмент информацию в одном 16-битном сегментном регистре. Реализация в нем нескольких уровней привилегий и механизмов защиты задач требует больше информации о каждом сегменте. Основное отличие модели сегментации памяти в процессоре i486 от процессора 8086 заключается в том, что теперь пользовательская программа не может свободно обращаться по любому адресу в пространстве памяти. Каждая программа, независимо от ее уровня привилегий, не может обращаться к сегменту до тех пор, пока он не «описан» для программы. Программе не разрешается обращаться по любому адресу, который она может сформировать.
Вместо простого определения сегмента путем загрузки его базового адреса в сегментный регистр системный программист определяет довольно много информации о каждом сегменте, в частности его базовый адрес, длину или размер, целевое использование (для хранения кода, стека или данных) и другие атрибуты. В задании атрибутов сегментов предоставляется довольно большая свобода. Например, базовый адрес может быть любым (не требуется его выравнивание на границу параграфа), а размер сегмента варьируется от одного байта до всего адресного пространства в 4 Гбайт. Последний размер показывает, что с помощью 32-битного индекса можно «пройти» все адресное пространство, не модифицируя содержимого сегментного регистра. Такая свобода определения сегментов предоставляет программисту полное управление использованием памяти и позволяет удовлетворить практически любые запросы памяти.
ДЕСКРИПТОР СЕГМЕНТА. Каждый сегмент в работающей системе характеризуется специальной 8-байтной структурой данных, называемой дескриптором сегмента (segment descriptor). В описание сегмента включается базовый адрес сегмента, размер сегмента, тип (определяющий целевое использование сегмента), уровень привилегий и дополнительная информация о состоянии, т.е. все то, что необходимо знать о сегменте. При создании дескриптора область адресного пространства определяется как используемая с учетом ограничений, содержащихся в дескрипторе. Число дескрипторов сегментов в системе практически не ограничивается. Если не описать область адресного пространства памяти дескриптором, соответствующий диапазон адресов оказывается недоступным и процессор отказывается обращаться к нему. Когда программа ошибочно или намеренно формирует такой недействительный адрес, процессор «перехватывает» виноватую команду до попытки считывания/записи по неопределенному адресу.
Формат дескриптора сегмента, приведенный на рис. 2.2, на первый взгляд кажется довольно запутанным. В частности, удивляет тот факт, что поля базового адреса и предела разбросаны по нескольким подполям. Объясняется такая «хаотичность» тем, что аналогичный дескриптор в процессоре 80286 содержит 0 в старшем слове (биты 63 — 48), а его поля базового адреса и предела составляют всего 24 и 16 бит, соответственно. Расширение размеров этих полей до 32 и 20 бит заставило в целях совместимости разместить их дополнительные биты в старшем слове дескриптора. Конечно, внутри процессора эти подполя объединяются. Рассмотрим назначение отдельных полей дескриптора сегмента.
Рис. 2.2. Формат дескриптора сегмента
Базовый адрес. 32-битное поле базового адреса занимает байты 2, 3, 4 и 7 дескриптора. Оно определяет любой начальный адрес сегмента в линейном адресном пространстве 4 Гбайт. Именно этот адрес сформирует процессор при задании нулевого смещения.
Предел. 20-битное поле предела (limit), которое называется еще границей сегмента, занимает байты 0 и 1, а также младшие четыре бита байта 6 дескриптора. Предел равен размеру сегмента в байтах минус 1 (но см. далее о гранулярности); можно также считать, что предел задает максимальное смещение в конкретном сегменте или последнюю адресуемую единицу в сегменте.
Казалось бы, что 20-битное поле предела позволяет определить сегмент, размер которого не превышает 1 Мбайт. На самом деле это не так. Сегмент действительно ограничен 1М элементов, но размер элементов задает специальный бит гранулярности G (Granularity) или дробности (это бит 55 в байте 6 дескриптора сегмента) — элементами сегмента могут быть байты или страницы из 4 Кбайт. Таким образом, сегмент с байтной гранулярностью (G = 0) измеряется в байтах и имеет максимальный размер 1 Мбайт, когда поле предела содержит 0FFFFFH. Сегмент со страничной гранулярностью (G = 1) измеряется в страницах и имеет максимальный размер 1М страниц, когда поле предела содержит 0FFFFFH; это соответствует 1М * 4К = 4 Гбайтам, т.е. всему линейному адресному пространству памяти процессора. В этом смысле термин «гранулярность» эквивалентен понятию разрешающей способности цифрового представления изображений. Отметим, что в процессоре 80286 все сегменты имеют байтную гранулярность, так как бит G всегда находится в состоянии 0. Когда сегмент имеет страничную гранулярность, для получения его предела в байтах необходимо к содержимому его поля предела «приписать» справа 12 единиц (или FFFH).
Предположим, например, что регистр DS адресует (косвенно, через дескрипторную таблицу) сегмент с байтной гранулярностью, имеющий предел 0001FH. Размер сегмента составляет 20Н (32 байта) и последний адресуемый байт имеет смещение 0001FH. Приведем простые примеры допустимых и недопустимых команд с обращением к этому сегменту.
Допустимые команды:
mov eax,[G000h]
mov eax,[001ch]
mov al,[001fh]
raov [001eh],ax
Недопустимые команды:
mov eax,[1234h]
mov eax,[001dh]
mov al,[0020h]
mov [001fh],ax
;Последний считываемый байт по ЗН
;Последний считываемый байт по 1FH
;Последний считываемый байт по 1FH
;Последний записываемый байт по 1FH
;Адрес памяти вне предела ;Размер элемента вне предела ;Адрес памяти вне предела ;Размер элемента вне предела
Теперь представим себе сегмент со страничной гранулярностью, имеющий предел 00000Н. Размер сегмента равен одной странице и последней адресуемой страницей является страница 0, а последним адресуемым байтом будет байт со смещением 00FFFH.
Допустимые команды:
Mov eax,[0000h]
Mov eax,[Offch]
mov al,[0fffh]
mov [0ffeh],ax
Недопустимые команды:
mov eax,[1234h]
mov eax,[Offdh]
mov al,[1020h]
mov [Offfh],ax
;Последний считываемый байт по ЗН
;Последний считываемый байт по OFFFH
;Последний считываемый байт по OFFFH
;Последний записываемый байт по OFFFH
;Адрес памяти вне предела ;Размер элемента вне предела ;Ддрес памяти вне предела ;Размер элемента вне предела
Байт 5 дескриптора сегмента содержит так называемые права доступа (Access Rights) и часто называется байтом AR. Рассмотрим назначение полей байта прав доступа.
Бит присутствия Р (Present) установлен в состояние 1, когда описываемый дескриптором сегмент находится (присутствует) в физической памяти. В системе виртуальной памяти операционная система может передавать содержимое некоторых сегментов на диск, когда физическая память заполнена. При этом она отмечает дескриптор передаваемого на диск сегмента как временно неприсутствующий, сбрасывая бит Р в 0. Когда программа загружает в сегментный регистр селектор и селектор выбирает дескриптор с Р = 0, возникает особый случай неприсутствия сегмента. Операционная система должна отыскать свободную область физической памяти (при этом, возможно, ей придется отправить на диск какой-то другой сегмент), скопировать содержимое запрошенного сегмента с диска в память, загрузить в дескриптор новый базовый адрес сегмента, установить бит Р в состояние 1 и осуществить рестарт (restart), т.е. повторное выполнение «виноватой» команды. Описанный процесс обращения к неприсутствующему сегменту с последующими передачами сегментов между основной памятью и диском обычно называется свопингом (swapping) или «подкачкой».
Двухбитное поле уровня привилегий дескриптора DPL (Descriptor Privilege Level) определяет уровень привилегий, ассоциируемый с той областью памяти, которую описывает дескриптор, и правильнее было бы назвать это поле уровнем привилегий сегмента. Уровень привилегий имеет значения от 0 (наибольшие привилегии) до 3 (наименьшие привилегии). Привилегии входят составной частью в механизм защиты процессора IA32.
Бит системный S (System) или сегмента (Segment) в дескрипторах сегментов памяти всегда установлен в состояние 1, а конкретное назначение сегмента описывается полем типа. Если бит S = 0, дескриптор описывает системный объект, как являющийся, так и не являющийся сегментом памяти (такие дескрипторы рассматриваются далее).
Трехбитное поле типа TYPE определяет целевое использование сегмента, задавая допустимые в сегменте операции. Имеются следующие типы сегментов:
-000В - сегмент данных, разрешено только считывание;
-001В - сегмент данных, разрешены считывание и запись;
- 010В - сегмент стека, разрешено только считывание (на практике такие сегменты не применяются);
- 011В - сегмент стека, разрешены считывание и запись;
-100В - сегмент кода, разрешено только выполнение;
- 101В - сегмент кода, разрешены выполнение и считывание;
-110В - подчиненный сегмент кода, разрешено только выполнение;
111В - подчиненный сегмент кода, разрешено выполнение и считывание.
Поле типа определяет правила доступа к сегментам. Например, в регистр CS нельзя загружать селекторы сегментов с типами 0 — 3 (это сегменты данных). Никакая программа не может модифицировать сегмент, для которого разрешено только считывание. Сегменты кода, которые разрешено только выполнять, невозможно считать (это предотвращает несанкционированное копирование программ), указывая префикс CS: замены сегмента. Попытка нарушить любое из этих правил вызывает особый случай защиты.
Бит доступа или обращения A {Accessed). Этот бит процессор автоматически устанавливает в состояние 1, когда осуществляется обращение к тому сегменту памяти, который определяется данным дескриптором. Обычно операционная система привлекает бит А для того, чтобы выбрать нечасто используемые сегменты, которые при необходимости можно передать на диск в процессе свопинга.
Четыре дополнительных поля дескриптора сегмента находятся в старшей тетраде байта 6.
Бит гранулярности G, определяющий размер элементов сегмента, был рассмотрен выше.
Бит размера по умолчанию D (Default Size) обеспечивает совместимость с процессором 80286. Когда бит D содержит 0, находящиеся в сегменте операнды считаются имеющими размер 16 бит. Если же бит D установлен в состояние 1, операнды в сегменте имеют размер 32 бита.
Процессор интерпретирует содержимое сегмента кода, дескриптор которого имеет D = 0, как 16-битный код процессора 80286. Сегмент кода, дескриптор которого имеет D = 1, считается содержащим 32-битный код процессора i486. Следовательно, благодаря биту D процессор i486 без специальных дополнительных мер может переключаться с выполнения 16-битного кода на 32-битный и наоборот.
Для сегментов данных и стека справедлива аналогичная интерпретация. Когда бит D = 0, стековые операции производятся с 16-битными элементами и в качестве указателя стека привлекается регистр SP. Кроме того, максимальный размер стека ограничен 64 Кбайтами, а не 4 Гбайтами.
Бит 53 зарезервирован фирмой Intel для будущих процессоров и программисты не должны использовать этот бит. Он должен содержать 0.
Бит пользователя U (User) предназначен для использования системными программистами по их усмотрению, а процессор игнорирует этот бит. Такие «свободные» биты в зарубежной литературе обычно отмечаются как AVL (AVaiLable — доступный, свободный/ Возможные применения бита U включают в себя отметку сегментов, предназначенных для «сбора мусора», или сегментов, базовые адреса которых нельзя модифицировать.
