IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  AIX и UNIX  >

Как создать расширение ядра AIX

Повышение квалификации

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Сандеш Чопдекар, разработчик программного обеспечения, IBM
Авинеш Кумар, разработчик программного обеспечения, IBM

07.12.2007

Эта статья показывает, как использовать ядро AIX для написания алгоритмов расширения его функций и создания системных вызовов, процессов ядра или файловых систем. Совершенствования архитектуры Power вместе с улучшения AIX® Version 5.3 способствовали быстрому росту популярности AIX. Подробные примеры в этой статье иллюстрируют новые возможности создания расширений ядра в AIX.

Введение

После выхода AIX® Version 5.3 и с учетом существенного улучшения архитектуры Power и усиления ее позиций на рынке Unix-систем разработчики по всему миру все активнее начинают создавать приложения для AIX. Эта статья поможет начать разработку расширений ядра AIX.

Ядро AIX предоставляет интерфейс для динамического расширения своих функций с помощью так называемых расширений ядра (kernel exensions). Расширения ядра - это программы, добавляемые в ядро для расширения его функций. Расширения являются важной частью архитектуры ядра AIX, они похожи на и динамически загружаемые модули, доступные на других платформах (например Linux®), где функция добавляется прямо в действующее ядро без перезагрузки машины.

Расширения ядра запускаются в безопасном домене ядра. Расширение может понадобиться в том случае, например, когда нужно создать системный вызов, процесс ядра или файловую систему. Расширение ядра работает в том же режиме, что и ядро. Если ядро работает в 64-битном режиме, то и расширение должно запускаться в этом режиме.

Эта статья предназначена для всех тех, кто хочет писать свои собственные расширения ядра под AIX. От читателя требуется лишь базовое знакомство с программированием в среде UNIX®.

Термин kernext иногда используется как сокращение для kernel extension, особенно в коде.



В начало


О расширениях ядра

Операции, являющиеся расширениями ядра AIX, могут принадлежать к следующим категориям:

  • Системные вызовы
  • Виртуальные файловые системы
  • Сервисы ядра, которые управляют расширениями ядра и драйверами устройств
  • Драйвера устройств
Вне зависимости от категории, к которой принадлежит программа, она будет называться расширением ядра.

Жизненный цикл расширения ядра имеет следующие стадии:

  • Загрузка - на этой стадии расширение загружается в память ядра.
  • Запуск - на этой стадии расширение запускается и указывается его точка входа. Иначе говоря, это инициализация.
  • Коммуникация - на этой стадии начинается коммуникация с расширением ядра и оно начинает выполнять свою работу.
  • Завершение - на этой стадии расширение прекращает свою работу.
  • Выгрузка - на этой стадии расширение ядра выгружается из памяти.

Системный вызов sysconfig() используется для того, чтобы контролировать эти стадии. sysconfig (для его запуска нужны права администратора) и является основными интерфейсом программирования приложений (primary application programming interface, API) для управления расширениями ядра. Его описание выглядит так:

int sysconfig(             (Defined in /usr/include/sys/sysconfig.h )
   int cmd,                /* function requested: load, unload, etc  */
   void *parmp,            /* address of struct containing info for cmd  */
   int parmlen            /* length of parmp information */
 );           

sysconfig() имеет параметр команды cmd, который определяет необходимое пользователю действие.

Некоторые основные действия перечислены в таблице 1 ниже. Полный их список вы найдете в /usr/include/sys/sysconfig.h.


Таблица 1. Основные действия
ДействиеОписание
*) SYS_KLOADЗагружает объектный файл расширения в память ядра.
*) SYS_SINGLELOAD Загружает объектный файл расширения только в том случае, если он еще не загружен.
*) SYS_QUERYLOADОпределяет, загружен ли указанный объектный файл ядра.
*) SYS_KULOAD Выгружает ранее загруженный объектный файл ядра.
*) SYS_CFGKMODВызывает указанный модуль на его точку входа для настройки.

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

Давайте посмотрим на некоторые важнейшие используемые структуры:

Struct cfg_load 

