Що робить центральний процесор, коли йому нема чого робити


Мужик приходить влаштовуватися працювати на будівництво. Його запитує майстер:
— Що вмієш робити?
— Можу копати…
— А що ще?
— Можу не копати...
Не секрет, що сучасні процесори працюють дуже швидко. Робота їх полягає в постійному витягу з пам'яті інструкцій та виконання передбачених у них дій. Однак виявляється, з тих чи інших причин часто потрібно пригальмувати цей процес. У прикладних програмах рідко доводиться замислюватися про те, що при цьому відбувається з процесором. Але от для творців системного софта це далеко не просте питання.
Неактивним процесор може бути не тільки для економії енергії, але і в результаті виникнення особливих ситуацій, в процесі виконання протоколів ініціалізації або як підсумок навмисних дій системних програм. Чому це цікаво? При написанні програмних моделей (у тому числі віртуальних машин) комп'ютерних систем, необхідно коректно моделювати переходи між станами віртуальних процесорів. В роботі системних програм регулярно виникають ситуації, коли по тим чи іншим причинам ЦПУ повинен «пригальмувати». Вміння коректно використовувати і моделювати ці ситуації залежить від знання і розуміння специфікацій.
У статті фокус робиться на програмній стороні питання станів процесора. Я не буду концентруватися на деталях реалізації (напруги, піни, частоти тощо), так як 1) вони істотно розрізняються між поколіннями і моделями процесорів навіть однієї архітектури, тоді як програмний інтерфейс залишається назад сумісним; 2) вони не помітні безпосередньо програм і ОС. Це спроба підсумувати інформацію, розкидану по багатьох сторінках довідника Intel IA-32 and Intel 64 Software Developer Manual.
Почнемо з простого і всім знайомій ситуації — процесор включений, бадьорий і веселий.

Активний стан

звичайний стан процесора, в якому він продовжує виконувати інструкції одну за одною. При цьому сучасні процесори можуть динамічно змінювати частоту свого тактового генератора для потреб управління енергоспоживанням. Використовуючи прийняту термінологію, в активному режимі логічний процесор залишається в стані C0, але може змінювати P-стани.
Частково цим процесом можна керувати програмно, з BIOS, ОС або прикладних програм. Проте останнє слово в управлінні при цьому залишається поза контролем програм, запущених на центральному процесорі.
У всіх інших режимах, що описуються далі, процесор не виконує інструкції.

HLT

Перший з неактивних режимів, що з'явилися ще в родоначальника серії Intel 8086, пов'язаний з однойменною інструкцією процесора. Виконавши цю інструкцію, процесор припиняє свою роботу, вже не виконуючи наступну команду. Починаючи з Intel 80486 DX4 в цьому режимі енергоспоживання ЦПУ зменшується в порівнянні з активним режимом. Як конкретно це робиться — залежить від реалізації.
Сам по собі вийти з такого сонного стану процесор не може. Потрібно зовнішнє подія. Це може бути звичайне переривання від пристрою, немаскируемое переривання (NMI), переривання системного режиму (SMI) або ж варіанти инициализирующих сигналів — INIT або RESET.
Можна повністю підвісити систему з допомогою HLTТак, якщо виконати HLT в режимі SMM (system management mode), в якому за замовчуванням блокуються всі переривання та немасковані переривання. Після цього тільки RESET зможе знову запустити обробку машинних команд.
Формально режим після HLT позначається як C1.

MWAIT та інші енергозберігаючі режими

