• Главная
  • Карта сайта
Не найдено

Анатомія завантажувальних модулів ядра Linux

  1. Інші статті Тіма з серії на developerWorks
  2. Анатомія модуля ядра
  3. Малюнок 1. Код простого завантаження модуля.
  4. Анатомія об'єктного коду модуля ядра
  5. Малюнок 2. Приклад завантаження модуля з розділами ELF
  6. Життєвий цикл завантаження модуля ядра
  7. Малюнок 3. Основні команди і функції, які беруть участь у завантаженні і вивантаженні модуля
  8. Подробиці завантаження модуля
  9. Малюнок 4. Внутрішній процес завантаження модуля (спрощено)
  10. Подробиці вивантаження модуля
  11. Малюнок 5. Внутрішній процес вивантаження модуля (спрощено).
  12. Оптимізація ядра для управління модулями
  13. подальше вивчення
  14. Ресурси для скачування

Розгляд для ядра версії 2.6

Ядро Linux відноситься до категорії так званих монолітних - це означає, що велика частина функціональності операційної системи називається ядром і запускається в привілейованому режимі. Цей підхід відрізняється від підходу мікроядра, коли в режимі ядра виконується тільки основна функціональність (взаємодія між процесами [inter-process communication, IPC], диспетчеризація, базовий введення-виведення [I / O], управління пам'яттю), а інша функціональність витісняється за межі привілейованої зони (драйвери, мережевий стек, файлові системи). Можна було б подумати, що ядро ​​Linux дуже статично, але насправді все якраз навпаки.

Інші статті Тіма з серії на developerWorks

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

Linux - не єдина (і не перше) динамічно змінюване монолітне ядро. Завантажувані модулі підтримуються в BSD-системах, Sun Solaris, в ядрах більш старих операційних систем, таких як OpenVMS, а також в інших популярних ОС, таких як Microsoft® Windows® і Apple Mac OS X.

Анатомія модуля ядра

Завантажувані модулі ядра мають ряд фундаментальних відмінностей від елементів, інтегрованих безпосередньо в ядро, а також від звичайних програм. Звичайна програма містить головну процедуру (main) на відміну від завантаження модуля, що містить функції входу і виходу (у версії 2.6 ці функції можна назвати як завгодно). Функція входу викликається, коли модуль завантажується в ядро, а функція виходу - відповідно при вивантаженні з ядра. Оскільки функції входу і виходу є одними, для вказівки призначення цих функцій використовуються макроси module_init і module_exit. Завантаження модуль містить також набір обов'язкових і додаткових макросів. Вони визначають тип ліцензії, автора і опис модуля, а також інші параметри. Приклад дуже простого завантаження модуля наведено на малюнку 1.

Малюнок 1. Код простого завантаження модуля.
Розгляд для ядра версії 2

Версія 2.6 ядра Linux надає новий, більш простий метод створення завантажувальних модулів. Після того як модуль створений, можна використовувати звичайні призначені для користувача інструменти для управління модулями (незважаючи на зміни внутрішнього устрою): insmod (встановлює модуль), rmmod (видаляє модуль), modprobe (контейнер для insmod і rmmod), depmod (для створення залежностей між модулями ) і modinfo (для пошуку значень в модулях макросу). За додатковою інформацією про створення завантажувальних модулів для ядра версії 2.6 зверніться до посилань в розділі ресурси .

Анатомія об'єктного коду модуля ядра

Завантаження модуль являє собою просто спеціальний об'єктний файл у форматі ELF (Executable and Linkable Format). Зазвичай об'єктні файли обробляються компоновщиком, який дозволяє символи і формує виконуваний файл. Однак у зв'язку з тим, що завантажується модуль не може дозволити символи до завантаження в ядро, він залишається ELF-об'єктом. Для роботи з завантажуються модулями можна використовувати стандартні засоби роботи з об'єктними файлами (які в версії 2.6 мають суфікс .ko, від kernel object). Наприклад, якщо вивести інформацію про модуль утилітою objdump, ви виявите декілька звичних розділів, в тому числі .text (інструкції), .data (початкові дані) і .bss (Block Started Symbol або неініціалізовані дані).

У модулі також виявляться додаткові розділи, відповідальні за підтримку його динамічної поведінки. Розділ .init.text містить код module_init, а розділ .exit.text - код module_exit code (малюнок 2). Розділ .modinfo містить тексти макросів, що вказують тип ліцензії, автора, опис і т. Д.

Малюнок 2. Приклад завантаження модуля з розділами ELF

Тепер, вивчивши основи завантажувальних модулів ядра, давайте розберемося, як модулі завантажуються в ядро ​​і як відбувається управління ними всередині ядра.

Життєвий цикл завантаження модуля ядра

Процес завантаження модуля починається в просторі користувача з команди insmod (вставити модуль). Команда insmod визначає модуль для завантаження і виконує системний виклик рівня користувача init_module для початку процесу завантаження. Команда insmod для ядра версії 2.6 стала надзвичайно простий (70 рядків коду) за рахунок перенесення частини роботи в ядро. Команда insmod не виконує ніяких дій по вирішенню символів (разом з командою kerneld), а просто копіює двійковий код модуля в ядро ​​за допомогою функції init_module; інше робить саме ядро.

Функція init_module працює на рівні системних викликів і викликає функцію ядра sys_init_module (рисунок 3). Це основна функція для завантаження модуля, яка звертається до кількох інших функцій для вирішення спеціальних завдань. Аналогічним чином команда rmmod виконує системний виклик функції delete_module, яка звертається в ядро ​​з викликом sys_delete_module для видалення модуля з ядра.

Малюнок 3. Основні команди і функції, які беруть участь у завантаженні і вивантаженні модуля

Під час завантаження і вивантаження модуля підсистема модулів підтримує простий набір змінних стану для позначення статусу модуля. При завантаженні модуля він має статус MODULE_STATE_COMING. Якщо модуль завантажений і доступний, його статус - MODULE_STATE_LIVE. Якщо модуль вивантажено - MODULE_STATE_GOING.

Подробиці завантаження модуля

Тепер давайте поглянемо на внутрішні функції для завантаження модуля (малюнок 4). При виконанні функції ядра sys_init_module спочатку виконується перевірка того, чи має викликає відповідні дозволи (за допомогою функції capable). Потім викликається функція load_module, яка виконує механічну роботу по розміщенню модуля в ядрі і проводить необхідні операції (я незабаром розповім про це). Функція load_module повертає посилання, яка вказує на тільки що завантажений модуль. Потім він вноситься в двусвязний список всіх модулів в системі, і все потоки, які очікують зміни стану модуля, повідомляються за допомогою спеціального списку. В кінці викликається функція init () і статус модуля оновлюється, щоб вказати, що він завантажений і доступний.

Малюнок 4. Внутрішній процес завантаження модуля (спрощено)

Внутрішні процеси завантаження модуля є аналіз і управління модулями ELF. Функція load_module (яка знаходиться в ./linux/kernel/module.c) починає з виділення блоку тимчасової пам'яті для зберігання всього модуля ELF. Потім модуль ELF зчитується з робочих просторів в тимчасову пам'ять за допомогою copy_from_user. Будучи об'єктом ELF, цей файл має дуже специфічну структуру, яка легко піддається аналізу і перевірки.

Наступним кроком є ​​ряд "санітарних перевірок" завантаженого образу (чи ELF-файл допустимим? Чи відповідає він поточної архітектурі? І так далі). Після того як перевірка пройдена, образ ELF аналізується і створюється набір допоміжних змінних для заголовка кожного розділу, щоб полегшити подальший доступ до них. Оскільки базовий адреса об'єктного файлу ELF дорівнює 0 (до переміщення), ці змінні включають відповідні зміщення в блок тимчасової пам'яті. Під час створення допоміжних змінних також перевіряються заголовки розділів ELF, щоб переконатися, що завантажується модуль коректний.

Розширені можливості пошуку модуля, якщо вони є, завантажуються з робочих просторів в інший виділений блок пам'яті ядра (крок 4), і статус модуля оновлюється, щоб позначити, що він завантажений (MODULE_STATE_COMING). Якщо необхідні дані для процесорів (згідно з результатами перевірки заголовків розділів), для них виділяється окремий блок.

У попередніх кроках розділи модуля завантажувалися в пам'ять ядра (тимчасову), і було відомо, які з них використовуються постійно, а які можуть бути видалені. На наступному кроці (7) для модуля в пам'яті виділяється остаточне розташування, і в нього переміщуються необхідні розділи (позначені в заголовках SHF_ALLOC або розташовані в пам'яті під час виконання). Потім проводиться додаткове виділення пам'яті розміру, необхідного для необхідних розділів модуля. Проводиться прохід по всіх майданчиках в тимчасовому блоці ELF ,, і ті з них, які необхідні для виконання, копіюються в новий блок. За нею йдуть деякі службові процедури. Також відбувається дозвіл символів, як розташованих в ядрі (включених в образ ядра при компіляції), так і тимчасових (експортованих з інших модулів).

Потім проводиться прохід за рештою розділами і виконуються переміщення. Цей крок залежить від архітектури і відповідно ґрунтується на допоміжних функціях, визначених для даної архітектури (./linux/arch/<arch>/kernel/module.c). В кінці очищається кеш інструкцій (оскільки використовувалися тимчасові розділи .text), виконується ще кілька службових процедур (очищення пам'яті тимчасового модуля, настройка sysfs) і, в підсумку, модуль повертає load_module.

Подробиці вивантаження модуля

Вивантаження модуля фактично являє собою дзеркальне відображення процесу завантаження за винятком того, що для безпечного видалення модуля необхідно виконати кілька "санітарних перевірок". Вивантаження модуля починається в просторі користувача з виконання команди rmmod (видалити модуль). Всередині команди rmmod виконується системний виклик delete_module, який в кінцевому рахунку ініціює sys_delete_module всередині ядра (поверніться до малюнку 3 ). Основні операції видалення модуля показані на малюнку 5.

Малюнок 5. Внутрішній процес вивантаження модуля (спрощено).

При виконанні функції ядра sys_delete_module (з ім'ям видаляється модуля в якості параметра) спочатку виконується перевірка того, чи має викликає відповідні дозволи. Потім за списком перевіряються залежності інших модулів від даного модуля. При цьому використовується список modules_which_use_me, що містить по елементу для кожного залежного модуля. Якщо список порожній, тобто залежностей не виявлено, то модуль стає кандидатом на видалення (інакше повертається помилка). Потім перевіряється, завантажений чи модуль. Ніщо не забороняє користувачеві запустити команду rmmod для модуля, який в даний момент встановлюється, тому дана процедура перевіряє, чи активний модуль. Після кількох додаткових службових перевірок передостаннім кроком викликається функція виходу даного модуля (надається самим модулем). На закінчення викликається функція free_module.

До моменту виклику free_module вже відомо, що модуль може бути безпечно видалений. Залежностей не виявлено, і для даного модуля можна почати процес очищення ядра. Цей процес починається з видалення модуля з різних списків, в які він був поміщений під час установки (sysfs, список модулів і т.д.). Потім ініціюється команда очищення, що залежить від архітектури (вона розташована в ./linux/arch/<arch>/kernel/module.c). Потім обробляються залежні модулі, і даний модуль видаляється з їх списків. В кінці, коли з точки зору ядра очищення завершена, звільняються різні області пам'яті, виділені для модуля, в тому числі пам'ять для параметрів, пам'ять для даних по процесорам і пам'ять модуля ELF (core і init).

Оптимізація ядра для управління модулями

Для багатьох додатків необхідна можливість динамічного завантаження модулів, але вивантажувати їх не обов'язково. Це дозволяє ядру бути динамічним при запуску (завантаження модулів в залежності від виявлених пристроїв), але незмінним під час роботи. Якщо не потрібно вивантажувати модулі після завантаження, можна зробити кілька удосконалень для скорочення кількості коду, необхідного для управління модулями. В цьому випадку можна відключити параметр настройки ядра CONFIG_MODULE_UNLOAD, видаливши тим самим значну частину функціональності ядра, пов'язану з вивантаженням модулів.

подальше вивчення

Це був лише загальний огляд процесів управління модулями в ядрі. Кращим джерелом додаткової інформації про управління модулями є сам вихідний код. Основні функції управління модулями містяться в ./linux/kernel/module.c (і відповідному файлі заголовка ./linux/include/linux/module.h). Кілька функцій, що залежать від архітектури, знаходяться в ./linux/arch/<arch>/kernel/module.c. Нарешті, функція автозавантаження ядра (яка автоматично завантажує модуль з ядра при необхідності) знаходиться в файлі ./linux/kernel/kmod.c. Ця функція включається за допомогою параметра настройки CONFIG_KMOD.

Ресурси для скачування

Схожі теми

  • Anatomy of Linux loadable kernel modules (EN) - оригінал статті.
  • Відвідайте блог Рости Рассела " Bleeding Edge ", Присвячений його поточним розробкам для ядра Linux. Рости - провідний розробник нової архітектури модулів Linux. (EN)
  • Керівництво з програмування модулів ядра Linux , Хоча злегка застаріло, містить велику кількість докладної інформації про завантажуються модулях і їх розробці. (EN)
  • У статті " Доступ до ядра Linux за допомогою файлової системи / proc "(DeveloperWorks, березень 2006 року) наведено детальний огляд програмування завантажувальних модулів ядра з використанням файлової системи / proc.
  • Детальніше дізнатися про роботу системи викликів можна зі статті " Kernel command using Linux system calls "(EN) (developerWorks, березень 2007 р).
  • Щоб дізнатися більше про ядрі Linux, прочитайте першу статтю Тіма " Анатомія ядра Linux "(DeveloperWorks, июнь 2007 г.) з цієї серії, в якій дано загальний огляд ядра Linux і деяких його цікавих особливостей.
  • Прочитайте чудове введення в формат ELF " Standards and specs: An unsung hero: the hardworking ELF "(EN) (developerWorks, грудень 2005 року). ELF є стандартним форматом об'єктних файлів для Linux. ELF - це гнучкий формат файлів, що охоплює виконувані образи, об'єктні файли, загальні бібліотеки і навіть дампи ядра. Більш детальну інформацію можна знайти також в довіднику за форматом (EN) (документ PDF) і в докладної книзі за форматами ELF (EN).
  • На сайті Captain's Universe є чудове введення в збірку завантажувальних модулів з прикладами make-файлів. Процес складання завантажувальних модулів в ядрі версії 2.6 був змінений (на краще). (EN)
  • Є кілька утиліт для установки, видалення та управління модулями. (EN) Модулі встановлюються в ядро ​​командою insmod , А віддаляються командою rmmod . Для запиту про те, які модулі зараз завантажені в ядро, використовуйте команду lsmod . Оскільки модулі можуть залежати один від одного, існує команда depmod для створення файлу залежностей. Для автоматичного завантаження залежних модулів до завантаження основного модуля використовуйте команду modprobe (Оболонка команди insmod). Нарешті, прочитати інформацію завантаження модуля можна за допомогою команди modinfo .
  • Стаття " Linkers and Loaders "(EN) в журналі Linux Journal (листопад 2002 г.) містить чудове введення в роботу редакторів зв'язків і завантажувачів, які використовують файли ELF (включаючи дозвіл символів і переміщення).
  • В розділі Linux сайту developerWorks є й інші ресурси для Linux-розробників. Ознайомтеся також з найпопулярнішими статтями і проводами . (EN)
  • Ознайомтеся з розділами рад і навчальних посібників по Linux на developerWorks.
  • використовуйте ознайомчі версії ПЗ IBM , Які можна завантажити безпосередньо з developerWorks, в вашому наступному проекті розробки для Linux. (EN)

Підпишіть мене на повідомлення до коментарів

И ELF-файл допустимим?
Чи відповідає він поточної архітектурі?
Провайдеры:
  • 08.09.2015

    Batyevka.NET предоставляет услуги доступа к сети Интернет на территории Соломенского района г. Киева.Наша миссия —... 
    Читать полностью

  • 08.09.2015
    IPNET

    Компания IPNET — это крупнейший оператор и технологический лидер на рынке телекоммуникаций Киева. Мы предоставляем... 
    Читать полностью

  • 08.09.2015
    Boryspil.Net

    Интернет-провайдер «Boryspil.net» начал свою работу в 2008 году и на данный момент является одним из крупнейших поставщиков... 
    Читать полностью

  • 08.09.2015
    4OKNET

    Наша компания работает в сфере телекоммуникационных услуг, а именно — предоставлении доступа в сеть интернет.Уже... 
    Читать полностью

  • 08.09.2015
    Телегруп

    ДП «Телегруп-Украина» – IT-компания с 15-летним опытом работы на рынке телекоммуникационных услуг, а также официальный... 
    Читать полностью

  • 08.09.2015
    Софтлинк

    Высокая скоростьМы являемся участником Украинского центра обмена трафиком (UA — IX) с включением 10 Гбит / сек... 
    Читать полностью