
- •3. Работа процессоров в защищенном и реальном режимах
- •3.1 Сегментация памяти в защищенном режиме
- •3.2. Страничная организация памяти
- •3.3. Защита памяти
- •3.4. Многозадачность
- •3.13. Структура сегмента tss
- •3.5. Реализация режима виртуального 8086 (v86)
- •3.6. Функционирование процессора в реальном режиме
- •4. Реализация прерываний и исключений. Обеспечение тестирования и
- •4.1. Виды прерываний и исключений, реализация их обслуживания
- •4.2. Обработка прерываний в реальном и защищенном режимах
- •4.3. Причины возникновения исключений [1,4]
- •4.4. Реализация и обслуживание виртуальных прерываний
- •4.5. Реализация прерываний в мультипроцессорных системах
- •4.6. Средства обеспечения отладки
- •4.7. Реализация тестирования и контроля функционирования
- •5. Режим системного управления работой процессора. Инициализация, мониторинг производительности и обмен по системной шине
- •5.1. Режим системного управления (smm)
- •5.2. Инициализация и реализация энергосберегающих режимов
- •5.3. Метки реального времени и мониторинг производительности
- •Оглавление
3.3. Защита памяти
Процессоры Р6 имеют специальные средства, обеспечивающие в защищенном режиме защиту от случайного (непредусмотренного решаемой задачей) обращения к сегментам и страницам, хранящимся в памяти. Система защиты предусматривает различные виды контроля, которые реализуются процессором :
• контроль доступа к сегментам и страницам, который обеспечивается описанной ниже системой привилегий;
• контроль использования сегментов и страниц, который вводит ряд ограничений на возможные виды обращения к ним: запрещение записи в сегменты данных (страницы), разрешенные только для чтения, запрещение чтения сегментов программ (страниц), разрешенных только для выполнения, запрещение обращения к незагруженным (отсутствующим) сегментам и страницам и ряд других;
•ограничение набора выполняемых команд в зависимости от уровня привилегий выполняемой программы (выделение привилегированных команд).
Для защиты информации, хранящейся в сегментах памяти, используется система привилегий, которая регулирует доступ к тому или иному сегменту в зависимости от уровня его защищенности и от степени важности (привилегированности) запроса. В процессорах Р6, так же как в более
ранних моделях 80286, 80386, 80486, Реntium установлены четыре уровня привилегий РL (privilege level), которые задаются номерами от 0 до 3. Наиболее привилегированным является уровень с меньшим номером. Степень защищенности сегмента так же имеет четыре уровня, которые схематически представляются в виде вложенных колец защиты (рис. 3.10).
Рис. 3.10. Уровни привилегий и защиты
Соответствующие уровни защищенности иллюстрируются на примере сегментов программ. Наименее защищенными (привилегированными) являются прикладные программы пользователя, для которых выделяется уровень с номером РL=3. Уровни с номерами РL=0, 1, 2 отводятся для системных программ (супервизора), которые можно разделить на три уровня в зависимости от требований к их защищенности. Наиболее защищенная часть — ядро операционной системы (ОС) имеет уровень РL=0. В ядро входит часть ОС, обеспечивающая инициализацию работы, управление доступом к памяти, защиту и ряд других жизненно важных функций, нарушение которых полностью выводит систему из строя. Основная часть программ ОС (утилиты) должна иметь уровень РL=1. К уровню РL=2 обычно относят ряд служебных программ ОС, например, драйверы внешних устройств, системы управления базами данных, специализированные подсистемы программирования и другие.
Для программ с различными уровнями привилегий организованы отдельные стеки. Таким образом, в системе, использующей все четыре уровня привилегий, функционируют четыре различных стека, каждый из которых обслуживает только программы соответствующего уровня. При передаче управления программе другого уровня производится переключение стеков.
В соответствии с уровнями привилегий и защищенности установлены следующие правила доступа для сегментов программ и данных.
1. Данные из сегмента, имеющего уровень защиты РL могут быть выбраны программой, имеющей такой же или более высокий уровень привилегий.
2. Сегмент программ (процедура), имеющий уровень защиты РL может быть вызван программой, имеющей такой же или более низкий уровень привилегий. Различные варианты вызова сегментов программ описаны ниже.
Уровни защиты и привилегий определяются двумя битами, значение которых указывает номер кольца защиты или уровня. В зависимости от места размещения эти биты имеют различное назначение.
Уровень привилегий дескриптора DPL. задается битами 5,6 в байте доступа дескриптора (см. рис.3.5). Указывает уровень защищенности сегмента, то есть номер кольца защиты, к которому он относится.
Уровень привилегий запроса RPL задается битами 0,1 селектора, загружаемого в сегментный регистр. Этот уровень устанавливается выполняемой программой, которая с помощью данного селектора обращается к памяти системы.
Текущий уровень привилегий CPL задается битами 0,1 селектора, размещенного в регистре сегмента программ СS. Определяет уровень привилегий выполняемого в настоящий момент сегмента программы.
Напомним, что меньшее значение DPL, RPL CPL соответствует более высокому уровню привилегий (защиты). Наиболее защищенный сегмент имеет значение DPL=0, наименее защищенный — DPL=3. Для наименее привилегированных программ пользователя CPL=3, наиболее привилегированные программы ядра ОС имеют CPL=0.
Процессор имеет специальную команду ARPL используемую для коррекции значения RPL селектора. Данная команда выполняет сравнение двух младших битов селекторов, предварительно загруженных в адресуемые командой регистры или ячейку памяти. Результатом команды является селектор, в котором эти биты имеют максимальное из значений, заданных в исходных селекторах.
Обращение к сегментам программ и данных в защищенном режиме производится с учетом описанной выше системы привилегий. При этом правила обращения зависят от типа сегмента.
Обращение к сегментам данных производится с помощью селекторов, загружаемых в регистры DS, ES, FS, GS. При обращении анализируются значения RPL селектора и CPL текущей программы. Эффективный уровень привилегий для запроса данных в этом случае определяется максимальным значением из RPL и CPL.
Обращение к запрашиваемому сегменту данных разрешается, если его уровень защиты DPL >= max(RPL CPL). Нарушение этого правила при обращении вызывает исключение типа #GР "нарушение общей защиты".
Таким образом, задавая определенное значение RРL в селекторе, можно управлять доступом текущей программы к сегментам данных, имеющим различный уровень защиты. Например, при RРL=0 доступ к данным будет определяться значением СРL текущей программы. Если задать RРL=3, то при любом СРL программа может обратиться только к наименее защищенным сегментам данных, относящимся к кольцу 3.
Обращение к сегменту стека выполняется путем загрузки селектора в регистр SS. Этот селектор должен выбирать дескриптор сегмента с разрешенной записью, то есть бит 1 в байте доступа должен иметь значение W=1 (см. рис.3.5,б). Значения RРL и DPL должны быть равны СРL. Нарушение этих правил (обращение к сегменту, для которого W=0; использование селекторов и дескрипторов, имеющих значения RРL и DPL, не равные СРL) приводит к исключению типа #GР. При обращении к дескриптору, имеющему значение бита присутствия Р=0 (отсутствующий сегмент) возникает исключение типа #SS "ошибка обращения к стеку".
Обращение к сегментам программ (передача управления) реализуется при выполнении команд межсегментного перехода JMP, вызова подпрограммы CALL и возврата из подпрограммы RЕТ, прерывания INT и возврата из прерывания IRET. Правила обращения к сегментам программ зависят от значения бита подчиненности С в байте доступа дескриптора ( рис. 3.5,а).
Обращение к подчиненным сегментам, для которых установлено значение С=1, допускается только из программ, имеющих такой же или более низкий уровень привилегий. Таким образом, в программах с текущим уровнем привилегий СРL могут выполняться межсегментные команды JMP, CALL с передачей управления подчиненному сегменту, имеющему DPL= < CPL. При такой передаче значение СРL сохраняется, то есть сохраняется уровень привилегий исходной (вызывающей) программы.
Обычно бит подчиненности С=1 устанавливается для сегментов, которые могут использоваться программами с различными уровнями привилегий, например для системных библиотек. При этом подчиненные сегменты должны размещаться в кольце защиты с номером, соответствующим максимальному уровню привилегий (минимальному значению СРL) вызывающих программ.
Обращение к неподчиненным сегментам, имеющим значение С=0, с помощью команд JMP и CALL допускается только в случае, если уровень привилегий текущей программы равен уровню защиты сегмента: СРL = DPL.
Обращение через шлюз используется для вызова неподчиненных сегментов программ с более высоким уровнем привилегий, чем текущая программа. Для реализации таких вызовов служат специально установленные точки входа в программы, которые называются шлюзами (или вентилями) вызова. Менее привилегированная процедура может вызвать более привилегированную, обращаясь к ней через дескриптор шлюза вызова, определяющий доступную точку входа. Этот способ обращения позволяет программам пользователя обращаться за обслуживанием к операционной системе. При этом допускаются обращения только к определенным процедурам, которые санкционируются путем введения в систему соответствующего шлюза. Тем самым исключается возможность несанкционированного обращения менее привилегированных процедур к более привилегированным, что позволяет защитить их от возможных искажений.
Отметим, что в процессорах Pentium вызов через шлюз может осуществляться командами CALL и JMP, тогда как в процессорах 486 и более ранних моделях такой вызов производился только командой CALL.
Для вызова более привилегированной программы команда CALL или JMP должна обратиться к хранящемуся в LDT дескриптору шлюза вызова, формат которого показан на рис.3.11,а.
Байты 7,6 Байт 5 Байт 4
31 16 15 14 13 12 11 8 7 5 4 0
-
Относительный адрес А31-16
Р
gDPL
1
TYPE
000
WC
Селектор сегмента
Относительный адрес А15-0
Байты 3,2 Байты 1,0
Рис. 3.11. Формат дескриптора шлюза
В байтах 2,3 дескриптора шлюза содержится селектор вызываемого сегмента программы, а байты 0, 1, 6, 7 задают относительный адрес команды, являющейся точкой входа в эту программу. Байт доступа 5 содержит бит присутствия Р и поле уровня привилегий дескриптора шлюза gDPL которые имеют такое же назначение, как и в дескрипторах сегментов. Поле ТУРЕ в байте доступа шлюза (табл. 3.2) содержит код 0100, если вызываемая программа написана для 16-разрядного процессора 80286, или код 1100, если программа написана для 32-разрядных процессоров 386, 486, Pentium, Р6. Пяти битовое поле WC в байте 4 указывает количество параметров, которые переносятся из стека, обслуживающего программы с текущим уровнем привилегий СРL, в стек, используемый программами с уровнем привилегий вызываемой программы. Параметры представляют собой 32-разрядные слова (16-разрядные для процессоров 80286), число которых может составлять от 0 до 31.
При вызове программ через шлюз должны выполняться следующие правила.
Значения RPL селектора, вызывающего шлюз, и СРL текущей программы должны быть меньше или равны значению gDPL в байте доступа шлюза. Таким образом, дескриптор шлюза должен иметь такой же или меньший уровень привилегий, чем запрос и текущая программа: gDPL >= (DPL,СРL).
Значение gDPL шлюза вызова должно быть больше или равно уровню CРL вызываемого сегмента программ: gDPL>=DPL.
Вызываемый сегмент программ должен иметь такой же или более высокий уровень привилегий DPL чем текущая программа: DPL <= CPL.
Последнее из перечисленных правил реализуется при выполнении команды CALL с обращением к любым видам сегментов программ (подчиненным и неподчиненным) и команды JUMP, вызывающей подчиненный сегмент. Если команда JUMP осуществляет переход к неподчиненному сегменту программ, то необходимо выполнение правила DPL=CPL.
Примеры реализации этих правил при различных комбинациях значений RPL, CPL gDPL DPL иллюстрируются на рис.3.12.
Если эти правила выполняются, то после вызова дескриптора шлюза в сегментный регистр СS загружается селектор — байты 3,2 этого дескриптора. Этот селектор выбирает из LDT дескриптор вызываемого сегмента программы. При этом младшие два бита (поле RPL) селектора игнорируются, а вместо них в регистр СS в качестве СРL заносится значение DPL из дескриптора вызываемого сегмента. В регистр ЕIР из дескриптора шлюза загружается относительный адрес входа в программу — байты О, 1, 6, 7 (для программ процессора 80286 в IР загружаются байты 0, 1).
Если вызванная программа имеет другой (более высокий) уровень привилегий, чем текущая, то при выполнении команд JMP, CALL с использованием шлюза вызова производится переключение стека. Выполняется обращение к стеку, организованному для программ с уровнем привилегий, соответствующим уровню вызванной программы. В этот стек последовательно вводятся старые значения SS и ЕSР; параметры, переносимые из старого стека; старые значения СS и ЕIР. Число переносимых параметров определяется полем WC (рис. 3.11), причем выбираются последние из параметров загруженных в старый стек. Последующие ячейки стека используются для хранения новых параметров. Переключение стека производится автоматически путем загрузки в регистры SS и ЕSP из сегмента состояния задачи ТSS нового содержимого, которое определяет начальный адрес стека для программ данного уровня привилегий.
Необходимо отметить, что переключение стека реализуется только при обращении к неподчиненным сегментам программ( имеющих в дескрипторе значение бита С=0). Если через шлюз осуществляется вызов подчиненного сегмента программ (значение бита С=1), то переключение стека не производится.
По команде RET производится восстановление из стека старого содержимого регистров СS, ЕIР (IР) и SS, ESP (SP). Таким образом, одновременно с возвратом к исходной программе происходит, и возвращение к старому стеку. Команда RET проверяет значение CPL и два младших разряда извлекаемого из стека старого содержимого СS, определяющие уровень привилегий программы, к которой осуществляется возврат. Команда выполняется только в том случае, когда значение этих битов больше или равно СРL, то есть возврат осуществляется к программе с таким же или меньшим уровнем привилегий.
Рис. 3.12. Варианты реализации передачи управления с использованием
шлюза вызова
Нарушение командами JMP, CALL RET указанных правил обращения к сегментам программ вызывает исключение типа #GР (нарушение защиты).
Чтобы избежать частых нарушений хода выполнения программы из-за несоблюдения правил доступа к сегментам, в набор команд процессора введены специальные команды, используемые для проверки различных условий доступа. Команда LAR осуществляет загрузку в регистр байта доступа сегмента, выбираемого с помощью селектора, который содержится в адресуемой ячейке памяти или регистре. После этой операции процессор может произвести побитный анализ содержимого байта доступа, определяя возможности обращения к данному сегменту.
Команда LSL загружает в регистр значение границы сегмента, который выбирается таким же образом, как командой LAR. Используя полученное значение этой границы, процессор может организовать контроль формирования адреса, чтобы избежать прерывания программы при выходе за пределы адресуемого сегмента.
Команды VERR, VERW проверяют возможности записи в сегмент данных и чтения из сегмента программ, устанавливаемые соответствующими битами дескрипторов. Если запись или чтение разрешены, то устанавливается значение признака ZF=1 в регистре EFLAGS. Предварительный анализ значения этого признака позволяет избежать запрещенных видов обращения к данному сегменту, вызывающих прерывание текущей программы. Адресация необходимого сегмента при выполнении команд VERR, VERW производится таким же образом, как и командой LAR.
Реализация ввода — вывода с помощью команд IN, OUT, INS, OUTS в защищенном режиме производится с учетом CPL выполняемой программы. Величина CPL сравнивается с значением поля IOPL в регистре EFLAG. Ввод-вывод производится только при выполнении условия CPL <= IOPL. Нарушение этого условия вызывает исключение типа #GР, если доступ к адресованному командой порту не разрешен специальной битовой картой ввода/вывода, задаваемой при решении отдельных задач.