Ідея з особливим режимом для енергозбереження центрального процесора отримала подальший розвиток у вигляді нової інструкції MWAIT. На відміну від HLT, яка не має операндів, MWAIT приймає два значення в регістрах EAX і ECX. При цьому в EAX міститься опис бажаного енергозберігаючого стану, чисельні значення для C-state і C-substate.
Регістр ECX визначає додаткові підказки (hints) для зазначеного в команді варіанти неактивного режиму. Зараз описується лише один такий хинт — прапор в нульовому біті. Про його призначення буде сказано трохи нижче.
В іншому поведінка процесора після виконання аналогічно HLT: процесор зупиняє роботу до прибуття зовнішніх сигналів. На відміну від HLT, що досягається в разі MWAIT економія енергії може бути більше. Якщо HLT — це стан C1, то з допомогою MWAIT можна запросити перехід процесора в більш глибокий сон — стану C2, C3… C6 і т. д. Кожен такий стан може мати під-стану. Конкретні допустимі комбінації варіюються, і для конкретної моделі процесора описуються в п'ятому аркуші інструкції CPUID.
Крім тонкого управління енергоспоживанням неактивного стану, більш цікаве призначення MWAIT полягає в тому, що вона підвищує ефективність синхронизационных процесів на багатопроцесорних системах.
Типова ситуація в паралельних алгоритмах: потік А чекає сигналу про готовність від потоку Б, після чого обидва вони можуть продовжити обчислення. У багатопроцесорних системах А і Б будуть виконуватися на різних логічних процесорах. Яким чином можна передати цей сигнал? Два варіанти:
  1. Помістити А в неактивний режим (наприклад, з допомогою HLT). Потім Б використовує межпроцессорное переривання, яке виводить А зі стану сну. Однак посилка і обробка такого переривання досить дорога в термінах часу, оскільки вона зажадає декількох переходів між режимами ядра і користувача, та й шлях сигналу переривання буде неблизьким.
  2. Потік А в «нескінченному» циклі перевіряє вміст деякої комірки пам'яті. Потік Б, що бажає послати повідомлення про готовність, записує нове значення у клітинку, що виводить А з циклу. У цьому випадку затримка доставки повідомлення менше. Однак очевидно, що проводить очікування не самим енергоефективним чином, спалюючи такти, але не просуваючись вперед.
MWAIT в парі з інструкцією MONITOR покликана усунути недолік другого підходу. Команда MONITOR приймає адресу в пам'яті в якості свого аргументу, після чого процесор починає «моніторити» його, очікуючи записи з інших потоків. Якщо такий запис станеться в той час, поки процесор знаходиться в сонному стані через MWAIT, то він буде виведений з нього.
Таким чином, стан сну, створене з допомогою MWAIT, може бути перервано з двох причин: зовнішні переривання або запис у комірку пам'яті, позначену з допомогою MONITOR. Але що буде, якщо переривання були заборонені на момент виконання MWAIT?
У перших реалізаціях MONITOR/MWAIT прибуття переривання не призвело б до виходу зі стану сну. Виявилося, що така поведінка не дуже зручно. Тому на сучасних процесорах MWAIT реалізує розширення, що включається за допомогою біта ECX[0], яке дозволяє навіть забороненим перериваннях виводити процесор з неактивного стану.
Хочу підкреслити декілька «факультативний» характер поведінки MWAIT. Вихід з неактивного стану може відбуватися по різних, не завжди контрольованою поточним додатком причин. Програми, що використовують її, повинні бути спроектовані так, щоб коректно працювати, навіть якщо виходи з сонного стану будуть відбуватися спонтанно. Тому в першому наближенні MWAIT можна вважати варіантом NOP — нічого не робить інструкції. Це досить типово для синхронизационных примітивів класу умовна змінна (conditional variable). Алгоритми, які їх використовують, зобов'язані коректно працювати в умовах можливості паразитних пробуджень.
На цьому закінчимо з функціональністю управління енергоспоживанням. Перейдемо до особливостей роботи процесора в перші і останні моменти перед його включенням і перезавантаженням. Як виявляється, при цьому він також може знаходитися в неактивних режимах.

Wait-for-SIPI

Ця досить незручне назва розшифровується як «очікування сигналу SIPI». SIPI, в свою чергу, є абревіатурою для «Start-up IPI». Нарешті, IPI — це «inter-processor interrupt», межпроцессорное переривання. Щоб зрозуміти, навіщо було введено стан wait-for-SIPI, треба мати загальне уявлення про те, як відбувається ініціалізація багатопроцесорні системи. Проблема наступна: якщо всі ядра, потоки і процесори після включення живлення кинуться виконувати один і той же завантажувальний код, то настане безлад. В загальних рисах досить складний і що варіюється в деталях на різних платформах процес можна описати наступним чином.
  1. Після включення живлення всі логічні процесори включаються в перегони, у результаті якої визначається один головний, т. зв. завантажувальний
    процесор (boot-strap processor, BSP). Всі інші процесори позначаються як прикладні процесори (application processor, AP).
  2. BSP починає виконувати завантажувальний код з ROM за адресою 0xfffffff0.
  3. Всі AP переводяться в режим wait-for-SIPI, чекаючи, коли BSP пришле їм SIPI. Це станеться тоді, коли критична частина системної ініціалізації буде проведена за допомогою коду, виконаного на BSP: побудова ACPI-таблиць в пам'яті, призначення унікальних ідентифікаторів APIC ID. Альтернативно, BSP може нікого більше і не будити, якщо, скажімо, багатопроцесорність була вручну вимкнена в BIOS.
