Создание драйвера устройства с XCode
В этом учебном руководстве Вы изучаете, как создать драйвер устройства Набора I/O для OS X. Вы создаете простой драйвер, распечатывающий текстовые сообщения, но фактически не управляющий устройством. Это учебное руководство не касается процесса для загрузки, или отладка Вашего драйвера — видят Отладку Расширения ядра с GDB после завершения этого учебного руководства для получения информации о загрузке и отладке.
Если Вы незнакомы с XCode, сначала считайте XCode Быстрый Гид.
План действий
Вот существенные шаги, которые Вы выполните:
Это учебное руководство предполагает, что Вы зарегистрированы как администратор Вашей машины, которая необходима для использования sudo
команда.
Ознакомьте Себя с Архитектурой Набора I/O
Каждый драйвер Набора I/O основывается на семье I/O Kit, наборе классов C++, реализующих функциональность, которая характерна для всех устройств определенного типа. Примеры семей I/O Kit включают устройства хранения (диски), сетевые устройства и устройства интерфейса пользователя (такие как клавиатуры).
Драйвер Набора I/O связывается с устройством, которым он управляет через объект провайдера, обычно представляющий шинное соединение для устройства. Объекты провайдера, делающие так, упоминаются как куски.
Драйвер Набора I/O загружается в ядро автоматически, когда это соответствует против устройства, представленного куском. Драйвер соответствует против устройства путем определения одного или более лиц, описаний типов устройства, которым может управлять драйвер.
После того, как драйвер Набора I/O соответствует против устройства и загрузок в ядро, он направляет I/O для устройства, а также службы продажи, связанные с устройством, такие как обеспечение микропрограммного механизма обновления.
Прежде чем Вы начнете создавать свой собственный драйвер, необходимо удостовериться, что Вы понимаете архитектуру Набора I/O путем чтения Обзора архитектуры в Основных принципах IOKit.
Создайте новый проект
Создание проекта драйвера Набора I/O в XCode так же просто как выбор надлежащего шаблона проекта и обеспечение имени.
Запуск XCode.
Выберите File> New> New Project. Панель New Project появляется.
В панели New Project выберите System Plug-in из списка категорий проектов слева. Выберите IOKit Driver из списка шаблонов справа. Нажать Далее.
На экране, появляющемся, войти
MyDriver
для названия продукта введите идентификатор компании и нажмите Далее.Выберите расположение для проекта и нажмите Create.
XCode создает новый проект и выводит на экран его окно проекта. Необходимо видеть что-то вроде этого:
Новый проект содержит несколько файлов, включая исходный файл,
MyDriver.cpp
, который не содержит кода.Удостоверьтесь, что kext создает для корректной архитектуры.
(Если Вы не видите экран выше, выберите MyDriver под Целями. Выберите вкладку Build Settings. Щелкните по треугольнику раскрытия, следующему за Архитектурой.)
Затем для Создания Активной Архитектуры Только удостоверяются, что выбрали No — это особенно важно при выполнении 32-разрядного ядра на 64-разрядной машине.
Отредактируйте информационный список свойств
Как все пакеты, драйвер устройства содержит информационный список свойств, описывающий драйвер. Значение по умолчанию Info.plist
файл, создаваемый XCode, содержит шаблонные значения, которые необходимо отредактировать для описания драйвера.
Драйвер устройства Info.plist
файл находится в формате XML. Каждый раз, когда возможно, необходимо просмотреть и отредактировать файл из XCode или в Редакторе Списка свойств приложение. Таким образом Вы помогаете гарантировать, чтобы Вы не добавляли элементы (такие как комментарии), который не может быть проанализирован ядром во время ранней начальной загрузки.
Нажмите Info.plist в окне проекта XCode.
XCode выводит на экран
Info.plist
файл в области редактора. Необходимо видеть элементы файла списка свойств, как показано на рисунке 1.По умолчанию редактор списка свойств XCode маскирует фактические ключи и значения списка свойств. Видеть фактические ключи и значения, Щелчок управления где угодно в редакторе списка свойств и выбрать Show Raw Keys/Values из контекстного меню.
Измените значение
CFBundleIdentifier
свойство для использования уникального префикса пространства имен.На строке для
CFBundleIdentifier
, дважды щелкните в Столбце значений для редактирования его. Выбратьcom.yourcompany
и измените его наcom.MyCompany
(или домен DNS Вашей компании наоборот). Значение должно теперь бытьcom.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier}
.Пакеты в OS X обычно используют соглашение о присвоении имен обратного DNS избежать конфликтов пространства имен. Это соглашение особенно важно для kexts, потому что все загрузились, kexts совместно используют единое пространство имен для идентификаторов пакета.
Последняя часть идентификатора пакета по умолчанию,
${PRODUCT_NAME:rfc1034identifier}
, когда Вы разрабатываете свой проект, заменяется установкой сборки Названия продукта для цели драйвера.Добавьте индивидуальность к своему водительскому
IOKitPersonalities
словарь.Щелкните
IOKitPersonalities
свойство для выбора его затем щелкните по его треугольнику раскрытия так, чтобы это указало вниз.Щелкните по Новому Дочернему символу по правой стороне выбранной строки. Свойство назвало
New item
появляется как дочерний элементIOKitPersonalities
свойство. Измените имяNew item
кMyDriver
.Сделайте
MyDriver
элемент словарь. Щелчок управления это и выбирает Value Type> Dictionary из контекстного меню.Ваш драйвер устройства требует одной или более записей в
IOKitPersonalities
словарь его информационного списка свойств. Этот словарь определяет свойства, используемые для соответствия Вашего драйвера к устройству и загрузке его.Заполните словарь индивидуальности.
Создайте дочерний элемент для
MyDriver
словарь. Переименуйте дочерний элемент отNew item
кCFBundleIdentifier
. Скопируйте и вставьте значение от верхнего уровня списка свойствCFBundleIdentifier
значение (com.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier}
) как значение.Создайте второй дочерний элемент для
MyDriver
словарь. Переименуйте дочерний элемент кIOClass
. Войтиcom_MyCompany_driver_MyDriver
как значение. Обратите внимание на то, что это - то же значение что касаетсяCFBundleIdentifier
, кроме него разделяет его элементы underbars вместо точек. Это значение используется в качестве имени класса для Вашего драйвера устройства.Создайте третий дочерний элемент для
MyDriver
словарь. Переименуйте дочерний элемент кIOKitDebug
. Войти65535
как значение и изменение тип значения от Строки до Числа. При указании ненулевого значения для этого свойства драйвер обеспечивает полезную отладочную информацию, когда это соответствует и загружается. При создании драйвера для общедоступного выпуска необходимо указать0
как значение для этого свойства или удаляют его полностью.Создайте еще два дочерних элемента для
MyDriver
словарь. Присвойте их имена и значения согласно Таблице 1.Таблица 1 MyDriver
значения словаря индивидуальностиИмя
Значение
IOProviderClass
IOResources
IOMatchCategory
com_MyCompany_driver_MyDriver
Эти элементы вместе определяют успешное соответствие для Вашего драйвера, так, чтобы он мог быть загружен. Они служат следующим целям:
IOProviderClass
указывает, что класс провайдера возражает, что Ваш драйвер может соответствовать на. Обычно драйвер устройства соответствует на куске, управляющем портом, с которым подключено Ваше устройство. Например, если Ваш драйвер соединяется с шиной PCI, необходимо указатьIOPCIDevice
как Ваш водительский класс провайдера. В этом учебном руководстве Вы создаете виртуальный драйвер без устройства, таким образом, это соответствует наIOResources
.IOMatchCategory
позволяет другим драйверам соответствовать на том же устройстве как Ваш драйвер, пока отличаются значения драйверов для этого свойства. Драйвер этого учебного руководства соответствует наIOResources
, специальный класс провайдера, обеспечивающий ресурсы в масштабе всей системы, таким образом, он должен включать это свойство, чтобы позволить другим драйверам соответствовать наIOResources
также. При разработке драйвера Вы не должны включать это свойство, если Ваш драйвер не соответствует на устройстве, которое другой драйвер может соответствовать на, такие как последовательный порт с многократными устройствами, присоединенными к нему.
Когда Вы закончили добавлять элементы списка свойств, список должен быть похожим на пример, показанный на рисунке 2.
Выберите File> Save для сохранения изменений.
Заполните заголовочный файл
Открытый MyDriver.h
в Вашем проекте Source
папка. Заголовочный файл по умолчанию не содержит кода. Рисунок 3 показывает, где найти MyDriver.h
файл в окне проекта.
Отредактируйте содержание MyDriver.h
соответствовать код в Перечислении 1.
Перечисление 1 MyDriver.h
содержание файла
#include <IOKit/IOService.h> |
class com_MyCompany_driver_MyDriver : public IOService |
{ |
OSDeclareDefaultStructors(com_MyCompany_driver_MyDriver) |
public: |
virtual bool init(OSDictionary *dictionary = 0); |
virtual void free(void); |
virtual IOService *probe(IOService *provider, SInt32 *score); |
virtual bool start(IOService *provider); |
virtual void stop(IOService *provider); |
}; |
Заметьте что первая строка MyDriver.h
включает заголовочный файл IOService.h
. Этот заголовочный файл определяет многие методы и службы то использование драйверов устройств. Заголовочный файл расположен в IOKit
папка Kernel.framework
. Когда Вы разрабатываете свой собственный драйвер, убедиться включать только заголовочные файлы от Kernel.framework
(в дополнение к заголовочным файлам Вы создаете), потому что только эти файлы имеют значение в среде ядра. При включении других заголовочных файлов драйвер мог бы скомпилировать, но ему не удается загрузиться, потому что функции и службы, определенные в тех заголовочных файлах, не доступны в ядре.
Обратите внимание на то, что при разработке собственного драйвера необходимо заменить экземпляры com_MyCompany_driver_MyDriver
с именем Вашего водительского класса.
В заголовочном файле каждого класса драйвера, OSDeclareDefaultStructors
макрос должен быть первой строкой в объявлении класса. Макрос берет один параметр: имя класса. Это объявляет конструкторов класса и деструкторы для Вас, таким образом который ожидает I/O Кит.
Реализуйте водительские точки входа
Открытый
MyDriver.cpp
в Вашем проектеSource
папка. Файл по умолчанию не содержит кода.Редактирование
MyDriver.cpp
соответствовать код в Перечислении 2.Перечисление 2
MyDriver.cpp
содержание файла#include <IOKit/IOLib.h>
#include "MyDriver.h"
// This required macro defines the class's constructors, destructors,
// and several other methods I/O Kit requires.
OSDefineMetaClassAndStructors(com_MyCompany_driver_MyDriver, IOService)
// Define the driver's superclass.
#define super IOService
bool com_MyCompany_driver_MyDriver::init(OSDictionary *dict)
{
bool result = super::init(dict);
IOLog("Initializing\n");
return result;
}
void com_MyCompany_driver_MyDriver::free(void)
{
IOLog("Freeing\n");
super::free();
}
IOService *com_MyCompany_driver_MyDriver::probe(IOService *provider,
SInt32 *score)
{
IOService *result = super::probe(provider, score);
IOLog("Probing\n");
return result;
}
bool com_MyCompany_driver_MyDriver::start(IOService *provider)
{
bool result = super::start(provider);
IOLog("Starting\n");
return result;
}
void com_MyCompany_driver_MyDriver::stop(IOService *provider)
{
IOLog("Stopping\n");
super::stop(provider);
}
OSDefineMetaClassAndStructors
макрос должен появиться перед определением любого из методов класса. Этот макрос берет два параметра: имя Вашего класса и имя суперкласса Вашего класса. Макрос определяет конструкторов класса, деструкторы и несколько других методов, требуемых Набором I/O.Это перечисление включает методы точки входа что использование Набора I/O для доступа к драйверу. Эти точки входа служат следующим целям:
init
метод является методом первой инстанции, обратился к каждому экземпляру Вашего класса драйвера. Это вызывают только один раз на каждом экземпляре.free
метод является последним методом, обратился к любому объекту. В любых выдающихся ресурсах, выделенных драйвером, нужно избавитьсяfree
. Обратите внимание на то, чтоinit
метод воздействует на объекты в общем; это должно использоваться только для подготовки объектов получить вызовы. Фактическая функциональность драйвера должна быть установлена вstart
метод.probe
метод вызывают, если Ваш драйвер должен связаться с аппаратными средствами, чтобы определить, существует ли соответствие. Этот метод должен оставить аппаратные средства в хорошем состоянии, когда это возвращается, потому что другие драйверы могут зондировать аппаратные средства также.start
метод говорит драйверу начинать управлять аппаратными средствами. Послеstart
вызывается, драйвер может начать направлять I/O, публикуя куски, и продав службы.stop
метод является первым методом, который вызовут, прежде чем будет разгружен Ваш драйвер. Когдаstop
вызывается, Ваш драйвер должен очистить любое состояние, которое он создал вstart
метод.start
иstop
методы говорят с аппаратными средствами через Ваш водительский класс провайдера.
IOLog
функция является ядром, эквивалентным изprintf
для драйвера Набора I/O.Сохраните свои изменения путем выбора File> Save.
Разработайте свой проект путем выбора Build> Build. Фиксируйте любые ошибки компилятора перед продолжением.
Добавьте объявления библиотеки
Поскольку kexts соединяются во время загрузки, kext должен перечислить свои библиотеки в его информационном списке свойств с OSBundleLibraries
свойство. На этом этапе создания Вашего драйвера необходимо узнать, каковы те библиотеки. Лучший способ сделать так состоит в том, чтобы работать kextlibs
инструмент на Вашем созданном kext и копии его вывод в Ваш kext’s Info.plist
файл.
Выполненный kextlibs на Драйвере
kextlibs
программа командной строки, которую Вы выполняете с Терминальным приложением. Его цель состоит в том, чтобы идентифицировать библиотеки, против которых должен соединиться Ваш kext.
Запустите Терминальное приложение, расположенное в
/Applications/Utilities
.В Окне терминала переместитесь в каталог, содержащий Ваш драйвер.
XCode хранит Ваш драйвер в
Debug
папкаbuild
папка Вашего проекта (если Вы не выбрали различную конфигурацию сборки или установили различное расположение для продуктов сборки с помощью Предпочтительного диалогового окна XCode):$ cd MyDriver/build/Debug
Этот каталог содержит Ваш драйвер. Это должно иметь имя
MyDriver.kext
. Это имя формируется из Названия продукта, как установлено в настройках сборки Вашей цели и суффиксе, в этом случае.kext
.Выполненный
kextlibs
на Вашем драйвере с-xml
флаг командной строки.Эта команда ищет все неразрешенные символы в исполнимой программе Вашего расширения ядра среди установленных расширений библиотеки (в
/System/Library/Extensions/
) и распечатывает фрагмент XML, подходящий для вставки вInfo.plist
файл. Например:$ kextlibs -xml MyDriver.kext
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kpi.iokit</key>
<string>10.2</string>
<key>com.apple.kpi.libkern</key>
<string>10.2</string>
</dict>
Удостовериться
kextlibs
вышедший с успешным состоянием путем проверки переменной оболочки$?
.$ echo $?
0
Если
kextlibs
печать любые ошибки или выходы с ненулевым состоянием, это, возможно, было неспособно определить местоположение некоторых символов. Для этого учебного руководства известны библиотеки, но в общем использовании необходимо использоватьkextfind
инструмент для нахождения библиотек для любых символов этимkextlibs
не может расположиться. Посмотрите Определяют местоположение Kexts.Выберите вывод XML
kextlibs
и выберите Edit> Copy.
Добавьте объявления библиотеки к информационному списку свойств
Ранее Вы отредактировали информационный список свойств с XCode графический редактор списка свойств. Для этой работы, однако, необходимо отредактировать информационный список свойств как текст.
Щелчок управления Info.plist в окне проекта XCode, затем выберите Open As> Source Code File из контекстного меню.
XCode выводит на экран
Info.plist
файл в области редактора. Необходимо видеть содержания XML файла списка свойств, как показано на рисунке 3. Обратите внимание на то, что ключи словаря и значения перечислены последовательно.Выберите все строки, определяющие пустой словарь OSBundleLibraries.
<key>OSBundleLibraries</key>
<dict/>
Текст вставки в информационный словарь.
Если
kextlibs
работал успешно, выберите Edit> Paste для вставки текста, который Вы скопировали с Терминала.Если
kextlibs
не работал успешно, вводят или вставляют этот текст в информационный словарь:<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kpi.iokit</key>
<string>10.2</string>
<key>com.apple.kpi.libkern</key>
<string>10.2</string>
</dict>
Сохраните свои изменения путем выбора File> Save.
Восстановите свой драйвер (выберите Build> Build) с новым информационным списком свойств. Фиксируйте любые ошибки компилятора перед продолжением.
Подготовьте драйвер к загрузке
Теперь Вы готовы подготовить свой драйвер к загрузке. Вы делаете это с kextutil
инструмент, который может исследовать kext и определить, в состоянии ли он быть загруженным. kextutil
может также загрузить kext в целях разработки, но та функциональность не охвачена в этом учебном руководстве.
Установите водительские полномочия
Kexts имеют строгие требования полномочий (см., что Расширения ядра Имеют Строгие Требования к защите для подробных данных). Самый простой способ установить эти полномочия состоит в том, чтобы создать копию Вашего драйвера как root
пользователь. Введите следующее в Терминал из надлежащего каталога и обеспечьте Ваш пароль, когда запрошено:
$ sudo cp -R MyDriver.kext /tmp |
Теперь, когда полномочия водительской временной копии корректны, Вы готовы работать kextutil
.
Выполненный kextutil
Введите следующее в Терминал:
$ kextutil -n -t /tmp/MyDriver.kext |
-n
(или -no-load
) опция говорит kextutil
не загрузить драйвер, и -t
(или -print-diagnostics
) опция говорит kextutil
распечатать результаты его анализа к Терминалу. Если Вы выполнили предыдущие шаги в этом учебном руководстве правильно, kextutil
указывает, что kext является загружаемым и должным образом соединен.
No kernel file specified; using running kernel for linking. |
Notice: /tmp/MyDriver.kext has debug properties set. |
MyDriver.kext appears to be loadable (including linkage for on-disk libraries). |
Уведомление свойства отладки вследствие ненулевого значения IOKitDebug
свойство в информационном списке свойств. Удостоверьтесь, что Вы устанавливаете это свойство в 0
или удалите его при создании драйвера для выпуска.
Куда пойти затем
Поздравления! Вы теперь записали, создали и подготовили свой собственный драйвер к загрузке. В следующем учебном руководстве в этом ряду, Отлаживая Расширение ядра с GDB, Вы изучите, как загрузить Ваш kext, отладить его и разгрузить его с установкой с двумя машинами.