Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Дополнение кода для системного вызова



Мы можем изменить Makefile в /kernel для включения файла в нашу функцию, но проще будет включить код функции в уже существующий файл в дереве исходников. Файл /kernel/sys. с содержит функции ядра для системных вызовов, а файл arch/ i386/kernel/sys_i3 86.с содержит системные вызовы х86 с нестандартной после­довательностью вызова. Мы добавляем туда исходный код для нашего системного вызо­ва, написанный на С. Этот код запускается в режиме ядра и выполняет всю работу. Все остальное в этой процедуре помогает нам получить эту функцию. Она обрабатывается через обработчик исключения х86:


Написание кода



kernel/sys.с 1: ..

2 3 4 5 б 7 8 9 10 11

/* где-то после последней функции*/

/* простая функция для демонстрации системного вызова. */ /* получение в номер, вывод, возвращение number+1 */

asmlinkage long sys_ourcall(long num) {

printk(" Inside our syscall num =%d \n", num);

return(num+1); }


Когда обработчик исключения выполняет int 0x80, он индексируется внутри табли­цы системного вызова. Файл /arch/i3 8 б /kernel /entry. S содержит функции обработчики прерывания нижнего уровня и таблицу системного вызова sys_ call_table. Таблица - это реализация в ассемблерном коде массива С с элементами длиной 4 байта. Каждый элемент или вхождение в этой таблице инициализируется для адресации функции. По соглашению мы должны приготовить имя нашей функции в sys__. Из-за того, что позиция в таблице определяется номером системного вызова, мы должны добавить имя нашей функции в конец списка. См. следующий код для изменения таблицы:

arch/i38б/kernel/entry.S

: .data 608: ENTRY(sys_call_table)

.long sys_restart_syscall /* 0 - old " setupО" системный вызов используется для перезапуска */

.long sys_tgkill /* 270 */

.long sys_utimes.1ong sys_fadvi s e б 4_6 4

.long sys_ni_syscall /* sys_vserver */
.long sys_ourcall /* our syscall will be 274 */

884: nr_syscalls=(.-sys_call_table)/4

Файл include/asiri/unistd.h связывает системные вызовы с их номерами пози­ции в sys_call_table. Также в этом файле находятся макросы для помощи пользова­тельским программам (написанным на С) загружать параметры в регистры. Здесь мы из­меняем unistd.h и вставляем наш системный вызов:



Глава 10• Добавление вашего кода в ядро


include/asm/unistd.h

б

/*

* Этот файл содержит номера системных вызовов.
*/

tdefine _____ NR_restart_syscall 0

#define _____ NR_exit 1

tdefine ______ NR_fork 2

#define _____ NR_utimes 271

#define _____ NR_fadvise64_64 272

#define _____ NR_vserver 273

#define _____ NR_ourcall 274

/* #define NR_syscalls 274 это старое значение перед нашим
системным вызовом */
15: #define NR_syscalls 275

Наконец, мы хотим создать пользовательскую программу для проверки нового сис­темного вызова. Как говорилось ранее в этом разделе, существует набор макросов, по­могающих программисту ядра загружать параметры из кода С в регистры х86. В /usr/ include/asm/unistd.h существует 7 макросов: _sy sea llx (type, name, ..), гдех - номер параметра. Каждый макрос предназначен для загрузки определенного количества параметров от 0 до 5, a syscall б (...) позволяет загрузить указатель на большее число параметров. Следующая демонстрационная программа получает один параметр. Для это­го примера (в строке 5) мы используем макрос _syscall (type, name, typel, namel) из /unistd.h, преобразующийся в вызов int 0x80 с правильными параметрами:

mytest.с

1 2 3 4 5 б 7 8 9 10

#include < stdio.h>

tinclude < stdlib.h>

#include Vusr/include/asm/unistd.h"

_syscall(long, ourcall, long, num);

