Внутренние кольца защиты (уровень привилегированности 0, 1 и 2) имеют свои собственные стеки для приема вызовов из менее привилегированных уровней. Если стек должна была обеспечить вызывающая процедура, и стек оказался слишком мал, то в результате недостаточного размера стека может произойти сбой вызываемой процедуры. Поэтому обеспечивается защита более привилегированных программ от сбоя вследствие менее привилегированных программ путем создания нового стека при вызове менее привилегированными процедурами более привилегированных. Создается новый стек, параметры вызова копируются из старого стека в новый, а значения регистров сохраняются, после чего продолжается обычное выполнение вызванной процедуры. При возврате из этой процедуры содержимое сохраненных регистров восстанавливается в исходном стеке. Полное описание механизма переключения задач приводится в Главе 7.
Процессор находит место для создания новых стеков при помощи сегмента состояния задачи (TSS), как показано на Рисунке 6-8. Каждая задача имеет собственный TSS. TSS содержит исходные указатели стека для внутренних колец защиты. Операционная система отвечает за создание каждого TSS и инициализацию соответствующих им указателей стека. Исходный указатель стека состоит из селектора сегмента и исходного значения регистра ESP (исходное смещение в сегменте). Исходные указатели стеков представляют собой значения, предназначенные исключительно для чтения. Процессор не изменяет их во время выполнения задач. Эти указатели стеков используются только для создания новых стеков при выполнении вызовов процедур с более высоким уровнем привилегированности. При возврате из вызванных процедур эти стеки исчезают. При следующем вызове процедуры происходит создание нового стека с использованием для этого исходного указателя стека.
При использовании шлюза вызова для изменения уровней привилегированности новый стек создается загрузкой адреса из TSS. Процессор использует DPL кодового сегмента назначения (новый CPL) для выбора исходного указателя стека для уровней привилегированности 0, 1 или 2.
DPL нового стекового сегмента должен быть равен новому CPL: в противном случае генерируется исключение сбоя в стеке. Ответственность за создание стеков и дескрипторов стекового сегмента для всех используемых уровней привилегированности лежит на операционной системе. Стеки должны быть доступны для чтения/записи, как задано в поле Типа соответствующих сегментных дескрипторов. Они должны содержать достаточно памяти, как задано полем Граница, чтобы там могло поместиться содержимое регистров SS и ESP, адрес возврата, параметры и временные переменные, требуемые для работы вызываемой процедуры.
Как и при вызове в пределах одного уровня привилегированности, параметры для всех процедур помещаются в стек. Затем эти параметры копируются в новый стек. Доступ к этим параметрам из вызываемой процедуры происходит по тем же адресам, по которым эти параметры находились бы без переключения стека. Поле Счетчика шлюза вызова сообщает процессору, сколько двойных слов (до 31) должно копироваться из стека вызывающей процедуры в стек вызываемой процедуры. Если этот счетчик равен 0, то копирования параметров не происходит.
Если требуется передать в вызываемую процедуру более 31 двойного слова данных, то один из параметров можно сделать указателем на структуру данных, либо сохраненные в нем значения регистров SS и ESP могут использоваться для доступа к параметрам в старой области стека. Во время вызова процедуры с другим уровнем привилегированности процессор выполняет следующие связанные со стеком действия:
Проверяется стек вызываемой процедуры, чтобы убедиться, что он достаточно велик для того, чтобы хранить параметры и сохраняемые значения регистров; в противном случае генерируется исключение переполнения стека.
Старое содержимое регистров SS и ESP помещается в стек вызываемой процедуры в виде двух двойных слов (16-разрядный регистр SS расширяется нулем до 32 битов; это заполненное нулем старшее слово резервировано Intel для внутреннего пользования; не должно использоваться).
Параметры копируются из стека вызывающей программы в стек вызываемой программы.
В новый стек помещается указатель команды, находящейся после команды CALL (старое содержимое регистров CS и IP). Содержимое регистров SS и ESP после вызова указывает на этот указатель адреса возврата в стеке.
На Рисунке 6-9 показаны кадры стека до, во время и после успешного вызова и возврата между процедурами с разными уровнями привилегированности.
TSS не имеет указателя стека для стека с уровнем привилегированности 3, поскольку процедура с уровнем привилегированности 3 не может быть вызвана процедурой с еще более низким уровнем. Стек для уровня привилегированности 3 предохраняется содержимым регистров SS и EIP, которые сохраняются в стеке привилегированного уровня, вызванного из уровня 3.
Старый стек Новый стек Старый стек до вызова после вызова, после возврата до возврата ----------------| | | Старый SS | | ||-------------| |--------------| |-------------|| | | Старый ESP | | |<-ESP|-------------| |--------------| |-------------|| Параметр 1 | | Параметр 1 | | ||-------------| |--------------| |-------------|| Параметр 2 | | Параметр 2 | | ||-------------| |--------------| |-------------|| Параметр 3 |<-ESP | Параметр 3 | | ||-------------| |--------------| |-------------|| | | Старый CS | | ||-------------| |--------------| |-------------| | Старый EIP |<-ESP |--------------| | | |--------------| Рисунок 6-9. Кадры стека при вызове процедуры с другим уровнем привилегированности
Вызов, использующий шлюз вызова, не проверяет значений слов, копируемых в новый стек. Вызванная процедура должна проверять допустимость каждого параметра. В следующих разделах обсуждается использование команд ARPL, VERR, VERW, LSL и LAR для проверки значений указателей.