- •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.2. Сегментно-сторінковий розподіл пам'яті
Якщо сторінковий механізм вимкнено (в регістрі сгО біт pg = 0), з дескриптора за розглянутими вище алгоритмами визначається фізична базова адреса сегмента, а після додавання до неї зміщення — фізична адреса даних у пам'яті. Якщо ж сторінковий механізм увімкнено (в регістрі сгО біт pg = 1), то з дескриптора за тими самими алгоритмами визначається лінійна базова адреса сегмента, а після додавання до неї зміщення — лінійна адреса даних. Для обчислення фізичної адреси здійснюється сторінкове перетворення. Те саме стосується не лише адрес даних, а й базових адрес таблиць дескрипторів і адрес самих дескрипторів. Сторінкове перетворення показано на рис. 10.4. Механізм сторінкового перетворення може використовувати атрибути захисту сторінок з дескриптора (див. табл. 10.5).
Важливою відмінністю сегментно-сторінкового розподілу пам'яті порівняно з сегментним розподілом пам'яті у процесорах х86 є те, що в режимі сегментно-сторінкового розподілу пам'яті максимальним віртуальним адресним простором є 4 Гбайт, і різні сегменти можуть перекриватися (вони можуть мати однаковий розмір у 4 Гбайт і перекриватися повністю). Тоді до однієї лінійної адреси можна звернутися через різні сегменти та обійти таким чином згадані вище функції захисту сегментів. Ці проблеми процесор не вирішує, а передає їх у сферу відповідальності операційної системи. Саме розробники операційної системи визначають, як будуть виділятися сегменти пам'яті процесам і потокам і як буде організовано взаємодію між ними, зокрема обмін даними.
Нумерація віртуальних сторінок — наскрізна та не залежить від поділу віртуального адресного простору на сегменти. Кожний процес має свій 4-гігабайтовий віртуальний адресний простір, а також власний набір розділів таблиць сторінок і власну таблицю розділів. Адресація таблиці розділів здійснюється через регістр сгЗ, отже, значення цього регістра специфічне для кожного процесу.
6. Керування задачами
Процесори х86 надають засоби для підтримки виклику процедур і задач [63, 92]. Виклик процедури означає виклик коду в межах одного процесу (потоку), коли відбувається переключення на інший сегмент коду (виклик процедури в межах
одного сегмента є тривіальним і не потребує спеціальних заходів захисту; відтак ми його не розглядатимемо), але зберігаються структури, що керують адресним простором процесу (таблиця LDT, таблиця сторінок). Після виклику задачі операційною системою створюється новий процес з усіма відповідними структурами і відбувається переключення на нього. Виклик задачі здійснюється також у бага-тозадачній операційній системі, коли відбувається переключення між процесами. У такій системі необхідні структури вже є, і потрібно лише переключитися на них, забезпечивши збереження відповідних структур поточного процесу. За будь-якого виклику використовується захист, заснований на рівнях привілеїв.
6.1. Виклик процедур
Виконуючи будь-який програмний код, сучасні операційні системи постійно викликають процедури, код яких розміщено в інших сегментах. Такі сегменти можуть належати іншому програмному модулю тієї самої програми, бібліотеці або операційній системі. Процесори х86 пропонують кілька способів виклику процедур з інших сегментів:
прямий виклик процедури з непідпорядкованого сегмента;
прямий виклик процедури з підпорядкованого сегмента;
непрямий виклик процедури через шлюз.
Правила розмежування доступу на підставі привілеїв ураховують окрім, власне, рівнів привілеїв CPL, RPL і DPL ще й так звану підпорядкованість сегмента, що містить код процедури. Підпорядкованість сегмента задається прапорцем С у байті захисту дескриптора сегмента коду (див. табл. 10.3): С = 1 — підпорядкований сегмент, С Щ 0 - непідпорядкований сегмент.
Прямий виклик процедури з непідпорядкованого сегмента
Цей спосіб полягає у розміщенні в полі команди JMP або CALL селектора, який вказує на дескриптор нового кодового сегмента, того, що містить код процедури, яку викликають. Початкова адреса (точка входження) процедури визначається з базової адреси сегмента, яка знаходиться у дескрипторі, та зміщення, заданого в команді JMP або CALL.
Для такого виклику встановлено суворі правила захисту. Якщо сегмент, який викликають, є непідпорядкованим, то виклик дозволено лише тоді, коли рівень привілеїв сегмента, з якого робиться виклик, дорівнює рівню привілеїв сегмента, який викликають, тобто CPL ~ DPL Виклик процедури за умови, що CPL > DPL (тобто поточний код має нижчий рівень привілеїв, ніж код, який намагаються викликати), заборонено з очевидних міркувань захисту критичного коду з більшими привілеями від виклику з процедур, що мають нижчі привілеї, наприклад, для захисту процедур ОС від безконтрольного виклику з процедур користувача (безконтрольного — оскільки за такого виклику можна задати будь-яку точку входження і передати через стек будь-які параметри).
Але й протилежна ситуація, а саме виклик за умови, що CPL < DPL (тобто поточний код має виший рівень привілеїв за код, який намагаються викликати), також заборонена. Це обмеження введено зтше міркувань, що у загальному випадку привілейований код не може використовувати процедури з низькими привілеями, позаяк останні вважаються ненадійними.
Прямий виклик процедури з підпорядкованого сегмента
Виклик підпорядкованих сегментів — це один зі способів, у який програми з низьким рівнем привілеїв можуть використовувати код, що має високий рівень привілеїв. Наприклад, це буває корисним, коли програми користувача застосовують системні бібліотеки. Виклик коду процедури, яка розміщується в підпорядкованому сегменті, здійснюється аналогічно виклику процедур із непідпорядкованих сегментів (точки входження так само можна задавати в довільний спосіб). Але у разі підпорядкованого сегмента виклик здійснюється за умови, що CPL > DPL, тобто код, що викликає, має привілеї, не вищі за привілеї коду, який викликають. Підпорядкований сегмент має особливу властивість. Код із підпорядкованого сегмента успадковує рівень привілеїв коду, що його викликав, тому, яким би не був DPL підпорядкованого сегмента, під час виклику коду CPL не змінюється. Наприклад, код системної бібліотеки, який міститься в сегменті з DPL ш 0 виконуватиметься з CPL т 0, якщо його було викликано з ядра ОС, і з CPL = 3, якщо його було викликано з програми користувача. Тож системний код, викликаний із програми користувача, буде мати обмежені можливості доступу до системних даних і достатні можливості для роботи з даними користувача.
Непрямий виклик процедури через шлюз
Можливостей, які надає виклик процедур із підпорядкованого сегмента, недостатньо, щоб реалізувати системні виклики, позаяк потрібно не лише виконувати визначений код, а й звертатися до системних даних. Механізм контрольованого виклику процедур, які виконуються зі своїм рівнем привілеїв, вищим за той, що має поточний код, реалізується за допомогою шлюзів.
Ш
люз
— це спеціальний системний дескриптор
(рис. 10.12, табл. 10.8). Шлюз, який може бути
розташовано і в таблиціGDT,
і
в таблиці LDT,
призначений
для виклику не сегмента коду, а окремої
процедури з нього. Для виклику цієї
процедури шлюз містить адресу її
точки входження — селектор сегмента і
зміщення. Виклик здійснюється шляхом
розміщення в полі команди JMP
або
CALL
селектора,
який вказує на шлюз (задане в команді
зміщення не береться до уваги).
Шлюз має власний DPL, який визначає можливість доступу до нього коду: виконується умова CPL <DPL, тоді код має привілеї, не нижчі за привілеї шлюзу. Рівень DPL сегмента того коду, що викликається через шлюз, із рівнем CPL не порівнюється, натомість порівнюється із RPL селектора, що міститься у шлюзі. Якщо виклик успішний, код виконується зі своїм CPL, заданим DPL сегмента.
Таблиця 10.8. Поля шлюзу виклику процедури
|
Номер байта |
Ширина |
Символьне |
Призначення 1 вміст полів |
|
ш шлюзі |
поля |
позначення |
|
|
|
(розради) |
|
|
|
0...1 |
16 |
offset_l |
Молодші 16 розрядів зміщення точки входження |
|
2...3 |
16 |
selector |
Селектор сегмента, який містить код |
|
А |
|
|
процедури |
|
ч біти 0...4 |
5 |
WC |
Лічильник параметрів |
|
біти 5.,.7 |
3 |
|
Заповнення нулями |
|
5 |
|
|
Байт захисту |
|
біти 0...3 |
4 |
Type |
Тип: С (386) або 4 (286) |
|
біт 4 |
у. |
S |
=0 — «системний» |
|
біти 5...6 |
2 |
DPL |
Рівень привілеїв шлюзу |
|
біт 7 |
І |
P |
Щ — шлюз відкритий |
|
|
|
|
=0 — шлюз закритий |
|
ш |
16 |
offset 1 |
Старші 16 розрядів зміщення точки входження |
Шлюзом можна керувати: біт Р у байті захисту шлюзу використовується для його «відкривання» або «закривання».
Виклик через шлюз надає також можливість контрольовано передавати параметри через стек. У будь-якому процесі передбачено кілька (до трьох) стеків, кожний з яких відповідає певному рівню привілеїв. Під час виклику через шлюз процедури, яка має рівень привілеїв, відмінний від CPL, процесор створює нови^стек шляхом завантаження в регістр ss селектора, що відповідає потрібному рівню привілеїв (цей селектор міститься в контексті процесу TSS). У новий стек із поточного копіюється стільки 32-розрядних слів (параметрів виклику процедури), скільки вказано в полі WC шлюзу. Також у новий стек копіюється селектор старого стека, який дає змогу повернутися до процедури, з якої було здійснено виклик.
