- •1. Завдання апаратного захисту
- •2. Підтримка керування пам'яттю
- •2.1. Віртуальні адреси
- •2.2. Віртуальна пам'ять
- •1. Завдання апаратного захисту
- •2. Підтримка керування пам'яттю
- •2.1. Віртуальні адреси
- •2.2. Віртуальна пам'ять
- •2.3. Трансляція адрес
- •3. Підтримка керування процесами
- •4. Особливості архітектури процесорів Intel х86
- •4.1. Регістри процесорів х86
- •4.2. Селектори та дескриптори сегментів і сторінок
- •5. Керування оперативною пам'яттю
- •5.1. Сегментний розподіл пам'яті
- •10. Порівнюються cpl, rpl і dpl:
- •5.2. Сегментно-сторінковий розподіл пам'яті
- •6. Керування задачами
- •6.1. Виклик процедур
- •6.2. Виклик задач
- •6.3. Привілейовані команди
5. Керування оперативною пам'яттю
Як уже зазначалося, архітектура процесорів х8б передбачає сегментну і сегмент-но-сторінкову моделі розподілу пам'яті. Засоби сегментної організації формують верхній рівень керування пам'яттю, а сторінкової — нижній (який можна вмикати та вимикати за допомогою прапорця pg в регістрі сгО) [63, 92].
5.1. Сегментний розподіл пам'яті
У сегментній моделі нам яті кожний сегмент утворює свій окремий адресний простір (див. рис. 10.1). Кількість сегментів визначається максимальною кількістю дескрипторів, яку може обробити процесор. Як уже зазначалося, кожний процес використовує одночасно дві таблиці — LDT і GDT; максимальна кількість дескрипторів у кожній із них визначається розрядністю індексу з селектора — 13 розрядів. Тобто в кожній таблиці може міститися до 213 дескрипторів, загалом — 16k (16 384) сегментів. З цього випливає, що в такому режимі кожний процес може мати 16k х 4 Гбайт ~ 64 Тбайт віртуального адресного простору.
Р
озглянемо
механізм трансляції адреси, коли процесор
працюєв
такому
режимі (рис. 10.10,10.11).