Эта структура передается sysconfig(), когда расширение загружается или выгружается. Она определена в /usr/include/sys/sysconfig.h следующим образом:

  
struct cfg_load
{
     caddr_t path;    /* указатель на путь к объектному модулю */
     caddr_t libpath;/* указатель на замещающий путь libpath (путь через каталог lib) */
     mid_t   kmid;     /* id модуля ядра (возвращаемый) */
  };     

struct cfg_load имеет следующую структуру:
  • path - эта команда указывает путь к объектному файлу вашего модуля расширения ядра.
  • libpath - Эта команда указывает путь поиска для объектного файла расширения ядра. Если это поле не заполнено, то используется поле path.
  • Kmid - эта команда содержит ID модуля ядра. В зависимости от опции, он передается в sysconfig(). Это поле или заполняется sysconfig(), или его нужно передавать sysconfig( ).

Структура Struct cfg_kmod передается sysconfig( ), когда активизируется точка входа модуля. Struct cfg_kmod определяется в /usr/include/sys/sysconfig.h следующим образом:

struct cfg_kmod  {
      mid_t   kmid;       /* модульный ID вызываемого модуля */
      int cmd;            /* командный параметр для модуля  */
      caddr_t mdiptr;     /* указатель на информацию для модуля */
      int mdilen;         /* величина информации для модуля */
};

Структура cfg_kmod имеет следующие поля:
  • kmid - эта команда указывает ID модуля расширения ядра, который возвращается после загрузки модуля.
  • cmd -эта команда указывает команду для модуля. Это может быть определяемое пользователем значение, или же оно может быть взято из <sys/device.h>, как делается в примере ниже.
  • mdiptr - эта команда используется для передачи данных расширению.
  • mdilen - эта команда выдает длину данных, передаваемых mdiptr.

Теперь давайте перейдем к более наглядным вещам.



В начало


Расширение ядра Hello World

Уже сейчас вы можете создать простое расширение ядра "Hello World". Надо написать две программы:

Чтобы откомпилировать код расширения Hello World, нужно ввести make в той папке, куда которую вы скопировали исходный текст программы. В целях безопасности сделано так, что только пользователь root может загружать или выгружать расширения ядра. Так как загруженный код работает в режиме ядра, он имеет полный доступ ко всем файлам и процессам в вашей системе. Поэтому даже использование программы setuid, которой владеет пользователь root, не является достаточным условием для загрузки расширения ядра - нужно еще войти в систему как root. См. листинг 1 ниже.


