LinuxKernelProgramming — различия между версиями

Материал из SEWiki
Перейти к: навигация, поиск
(Печать всех имеющихся процессов)
Строка 1: Строка 1:
 
Лектор - Кринкин Кирилл Владимирович
 
Лектор - Кринкин Кирилл Владимирович
  
== Лекции ==
+
== Подготовка к работе ==
  
== Программа курса ==
+
Все работы рекомендуется проводить в виртуальном окружении, для этого можно использовать [https://www.virtualbox.org/wiki/Downloads VirtualBox].
  
== Установка OpenSSH-Server ==
+
Для сдачи работ должен использовать git на гуглкоде http://code.google.com/p/linux-kernel-course/
 +
 
 +
Для этого
 +
* скачиваем ядро: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 +
* откатываемся к указанному коммиту: git reset --hard c579bc7e316e7e3f3b56df5e17f623325caa9783
 +
* отсылаем в качестве домашней работы файлы, полученные командой: git format-patch c579bc7e316e7e3f3b56df5e17f623325caa9783
 +
 
 +
=== Установка OpenSSH-Server в VirtualBox ===
 
Для того, чтобы получить возможность пользоваться буфером обмена (вставлять текст в консоль) и не ставить VirtualBox Guest Additions, можно установить в виртуальную машину OpenSSH-Server, и подключаться к нему любым SSH клиентом.
 
Для того, чтобы получить возможность пользоваться буфером обмена (вставлять текст в консоль) и не ставить VirtualBox Guest Additions, можно установить в виртуальную машину OpenSSH-Server, и подключаться к нему любым SSH клиентом.
 
Для этого необходимо добавить новую сетевую карту в виртуальную машину. Это делается в настройках, ДО ВКЛЮЧЕНИЯ виртуальной машины: в настройках нужно перейти на страницу с настройками сети, перейти на вкладку со вторым адаптером (первый адаптер используется виртуальной машиной для доступа к интернет через NAT) и выбрать подключение "Host-only adapter" (смотри пример на картинке).
 
Для этого необходимо добавить новую сетевую карту в виртуальную машину. Это делается в настройках, ДО ВКЛЮЧЕНИЯ виртуальной машины: в настройках нужно перейти на страницу с настройками сети, перейти на вкладку со вторым адаптером (первый адаптер используется виртуальной машиной для доступа к интернет через NAT) и выбрать подключение "Host-only adapter" (смотри пример на картинке).
Строка 29: Строка 36:
 
Так же рекомендуется в подпункте Translation пункта Window указывать UTF-8 в качестве Character set translation on received data - в частности, это необходимо для правильного отображения Midnight Commander.
 
Так же рекомендуется в подпункте Translation пункта Window указывать UTF-8 в качестве Character set translation on received data - в частности, это необходимо для правильного отображения Midnight Commander.
  
== Сборка ядра 3.3.0-rc2 ==
+
=== Сборка ядра 3.3.0-rc2 ===
 
Сборка ядра 3.3.0-rc2 (в соответствии с рекомендациями readme)
 
Сборка ядра 3.3.0-rc2 (в соответствии с рекомендациями readme)
 
  wget https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.3-rc2.tar.bz2
 
  wget https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.3-rc2.tar.bz2
Строка 44: Строка 51:
 
  shutdown -r now
 
  shutdown -r now
  
== Написание модулей ==
+
=== Использование patch ===
 +
 
 +
== Создание модулей для ядра Linux ==
  
 
=== Введение ===
 
=== Введение ===
Строка 60: Строка 69:
 
По своей структуре, модуль похож на обычную прогамму (так же имеется точка входа, и необходима компиляция в бинарный вид) но имеет прямой доступ к структурам и функциям ядра, в то время как обычные программы такой доступ могут получить только через обёртки.
 
По своей структуре, модуль похож на обычную прогамму (так же имеется точка входа, и необходима компиляция в бинарный вид) но имеет прямой доступ к структурам и функциям ядра, в то время как обычные программы такой доступ могут получить только через обёртки.
  
=== Код модуля ===
+
=== Сборка модуля как отдельного объекта (Kernel object) ===
 +
 
 +
==== Код модуля ====
 
<source lang="c">
 
<source lang="c">
 
#include <linux/module.h> // Этот файл подключается в любом модуле по соглашению
 
#include <linux/module.h> // Этот файл подключается в любом модуле по соглашению
Строка 83: Строка 94:
 
MODULE_LICENSE("GPL"); // Указывает на лицензию, под которой распространяется данный модуль
 
MODULE_LICENSE("GPL"); // Указывает на лицензию, под которой распространяется данный модуль
 
</source>
 
</source>
=== Сборка модуля ===
+
==== Сборка модуля (make) ====
  
 
Файл с кодом модуля (myModule.c) должен находиться в одной папке с make-фалом, в котом должно быть написано
 
Файл с кодом модуля (myModule.c) должен находиться в одной папке с make-фалом, в котом должно быть написано
Строка 92: Строка 103:
 
В итоге должен получиться файл модуля myModule.ko
 
В итоге должен получиться файл модуля myModule.ko
  
=== После сборки модуля ===
+
==== Загрузка модуля ====
  
 
Теперь полученный модуль можно загрузить (эта команда требует прав суперпользователя). Для этого используется команда
 
Теперь полученный модуль можно загрузить (эта команда требует прав суперпользователя). Для этого используется команда
 
  insmod <имя модуля>
 
  insmod <имя модуля>
Список загруженных модулей хранится в /proc/modules, так что можно просмотреть этот файл
+
Список загруженных модулей хранится в /proc/modules (так что можно просмотреть этот файл cat /proc/modules) либо воспользоваться командой
cat /proc/modules
+
или воспользоваться командой
+
 
  lsmod
 
  lsmod
 
Выгружать модуль можно командой (также требует прав суперпользователя)
 
Выгружать модуль можно командой (также требует прав суперпользователя)
 
  rmmod <имя модуля>
 
  rmmod <имя модуля>
  
== Печать всех имеющихся процессов ==
+
==== Примечания ====
  
Код модуля
+
Результат работы модуля выводится в /var/log/syslog, для его просмотра рекомендуется на отдельной консоли использовать
<source lang="c">
+
tail -f /var/log/syslog
#include <linux/module.h> // Этот файл подключается в любом модуле по соглашению
+
#include <linux/kernel.h> // Содержит макросы для функции printk()
+
#include <linux/init.h> // Содержит определения макросов __init и __exit
+
#include <linux/sched.h>
+
void show_proc_list(void) // Функция для вывода всех имеющихся процессов
+
{
+
  struct task_struct *task;
+
  for_each_process(task)
+
  {
+
printk("%s [%d]\n",task->comm , task->pid);
+
  }
+
}
+
static int __init start(void) // Точка входа в модуль
+
{
+
  show_proc_list(); // Вызов функции
+
  return 0; // в случае успешной загрузки возвращать нулевое значение
+
}
+
static void __exit stop(void) // Точка выхода
+
{
+
  //printk("Module unloaded\n");
+
}
+
module_init(start);
+
module_exit(stop);
+
MODULE_LICENSE("GPL"); // Указывает на лицензию, под которой распространяется данный модуль
+
</source>
+
  
Собирается аналогично модулю из предыдущего пункта. Результат выводится в /var/log/syslog
+
=== Сборка модуля вместе с ядром (Kbuild) ===
 +
 
 +
Модули для ядра можно собирать при помщи системы Kbuild. инструкции для сборки должны находиться в файле Kconfig.
 +
 
 +
==== Код Kconfig ====
  
Для его просмотра рекомендуется на отдельной консоли использовать
 
tail -f /var/log/syslog
 
  
== Программа курса ==
 
  
 
== Список литературы ==
 
== Список литературы ==

Версия 13:50, 24 марта 2012

Лектор - Кринкин Кирилл Владимирович

Подготовка к работе

Все работы рекомендуется проводить в виртуальном окружении, для этого можно использовать VirtualBox.

Для сдачи работ должен использовать git на гуглкоде http://code.google.com/p/linux-kernel-course/

Для этого

  • скачиваем ядро: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  • откатываемся к указанному коммиту: git reset --hard c579bc7e316e7e3f3b56df5e17f623325caa9783
  • отсылаем в качестве домашней работы файлы, полученные командой: git format-patch c579bc7e316e7e3f3b56df5e17f623325caa9783

Установка OpenSSH-Server в VirtualBox

Для того, чтобы получить возможность пользоваться буфером обмена (вставлять текст в консоль) и не ставить VirtualBox Guest Additions, можно установить в виртуальную машину OpenSSH-Server, и подключаться к нему любым SSH клиентом. Для этого необходимо добавить новую сетевую карту в виртуальную машину. Это делается в настройках, ДО ВКЛЮЧЕНИЯ виртуальной машины: в настройках нужно перейти на страницу с настройками сети, перейти на вкладку со вторым адаптером (первый адаптер используется виртуальной машиной для доступа к интернет через NAT) и выбрать подключение "Host-only adapter" (смотри пример на картинке).

Настройка дополнительной сетевой карты в VirtualBox

Если VirtualBox выдает ошибку при выборе "Host-only Adapter", то вероятнее всего это связано с тем, что не установлен виртуальный адаптер. Добавить его можно в сетевых настройках VirtualBox (File->Preferences->Networks).

Добавление виртуального адаптера

Теперь необходимо включить на этой сетевой карте возможность получить IP адрес по DHCP. Для этого нужно выполнить следующие две команды (предполагается, что в системе до этого была только одна сетевая карта):

echo 'allow-hotplug eth1' >> /etc/network/interfaces
echo 'iface eth1 inet dhcp' >> /etc/network/interfaces

и установить OpenSSH-Server

apt-get install openssh-server

Теперь можно из основной системы произвести подключение к виртуальной. Для этого нужно использовать SSH-клиент, такой как putty которому нужно сообщить IP адрес виртуальной машины (его можно узнать командой ifconfig, и, скорее всего, это будет 192.168.56.101).

Использование Putty для SSH соединения

Важно помнить, что по умолчанию SSH не позволяет подключаться, используя учётную запись root. Если необходимы права суперпользователя, в начале подключитесь используя свою учётную запись на виртуальной машине (приняв перед этим сертификат безопасности), а потом используйте su.

Так же рекомендуется в подпункте Translation пункта Window указывать UTF-8 в качестве Character set translation on received data - в частности, это необходимо для правильного отображения Midnight Commander.

Сборка ядра 3.3.0-rc2

Сборка ядра 3.3.0-rc2 (в соответствии с рекомендациями readme)

wget https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.3-rc2.tar.bz2
su -c “apt-get install bzip2”
tar -xjf linux-3.3-rc2.tar.bz2
cd linux-3.3-rc2/
mkdir -p ~/build/linux-3.3-rc2
su -c “apt-get install libncurses5-dev”
make 0=~/build/linux-3.3-rc2 nconfig
make 0=~/build/linux-3.3-rc2
su -c “make 0=~/build/linux-3.3-rc2 modules_install install”
su -c “update-initramfs -c -k 3.3.0-rc2”
su -c “update-grub2”
shutdown -r now

Использование patch

Создание модулей для ядра Linux

Введение

Некоторые отличия Ядра от программ, выполняемых в пространстве пользователя:

  • Ядро LINUX пишется с расчётом на компилятор GNU C (разработчики ориентируются на стандарт ISO C99). В коде можно использовать ассемблерные вставки (директива asm()), аннотацию ветвления (likely() - более вероятная ветвь, unlikely() - менее вероятная) и весьма странный кодстайл.
  • Ядро не имеет доступа к стандартным библиотекам языка программирования C. Это сделано из соображений увеличения скорости выполнения и уменьшения объёма кода.
  • Отсутствует защита памяти. Если обычная программа предпримет попытку некорректного обращения с памятью, то ядро сможет выгрузить такую программу, но если само ядро предпримет такую же попытку, то его будет некому проконтролировать. Так же важно помнить об отсутствии замещения страниц, т.е. каждому байту, используемому ядром, соответствует байт реальной физической памяти.
  • В ядре используются только целочисленные вычисления. Это тоже сделано для ускорения работы, т.к. операции с плавающей точкой значительно более ресурсоёмки (в частности, активнее используются регистры CPU).
  • Объём стека фиксирован, и обычно равен двум страницам памяти (8 Кбайт для x86, и 16 Кбайт для x64). По этой причине не рекомендуется использовать рекурсию.
  • Важным требованием является переносимость - код должен компилироваться на максимально большом количестве систем.

Загружаемый объект ядра называется модулем. Динамическая загрузка и выгрузка модулей по мере необходимости появилась благодаря Питеру Мак-Дональду и впервые была представлена в версии ядра 0.99.
По своей структуре, модуль похож на обычную прогамму (так же имеется точка входа, и необходима компиляция в бинарный вид) но имеет прямой доступ к структурам и функциям ядра, в то время как обычные программы такой доступ могут получить только через обёртки.

Сборка модуля как отдельного объекта (Kernel object)

Код модуля

#include <linux/module.h> // Этот файл подключается в любом модуле по соглашению
#include <linux/kernel.h> // Содержит макросы для функции printk()
#include <linux/init.h> // Содержит определения макросов __init и __exit
void printHW(void) // Функция для вывода приветствия
{
    printk("Hello, world\n"); // выводит сообщение на экран и в лог messages
}
EXPORT_SYMBOL(printHW); // Экспорт функций ядра - предоставляет доступ к функции другим модулям ядра
static int __init start(void) // Точка входа в модуль
{
    printHW(); // Вызов функции
    return 0; // в случае успешной загрузки возвращать нулевое значение
}
static void __exit stop(void) // Точка выхода
{
    //printk("Module unloaded\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL"); // Указывает на лицензию, под которой распространяется данный модуль

Сборка модуля (make)

Файл с кодом модуля (myModule.c) должен находиться в одной папке с make-фалом, в котом должно быть написано

obj-m += myModule.o

Тогда сборку модуля можно запустить командой

make -C ./linux-3.3-rc2 SUBDIRS=$PWD modules

Внимание, замените путь к исходным кодам ядра на тот, куда вы извлекли содержимое архива linux-3.3-rc2.tar.bz2 В итоге должен получиться файл модуля myModule.ko

Загрузка модуля

Теперь полученный модуль можно загрузить (эта команда требует прав суперпользователя). Для этого используется команда

insmod <имя модуля>

Список загруженных модулей хранится в /proc/modules (так что можно просмотреть этот файл cat /proc/modules) либо воспользоваться командой

lsmod

Выгружать модуль можно командой (также требует прав суперпользователя)

rmmod <имя модуля>

Примечания

Результат работы модуля выводится в /var/log/syslog, для его просмотра рекомендуется на отдельной консоли использовать

tail -f /var/log/syslog

Сборка модуля вместе с ядром (Kbuild)

Модули для ядра можно собирать при помщи системы Kbuild. инструкции для сборки должны находиться в файле Kconfig.

Код Kconfig

Список литературы