main() {

printf(*our syscall --> num in=5, num out = %d\n", ourcall(5)); }


10.3 Сборка и отладка



Сборка и отладка

Добавление вашего кода в ядро обычно требует нескольких циклов программирования и отладки. В этом разделе мы опишем, как можно отладить написанный вами код ядра и как собрать связанные с отладкой инструменты.

Отладка драйвера устройства

В предыдущих разделах мы использовали файловую систему /proс для получения ин­формации об ядре. Мы можем сделать доступной информацию о нашем драйвере устрой­ства для пользователя через /ргос, что является отличным способом отладки части ва­шего драйвера устройства. Каждый узел в файловой системе /ргос связан с функцией ядра при чтении и записи. В ядре 2.6 большинство записей в части ядра, включая устрой­ства, выполняется через sysf s вместо /ргос. Операции модифицируют специальные атрибуты объектов ядра во время выполнения ядра; /ргос остается полезным инстру­ментом для операций только чтения, требующих большего количества данных, чем пара атрибут-значение, а этот раздел работает только с чтением из вхождений /ргос.

Первый шаг позволяет получить доступ к чтению с вашего устройства с помощью соз­дания вхождения в файловой системе /ргос с помощью create_proc_read_entry ():

include/linux/proc_fs.h

146 static inline struct proc_dir_entry *create_proc_read_entry(const
char *name/

147 mode_t mode, struct proc_dir_entry *base,

148 read_proc_t *read_proc, void * data)

*name - это вхождение узла, появляющегося в /ргос, mode 0 позволяет файлу быть читаемым отовсюду. Если вы создаете несколько различных файлов ргос для одно­го драйвера устройства, сначала стоит создать директорию ргос с помощью proc_mkdir () и затем помещать каждый файл в нее; *base - это путь директории внутри /ргос для размещения файлов; значение NULL помещает файл прямо в /ргос. Функция *read_proc вызывается при чтении файла, а указатель *data передается обратное *read_proc:

include/linux/proc_fs.h

44 typedef int (read_proc_t)(char *page, char **start, off_t off,

45 int count, int *eof, void *data);

Это прототип для функций, которые будут осуществлять чтение через файловую сис­тему /ргос; *раде - это указатель на буфер, куда функции записывают свои данные во



Глава 10• Добавление вашего кода в ядро


время чтения файла /ргос. Функция должна начать с записи по байту of f в *page и за­писи остальных count байт. Так как обычно чтение возвращает только небольшое ко­личество информации, многие реализации игнорируют как off, так и count. Дополни­тельно **start обычно игнорируется и редко используется в ядре. Если вы реализуете функцию чтения, возвращающую определенное количество данных, то **start, off и count можно использовать для управления чтением небольших порций за определен­ное время. Когда чтение закончено, функция должна записывать 1 в * eof. Наконец, *data является параметром, передаваемым в функцию чтения, определенную в create^ proc__read_entry ().

Резюме

Эта глава описывает драйвер устройства, модули и системные вызовы. Мы описали не­сколько способов, которыми Linux использует драйверы устройств. Точнее говоря, мы рассмотрели следующие темы:

в Мы описали дерево /dev в файловой системе Linux и объяснили, как определить, какое устройство контролируется и с помощью какого драйвера устройства.

• Мы объяснили, как драйверы устройств используют структуры файлов и структуры файловых операций для обработки ввода-вывода файловой системы.

• Мы описали разницу между памятью пользовательского уровня и памятью пространства ядра и то, как драйвер устройства может копировать данные из одной области в другую.

• Мы рассмотрели конструкцию очереди ожидания в ядре и показали, как она исполь­зуется, когда драйверу устройства нужно подождать освобождения определенного ресурса.

• Мы исследовали теорию, стоящую за очередью ожидания и прерываниями, являющимися методами, используемыми ядром Linux для очистки прерываний и обработки драйверов устройств, когда процессор нужно передать другому процессу.

• Мы представили вашему вниманию системные вызовы Linux и описали их базовые функции.

• Мы описали разницу между блочными и символьными устройствами и новую модель устройств, представленную в Linux 2.6. Также сюда включен короткий обзор

sysfs.

В первой части гл. 10 об этих темах говорилось на абстрактном уровне, и мы просле­дили их практическое применение на примере специального драйвера устройства /dev/ random. Вторая часть гл. 10 предоставляет более конкретные примеры и код для не­посредственного создания драйвера устройства.


Упражнения



Точнее говоря, мы рассмотрели детали следующих концепций:

• Мы показали, как мы конструируем узлы в /dev, которые нужно связать с драйверами устройств, и как создаются динамические модули.

• Мы описали новые методы в Linux 2.6 для экспорта символов из модуля драйвера устройства.

• Мы продемонстрировали, как драйвер устройства предоставляет функцию IOCTL, позволяющую устройству работать с Linux через файловую систему.

• Мы объяснили, как возникают прерывания и помещение в пул, а также разницу между циклическими блокировками на архитектурах х86 и РРС.

• Мы объяснили, как добавить простой системный вызов в ядро Linux.

Гл. 10 представляет мощную основу для разработки драйверов устройств в 2.6 и объ­единяет в единое целое идеи и концепции, представленные ранее в этой книге.

Упражнения

1. См. создание ядра и пользовательского кода в гл. 3, «Процессы: принципиальная модель выполнения». Перекомпилируйте ядро и скомпилируйте my test. с. Запус­тите my test. с и рассмотрите вывод.

2. Добавьте другой параметр в ourcall.

3. Создайте системный вызов из ourcall.

4. Объясните сходства и различия между системными вызовами и драйверами устройств.

5. Почему мы не можем использовать memcpy для копирования данных между поль­зовательским пространством и пространством ядра?

6. В чем разница между функциями верхней половины и нижней половины?

7. В чем разница между тасклетами и work_queue?

8. Когда устройство обрабатывает больше чем просто чтение и запись, как с ним обща­ется Linux?

9. Чему равно численное значение снятой циклической блокировки на архитектуре х86? НаРРС?

10. Одним предложением объясните разницу между блочными и символьными устрой­ствами.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 973; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.02 с.)
Главная | Случайная страница | Обратная связь