Листинг 1. Управляющее приложение: kctrl.c
1 /* Управляющее приложение */
2
3 #include  <stdio.h>
4 #include  <errno.h>
5 #include  <string.h>
6 #include  <sys/types.h>
7 #include  <sys/stat.h>
8 #include  <sys/sysconfig.h>
9 #include  <sys/device.h>
10
11 int main(int argc, char *argv[])
12 {
13     struct  cfg_kmod    opt_kmod;
14     struct  cfg_load    opt_load, query_load;
15     struct  stat        statbuf;
16     char    szKernExt[256], c;
17
18     /* Проверка привелегий пользователя  */
19     if (getuid() != 0) {
20         fprintf(stderr, " Not SuperUser.\n");
21         exit(EACCES);
22     }
23
24     /* проверка аргументов */
25     if (argc != 2) {
26         printf ("Usage: %s <kernel_extension>\n", argv[0]);
27         exit(EINVAL);
28     }
29
30     strcpy(szKernExt,argv[1]);
31
32         /* Проверка существования файла */
33     if (stat(szKernExt,&statbuf) != 0) {
34         perror("stat");
35         exit(errno);
36     }
37
38     /* Заполнение структуры cfg_load */
39     opt_load.path = szKernExt;      /* имя файла  */
40     opt_load.libpath = NULL;        /* нет такой библиотеки */
41     opt_load.kmid = 0;
42
43     /* Выполнение различных операций над расширением ядра */
44     while(1) {
45
46         fprintf (stderr, "\n Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, 
                (q)uery or (e)nd\n");
47
48         while((c = getchar()) < 'a' && c > 'z')  ;  /* отбрасывание лишних данных */
49
50         switch(c) {
51
52         case 'l':         /* загрузка расширения ядра*/
53
54                         /* запрос загрузки расширения ядра  */
55                      if (sysconfig(SYS_KLOAD,&opt_load,sizeof(struct   cfg_load)))
56                 perror("sysconfig(SYS_KLOAD)");  /* выдача сообщения об ошибке  */
57            else                         /* в ином случае             */
58               printf("Extension Successfully loaded, kmid is %d\n", opt_load.kmid);
59
60                         break;
61
62                 case 'i': /* Инициализация расширения ядра */
63
64                 /* Инициализация расширения ядра */
65             opt_kmod.kmid = opt_load.kmid;
66             opt_kmod.cmd = CFG_INIT;
67             opt_kmod.mdiptr = NULL;
68             opt_kmod.mdilen = 0;
69             if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_kmod)))
70                 perror("sysconfig(SYS_CFGKMOD)");  /* выдача сообщения об ошибке */
71                         else
72                                 printf(" Extension Initialized \n");
73
74             break;
75
76         /* Выгрузка расширения ядра */
77         case 'u':
78             /* Проверка того, загружено ли расширение ядра */
79             if (opt_load.kmid == 0)
80                 printf("kernel Extension not loaded\n");
81             else  {
82                 if (sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)))
83                     perror("sysconfig(SYS_KULOAD)");
84                 else                    
85                     fprintf(stderr, "KernExt Successfully Unloaded \n");
86             }
87
88             break;
89
90          /* Завершение расширения ядра */
91                 case 't':
92
93             /* Проверка того, загружено ли расширение ядра */
94             if (opt_load.kmid == 0)
95                 fprintf(stderr, "Extension not loaded\n");
96             else  {
97               opt_kmod.kmid = opt_load.kmid;
98               opt_kmod.cmd  = CFG_TERM;    /* Завершение расширения ядра */
99               opt_kmod.mdiptr = NULL;
100               opt_kmod.mdilen = 0;
101               if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct  cfg_kmod)))
102                   perror("sysconfig(SYS_CFGKMOD)");  /* выдача ошибки */
103                            else
104                                fprintf(stderr, " KernExtension  Terminated \n");
105                               }
106
107                         break;
108
109
110         /* запрос о существовании расширения ядра */
111         case 'q':
112
113             query_load.path     = opt_load.path;
114             query_load.libpath  = opt_load.libpath ;
115             query_load.kmid     = 0;
116
117             if (sysconfig(SYS_QUERYLOAD,&query_load,sizeof(struct cfg_load)))
118                 perror("sysconfig(SYS_QUERYLOAD)");
119             else
120                       {
121                             if(query_load.kmid > 0)
122                       fprintf(stderr, " Extension is loaded, with kmid   %d \n",
                                query_load.kmid);
123                             else
124                       fprintf(stderr, " Extension is not loaded \n");
125                       }
126
127             break;                       /* сделано  */
128
129
130         case 'e':
131             exit(0);
132
133
134         default:
135             fprintf(stderr, "Incorrect option \n");
136             break;
137         }
138         getchar();
139     }
140
141         return 0;
142 }

Теперь надо определить переменные, в том числе переменные struct cfg_kmod и struct cfg_load.

struct  cfg_kmod    opt_kmod;
struct  cfg_load    opt_load, query_load;

Загрузка расширения ядра

Для того, чтобы загрузить расширение ядра, нужно сначала вызвать sysconfig с командным параметром SYS_KLOAD. opt_load и sizeof(struct cfg_load) передаете следующим образом:

sysconfig(SYS_KLOAD,&opt_load,sizeof(struct cfg_load))

После успешного обращения к sysconfig на экране печатается kmid.

Далее заполняется структура cfg_load в поле пути к расширению ядра:

opt_load.path = szKernExt;

Следует установить libpath в NULL, так как в этом случае не будет зависимости от какой-либо внесистемной библиотеки:

opt_load.libpath = NULL;

Заполним поле kmid нулем:

opt_load.kmid = 0;

Запустим программу, как это показано ниже:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
l
Extension Successfully loaded, kmid is 49033924

Теперь можно просматривать список загруженных на системе расширений ядра с помощью команды genkex:

[root@aix1] genkex 
Text address     Size File
2ec3000      2d8 ./kernext_hello 
<Snip>

Инициализация расширения ядра

