Разделение адресного пространства на сегменты (сегментация)
В реальном режиме работы процессора адресное пространство процесса (программы) делится на равные части механически, без учета смыслового значения данных. В одном сегменте могут оказаться и коды команд, и инициализируемые переменные, и массив исходных данных программы. Такой подход не позволяет обеспечить дифференцированный доступ к разным частям программы, а это свойство могло бы быть очень полезным во многих случаях. Например, можно было бы запретить обращаться с операциями записи в сегмент программы, содержащий коды команд, разрешив эту операцию для сегментов данных. Также полезно запретить операции записи со стороны прикладных процессов для системных таблиц, очевидно, что, сама операционная система при этом должна иметь возможность менять содержимое этих таблиц.
Кроме того, разбиение виртуального адресного пространства на «осмысленные» части (которые и называются сегментами) делает принципиально возможным совместное использование фрагментов программ разными процессами. Пусть, например, двум процессам требуется одна и та же подпрограмма, тогда в память достаточно загрузить только одну копию кода. Коды этой подпрограммы могут быть оформлены в виде отдельного сегмента и включены в виртуальные адресные пространства обоих процессов. Таким образом, оба процесса получат доступ к одной и той же копии подпрограммы.
Итак, адресное пространство процесса делится на части — сегменты, размер которых определяется с учетом смыслового значения содержащейся в них информации. Отдельный сегмент может представлять собой подпрограмму, массив данных и т. п. (Еще раз прошу обратить внимание – в реальном режиме размеры всех сегментов одинаковые (64 Кбайта), а в защищенном каждый сегмент имеет собственный размер.)
На этапе создания процесса во время загрузки его образа в оперативную память система создает в памяти локальную таблицу дескрипторов–описателей сегментов (LDT) процесса. Каждый дескриптор описывает свой сегмент. Кроме локальных таблиц дескрипторов сегментов система создает одну глобальную таблицу дескрипторов (GDT), где хранятся дескрипторы сегментов, занятых операционной системой. Доступ к глобальной таблице имеют все выполняемые задачи.
Независимо от вида таблицы каждый дескриптор содержит следующую информацию, характеризующую сегмент:
1. базовый адрес сегмента в оперативной памяти. Сегмент может начинаться в любой точке адресного пространства объемом 232 = 4Гбайт. Это адресное пространство носит название линейного, а адрес в нем соответственно линейным адресом (для процессоров с разрядностью адресной шины 36 разрядов объем адресного пространства будет соответственно 236 = 64Гбайт.);
2. размер сегмента в байтах. Максимальный размер сегмента определяется разрядностью линейного адреса, при 32-разрядной организации процессора он равен 4 Гбайт;
3. тип сегмента (сегмент кода, сегмент данных, системный сегмент) и права на его использование (возможность модифицировать сегмент кода, считывать содержимое сегмента или выполнять этот код);
4. право доступа (позволяет указать, что данный сегмент доступен только для чтения);
5. уровень привилегий сегмента.
Рассмотрим понятие уровень привилегий более детально.
Привилегии это свойство, которое определяет, какие компьютерные операции разрешаются в любой момент времени и какие доступы к памяти законны. Привилегии используются для обеспечения безопасности в компьютерной системе.
Защита на уровне сегментов представлена четырьмя уровнями привилегий (Privilege Level, PL). Четыре уровня привилегий можно интерпретировать в виде колец защиты (рис. 22). Центр - уровень 0 - предназначен для сегментов, содержащих наиболее критичные программы (обычно ядро операционной системы). Внешние кольца предназначены для сегментов с менее критичными программами или данными. Обычно процессы имеют следующие привилегии:
- 0 – ядро операционной системы, системные драйверы.
- 1 – программы обслуживания аппаратуры, драйверы, программы, работающие с портами ввода/вывода компьютера.
- 2 – системы управления базами данных, расширения операционной системы.
- 3 – прикладные программы, запускаемые пользователем.
Рисунок 22 Кольца защиты системы
Программа может обратиться к сегменту данных, который находится на том же или более низком уровне привилегий т.е. программе будет предоставлен доступ к сегменту только в том случае, когда уровень привилегий дескриптора запрашиваемого сегмента больше или равен ее уровню привилегий. Если доступ к данным не разрешен, система генерирует прерывание «нарушение защиты», в этом случае вы увидите примерно такое сообщение (рис. 23).
Рисунок 23 Сообщение системы в случае нарушения защиты
Теперь разберемся, как формируется нужный нам физический адрес. Преобразование виртуального адреса в физический происходит в два этапа. На первом этапе работает механизм сегментации, который мы и разбираем.
Так же как и в случае реального режима будет использоваться двухкомпонентный логический адрес. По-прежнему логический адрес формируется при помощи сегментных регистров и регистров, где хранится смещение. Однако сегментные регистры содержат теперь не сегментный адрес, а так называемый селектор, часть которого (13 бит) представляет собой индекс в дескрипторной таблице, т.е. указывает на дескриптор, в котором находится полная информация о сегменте. Как это происходит показано на рис. 24. .Иначе это преобразование называется трансляция логического адреса в линейный.
Логический адрес состоит из 16-битового селектора сегмента (записываемого в специальный сегментный регистр) и 32-битового смещения в этом сегменте. Логический адрес преобразуется в линейный адрес сложением смещения и адреса сегмента. Адрес сегмента берется из таблицы глобальных дескрипторов (GDT), либо из таблицы локальных дескрипторов (LDT).
Бит Т (13-й разряд) в селекторе сегмента определяет, какая таблица (глобальная или локальная) должна быть использована, а собственно сам дескриптор определяется на основании 13 младших разрядов селектора сегмента. Можно сказать, что эти младших 13 разрядов являются 13-разрядным индексом в таблице дескрипторов, а еще проще, номером нужного нам дескриптора в таблице. На основании известного системе адреса таблицы дескрипторов (определяется специальными регистрами) и номера сегмента вычисляется адрес дескриптора сегмента.
Получив доступ к дескриптору, анализируются его поля, выполняется проверка возможности выполнения заданной операции (возможность доступа к сегменту). Если доступ разрешен, то из дескриптора извлекается адрес этого сегмента и вычисляется линейный адрес. Если доступ невозможен, возникает прерывание. Для нахождения линейного адреса к адресу сегмента добавляется смещение, заданное в исходном логическом адресе. Как мы уже писали, смещение хранится в специальном 32- разрядном регистре. С точки зрения процесса смещение это и есть адрес внутри сегмента, он находятся в диапазоне от 00000000h до FFFFFFFFh.. В результате проведенного преобразования мы получили требуемый 32- разрядный линейный адрес. Полученный линейный адрес является виртуальным, т.е. не может быть непосредственно отправлен на шину адреса. Для перехода от линейного адреса к физическому требуется второй этап преобразования.
Механизм страничной памяти.
Второй этап преобразования требуется, потому что реальный компьютер не имеет, как правило, установленных 4Гб памяти, т.е. возникает необходимость перейти от виртуального линейного адреса к физическому.
На втором этапе работает страничный механизм (см. рис. 25). Полученный линейный виртуальный адрес преобразуется в искомый физический адрес. Особенностью этого преобразования является то, что процессор в этом случае оперирует с блоками равной длины (4Кбайт) – страницами, на которые разбита вся память (как физическая, так и виртуальная, соответствующие страницы также будут называться физическая и виртуальная).
Рисунок 25 Отображение виртуальных страниц в физические |
Каждая виртуальная страница памяти физически хранится в некоторой физической странице, причем на одну физическую страницу может приходиться несколько виртуальных. Самое интересное - то, что программа пользуется линейными виртуальными адресами и ничего не знает о том, где физически находится элемент данных, к которому она обращается по виртуальному адресу - да ей это и не нужно знать. Собственно трансляция (преобразование виртуального адреса в физический) выполняется аппаратно процессором. Кроме того, механизм страничной трансляции предусматривает возможность реализации подкачки.
Выполнен такой механизм следующим образом. Каждое приложение имеет свою таблицу страниц, в которой прописаны соответствия линейных и физических адресов для каждой страницы, а также информация о правах доступа к странице и специальные признаки - признак присутствия страницы и, так называемый, признак грязности страницы.
В случае, когда приложению требуются какие-то данные, оно указывает виртуальный адрес, процессор преобразует его в физический и считывает с этого физического адреса требуемые данные. Допустим, тут в работу вступает другое приложение и выделяет себе большую область данных, но физической памяти не хватает для выделения столь большого объема. Тут в работу вступает механизм подкачки: операционная система ищет давно не использовавшиеся виртуальные страницы первого приложения и сбрасывает их содержимое в файл подкачки и тут же помечает эти виртуальные страницы как «отсутствующие», т. е. сброшенные в файл подкачки. Тут же выделяются виртуальные страницы второму приложению и в соответствие им ставятся физические адреса, содержимое которых было только что сброшено в файл. С этими адресами второе приложение и работает.
Когда механизм переключения задач переключается снова на первую программу, она, пытается обратиться к сброшенным в файл подкачки данным, и тут процессор обнаруживает признак отсутствия страницы, и вызывает специальные функции операционной системы, которые проделывают работу в обратном направлении - теперь виртуальные страницы второго приложения сбрасываются на диск и помечаются отсутствующими, а содержимое виртуальных страниц первого приложения загружается из файла в оперативную память и страницы эти помечаются как присутствующие. Дополнительный признак - признак «грязности» - выставляется всякий раз, как только происходит запись в страницу, и позволяет операционной системе не сохранять данные страницы в файле в момент ее сброса, так как изменений не было, тем самым сэкономив время.
Рассмотри подробнее как работает механизм страничной памяти, т.е. как из линейного адреса страницы определяется ее физический адрес. В основе этого механизма лежит процесс вычисления физического адреса страницы на основе линейного, который часто называют трансляцией страниц.
Как уже было сказано выше, информация о страницах находится в таблицах страниц, которые содержат дескрипторы (строки таблицы), описывающие отдельные страницы памяти. Эти дескрипторы содержат:
- физические адреса страниц. Если точнее, то дескриптор содержит старшие 20 бит физического адреса страницы, младшие 12 бит адреса страницы всегда равны нулю;
- бит присутствия — Р (Present). P=l означает, что эта страница в данный момент присутствует в физической памяти, т.е. возможно использование дескриптора данной страницы для трансляции адреса;
- признак грязности — D (Dirty), который устанавливается перед операцией записи по адресу, в преобразовании которого участвует данный дескриптор. Таким образом помечается «грязная» страница, которую в случае замещения необходимо выгрузить на диск.
Физически таблица страниц реализована как двухуровневая таблица - имеется каталог таблиц страниц (или просто каталог). Каталог это, размещенный в памяти, массив 1024 строк (или записей - дескрипторов). Каждая строка содержит адрес таблицы страниц, каждая таблица страниц состоит из 1024 строк – дескрипторов страниц.
Теперь опишем как именно происходит преобразование линейного адреса в физический (см. рис. 26).
Рисунок 26. Страничный механизм (Линейная адресная трансляция ).
В процессе страничной трансляции адресов полученный линейный адрес разбивается на три части. Старшие десять бит линейного адреса являются индексом (номером) строки из каталога таблиц. По этой строке определяется физический адрес нужной в данный момент таблицы страниц. (Место размещения каталога в памяти известно, так как на его адрес указывает специальный регистр.)
Следующие десять бит линейного адреса (биты 21-12) содержат номер строки (дескриптора) из этой таблицы страниц, т.е. эта часть линейного адреса позволяет выбрать нужный дескриптор страницы из таблицы страниц. Выбранный дескриптор определяет физический адрес страницы.
Младшие 12 бит линейного адреса определяют смещение от начала страницы. Для того чтобы получить физический адрес нужно к найденному физическому адресу страницы добавить это смещение (напоминаем, что 12 младших разрядов этого адрес всегда равны нулю, поэтому смещение можно просто «пристыковать» к адресу страницы).
Если страницы в данный момент нет в физической памяти (признак присутствия P=0), то возникает прерывание (Page fault interrupt – отказ страницы). Обработчик этого прерывания должен выполнить соответствующие манипуляции по устранению данной проблемы, т.е. подгрузить страницу с жесткого диска (или наоборот – скинуть ненужную страницу на диск). Подгрузка (выгрузка) страниц происходит с файла подкачки, это по сути и есть те самые странички памяти на диске, которые после возникновения прерывания должны быть загружены в оперативную память (или наоборот). Как только страница была благополучно водворена на место, то выполнение прерванной программы продолжается с той самой инструкции, которая вызвала прерывание.
Кэширование данных.