Сегментация
Описанная выше виртуальная память представляет собой одномерное пространство, то есть виртуальные адреса идут по порядку от 0 до некоторого максимума. В этом адресном пространстве могут одновременно располагаться различные наборы данных, например CODE, DATA, STACK. В случае использования виртуальных адресов программа не видит разницы между разными наборами данных и может, например, попытаться поменять данные из набора CODE.
В таких обстоятельствах удобно было бы иметь несколько отдельных виртуальных адресных пространств. Самым простым решением является обеспечение компьютера так называемыми сегментами. Каждый сегмент может иметь разную длину, свои атрибуты защиты и начинаться с любого адреса. Для адресации внутри сегмента вместо 32-разрядного виртуального адреса используется пара значений: номер сегмента и смещение внутри сегмента (sg:offs). Поскольку сегменты независимы друг от друга, они самостоятельно могут изменять размер. Сегмент является логическим объектом, что должно учитываться программистом при написании программы (например, сегмент не должен одновременно содержать данные и код). При наличии различных атрибутов защиты и отсутствии криворукости у разработчика можно избежать попыток несанкционированного доступа к разным типам данных.
Сегментация с использованием страниц в системах Intel Pentium
Виртуальная память компьютера Pentium поддерживает 16к независимых сегментов. Основой виртуальной памяти являются две таблицы: GDT, LDT (глобальная и локальная таблицы дескрипторов). У каждой программы есть своя собственная локальная таблица дескрипторов. Глобальная таблица одна для всех программ и несет информацию о системных сегментах, в том числе сегментах ОС. Чтобы получить доступ к сегменту, программа должна загрузить в один из сегментных регистров 16-разрядный селектор.
Третий бит указывает на принадлежность сегмента к локальному либо глобальному. Индекс указывает на номер дескриптора соответствующей таблицы. Каждая таблица содержит 8к дескрипторов. Дескриптор 0 является запрещенным. Во время загрузки селектора соответствующий дескриптор извлекается из таблицы и записывается в микропрограммные регистры для быстрого доступа к нему. Размер дескриптора - 8 байт.
При обращении к сегментному регистру (селектору), программа может найти в микропрограммных регистрах соответствующий дескриптор. Если сегментный регистр (селектор) равен нулю, то сегмент не существует и система вызывает прерывание. Далее проверяется бит присутствия. В случае нуля так же происходит прерывание. Далее проверяется, не выходит ли смещение за границы сегмента (смещение сравнивается со значением поля Lim). Если бит G равен нулю, то поле Lim указывает размер в сегментах с точностью до 1 байта. Если G равно единице, то размер указывается в страницах по 4к каждая. При выходе за пределы сегмента вызывается прерывание. Если все проверки пройдены, то значение Base (адрес начала сегмента) складывается со смещением Offset и получается 32-разрядный линейный адрес. Если бит G равен нулю, линейный адрес интерпретируется как физический. Если бит G равен единице, то доступна страничная подкачка и линейный адрес преобразуется в физический с помощью двухуровневой таблицы страниц.
Система Pentium поддерживает 4 уровня защиты (привилегии):
0 - ядро;
1 - системные службы;
2 - DLL;
3 - программы пользователя.
Разрешается получение доступа к данным высших уровней. К низшим - запрещены. Возможен вызов процедур разных уровней с помощью функции CALL, но строго контролируемым образом. Для этого процедура CALL должна содержать специальный селектор, который определяет дескриптор, называемый шлюзом вызова (call gate), который передает адрес вызываемой процедуры