После загрузки расширения вызовем sysconfig( ) чтобы активизировать его точку входа с помощью команды CFG_INIT.

Управляющее приложение использует программу sysconfig(). Заполним struct cfg_kmod opt_kmod, как это показано ниже:

opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd = CFG_INIT;
opt_kmod.mdiptr = NULL;
opt_kmod.mdilen = 0;

Заполним поле kmid идентификатором расширения, который был получен при последнем обращении к sysconfig( ).

Команда CFG_INIT активизирует точку входа расширения ядра. Пока что не надо передавать расширению аргументы, поэтому mdiptr равно NULL. Mdilen содержит величину mdiptr.

В данном для примера расширении ядра мы добавили операции, которые печатают выдачу в файле syslog. Ниже дается пример выдачи syslog:

Apr  3 08:22:40 aix1 kern:debug unix: Enter hello_init:: command = 0x1
Apr  3 08:22:40 aix1 kern:debug unix:  Initializing Hello World  KernExt

Запрос о загрузке расширения ядра

С помощью struct cfg_load можно выяснить, загружено ли расширение. Для этого можно использовать переменную query_load.

Теперь заполним значения path и libpath с помощью переменной opt_load и вызовем sysconfig с помощью команды SYS_QUERYLOAD, как это показано ниже:

query_load.path     = opt_load.path;
query_load.libpath  = opt_load.libpath ;
query_load.kmid     = 0; 

Если расширение ядра загружено, то поле kmid содержит kmid этого расширения, и значение этого поля всегда больше нуля. kmid выводится в таком виде:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
q
Extension is loaded, with kmid 49033924

Прекращения действия расширения ядра

Чтобы прекратить действие расширения надо вызвать sysconfig() с помощью команды CFG_TERM, встроенной в struct cfg_kmod и затем заполнить значения переменной opt_kmod, как это показано ниже:

opt_kmod.kmid = opt_load.kmid;
opt_kmod.cmd  = CFG_TERM;
opt_kmod.mdiptr = NULL;
 opt_kmod.mdilen = 0;

Теперь, когда известно kmid, можно заполнить команду как CFG_TERM, следующим образом:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
t
KernExtension Terminated

В выдаче syslog будут такие строки:

Apr  3 08:22:43 fsaix9 kern:debug unix: Enter hello_init:: command = 0x2
Apr  3 08:22:43 fsaix9 kern:debug unix:  Terminating Hello World  KernExt

Выгрузка расширения ядра

Для выгрузки расширение надо вызвать sysconfig с параметром SYS_KULOAD и передать struct cfg_load, у которого заполнены поля path и kmid, как это показано ниже :

sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)

Для выгрузки расширения нужно использовать опцию "u" и выберите Enter:

[root@aix1] ./kctrl ./kernext_hello
Enter choice, (l)oad, (u)nload, (i)nit, (t)erm, (q)uery or (e)nd
u
KernExt Successfully Unloaded

Будьте осторожны при использовании sysconfig()- неправильные значения kmid могут вызвать сбой в системе (см. Листинг 2).


Листинг 2. Расширение ядра Hello World: kernext_hello.c
1 /* Расширение ядра Hello World */
2 #include <errno.h>
3 #include <syslog.h>
4 #include <sys/device.h>
5
6
7
8  int hello_init(int cmd, struct uio *uio)
9  {
10
11    bsdlog(LOG_DEBUG | LOG_KERN, "Enter hello_init::A command = 0x%x \ n",cmd);
12
13    if (cmd == CFG_INIT)
14          bsdlog(LOG_DEBUG | LOG_KERN, " Initializing Hello World  KernExt \n");
15    else if (cmd == CFG_TERM)
16              bsdlog(LOG_DEBUG | LOG_KERN, " Terminating Hello World   KernExt \n");
17    else
18              bsdlog(LOG_DEBUG | LOG_KERN, " Unknown command to  Adv  KernExt \n");
19
20
21       return 0;
22  }

Расширение не имеет программы main(); вместо нее оно имеет точку входа, которая активизируется контролирующим приложением, когда команда CFG_INIT запускается с использованием SYS_CFGKMOD вместе с sysconfig().

