Теорія операційної системи

:: Меню ::

Головна
Представлення даних в обчислювальних системах
Машинні мови
Завантаження програм
Управління оперативною пам'яттю
Сегментна і сторінкова віртуальна пам'ять
Комп'ютер і зовнішні події
Паралелізм з точки зору програміста
Реалізація багатозадачності на однопроцесорних комп'ютерах  
Зовнішні пристрої
Драйвери зовнішніх пристроїв
Файлові системи
Безпека
Огляд архітектури сучасних ОС

:: Друзі ::

Карта сайту
 

:: Статистика ::

 

 

 

 

 

Сегменти, сторінки і системні виклики

  Про, породження Землі і Тьми, ми наказуємо тобі відректися...- твердим, наказовим тоном почав Гальдер.
Смерть кивнув.
— ТАК, ТАК, ЗНАЮ Я ВСЕ ЦЕ. ВИЗИВАЛІ-ТО ЧЕГО'' Т. Пратчетт

Реалізувавши сторінкову або сегментну віртуапьную пам'ять, ми стикаємося з тією ж проблемою, про яку йшла мова в разд. Системи з базовою віртуальною адресацією: призначені для користувача програми не мають доступу до адресних просторів один одного і до таблиці дескрипторів, але ж їм треба мати можливість викликати системні сервіси і передавати їм параметри!
Один з основних способів вирішення цієї проблеми схожий на метод, вживаний в системах з базовою адресацією: вводяться два режими роботи процесора, "системний" і "призначений" для користувача, в яких використовуються різні таблиці дескрипторів. Перемикання з призначеного для користувача режиму в системний здійснюється спеціальною командою, яка викликає певну процедуру в системному адресному просторі.
Відому складність при цьому представляє передача параметрів: як наголошувалося вище, призначений для користувача адресний простір може відображувати на фізичні адреси вельми химерним чином. Для дозволу покажчика в цьому адресному просторі нам або необхідно аналізувати призначену для користувача таблицю дескрипторів уручну, або якимсь способом тимчасово перемкнути диспетчер пам'яті на використання цієї таблиці.
Більшість процесорів з диспетчером пам'яті надають команд, копіювання даних з призначеного для користувача адресного простору в системне і назад. Звичайно ж. доступні ці команди лише з системного режиму.
Деяка архітектура надає і витонченіші способи реалізації системних викликів і передачі управління між системою і прикладною програмою.

Віртуальна пам'ять і режими процесора VAX
Наприклад, мінікомп'ютери VAX мають чотири режими роботи процесора (в порядку зростання прав доступу): режим користувача (User), режим супервізора (Supervisor), режим виконавця (Executive) і режим ядра (Kernel) Режим роботи визначається бітами 22 і 23 в слові достатку процесора (мал. 5.5). Кожен з режимів має власний покажчик стека. Операційна система Vax/vms використовує три з доступних режимів (призначений для користувача, старанний і ядра), а BSD Unix - лише два.

Кожна сторінка адресного простору може мати різні права доступу для різних режимів. При цьому дотримуються наступні правила.

  1. 1. Допустимі лише права читання і запису.
  2. 2. Право запису завжди видається разом з правом читання.
  3. 3. Кожен більш привілейований режим завжди має ті ж права, які мають менш привілейовані режими, плюс, можливо, якісь ще. Така організація доступу називається кільцями захисту.

Мал. 5.5. Слово достатку процесора VAX

Ті, що всі допускаються цими правилами комбінації прав можуть бути закодовані за допомогою чотирьох біт в дескрипторі сторінки (таблиця. 5.1). Перемикання режимів здійснюється командами СНМК, СНМЕ CHMS і CHMU. Ці команди поміщають слово достатку процесора і лічильник команд в стек, відповідний новому режиму, зберігають попередній режим в спеціальному полі слова достатку (навіщо потрібно зберігати режим в двох місцях, ми зрозуміємо ледве пізніше), встановлюють новий режим і, нарешті, передають управління за фіксованою адресою, аналогічно команді SYSCALL в системах з двома рівнями доступу. Передача управління за фіксованою адресою дозволяє нам захиститися від безконтрольного підвищення рівня доступу, а всі попередні операції дають можливість повернутися на попередній рівень доступу з одночасною передачею управління, використовуючи спеціальну команду REI яка відновлює і лічильник команд, і слово достатку. Команди СHМ(Х) зазвичай використовуються для підвищення рівня доступу, а REI може використовуватися лише для його пониження або повернення на той же рівень (мал. 5.6).

Мал. 5.6. Перемикання режимів процесора VAX

Таблиця 5.1. Коди захисту для різних режимів доступу процесора VAX. Цитується по [Прохоров, 1990]