У стані wait-for-SIPI процесор не виконує інструкції. Крім того, він ігнорує зовнішні переривання від пристроїв, сигнали INIT і NMI, затримує SMI-переривання. Фактично, єдине, що має виводити його з цього стану — це сигнал SIPI. Зазначу, що специфікації нічого не говорять про енергоспоживання в цьому режимі.
Хочу зазначити, що при подальшій завантаження системи, всі AP можуть знову бути вимкнені і включені кілька разів. Наприклад, завантажувач ОС може бути написаний тільки для одного потоку, так і самі ОС зазвичай вважають за краще вводити процесори в бій по одному. При цьому стан wait-for-SIPI вже не використовується — в справу йде HLT або просто нескінченний цикл на AP.
Більшості програмістів, навіть системним, не доведеться зустрічати режим wait-for-SIPI у своїй практиці, просто тому що він відбувається одноразово і досить рано у процесі роботи будь-якої системи. Однак з цього правила є виняток. Що станеться, якщо запускається віртуальна машина, що використовує апаратну підтримку віртуалізації Intel VT-x, з декількома логічними процесорами? Виявляється, що в режимі VMX non-root (гостьова система) процесор можна також поміщати в різні режими. Крім активного, підтримуються неактивні режими HLT, Shutdown (про нього трохи далі) і wait-for-SIPI. У цьому стані поведінка процесора дуже схоже на те, що відбувається і при звичайній ініціалізації AP. А саме: він нічого не робить, ігнорує багато приходять сигнали, і лише при появі SIPI виходить з гостьового режиму в господарський (відбувається VM-exit). Зазначу, що рішення про те, чи використовувати механізм SIPI, залежить від конкретного монітора віртуальних машин; на практиці, деякі їх них реалізують власний протокол пробудження BSP і AP всередині ВМ.

Shutdown