В этом примере у расширения имеется только одна функция - точка входа этого расширения hello_init(). Точка входа имеет два аргумента. Один из них - это целочисленный командный параметр, передаваемый от sysconfig(), который встроен в struct cfg_kmod. Другой параметр - это struct uio, использующийся для передачи данных расширению. В расширении Hello World не используется struct uio, как это показано в предыдущем разделе.

По умолчанию имя точки входа должно быть __start( ). Если оно имеет другое значение, как в данном случае, то необходимо указать его в коде расширения.

Расширение ядра Hello World подтверждает прием команд и печатает их. Оно использует для печати bdslog(). Первый аргумент bsdlog - это приоритет. Для задания приоритета используются два ключа:

  • LOG_DEBUG, который сообщает syslog, что это сообщение отладки
  • LOG_KERN, который сообщает syslog, что это сообщение от ядра

Чтобы получить сообщение, нужно убедиться в том, что syslogd настроен.

Например, в /etc/syslog.conf можно добавить что-то вроде этого:

*.debug         /tmp/syslog.out     rotate size 100k files 4

Затем надо ввести ps –aef | grep syslog, а затем kill –HUP.

Процесс сборки в листинге 3 ниже - это Makefile расширения Hello World.


Листинг 3. Makefile расширения ядра Hello World
1  all: kernext_hello kctrl
2
3  kctrl: kctrl.c
4      cc -o kctrl kctrl.c
5
6
7  kernext_hello: kernext_hello.c
8      cc -q32 -o kernext_hello32.o -c kernext_hello.c
9      ld -b32 -o kernext_hello32 kernext_hello32.o -e hello_init 
             -bI:/usr/lib/kernex.exp -lsys -l csys
10      cc -q64 -o kernext_hello64.o -c kernext_hello.c
11      ld -b64 -o kernext_hello64 kernext_hello64.o -e hello_init 
             -bI:/usr/lib/kernex.exp -lsys -l csys
12      rm -f kernext_hello
13      ar -X32_64 -r -v kernext_hello kernext_hello32 kernext_hello64
14
15  clean:
16      rm -f *.o kernext_hello kernext_hello32 kernext_hello64 kctrl  2> /dev/null

В Makefile имеются два целевых объекта: контролирующее приложение и расширение Hello World.

Команда для управляющего приложения достаточно проста, в ней вы указываете объектный файл с помощью опции -o:

4     cc -o kctrl kctrl.c



В начало


Сборка расширения ядра

Расширения ядра компилируются, а затем связываются ссылками. Как уже было сказано, если точка входа расширения ядра иная, нежели данная по умолчанию __start, ее нужно указывать с помощью переключателя -e на ld редактора связей.

Надо заметить, что расширения не должны собираться с помощью cc; ld должен использоваться на последнем шаге связывания.

Чтобы собрать 32-битную и 64-битную версию расширения, используются ключи –q32 и –q64, соответственно.

В данном случае, точка входа расширения это не __start(), так что используйте переключатель –e для идентификации точки входа. Так как в расширении используются экспортируемые из ядра идентификаторы, то задавать эту зависимость нужно с помощью -bI:/usr/lib/kernex.exp, что указывает на нужный файл.

AIX предоставляет две библиотеки, libsys.a и libcsys.a, которые могут использоваться расширениями ядра. С этими библиотеками можно связаться с помощью переключателей –lsys и –lcsys в расширении.

Поддержка 32- и 64-битного режимов

AIX запускается в 32- и 64-битном режимах, и его расширения ядра тоже двухрежимные. Двухрежимные расширения могут использоваться для упрощения возможности загрузки и в 32-битном, и в 64-битном режиме. Двухрежимное расширение ядра представляет из себя архивный файл, который содержит как 32-битную, так и 64-битную версию расширения. Когда в sysconfig указан путь, или запрос kmod_load является архивом, загрузчик загружает первый элемент архива, режим объекта которого соответствует режиму запуска ядра. В расширении Hello World двухрежимность создается при объединении 32- и 64-битного расширений.

Особенность расширений ядра в AIX состоит в том, как AIX идентифицирует эти расширения. AIX распознает расширения ядра по путям к ним. Для активизации расширения можно использовать различные пути, например абсолютный путь (например, из папки /tmp):

