Отладка драйверов удара молнии
Эта глава содержит подсказки по отладке, которые могут быть полезными при разыскивании проблем в драйверах Удара молнии.
Отладка VT-d I/O Виртуализация MMU
Более новые Способные к удару молнии Macs предоставляют поддержку для I/O виртуализация MMU (VT-d). Эта технология позволяет виртуальным машинам иметь прямой доступ к аппаратным средствам. В результате этой поддержки, когда Ваше устройство выполняет операции DMA, адресуется I/O, это использует, может отличаться от физических адресов, как замечено ядром OS X.
Полная спецификация может быть найдена здесь: Intel® Virtualization Technology для Направленной Спецификации I/O.
Системы Ivy Bridge рабочий OS X v10.8.2 и позже включают модуль Intel VT-d как DMA remapper. Эта функциональность поддерживается текущим APIs почти таким же способом как контроллер DART на компьютерах PowerMac G5. (Чтобы изучить, как это работает на высоком уровне, считайте Поддержку DMA на 64-разрядных Архитектурах системы).
Когда VT-d включен, некоторые изменения, которые Вы рассмотрите как, результаты этого:
Если Вы пишете программы DMA, несмотря на то, что физические сегменты, возвращенные
IOMemoryDescriptorилиIODMACommandнепрерывные диапазоны адресов I/O, адреса I/O для сегментов могут отличаться, чем физические адреса CPU, и диапазоны больше не обязательно непрерывны в физической памяти с точки зрения CPU.В результате сегменты обычно будут тем же размером как полное
IOMemoryDescriptorразмер (для фактически непрерывногоIOMemoryDescriptorобъект с единственным исходным буфером).По умолчанию запросы на физически непрерывную память возвращают память, которая непрерывна только с точки зрения устройств ввода-вывода и может не быть физически непрерывной в RAM.
Если память должна быть непрерывной к CPU также, необходимо передать
kIOMemoryHostPhysicallyContiguousопция кIOBufferMemoryDescriptorкогда Вы запрашиваете память. Если никакие физически непрерывные блоки не доступны, как прежде, такие запросы могут перестать работать.Если дескрипторы памяти или команды DMA должным образом не подготовлены к чтению или записи, транзакции теперь перестали работать.
prepareметод добавляет отображающуюся запись в таблицу преобразования адресов I/O. Необходимо вызватьprepare(и укажите корректное направление), прежде чем Вы скажете устройству считывать данные из или данные записи к той области памяти.Необходимо также сбалансировать каждого
prepareвызовите с соответствующим вызовом кcompleteметод. Если Вы не сделаете, то Ваш драйвер в конечном счете заполнит таблицу отображения, и Вы доберетесь, ядро паникуют в следующий раз, когда драйвер пытается добавить запись таблицы отображения.prepareиcompleteметоды имеют дополнительные издержки, хотя это влияние частично уравновешено более коротким рассеянием - собирают списки.
Если Вы просите неотображенные физические адреса — путем вызова IOMemoryDescriptor объект getPhysicalSegment метод с опцией kIOMapperNone или IODMACommand объект initWithSpecification метод с mappingOptions набор к чему-то другому, чем kMapped— и попытайтесь использовать их для DMA, Ваш драйвер повредится.
Включение паника VT-d
По умолчанию отказы VT-d регистрируются к /var/log/system.log. Отказ VT-d похож на следующее:
vtd[0] fault: device 13:0:0 reason 0x6 R:0x3dff000 |
В примере выше, 13:0:0 шина, устройство и функция устройства, генерировавшего отказ. Можно определить, произвело ли устройство отказ путем взгляда на pci-debug поле в выводе ioreg или в приложении IORegistryExplorer и сравнении значений.
Для списка кодов причин посмотрите Intel® Virtualization Technology для Направленной Спецификации I/O.
R указывает, что операция чтения инициировала отказ. (W указывает запись.) Окончательное значение является адресом, который устройство пыталось считать или записать (выраженный как адрес I/O-space).
При отладке отказов может быть полезно сконфигурировать ядро для паники каждый раз, когда происходит отказ. Чтобы сделать это, добавьте, что следующий флаг в Вашем ядре загружает args:
pci=0x100 |
Отключение VT-d
При отладке драйверов устройств PCIe часто полезно временно отключить VT-d так, чтобы адреса I/O совпали с соответствующими физическими адресами. Для отключения VT-d добавьте, что следующие к ядру загружают args:
dart=0x0 |
Если проблема, которую Вы отлаживаете, уходит в этом режиме, она обычно указывает одну из следующих ошибок:
Некоторая часть Вашего кода неправильно передает физический адрес в RAM к Вашему устройству в целях DMA вместо адреса I/O.
Вашему коду не удалось вызвать
prepareили вызванныйprepareнеправильно наIOMemoryDescriptorобъект перед использованием его для выполнения DMA.
Отладка пауза PCIe
По умолчанию ядро OS X распространяет распределения адресов PCI. В результате события паузы PCIe нечасто имеют место, который делает эти события оспариванием для отладки. Можно сделать отладку проще путем отключения этого поведения распространения выделения. С распространением отключенного, почти каждое событие замены в горячем режиме инициировало событие паузы.
Для отключения распространения выделения добавьте следующий к ядру boot-args строка:
pci=0x200 |
Предотвращение утечек памяти
Драйверы должны гарантировать выпуск любого и всех ресурсов, полученных за жизненный цикл драйвера. В частности диапазоны I/O с отображенной памятью, память и объекты должны все быть освобождены и перепроверены для любых утечек. Использование инструментов такой как может помочь идентифицировать некоторые из этих типов утечек. Стандартная форма утечек представлена ссылками (т.е. сохраните количества). Часто, трудно определить источник этих ссылок. Один способ определить источник этих ссылок состоит в том, чтобы переопределить ioclasscounttaggedRetain() метод и получает след вызывающей стороны, к которой можно тогда отправить printf(), kprintf(), или IOTimeStampConstant().
Перечисление 4-1 , ищущее утечки памяти
void |
AppleSamplePCI::taggedRetain ( const void * tag ) const |
{ |
void * bt[16] = { 0 }; |
OSBacktrace ( &bt[0], sizeof ( bt ) / sizeof ( bt[0] ) ); |
super::taggedRetain ( tag ); |
} |
Используя стандарт symbolication инструменты позволяет Вам определять, какие функции или методы заставили ссылку (ки) быть взятой. Кроме того, можно переопределить taggedRelease() и соответствуйте сохранение и выпуски для нахождения вызовов к taggedRetain(), которые не имеют никакого соответствующего вызова к taggedRelease().