Цей механізм ініціюється за спроби звернутися до будь-яких даних у пам'яті (наприклад, коли дані завантажуються в регістр процесора чи записуються з регістра в пам'ять, та під час роботи зі стеком) або до нового сегмента (завантаження селектора в сегментний регістр). Принципово цей механізм відповідає схемі, наведеній на рис. 10.3. Насправді ж перша частина алгоритму виконується лише під час завантаження селектора в сегментний регістр. Якщо здійснюється доступ до даних всередині сегмента, пошук дескриптора сегмента не виконується, позаяк процесор має спеціальні 64-розрядні регістри для зберігання дескрипторів, що відповідають завантаженим у сегментні регістри селекторам. Ці дескрипторні регістри є тіньовими, програмно недоступними. Дескриптор завантажується разом із селектором.
Завантаження селектора в сегментний регістр
Розглянемо процедуру завантаження селектора в сегментний регістр. Спочатку процесор має знайти у пам'яті відповідний дескриптор і здійснити необхідні перевірки.
Якщо у селекторі прапорець ТІ « 0, то дескриптор міститься в глобальній таблиці дескрипторів GDT. Базова адреса і межа (тобто розмір) таблиці GDT визначаються з регістра gdtr. Для вибору потрібного дескриптора використовується індекс, що міститься в селекторі. Індекс — це фактично номер дескриптора в таблиці. Оскільки адресація здійснюється побайтово, індекс необхідно помножити на 8 (розмір дескриптора в байтах), що досягається зміщенням уліво на три розряди. Насправді ж, через те що індекс у селекторі займає 13 старших розрядів, він вже фактично зсунутий на три розряди вліво, тому достатньо обнулити три молодших розряди селектора і додати останній до базової адреси таблиці. Далі здійснюється перша операція, що стосується захисту сегментів пам'яті, — перевіряється, чи не виходить дескриптор за встановлену межу таблиці GDT. Якщо ні — відбувається звернення до дескриптора. У разі виходу за межу генерується внутрішнє переривання процесу — виняткова ситуація 11.
Якщо ж у селекторі прапорець ТІ = 1, дескриптор міститься в таблиці LDT. Тоді спочатку визначається поточна таблиця LDT, для чого як селектор використовують уміст регістра Idtr. Після виконання операції, аналогічної описаній вище, з таблиці GDT вибирається дескриптор, що описує таблицю LDT (нагадаємо, що таблиця дескрипторів - це спеціальний вид сегмента). При цьому перевіряється, чи відповідає тип дескриптора таблиці дескрипторів (див. табл. 10.4) та чи є таблиця в пам'яті (біт Р байта AR дескриптора дорівнює 1). З дескриптора таблиці LDT визначаються базова адреса таблиці та її межа. Потім із цієї таблиці обирається потрібний дескриптор, так само, як із таблиці GDT і з тими самими перевірками. (На рис, 10.10 і 10.11 операції перевірки виходу поза межі таблиць і сегментів не показано.)
В обох випадках було розглянуто процедуру до моменту звернення до дескриптора сегмента, селектор якого ми завантажуємо в регістр.
Д
алі
здійснюється перевірка сумісності
типів селектора і дескриптора. Дескриптор
має описувати сегмент у пам'яті (бітS
= 1). Якщо селектор завантажується в
регістр, що вказує на сегмент даних, то
несумісним буде дескриптор, що описує
сегмент коду із захистом від читання
(біт Е w
1,
біт R
== 0). Якщо селектор завантажується в
регістр cs,
то
сумісним буде лише сегмент коду, і
аналогічно під час завантаження
селектора в регістр ss
сумісним
буде лише сегмент стека (табл. 10.6).
Очевидно, більш суворі умови сумісності
для сегментів стека і коду спрямовані
на запобігання «підсовування» процесору
зловмисного коду через сегменти даних,
У випадку коли перевірка дає негативний
результат, фіксується несумісність
типів — генерується виняткова ситуація
13 (загальна помилка захисту).
Потім перевіряються привілеї доступу до сегмента. Для цього порівнюються значення RPL (рівень привілеїв селектора, який ми завантажуємо в сегментний регістр процесора), DPL (рівень привілеїв дескриптора, на який посилається селектор, що ми його завантажуємо) і CPL (поточний рівень привілеїв, тобто рівень привілеїв процесу, що виконується), який дорівнює RPL селектора, що знаходиться в регістрі cs). Для сегмента стека (за спроби завантажиш селектор у регістр ss) має виконуватися рівність DPL ш RPL = CPL. Для решти сегментів рівень DPL має бути не вищим за рівні RPL і CPL, тобто DPL > RPL і DPL > CPL (нагадаємо, що найвищому рівню привілеїв відповідає значення 0, а найнижчому — 3). Якщо потрібне співвідношення не виконується, фіксується недостатній рівень привілеїв — виняткова ситуація 13 (загальна помилка захисту).
Розглянемо приклад [91]. Зауважимо, що, описуючи послідовність перевірок, ми припускалися, що у разі фіксації помилки виконання алгоритму припиняється і викликається оброблювач відповідного переривання.
Приклад 1. Завантаження селектора в сегментний регістр
Виконується команда
mov ds, ах
Регістр ах містить значення 0x37 * 0000000000110111. Процес виконується в нульовому кільці захисту, тобто CPL = 0.
Аналізується біт ТІ селектора. ТІ - 1 (тобто дескриптор знаходиться в LDT).
Обчислюється фізична адреса дескриптора dt локальної таблиці дескрипторів LDT, що відповідає поточному процесу (дескриптор dt знаходиться в таблиці GDT).
З дескриптора dt добувається межа LDT ldtjimit.
Якщо в dt G=l, то ldt_limit Ьш 4096 (межа у 4-кілобітових сторінках).
Із селектора добувається індекс дескриптора: index = 6
Перевіряється, чи не виходить індекс за межі таблиці LDT: (index +1) * 8 - 1 = 55
Якщо Idt limit < 55, фіксується некоректність селектора (помилка 11).
7. З таблиці LDT добувається дескриптор d сегмента:
offset = index * 8 = 48; d_addr = Idt_base + offset
Якщо в d біт S = 0 або одночасно E * 1 і R e 0, фіксується несумісність типів селектора і регістра (помилка 13).
Із селектора добувається RPL:
RPL f З