на Жаль, код, який пишуть люди, не бездоганний. Серйозні помилки в прикладних програмах найчастіше призводять до їх завершення під пильним наглядом операційної системи. Але ось хто подбає про саму ОС, якщо вона впаде? В якості її «наглядачів» можуть виступати програмні монітори вирутальных машин або, якщо вони не використовуються, сама апаратура, тобто процесор і його особливі стану. Про них і поговоримо.
Типова ситуація під час роботи будь-якої програми — виникнення виняткової ситуації (interruption). Вона далеко не завжди і зовсім не обов'язково означає помилку; переривання поточної програми може бути тимчасовим, пов'язаним з роботою зовнішніх пристроїв, або бути инициированно самим додатком навмисно, щоб запросити в ОС деякі сервіси (див. класифікацію таких ситуацій в моєму коментарі).
При виникненні виняткової ситуації відбувається перемикання стану процесора, в чомусь схоже на дуже ускладнений виклик процедури. Нас зараз не цікавлять його деталі (ця стаття не про винятки), важливий лише факт, що в цьому процесі щось може піти не так — виникнути виняток при спроби обробки винятку. У специфікації Intel IA-32 цей випадок іменується Double Fault — подвійний промах. Як і інші виключення, він має свій номер (8) і запис в системній таблиці переривань. ОС може налаштувати для нього свій власний програмний обробник.
Але що буде, якщо і при спробі переходу в обробку Double Fault виникне виняток? Гадати не потрібно — така ситуація зветься Triple Fault, потрійний промах. Ось тільки для нього обробника вже не передбачено; замість цього процесор переводиться в режим shutdown — зупинка.
Цей режим схожий на стан після HLT. У ньому процесор припиняє виконання інструкцій до прибуття сигналів NMI, SMI, RESET або INIT. Що насправді станеться з системою в стані shutdown, залежить від реалізації. Наприклад, може бути включений світловий індикатор на передній панелі, згенеровано немаскируемое переривання для того, щоб записати діагностичну інформацію, проведена перезавантаження системи (гаряча чи холодна), або згенерований сигнал SMI.
Мабуть, найбільш часта реакція на перехід процесора в режим shutdown — це перезавантаження всієї системи. В Linux навмисне переведення процесора в режим зупинки — це один з шести методів (останній, самий розпачливий) опрацювати запит на reboot.
Як і у випадку з wait-for-SIPI, віртуалізація додає нюансів поведінки процесора в режимі shutdown. Потрійний промах в режимі non-root, звичайно ж, не перезавантажує всю систему. Він викликає VM-exit, дозволяючи монітора ВМ обробити ситуацію в «глючной» гостьовій системі. Крім того, монітор може запускати гостя в режимі non-root в стані shutdown (вже не знаю, навіщо це може знадобитися).
Ще про Shutdown
Дуже уважний читач документації може виявити, що деякі виходи VM-exit з порушеним станом процесора можуть перевести процесор в так званий режим VMX-abort shutdown. Він настільки суворий, що з нього процесор може вивести тільки RESET; всі інші сигнали він ігнорує.
Хочу відзначити, що звичайний Triple Fault в системному коді викликати досить просто, достатньо просто не налаштовувати системні таблиці і трохи почекати. Перше ж дозволене переривання призведе до (не)бажаного ефекту і перезавантаження.
А ось подія VMX-abort з подальшим остановом отримати не так просто. Воно може виникнути лише під час виходу з гостя в монітор (перехід з non-root в root). Перш ніж вийти, треба ввійти (здійснити VM-entry). Але тільки при вході в non-root проводиться величезна кількість перевірок, у тому числі таких, що забороняють роботу з неконсистентным станом. Якщо щось було налаштовано невірно, то спроба входу в гостьову ВМ відразу повернеться з кодом помилки. Під час роботи гість значно обмежений у правах і самостійно зруйнувати системні структури зазвичай не може. Іншими словами, зазвичай помилка в програмі монітора проявляється раніше, при вході. Необхідно бути дуже винахідливим (наприклад, напартачити з ізоляцією пам'яті або модель-специфічними регістрами), щоб отримати саме помилку при VM-exit.

Екзотика: SENTER sleep і TXT shutdown

Наостанок, варто згадати про розширення SMX (safer mode extensions), який є програмним інтерфейсом до набору платформних технологій Intel TXT (trusted execution technology). Процесори, що підтримують SMX, отримують ще два неактивних режиму.
  1. Першочергове завдання будь-якої технології, пов'язаної з безпекою — це встановити, яким сутностей (кодом, елементів середовища виконання) можна довіряти, тобто виділити корінь довіри. Найпростіше це зробити, якщо в системі активний тільки один процесор, — в цьому випадку на процесорах не зможе залишитися ненадійних програм.
Виконання інструкції GETSEC[SENTER] на одному логічному процесорі вводить інші процесори в нове неактивний стан SENTER Sleep. Після цього програма, що виконується на останньому активному процесорі, має перевести систему в так зване «засвідчена» оточення (measured environment), Як тільки завірений оточення готове, в ньому можуть працювати і інші процесори. Для цього вони виводяться з стану SENTER sleep за допомогою інструкції GETSEC[WAKEUP].
  1. Як завжди, в процесі роботи довіреної коду можливі помилки, пов'язані з доступом до неправильним ресурсів, винятками або несхождениям результатів криптографічних перевірок. Виникають вони або з вини недбайливих програмістів, або через навмисних спроб порушити роботу завіреного оточення ззовні. У другому випадку метою є компрометація оточення з підстановкою недоверенного коду або отриманням секретів.
При детектуванні неприпустимих подій у завіреному оточенні процесор переводиться у новий стан — TXT-shutdown. Його особливість полягає в тому, що інформація про причину зупинки зберігається в платформних регістрах і виживає після перезавантаження, що дозволяє проаналізувати її згодом. Ех, от би і для звичайного Triple Fault було б щось таке! Помітно допомогло б з діагностикою проблем.
Дякую за увагу!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.