Предыдущая глава | ПЕРЕКЛЮЧЕНИЕ ПРОЦЕССОРА | Следующий раздел |
Переключение ЦП требуется выполнять в трех случаях:
1) при выполнении межсегментных переходов в пределах текущего процесса;
2) для смены выполняемого процесса;
3) для обработки прерываний.
Все эти переключения ЦП выполняются чисто аппаратными средствами.
Роль программы сводится к выдаче команды передачи управления, инициирующей переключение ЦП.
Внутрисегментные переходы в защищенном режиме ЦП выполняют те же машинные команды передачи управления, что и в реальном режиме: jmp, call, ret. Для этого, как и в реальном режиме, в качестве параметра команд jmp и call задается внутрисегментное смещение, команда ret получает это смещение из стека. В результате выполнения команды заданное смещение будет записано в качестве нового содержимого указателя команды EIP. Единственное отличие: при выполнении внутрисегментного перехода в защищенном режиме ЦП проверяет, не вышел ли адрес перехода за пределы данного сегмента.
Эти же команды переходов могут быть использованы и для межсегментных переходов в пределах текущего процесса. Требует пояснения термин «эти же команды». Речь идет о совпадении ассемблерных мнемоник команд, но не о машинных кодах операций, которые для внутрисегментных и межсегментных переходов будут различны.
При межсегментной передаче управления меняется не только содержимое EIP, но и CS. Далее мы будем называть сегмент, из которого делается переход, исходным сегментом, а сегмент, в который переход делается – целевым сегментом. В основе ограничений на межсегментные переходы лежит сравнение текущего уровня привилегий CPL (совпадает с DPL исходного сегмента) и DPL целевого сегмента. Если результаты сравнения неудовлетворительны, возникает исключение и процесс уничтожается.
Межсегментные переходы с помощью команд jmp и call можно выполнить двумя способами. Первый способ – прямой вызов целевого сегмента кода. Он предполагает задание в качестве операнда команды jmp (call) селектора этого сегмента кода. Второй способ – косвенный вызов целевого сегмента, используя вентиль вызова. Сначала рассмотрим прямые вызовы.
Реализация межсегментных прямых переходов схематично показана на рис.44. На выполнение прямого вызова целевого сегмента влияет бит подчинения C – бит 2 в байте доступа дескриптора целевого сегмента (см. рис. 37). Если C=0, то целевой сегмент называется несогласованным. Такой сегмент может быть вызван только из выполняемого сегмента, имеющего не меньшие привилегии, чем целевой сегмент: CPL<DPL.
Рис. 83. Прямые межсегментные переходы
Если процесс находится в состоянии «Задача», то его программа выполняется в кольце 3, и поэтому она не может вызывать несогласованные сегменты, находящиеся в кольце 0. Это позволяет блокировать несанкционированные вызовы модулей ядра ОС. Поэтому в системе UNIX прямые межсегментные переходы используются или для передачи управления между прикладными сегментами (процесс в состоянии «Задача»), или между системными сегментами (процесс в состоянии «Ядро»). При возврате из целевого сегмента с помощью команды ret также проверяется уровень привилегий того сегмента, в который делается переход. Так как такой переход возможен только в сегмент, имеющий не лучший уровень привилегий, то это предотвращает использование команды ret для несанкционированного доступа к модулям ядра.
Один из способов предоставления обслуживания прикладным программам со стороны модулей ядра ОС состоит в размещении этих модулей в согласованных сегментах. Байт доступа дескриптора такого сегмента имеет бит C=1. Согласованный сегмент можно вызывать из программных сегментов, находящихся на любом кольце защиты (см. рис.44). Но всегда после своего вызова такой целевой сегмент будет выполняться с привилегиями исходного сегмента. Так как фактического переключения ЦП в более приоритетный режим не происходит, то данный метод имеет ограниченное применение для реализации системных вызовов UNIX.
Рис. 84. Структура вентиля вызова
Для реализации системных вызовов удобно использовать метод косвенных переходов, основанный на применении вентилей вызова. Каждый вентиль вызова представляет собой особый системный дескриптор (рис.45).
Рис. 85. Косвенный переход через вентиль вызова
В вентиле вызова селектор задает целевой сегмент, а смещение указывает на точку входа в этот сегмент. Благодаря смещению один и тот же сегмент может иметь несколько точек входа. Поле DPL вентиля вызова задает минимальный уровень привилегий, необходимый для получения доступа через этот вентиль. Например, если DPL=3, то любая программа может получить доступ к целевому сегменту, несмотря на то, что приоритет этого сегмента наивысший (0). Благодаря заданию в вентиле смещения обеспечивается гарантия того, что не будет осуществлен доступ к запретной части сегмента.
На рис. 46 схематично показана реализация косвенного перехода к целевому сегменту с помощью команды call и обратного перехода к исходному сегменту командой ret. Данная схема не содержит сведений о передаче информации на вход целевого сегмента, то есть параметров соответствующего системного вызова. Для такой передачи используется следующий подход. Так как исходный и целевой сегменты выполняются в разных кольцах защиты, то они используют разные стеки. При вызове целевого сегмента через вентиль вызова ЦП аппаратно копирует из стека вызывающей программы столько 16-битных слов, сколько задано в 5-битном счетчике слов в вентиле вызова. Максимальное число слов – 31.
Вентиль вызова представляет собой идеальное средство для реализации системных вызовов. С одной стороны все точки входа в ядро могут быть представлены в GDT с помощью своих вентилей входа, а с другой, исключается возможность несанкционированного доступа к внутренним модулям ядра.
Предыдущая глава | В начало | Следующий раздел |