Код Kernel Executive Supervisor User
0000 - - - -
0001 Не передбачений
0010 RW - - -
0011 R - - -
0100 RW RW RW RW
0101 RW RW - -
0110 RW R - -
0111 R R - -
1000 RW RW RW -
1001 RW RW R -
1010 RW R R -
1011 R R R -
1100 RW RW RW R
1101 RW RW R RW
1110 RW R R R
1111 R R R R

R — право читання, W — право запису------відсутність прав.

32-бітове адресний простір процесора VAX розбитий на чотири частини, кожна об'ємом по гігабайту. Перший гігабайт адрес призначений для коди і даних призначеної для користувача програми, другої, — для призначеного для користувача стека, третій — для системи, четвертий не використовується (мал. 5.7). Кожна з частин має власний покажчик на таблицю дескрипторів сторінок. Поважно відзначити, що ділення адресного простору на таблиці не обов'язково пов'язане з правами доступу на окремі сторінки — в системній таблиці можуть бути сторінки, доступні для запису з призначеного для користувача режиму (на практиці цього ніколи не буває, але на рівні диспетчера пам'яті контролю за цим не реалізовано), а в призначеній для користувача — сторінки, доступні лише ядру.

Мал. 5.7. Адресний простір VAX

Системна таблиця сторінок одна у всій системі і міститься в адресних просторах всіх завдань. Навпаки, призначені для користувача таблиці в кожного завдання свої (уважний читач може відзначити певну паралель між цією структурою і описаним в разд. Банки пам'яті перемикачем банків пам'яті, який присутній у всіх банках). Для того, щоб спростити системі управління призначеними для користувача таблицями дескрипторів, ці таблиці зберігаються не у фізичному, а у віртуальному системному адресному просторі, і при доступі до них відбувається подвійна трансляція адреси.
Ядро системи, таким чином, присутнє в адресних просторах всіх завдань. Багато системних модулів (наприклад, функція для здобуття поточного реального часу) доступні для читання з призначеного для користувача режиму і можуть викликатися безпосередньо, як звичайні процедури. Адреси точок входу цих процедур розміщені в спеціальній таблиці на початку системного адресного простору (мал. 5.8). Інші системні модулі (наприклад, підсистема роботи з файлами, RMS — Record Management Service (Служба управління записами)) вимагають підвищення рівня доступу: дійсно, якщо одне із завдань працює з файлами з обмеженим доступом, було б безрозсудно дозволяти всім останнім завданням бачити використовувані при цьому системні буфери. Точки входу цих процедур розміщуються в тій же таблиці, що і системні підпрограми, що прямо викликаються, але тіла цих процедур складаються лише з двох команд: перемикання режиму процесора і повернення.

Мал. 5.8. Точки входу системних підпрограм Vax/vms

Процедура, що працює в "підвищеному" (більш привілейованому) режимі процесора, має повний доступ до всіх даних режимів з нижчим рівнем доступу. Завдяки цьому ми можемо передати привілейованій процедурі покажчик, і вона дістанеться до наших даних простим дозволом цього покажчика, без яких би то не було спеціальних команд.
Втім, при такому підході виникає певна проблема. Оскільки система і користувач знаходяться в одному адресному просторі, користувач може "підсунути" системі покажчик на сторінку, до якої сам не має доступу, — наприклад, попросити рахувати щось з файлу в системний сегмент даних. Для виключення таких ситуацій VAX надає команди PROBSR і PROBEW, які перевіряють, чи існує доступ до вказаної сторінки в попередньому режимі роботи процесора. Як ми пам'ятаємо, попередній режим зберігається не лише в стеку, але і в слові достатку процесу, і потрібно це саме для таких перевірок.
Видно, що обійтися без спеціальних команд все-таки не удалося. До того ж платою за прийняте в VAX технічне рішення опинилося скорочення корисного адресного простору завдання в два, а насправді навіть в чотири (КТО потрібний стек розміром 1 Гбайт?) рази. У 70-і роки, коли розроблявся VAX, це ще не видавалося проблемою.

Рівні доступу 80286
Ледве далі в близькому напрямі просунулися розробники 80286: в цього процесора рівень доступу визначається старшими двома бітами селектора сегменту (мал. 5.9). Код, що виконується в сегменті з рівнем доступу 2, має доступ до всіх сегментів свого і нижчих рівнів. Міжсегментний перехід з підвищенням рівня доступу можливий лише через сегменти із спеціальним дескриптором, так звані шлюзи (gate).

Мал. 5.9. Структура адреси процесора i80286

