Драйвери розумного чи віртуального заліза

Для початку введемо визначення bus master: пристрій, здатний бути не тільки веденим, а й провідним на шині комп'ютера. Тобто не лише відповідати на транзакції введення-виводу, ініційовані процесором, а й самостійно їх ініціювати — з власної ініціативи «ходити» на згадку.

Вже в режимі DMA робота драйвера виглядає по-іншому - від драйвера потрібно не виконувати введення-виведення, а підготувати налаштування для пристрою, активувати його, дочекатися переривання після закінчення введення-виведення, і перевірити успішність операції. Все сказане в попередній статті вірно і для DMA пристроїв, але на додаток до сказаного, драйвер повинен розуміти схему взаємодії пристрою та DMA контролера, а іноді і явно аллокувати та налаштовувати контролер: якщо в старих пристроях прив'язка порту вводу-виводу до контролера DMA робилася , то зараз у багатьох випадках можливий повний роутинг чи вибір каналу DMA із 2-4 варіантів.

Окремо слід зауважити, що сама ініціація чергової транзакції вводу-виводу може бути автоматичною (DMA б'є з максимально можливою швидкістю), автоматичною з налаштуванням темпу (щоб не з'їсти всю пропускну спроможність шини) або за подією.

При цьому подією в розвинених системах може бути переривання, просто зміна стану ніжки мікроконтролера, або джерелом події може бути інший пристрій. Наприклад, таймер. Це дозволяє сполучити воєдино ЦАП, DMA engine і таймер так, щоб подача чергового байта ЦАП відбувалася із заданою (таймером) частотою. Є й інші варіанти агрегування пристроїв, наприклад, включення одного каналу DMA після роботи іншого. Без привернення уваги процесора.

Доречно також сказати, що DMA контролери іноді вміють явно сполучати пару каналів,щоб забезпечувати безперервність потоку даних по закінченні роботи одного каналу запускається другий і генерується переривання, яким процесор знову завантажує роботою перший канал — для того ж ЦАП це може бути життєво важливо.

Повернемося зі світу контролерів до «дорослих» машин. Більшість сучасних підсистем введення-виведення вже не базуються на зовнішньому DMA, а мають його аналог прямо всередині.

Це пристрої з режимом "майстер шини", bus master.

Найпростіше їх уявити саме як пристрої, що мають вбудований у себе, особистий та оптимально влаштований контролер DMA.

Крім структури дескрипторів для такого пристрою потрібні ще інструменти для обміну подіями: процесор повинен вміти повідомити, що змінив або доповнив дескриптори, а пристрій - що закінчив введення-виведення частково або повністю. Друге виконується, природно, через переривання, а для першого часто застосовується регістр (дверний дзвінок - doorbell), в який процесор "стукає", щоб звернути увагу пристрою на зміни.

При цьому є небезпека змінити те, що пристрій зараз обробляє, що накладає додаткові обмеження на структуру драйвера.

Окремо у цьому ряду стоять virtio пристрої. З'явилися вони як наслідок переможної ходи гіпервізорів світом. Традиційно гіпервізор пропонував гостьовий ОС деякий набір віртуальних пристроїв, які копіювали той чи інший популярний фізичний пристрій. Відому мережеву картку чи дисковий контролер. Але емулювати «залізне» пристрій важко, незручно й нудно - часто, доводиться підтримувати зовсім не потрібні у віртуальному світі властивості, при цьому для цілей віртуалізації структура реального залізного пристрою, як правило, неоптимальна.

У драйверах virtio ядрозаповнює пакет і вимагає узагальнений драйвер vitio "передати" його пристрою. Тепер поки пристрій не "передасть" пакет назад, чіпати його не можна. І навпаки, якщо пристрій вміє робити введення із зовнішньої ініціативи, йому потрібно передати кілька порожніх (підготовлених для читання) пакетів — у міру надходження даних (наприклад, вхідних мережевих повідомлень) пакети заповнюватимуться і передаватимуться назад, ядру гостьової ОС.

Крім того, стандарт virtio підтримує можливість стандартним чином ядру і пристрою домовлятися про режим робіт і функції, що підтримуються. Наприклад, мережний драйвер virtio може вміти або не вміти рахувати і вставляти в надіслані IP-пакети контрольну суму.

У деяких ОС (Фантом "змалював" це з NT, звідки вони змалювали - не знаю) існує штатна підтримка запуску коду всередині "легких" ниток - Deferred Procedure Call. Це дозволяє знизити час знаходження драйвера в перериванні: хендлер переривання лише фіксує подію і, як максимум, зчитує з пристрою статус один регістр. Решта робиться в DPC, яка швидко активується та доробляє розпочате.

Відверто сказати, сенсу в цьому не так вже й багато — простіше запустити в драйвері його власну високопріоритетну нитку і робити введення-виведення з неї. Однак можуть бути варіанти. Можна виділити DPC групу пріоритетів і гарантувати їм пріоритет завжди вищий, ніж нитки. Можна забезпечити надшвидкий шедулінг і передавати таким ниткам процесор відразу на виході саме з того переривання, яке цей DPC запросив, знизивши латентність.

Окремо відзначимо, що з DPC можна багато того, що в перериванні не можна. Що саме залежить від ОС. У Фантомі всередині DPC можна все, навіть заснути на місяць. Гріх, але можна. NT, ЕМНІП, все ж, якосьобмежує права DPC (тобто це не звичайні нитки), але деталей я не пам'ятаю.

На цьому я відчуваю, що виконав свій обов'язок щодо драйверів. :)