[root@aix1] ./kctrl  /tmp/kernext_hello

либо активизировать расширение следующим образом:
[root@aix1] ./kctrl ./kernext_hello

Оба эти экземпляра расширений ядра будут считаться ядром различными расширениями ядра.



В начало


Усовершенствованное расширение ядра

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

Нужно записать два файла, связанных с системным вызовом, который требуется добавить в действующее ядро. Один из них экспортирует идентификатор syscall (demo_syscall.exp), а в другом содержится код системного вызова (demo_syscall.c): одна контролирующая загрузку и выгрузку нового системного вызова программа (kctrl.c), одна программа-образец (invoke_syscall.c), использующая новый системный вызов, и Makefile для сборки всего этого, что и показано в листинге 4 ниже.


Листинг 4. Файл demo_syscall.exp
        
1 #!/unix
2 demo_syscall syscall  

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


Листинг 5. Идентификатор системного вызова
1 /* Несколько усовершенствованное расширение ядра */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <syslog.h>
6 #include <sys/device.h>
7
8 int demo_syscall_init(int cmd, struct uio *uio)
9 {
10       int iErr = 0;
11
12       bsdlog(LOG_DEBUG | LOG_KERN, "demo_syscall_init:A command = 0x%x  \n",cmd);
13
14       if (cmd == CFG_INIT) {
15
16               bsdlog(LOG_DEBUG | LOG_KERN, " Loading Adv KernExt \n");
17               if(iErr = pincode(demo_syscall_init))
18                       return iErr;
19
20       } else if (cmd == CFG_TERM) {
21
22               bsdlog(LOG_DEBUG | LOG_KERN, " UnLoading Adv KernExt \n");
23               if(iErr = unpincode(demo_syscall_init))
24                       return iErr;
25
26       } else {
27               bsdlog(LOG_DEBUG | LOG_KERN, " Unknown command to  Adv KernExt \n");
28               return -1;
29       }
30
31       return 0;
32 }
33
34   /* Применение demo syscall */
35   demo_syscall(int arg)
36   {
37        return(arg + 25);
38   }

Этот новый системный вызов работает довольно просто. Он всего лишь прибавляет 25 к передаваемому аргументу и возвращает получающуюся сумму (см. листинг 6).


