Глава 4. Шлюз вызова.
Для обеспечения контролируемого доступа к сегменту кода на другом уровне привилегий, процессор предоставляет 4 специальных типа дескрипторов, так называемых шлюзов:
| Шлюз вызова (Call gate)
| Шлюз ловушки (Trap gate)
| Шлюз прерывания (Interrupt gate)
| Шлюз задачи (Task gate)
| |
Шлюзы ловушки и прерывания используются в дескрипторной таблице прерываний (IDT) и описаны в разделе "Прерывания в защищённом режиме". Шлюз задачи используется для передачи управления задаче и подробно описан в разделе "Мультизадачность". Здесь же описан только шлюз вызова.
Шлюз вызова позволяет передавать управление с одного уровня привилегий на другой. Также шлюз вызова полезен при передаче управления между 16- и 32-разрядным кодом.
На рис. 4-1 приведен формат дескриптора шлюза вызова.
Этот дескриптор можно размещать в GDT и LDT, но не в IDT. Дескриптор шлюза вызова выполняет 6 функций:
| Определяет сегмент кода, к которому будет доступ.
| Определяет точку входа в этом сегменте.
| Определяет уровень привилегий, который должна иметь вызывающая процедура.
| При смене стека, он указывает число необязательных параметров, копируемых процессором из одного стека в другой.
| Определяет размер значений, записываемых в целевой стек: 16-разрядный шлюз использует 16-разрядные значения, 32-разрядный - 32-разрядные.
| Определяет присутствие шлюза вызова.
| |
Поле селектора в шлюзе вызова определяет целевой сегмент кода, смещение задаёт точку входа. DPL определяет уровень привилегий шлюза вызова, который должна иметь процедура, чтобы передать управление через него.
Флаг P определяет присутствие дескриптора шлюза вызова в памяти. Поле счётчика определяет число параметров (16- или 32-разрядных, в зависимости от разрядности шлюза), копируемых из стека вызывающей процедуры в стек вызываемой процедуры (если происходит смена стека).
Как правило, флаг P (присутствие дескриптора) всегда установлен, если же он сброшен (т.е. равен 0), то при обращении к шлюзу процессор генерирует исключение неприсутствующего сегмента (#NP). Используя бит P система может определить число переходов через этот шлюз. Для этого бит присутствия шлюза сбрасывается, а функции обработчика исключения #NP сводятся к увеличению на 1 счётчика переходов через шлюз и установке бита P. После возврата из такого обработчика процессор снова попытается передать управление через шлюз и сделает это, если больше никаких нарушений в нём не обнаружит.
Шлюз вызова по сути определяет дальнюю точку входа (селектор:смещение) для процедуры. При передаче управления через шлюз вызова, вызывающая процедура должна использовать далёкий адрес, селектор которого указывает на шлюз, смещение при этом будет проигнорировано процессором (см. рис. 4-2). Селектор, указанный в шлюзе вызова, может выбирать дескриптор из GDT или LDT.
При передаче управления через шлюз вызова, используются 4 типа уровней привилегий:
| CPL,
| RPL селектора шлюза вызова,
| DPL дескриптора шлюза вызова,
| DPL дескриптора целевого сегмента кода.
| |
Также учитывается флаг C (подчинение) в дескрипторе сегмента кода.
Правила проверки уровня привилегий отличаются, в зависимости от того, какой командой было передано управление (см. таб. 4-1):
| Команда | Правила проверки привилегий |
| CALL | CPL ≤ DPL шлюза вызова
RPL ≤ DPL шлюза вызова DPL целевого подчинённого сегмента ≤ CPL DPL целевого неподчинённого сегмента ≤ CPL |
| JMP | CPL ≤ DPL шлюза вызова
RPL ≤ DPL шлюза вызова DPL целевого подчинённого сегмента ≤ CPL DPL целевого неподчинённого сегмента = CPL |
Поле DPL дескриптора шлюза вызова определяет наибольший номер уровня привилегий, с которого вызывающая процедура может обращаться к шлюзу. Таким образом, для доступа к шлюзу CPL вызывающей процедуры должен быть не больше DPL шлюза.
RPL селектора шлюза вызова должен удовлетворять тем же условиям, что и CPL вызывающей процедуры, т.е. RPL должен быть не больше DPL шлюза.
Если проверка уровня привилегий между вызывающей процедурой и шлюзом вызова успешна, то процессор проверяет DPL дескриптора сегмента кода, сравнивая его с CPL вызывающей процедуры.
Правила проверки уровня привилегий отличаются для команд JMP и CALL. Только команда CALL может использовать шлюз вызова для передачи управления более привилегированному неподчинённому сегменту кода (т.е., чей DPL ≤ CPL). Команда JMP может использовать шлюз вызова только для передачи управления в неподчинённый сегмент кода с DPL = CPL. Команды JMP и CALL обе могут передавать управление более привилегированному подчинённому сегменту кода (т.е., чей DPL ≤ CPL).
Если вызов производится на более привилегированный неподчинённый сегмент кода, то CPL опускается до значения DPL и производится переключение стека. Если же передача управления происходит в подчинённый сегмент кода, то CPL не меняется и стек не переключается.
Шлюзы вызова позволяют одному сегменту кода иметь доступ к процедурам, располагающимся на разных уровнях привилегий. Например, операционная система, находящаяся в сегменте кода, может иметь некоторые сервисы, которые могут использоваться как ею самой, так и прикладными программами (например, процедуры по обработке ввода/вывода символов).
| Следующая глава | Оглавление | Вопросы? Замечания? Пишите: sasm@narod.ru |
| Copyright © Александр Семенко. |
|
|