У цій архітектурі для перевірки прав доступу до сегменту в попередньому режимі роботи не потрібні спеціальні команди, досить перевірки селектора сегменту.
80286, хоча і надавав майже повноцінну сегментну адресацію, не мав сегментних відмов, тому використовувати всі переваги віртуальної пам'яті на цьому процесорі було неможливо. Другим недоліком була відсутність режиму сумісності з 8086 — не існувало можливості створити таку таблицю трансляції, яка б відтворювала специфічну структуру адресного простору цього процесора. Частково це було обумовлено і використанням бітів в селекторі сегменту для завдання прав доступу. Обидві ОС, які розроблялися для цього процесора, - Win16 і Os/2 1 .х — великого успіху не мали.
Os/2 використовує три режими доступу: призначений для користувача, системні DLL і власне ядро, з чотирьох, що надаються архітектурою х86 (мал. 5.10).
Windows NT (яка починала свою кар'єру як Os/2 New Technology) спочатку проектувалася як переносима ОС. Вимога переносимості на RISC-архитектуры з двома рівнями привілеїв змусила розробників відмовитися від рівня системних DLL. Пізніше фірма Microsoft поступово відмовилася від підтримки всієї апаратної архітектури, окрім х86 (довше за всіх вони трималися за DEC Alpha), але дворівнева структура доступу так і залишилася в нових версіях цієї системи — Windows 2000/xp.

Мал. 5.10. Рівні доступу в Os/2

Системи сімейства Unix використовують х86 як нормальну 32-розрядну машину з дворівневим доступом: призначеному для користувача завданню виділяється один сегмент, ядру— інший. 4-х гігабайтного сегменту х86, розбитого на сторінки розміром по 4 Кбайт, досить для більшості практичних цілей. Наприклад, в Linux системний виклик виконується командою int 8oh. Селектор призначеного для користувача сегменту поміщається в регістр FS. Для доступу до цього сегменту з модулів ядра використовуються процедури memcpy_from_fs і memcpy_to_fs.

Багаторівневий доступ, заснований на концепції кілець, не має принципових переваг в порівнянні з двома рівнями привілеїв. Як і в дворівневій системі, призначені для користувача модулі вимушені повністю довіряти привілейованим, привілейовані ж модулі не можуть захиститися навіть від помилок у власному коді. Найкраще, що може зробити Windows XP, виявивши спробу звернення до неприпустимої адреси в режимі ядра, — це намалювати на синьому екрані дамп регістрів процесора. У Os/2, фатальна помилка в привілейованих модулях, що виконуються в другому кільці захисту, не обов'язково приводить до зупинки ядра, але підсистема, в якій сталася помилка, виявляється непрацездатна. Якщо зіпсований призначений для користувача інтерфейс або мережева підсистема, система в цілому стає даремною і потребує перезавантаження.
Крім того, розділення адресних просторів створює складнощі при розділенні коди і даних між процесами: об'єкти, що розділяються, можуть опинитися відображують в різних процесах на різні адреси, тому в таких об'єктах не можна зберігати покажчики (детальніше за див. разд. Бібліотеки, що розділяються). Прагнення обійти ці труднощі і створити систему, в якій поєднувалися б переваги як єдиного (легкість і природність межпроцессного взаємодії), так і роздільних (захист процесів один від одного) адресних просторів, багатьох років займало розуми розробників апаратної архітектури.
Наприклад, машини фірми Burroughs надавали користувачеві і системі єдиний адресний простір, розбитий на сегменти (єдину таблицю дескрипторів сегментів). При цьому виникає питання: якщо всі завдання використовують одну таблицю, як може вийти, що різні завдання мають різні права на один і той же сегмент?
Рішення цього питання полягає в тому, що права доступу кодуються не дескриптором, а селектором сегменту. Таким чином, різні права доступу на один сегмент — це, строго кажучи, різні адреси. Зрозуміло, що таке розділення працює лише постільки, поскільки призначена для користувача програма не може формувати довільні селектори. У комп'ютерах Burroughs це досягалося тегової архітектурою: кожне слово пам'яті забезпечувалося додатковими бітами тегом (tag)який визначав типа даних, що зберігаються в цьому слові, і допустимі над ним операції. Бітові операції над покажчиками не допускалися. Завдяки цьому завдання не могло сформувати не лише довільні права доступу, але і взагалі довільний покажчик.
Аналогічним чином реалізований захист пам'яті в As/400 [redbooks.ibm.com sg242222.pdf). Призначені для користувача програми мають спільний адресний простір. Первинно це спільний простір імен, в процесі ж перетворення імені в адресу бінарне представлення селектора сегменту забезпечується і бітами доступу, які потім обробляються точно так, як і в машинах Burroughs, і так само недоступні призначеному для користувача коду для модифікації.
Реалізації мови З для цієї архітектури допускають використання покажчиків лише в межах одного сегменту коди або даних, але не дозволяють формувати засобами З довільні селектори сегментів, останні ж мови, використовувані на цій платформі (Cobol, RPG, мови процедур СУБД, що зберігаються) взагалі не мають покажчика як поняття.
Ще далі в тому ж напрямі просунулися розробники фірми Intel, створюючи експериментальний мікропроцесор 1АРХ432, описаний в наступному розділі.

 

:: Реклама ::

 

:: Посилання ::


 

 

 


Copyright © Kivik, 2017