UDM универсальный диспетчер устройств
К этому моменту ядро знает две вещи: от сканирования PCI оно знает устройства как числа (производитель, модель, класс), от ACPI оно знает железо прерываний. Но это ещё не работающая система. Кто-то должен решить, что этот чип Intel с ID 0x100e получит драйвер E1000, а тот контроллер, драйвер AHCI. Это сватовство между устройствами и драйверами, это работа UDM универсального диспетчера устройств.
Какой драйвер подходит? Две стратегии
Из трёх чисел, что даёт сканирование PCI, UDM выводит имя драйвера, причём двумя стратегиями одна за другой. Первая точная: таблица, которая отображает известные ID производителя и модели прямо на нужный драйвер.
const char* udm_heuristic_driver(uint16_t vendor, uint16_t device, uint8_t class_code) {
if (vendor == 0x8086) { // Intel
if (device == 0x100e || device == 0x100f /* ... */) return "e1000_driver";
if (device == 0x2922 /* ... */) return "ahci_driver";
} else if (vendor == 0x10ec) { // Realtek
if (device == 0x8139) return "rtl8139_driver";
if (device == 0x8169 || device == 0x8168) return "rtl8169_driver";
} else if (vendor == 0x1022) { // AMD
if (device == 0x2000) return "pcnet_driver";
} /* ... VirtIO и т.д. ... */
// Вторая стратегия: точная модель неизвестна, но помогает класс
switch (class_code) {
case 0x01: return "ahci_driver"; // какой-то контроллер хранилища
case 0x02: return "generic_network_driver"; // какая-то сетевая карта
/* ... */
}
}
Если точная таблица ничего не находит, вступает вторая стратегия, откат по классу. Даже неизвестный прежде контроллер хранилища так получает драйвер AHCI, пока следует стандарту AHCI. Так известное железо получает наилучший драйвер, а неизвестное хотя бы подходящий.
От находки к работающему драйверу
Весь процесс, это короткая цепочка. Сканирование PCI находит устройство, UDM назначает ему имя драйвера эвристикой, грузит этот драйвер, а тот отчитывается своей таблицей функций и конкретным устройством.
// драйвер AHCI регистрирует свою таблицу функций и найденное устройство
udm_register_storage_driver(STORAGE_CONTROLLER_AHCI, &ahci_ops);
udm_register_device("hd0", UDM_DEVICE_TYPE_STORAGE, pci_info, &ahci_ops, priv, sectors);
В конце система знает каждое устройство по имени (hd0, eth0), знает, какой драйвер за ним и как его вызывать. Именно этот список был негласной основой всего, что происходило в частях про Storage и сеть, там всегда было лишь "драйвер", а здесь он назначается.
Важно тут - тот же механизм работает не только при загрузке. Если устройство вставляют во время работы, UDM снова сканирует и регистрирует его. Если убирают, снова убирает запись. Это hotplug и он держит реестр устройств всегда актуальным.
Здесь "драйвер" становится конкретным устройством
Помнишь ops->read из главы про Storage? Здесь то место, где эта таблица функций создается. Драйвер регистрирует свои ops при старте, а слой Storage позже запрашивает их обобщённо.
позже, при чтении (из главы про Storage):
const udm_storage_driver_ops_t* ops = udm_get_storage_driver_ops(dev->controller_type);
ops->read(dev->base_1, ...); // обобщённый вызов, UDM создал таблицу
В этом весь смысл OPs - слою Storage не нужно знать, IDE или AHCI за драйвером. Он просто вызывал ops->read, а UDM заранее положил нужную таблицу с OPs. Чтобы добавить новый тип контроллера, пишешь новый драйвер с новой таблицей ops и один раз вызываешь udm_register_storage_driver не трогая слой Storage.
Честное место
Эвристика хороша лишь настолько, насколько хороша её таблица. Каждое известное устройство сидит там рукотворной записью, а новое железо просто надо вносить. Откат по классу ловит многое, но не всё, экзотическое устройство, не следующее стандарту, остаётся без драйвера. И один пример мне попадался при разработке - фантомный слот иногда сообщает ID производителя 0x0000, и кто не отфильтрует его последовательно, вдруг пытается найти драйвер для устройства, которого вовсе нет. Таких призраков надо ловить в нескольких местах.
Что дальше
UDM назначает драйверы во время работы и загрузки системы, но эти назначения живут лишь в памяти компа и принимаются заново при каждой загрузке. Чтобы система знала и через перезагрузки, какие устройства есть и какие уже подтверждены, существует описание этих назначений в файле TOML. Это Device Manifest, следующая часть.
Было бы интересно увидеть ваши комментарии и улучшить статьи.
◀ Предыдущая статья Содержание Следующая статья ▶
*Система не стоит на месте, поэтому в дальнейшем тексты могут не совпадать с реальным положением