Листинг 6. Листинг kctrl.c
1 /* Управляющее приложение для расширения ядра */
2
3 #include  <stdio.h>
4 #include  <errno.h>
5 #include  <string.h>
6 #include  <sys/types.h>
7 #include  <sys/stat.h>
8 #include  <sys/sysconfig.h>
9 #include  <sys/device.h>
10
11 int main(int argc, char *argv[])
12 {
13     struct  cfg_kmod    opt_kmod;
14     struct  cfg_load    opt_load, query_load;
15     struct  stat        statbuf;
16     char    szKernExt[256], c;
17
18     /* Проверка привелегий пользователя  */
19     if (getuid() != 0) {
20         fprintf(stderr, " Not SuperUser.\n");
21         exit(EACCES);
22     }
23
24     /* Проверка аргументов */
25     if (argc != 2) {
26         printf ("Usage: %s <kernel_extension>\n", argv[0]);
27         exit(EINVAL);
28     }
29
30     strcpy(szKernExt,argv[1]);
31
32         /* Проверка существования файла */
33     if (stat(szKernExt,&statbuf) != 0) {
34         perror("stat");
35         exit(errno);
36     }
37
38     /* Заполнение структуры cfg_load */
39     opt_load.path = szKernExt;      /* file name */
40     opt_load.libpath = NULL;        /* no library  */
41     opt_load.kmid = 0;
42
43     /* Выполнение различных операций с расширением ядра */
44     while(1) {
45
46         fprintf (stderr, "\n Enter choice, (l)oad, (u)nload, (i)nit, (t) erm, 
                (q)uery or (e)nd\n");
47
48         while((c = getchar()) < 'a' && c > 'z')  ;  /* отбрасывание лишних данных */
49
50         switch(c) {
51
52         case 'l':         /* загрузка расширения ядра      */
53
54                       /* запрос загрузки расширения ядра   */
55                    if (sysconfig(SYS_KLOAD,&opt_load,sizeof(struct   cfg_load)))
56               perror("sysconfig(SYS_KLOAD)");  /* выдача сообщения об ощибке  */
57            else
58              printf("Extension Successfully loaded, kmid is %d\n", opt_load.kmid);
59
60                         break;
61
62                 case 'i': /* Инициализация расширения ядра */
63
64                 /* Инициализация расширения ядра  */
65             opt_kmod.kmid = opt_load.kmid;
66             opt_kmod.cmd = CFG_INIT;
67             opt_kmod.mdiptr = NULL;
68             opt_kmod.mdilen = 0;
69             if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct cfg_load)) )
70                 perror("sysconfig(SYS_CFGKMOD)");  /* выдача сообщения об ошибке */
71                         else
72                                 printf(" Extension Initialized \n");
73
74             break;
75
76         /* Выгрузка расширения ядра */
77         case 'u':
78             /* Проверка того, загружено ли расширение ядра */
79             if (opt_load.kmid == 0)
80                 printf("kernel Extension not loaded\n");
81             else  {
82                 if (sysconfig(SYS_KULOAD,&opt_load,sizeof(struct cfg_load)))
83                     perror("sysconfig(SYS_KULOAD)");
84                 else
85                     fprintf(stderr, "KernExt Successfully Unloaded \n");
86             }
87
88             break;
89
90          /* Завершение расширения ядра   */
91                 case 't':
92
93             /* Проверка того, загружено ли расширение ядра */
94             if (opt_load.kmid == 0)
95                 fprintf(stderr, "Extension not loaded\n");
96             else  {
97                opt_kmod.kmid = opt_load.kmid;
98                opt_kmod.cmd  = CFG_TERM;    /* Завершение расширения ядра */
99                opt_kmod.mdiptr = NULL;
100                opt_kmod.mdilen = 0;
101                if (sysconfig(SYS_CFGKMOD,&opt_kmod,sizeof(struct  cfg_kmod)))
102                    perror("sysconfig(SYS_CFGKMOD)");  /* выдача ошибки */
103                           else
104                               fprintf(stderr, " KernExtension  Terminated \n");
105                            }
106
107                        break;
108
109
110         /* запрос о существовании расширения ядра */
111         case 'q':
112
113             query_load.path     = opt_load.path;
114             query_load.libpath  = opt_load.libpath ;
115             query_load.kmid     = 0;
116
117             if (sysconfig(SYS_QUERYLOAD,&query_load,sizeof(struct cfg_load)))
118                 perror("sysconfig(SYS_QUERYLOAD)");
119             else
120                     {
121                            if(query_load.kmid > 0)
122                    fprintf(stderr, " Extension is loaded, with kmid %d \n", 
                            query_load.kmid);
123                            else
124                    fprintf(stderr, " Extension is not loaded \n");
125                     }
126             break;
127
128         case 'e':
129             exit(0);
130
131
132         default:
133             fprintf(stderr, "Incorrect option \n");
134             break;
135         }
136         getchar();
137     }
138
return 0;
140  }

Листинг 7 - это контролирующая программа, обеспечивающая загрузку и выгрузку расширения ядра.


Листинг 7. Листинг invoke_syscall.c
1 /* Вызов созданного системного вызова Demo */
2 #include <stdio.h>
3
4 int main()
5 {
6      int iVal = 0;
7
8      fprintf(stderr, " Invoking demo syscall \n");
9
10      if ( (iVal = demo_syscall(99)) < 0)
11      {
12         perror("demo_syscall error");
13         exit(1);
14      }
15
16      fprintf(stderr, " Got Value - %d\n",iVal);
17
18
19         return 0;
20 }

Это просто программа-пример, использующая новый системный вызов.

Листинг 8 ниже представляет собой Makefile для сборки всех программ усовершенствованного расширения ядра.


Листинг 8. Makefile для сборки всех программ усовершенствованного расширения ядра
1 all: demo_syscall invoke_syscall kctrl
2
3 kctrl: kctrl.c
4      cc -o kctrl kctrl.c
5
6 invoke_syscall: invoke_syscall.c
7      cc  -o invoke_syscall -bI:demo_syscall.exp invoke_syscall.c
8
9 demo_syscall: demo_syscall.c
10      cc -q32 -o demo_syscall32.o -qlist -qsource -c demo_syscall.c
11      mv demo_syscall.lst demo_syscall32.lst
12      ld -b32 -o demo_syscall32 demo_syscall32.o -e demo_syscall_init
            -bI:/usr/lib/kernex.exp -bE:demo_syscall.exp -lsys -l csys
13      cc -q64 -o demo_syscall64.o -qlist -qsource -c demo_syscall.c
14      mv demo_syscall.lst demo_syscall64.lst
15      ld -b64 -o demo_syscall64 demo_syscall64.o -e demo_syscall_init
             -bI:/usr/lib/kernex.exp -bE:demo_syscall.exp -lsys -l csys
16      rm -f demo_syscall
17      ar -X32_64 -r -v demo_syscall demo_syscall32 demo_syscall64
18
19 clean:
20      rm -f *.o invoke_syscall demo_syscall demo_syscall32 demo_syscall64 kctrl
            demo_syscall64.lst demo_syscall32.lst 2> /dev/null



Ресурсы

Научиться
  • Оригинал этой статьи (EN)

  • AIX 5L Version 5.3 Kernel Extensions and Device Support Programming Concepts (Расширения ядра в AIX 5L Version 5.3 и принципы программирования для поддержки работы устройств): подробное описание программирования ядра и среды ядра операционной системы AIX.(EN)

  • AIX 5L Version 5.3 Technical Reference: Kernel and Subsystems, Volume 1(Технический справочник по AIX 5L Version 5.3: Ядро и подсистемы, Том 1): это справочник для системных программистов с детальной информацией о сервисах ядра, драйверах устройств и файловых систем операционной системы AIX.(EN)

  • AIX 5.L Version 5.3 Technical Reference: Kernel and Subsystems, Volume 2(Технический справочник по AIX 5L Version 5.3: Ядро и подсистемы, Том 2): это справочник для системных программистов с детальной информацией о подсистемах настройки, коммуникаций, LFT, различных подсистемах принтеров, а также подсистеме SCSI, Integrated Device Electronics, подсистеме SSA и последовательной подсистеме DASD операционной системы AIX.(EN)

  • OpenAFS : OpenAFS портирован на AIX и в нем удачно реализована файловая система AIX.(EN)

  • AIX and UNIX: раздел AIX и UNIX на developerWorks содержит сотни статей и руководств различных уровней сложности.

  • Новые пользователи AIX и UNIX: страничка для новичков AIX и UNIX.

  • Мероприятия и web-конференции developerWorks: последние новости о мероприятиях и web-конференциях developerWorks.

  • AIX 5L Wiki: сообщество разработчиков документации AIX.(EN)

  • Podcast-каналы: аудозаписи презентаций экспертов IBM.(EN)

Получить продукты и технологии

Обсудить


Об авторах

Сандеш Чопдекар (Sandesh Chopdekar) является штатным разработчиком программного обеспечения в IBM и специализируется в области распределенных файловых систем и сетей. В настоящее время он является участником проекта MCP в LTC в Пуне, Индия. До IBM Сандеш работал в дочерней компании Citicorp. Он имеет степень бакалавра по химии университета Мубаи.


Авинеш Кумар (Avinesh Kumar) является разработчиком системного программного обеспечения в Andrew File System Team в IBM Software Labs в Пуне (Индия). Он занимается отладкой дампов и крахов ядра и пользовательских программ, а также анализом сообщений об ошибках в системах Linux, AIX и Solaris. Авинеш имеет MCA от факультета вычислительной техники Пунского университета. Он энтузиаст Linux и проводит свободное время, изучая ядро Linux на своем компьютере с Fedora Core 6.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



ДаНетНе знаю
 


 


12345
 


В начало


Microsoft, Windows, Windows NT, и логотип Windows - торговые марки корпорации Microsoft в США и/или в других странах.

UNIX является зарегистрированной торговой маркой The Open Group в США и/или в других странах. Другая компания, продукт или название услуги могут быть торговыми марками или знаками обслуживания, принадлежащими иным физическим или юридическим лицам.

IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.

    IBM в России Конфиденциальность Контакты