Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе описывается, как транспорт KDNET можно расширить для запуска на любом оборудовании с помощью отдельного DLL модуля расширения для драйвера оборудования. Модули расширяемости транспорта KDNET разрабатываются поставщиками сетевых карт для добавления поддержки отладки ядра в определенные сетевые карты.
Обзор KDNET
KDNET — это транспорт ядра для отладки, который обеспечивает отладку ядра Windows через сеть. Первоначально она использовалась для поддержки отладки ядра с сетевыми адаптерами Ethernet. Он разработан таким образом, чтобы уровень поддержки оборудования был встроен в отдельный модуль от сетевой обработки пакетов и уровня интерфейса ядра. Этот уровень поддержки драйвера оборудования называется модулем расширяемости KDNET.
KDNET — это единственный транспорт, который можно расширить для запуска на любом оборудовании с помощью отдельной библиотеки dll модуля расширения драйвера оборудования. Это цель поддерживать все отладки Windows через KDNET и модули расширяемости KDNET. Все остальные библиотеки DLL транспорта ядра (kdcom.dll, kd1394.dll, kdusb.dll и т. д.) в конечном итоге будут устаревшими и удалены из Windows.
Существует два типа интерфейсов, которые KDNET использует для взаимодействия с модулями расширяемости KDNET. Один из них — это интерфейс на основе пакетов, используемый для сетевых адаптеров, USB и беспроводного оборудования, а другой — интерфейс на основе байтов, который используется для поддержки KDNET через последовательное оборудование.
Модули расширяемости KDNET должны соответствовать очень строгим требованиям, чтобы правильно работать. Так как они используются для отладки ядра, они будут вызываться и выполняться, когда система задерживает дальнейшее выполнение кода. Как правило, все процессоры в системе блокируются в IPI, за исключением процессора, который взаимодействует с приложением отладчика, работающим на хост-компьютере через транспорт отладки ядра. Этот процессор обычно работает с полностью отключёнными прерываниями и, по сути, находится на отладочном интерфейсе в ожидании команд от отладчика.
Импорт и экспорт
Модули расширяемости KDNET имеют ровно один явный экспорт — KdInitializeLibrary. Они также не имеют явных импортов. При вызове KdInitializeLibrary, KDNET передает модулям расширяемости указатель на структуру со списком подпрограмм, которые они могут вызывать. Другие подпрограммы не могут быть вызваны. Период. Модули расширяемости KDNET, имеющие какие-либо импорты, неправильно разработаны и не поддерживаются.
Если вы дампируете импорт и экспорт модулей расширяемости KDNET с помощью ссылки /dump/exports и ссылки /dump /import, вы увидите, что у них есть только один экспорт (KdInitializeLibrary) и нет импорта. Модули расширения KDNET сообщают о своих дополнительных возможностях KDNET, заполняя указатели функций в структуре экспортных функций, на которую KDNET передает указатель при вызове KdInitializeLibrary. Затем KDNET использует указатели функций в этой структуре для вызова модуля расширения и передачи данных с помощью оборудования, поддерживаемого этим модулем. KDNET определяет, является ли модуль модулем на основе пакетов или байт, просматривая, какие конкретные функции модуль заполняет в таблице экспортных функций в структуре. Некоторые из этих функций предназначены для поддержки оборудования на основе пакетов, а другие — для последовательного оборудования. Некоторые функции в таблице используются как последовательным, так и пакетным оборудованием (KdInitializeController, KdShutdownController, KdGetHardwareContextSize).
Проектирование кода
Модули расширяемости KDNET должны быть записаны как один потоковый код. Они не должны выполнять синхронизацию. Все отладочные транспортные механизмы ядра зависят от ядра Windows, чтобы обеспечить правильную синхронизацию при активации отладчика. Ядро имеет блокировку отладчика, которая принимается при входе отладчика ядра, а также блокирует другие процессоры в системе в IPI при вводе отладчика. Эти процессоры будут выпущены, только если отладчик ядра, запущенный на узле, сообщает целевому компьютеру разрешить выполнение. Так как ядро выполняет эту синхронизацию, модули расширяемости KDNET не должны использовать в коде какие-либо спин-блокировки, мьютексы, шлюзы или любой другой механизм синхронизации Windows. Они должны быть написаны для прямого программирования их соответствующего оборудования с целью отправки и приема пакетов и байтов.
Код модуля расширяемости KDNET должен быть сделан как можно проще. Это поможет гарантировать, что в настоящее время код модуля расширения KDNET недоступен без использования аппаратного отладчика. Нельзя использовать отладчик ядра для отладки кода транспорта отладки для ядра. Попытка сделать это приведет к перезагрузке компьютера из-за переполненного стека ядра (что обычно заканчивается двойной ошибкой и перезагрузкой), или дедлока, или приведет к повторному срабатыванию транспорта, что в большинстве случаев мешает его правильному функционированию.
Соглашения об именовании модулей расширения KDNET
Модуль транспорта отладки ядра должен соответствовать одному из двух соглашений об именовании модулей расширяемости KDNET. Если модуль предназначен для поддержки pci, оборудование, оно должно называться kd_YY_XXXX.dll где XXXX является идентификатором поставщика PCI оборудования в шестнадцатеричном режиме, а YY — класс PCI для вашего оборудования. Существует несколько модулей расширяемости KDNET, которые отправляются в поле в окнах, поддерживающих оборудование на основе PCI. Например, kd_02_8086.dll Intel, kd_02_14e4.dll Broadcom и kd_02_10ec.dll Realtek. Вы можете найти зарегистрированные идентификаторы поставщиков PCI на https://www.pcisig.com/membership/member-companies, а все модули расширения KDNET с поддержкой PCI используют идентификатор поставщика оборудования (VID), который они поддерживают, в шестнадцатеричном виде в качестве последних 4 символов в названии своего модуля. Код класса для большинства встроенных модулей равен 02, так как они являются устройствами сетевого класса и поэтому имеют класс PCI 0x02 в пространстве конфигурации PCI. Winload.exe создает имя модулей расширяемости KDNET на основе PCI, считывая класс устройства PCI и PCI VID выбранного устройства отладки из пространства конфигурации PCI и пытается загрузить модуль с этими идентификаторами в имени. Если устройство имеет код класса PCI, который не является сетевым 0x02 классом, необходимо использовать правильный код класса PCI в шестнадцатеричном коде для устройства в имени модуля расширяемости KDNET. В противном случае модуль не будет загружен правильно с помощью winload. В _02_ каждом из этих имен используется код класса PCI для устройств сетевого класса в шестнадцатеричном формате. Этот код также находится и считывается из пространства конфигурации PCI отладочного устройства.
Если у вас имеется устройство с записью таблицы DBG2, которое не является устройством на базе PCI, соглашение об именовании модуля отличается. Соглашение об именовании устройств отладки таблицы DBG2 выглядит как kd_XXXX_YYYY.dll, где XXXX — это шестнадцатеричный PortType из таблицы DBG2, а YYYY — шестнадцатеричный PortSubtype из записи таблицы DBG2. Kd_8003_5143.dll — это библиотека DLL в папке "Входящие" для поддержки net (0x8003) PortType с подтипом 0x5143. В этом случае 5143 является идентификатором вендора PCI Qualcomm, поскольку он предназначен для поддержки KDNET на USB-контроллерах Qualcomm. Для записей в таблице Net DBG2 подтип порта определяется как идентификатор вендора PCI для производителя оборудования. Обратите внимание, что вы можете поддерживать последовательные устройства, USB устройства и другие устройства таблицы DBG2 с помощью этих правил именования. Ниже приведены поддерживаемые в настоящее время значения PortType в шестнадцатеричном формате: 8000 для серийных устройств, 8001 для 1394 устройств, 8002 для USB-устройств, 8003 для устройств NET. Обратите внимание, что подтипы для серийных и USB-устройств должны быть зарезервированы корпорацией Майкрософт. Корпорация Майкрософт поддерживает список выделенных серийных и USB-подтипов. Пожалуйста, отправьте почту на kdnet@microsoft.com, чтобы зарезервировать последовательный или USB-подтип, если существующие поддерживаемые типы не будут работать с вашим оборудованием.
Импорт возможностей расширения KDNET
Ниже приведен список подпрограмм, которые можно вызвать из модуля расширяемости KDNET. Обратите внимание, что все эти функции передаются в функцию KdInitializeLibrary, а заголовочный файл kdnetextensibility.h перенастраивает обычные вызовы этих функций для прохождения через таблицу импорта. Код должен вызывать их через таблицу импорта, чтобы модуль не импортировал. Вы не можете вызывать другие подпрограммы, экспортируемые ядром, HAL или любым другим модулем ядра. Вы можете вызывать только эти подпрограммы. Этот набор подпрограмм оказался достаточным для разработки всех модулей расширяемости KDNET в коробке и должен быть достаточно для обычных сценариев. Если вам нужны дополнительные подпрограммы, экспортируемые ядром, но не указанные в этом списке, отправьте сообщение на kdnet@microsoft.com, объяснив ваш сценарий, а также какие дополнительные подпрограммы вам нужны и почему. Обратите внимание, что этот список будет пополняться только в основных циклах выпуска Windows, если вообще будет пополняться. Обратите внимание, что большинство этих подпрограмм соответствуют непосредственно API ядра Windows, которые поддерживаются ядром или HAL. Две процедуры настроены только для KDNET.
Важно правильно включить kdnetextensibility.h в заголовки, чтобы правильно перенаправлять подпрограммы с помощью таблицы импорта. Если это не сделано, модуль будет импортировать и не будет поддерживаться.
Чтение подпрограмм памяти записи
Следующие подпрограммы следует использовать для чтения и записи в память, сопоставленную с памятью устройства. Они имеют то же соглашение о вызовах и сопоставляются с соответствующими подпрограммами ядра: READ_REGISTER_UCHAR, READ_REGISTER_USHORT, READ_REGISTER_ULONG, WRITE_REGISTER_UCHAR, WRITE_REGISTER_USHORT, WRITE_REGISTER_ULONG и на 64-разрядных платформах только READ_REGISTER_ULONG64 и WRITE_REGISTER_ULONG64. Доступ ко всей памяти устройства должен выполняться с помощью этих подпрограмм, так как они гарантируют, что операции чтения и записи не переупорядочены процессором. Обратите внимание, что на msdn.microsoft.com документированы подпрограммы Windows CE Compact 2013, с соглашением о вызове, которое соответствует этим подпрограммам. К сожалению, кажется, что процедуры NT не задокументированы, но соглашение о вызове такое же.
Читать процедуры работы с портами ввода-вывода
Следующие подпрограммы следует использовать для чтения и записи в порты ввода-вывода устройства. Они имеют то же соглашение о вызовах и сопоставляются с соответствующими подпрограммами ядра: READ_PORT_UCHAR, READ_PORT_USHORT, READ_PORT_ULONG, WRITE_PORT_UCHAR, WRITE_PORT_USHORT и WRITE_PORT_ULONG. Доступ ко всем портам ввода-вывода устройства должен выполняться с помощью этих подпрограмм. Обратите внимание, что msdn.microsoft.com документирует подпрограммы Windows CE Compact 2013, соответствующие правилам вызова этих подпрограмм.
Дополнительные рутины
Следующие дополнительные подпрограммы можно вызывать, и обычно следует вызывать их с указанными параметрами. Обратите внимание, что подобное действие при правильном включении заголовка kdnetextensibility.h перенаправляет вызовы функций через таблицу импорта расширяемости KDNET, в результате чего в вашем модуле отсутствуют явные импорты, что необходимо для модулей расширяемости KDNET.
PHYSICAL_ADDRESS
KdGetPhysicalAddress (
__in PVOID Va
);
VOID
KeStallExecutionProcessor (
__in ULONG Microseconds
);
ULONG
KdGetPciDataByOffset (
__in ULONG BusNumber,
__in ULONG SlotNumber,
__out_bcount(Length) PVOID Buffer,
__in ULONG Offset,
__in ULONG Length
);
ULONG
KdSetPciDataByOffset (
__in ULONG BusNumber,
__in ULONG SlotNumber,
__in_bcount(Length) PVOID Buffer,
__in ULONG Offset,
__in ULONG Length
);
VOID
KdSetDebuggerNotPresent (
__in BOOLEAN NotPresent
);
VOID
PoSetHiberRange (
_In_opt_ PVOID MemoryMap,
_In_ ULONG Flags,
_In_ PVOID Address,
_In_ ULONG_PTR Length,
_In_ ULONG Tag
);
VOID
KeBugCheckEx (
__in ULONG BugCheckCode,
__in ULONG_PTR BugCheckParameter1,
__in ULONG_PTR BugCheckParameter2,
__in ULONG_PTR BugCheckParameter3,
__in ULONG_PTR BugCheckParameter4
);
PVOID
KdMapPhysicalMemory64 (
_In_ PHYSICAL_ADDRESS PhysicalAddress,
_In_ ULONG NumberPages,
_In_ BOOLEAN FlushCurrentTLB
);
VOID
KdUnmapVirtualAddress (
_In_ PVOID VirtualAddress,
_In_ ULONG NumberPages,
_In_ BOOLEAN FlushCurrentTLB
);
ULONG64
KdReadCycleCounter (
__out_opt PULONG64 Frequency
);
Обратите внимание, что функция PoSetHiberRange должна вызываться только из подпрограммы KdSetHibernateRange. Кроме того, большинство модулей расширяемости KDNET не должны вызывать KeBugCheckEx, KdMapPhysicalMemory64 и KdUnmapVirtualAddress. С другой стороны, все модули расширяемости KDNET должны вызывать KdGetPhysicalAddress для получения адресов физической памяти, необходимых для программирования обработчиков DMA устройства, и многие должны вызывать KeStallExecutionProcessor, KdGetPciDataByOffset и KdSetPciDataByOffset. Последние две подпрограммы предназначены для доступа к пространству конфигурации PCI устройства.
Экспорт возможностей расширения KDNET
Ниже приведено краткое описание каждой процедуры расширения KDNET. Необходимо реализовать все подпрограммы, необходимые для модуля расширяемости KDNET на основе пакетов, либо модуля расширяемости KDNET на основе последовательного интерфейса. Ниже приведены экспорты модуля расширяемости пакета KDNET.
KdInitializeLibrary
/*++
Routine Description:
This routine validates that the ImportTable is a supported version. Makes
a copy of the ImportTable in its own global memory, and writes pointers to
functions that it exports into the Exports pointer also located in that
table.
This routine also writes the size in bytes of the Memory it needs into
the Length field of the Memory structure contained in the debug device
descriptor passed to this routine.
When kernel debugging is enabled, this routine will be called twice during
boot. The first time by winload to determine how much memory to allocate
for KDNET and its extensibility module, and the second time by KDNET when
the kernel first initializes the kernel debugging subsystem.
Arguments:
ImportTable - Supplies a pointer to the KDNET_EXTENSIBILITY_IMPORT
structure.
LoaderOptions - Supplies a pointer to the LoaderOptions passed to the
kernel. This allows settings to be passed to the KDNET extensibility
module using the loadoptions BCD setting.
Device - Supplies a pointer to the debug device descriptor.
Return Value:
STATUS_INVALID_PARAMETER if the version of the import or export table is
incorrect.
STATUS_SUCCESS if initialization succeeds.
--*/
NTSTATUS
KdInitializeLibrary (
__in PKDNET_EXTENSIBILITY_IMPORTS ImportTable,
__in_opt PCHAR LoaderOptions,
__inout PDEBUG_DEVICE_DESCRIPTOR Device
)
{
NTSTATUS Status;
PKDNET_EXTENSIBILITY_EXPORTS Exports;
__security_init_cookie();
Status = STATUS_SUCCESS;
KdNetExtensibilityImports = ImportTable;
if ((KdNetExtensibilityImports == NULL) ||
(KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS)) {
Status = STATUS_INVALID_PARAMETER;
goto KdInitializeLibraryEnd;
}
Exports = KdNetExtensibilityImports->Exports;
if ((Exports == NULL) || (Exports->FunctionCount != KDNET_EXT_EXPORTS)) {
Status = STATUS_INVALID_PARAMETER;
goto KdInitializeLibraryEnd;
}
//
// Return the function pointers this KDNET extensibility module exports.
//
Exports->KdInitializeController = KdInitializeController;
Exports->KdShutdownController = KdShutdownController;
Exports->KdSetHibernateRange = KdSetHibernateRange;
Exports->KdGetRxPacket = KdGetRxPacket;
Exports->KdReleaseRxPacket = KdReleaseRxPacket;
Exports->KdGetTxPacket = KdGetTxPacket;
Exports->KdSendTxPacket = KdSendTxPacket;
Exports->KdGetPacketAddress = KdGetPacketAddress;
Exports->KdGetPacketLength = KdGetPacketLength;
Exports->KdGetHardwareContextSize = KdGetHardwareContextSize;
//
// Return the hardware context size required to support this device.
//
Status = ContosoInitializeLibrary(LoaderOptions, Device);
KdInitializeLibraryEnd:
return Status;
}
Эта подпрограмма вызывается для передачи подпрограмм импорта и экспорта между KDNET и этим модулем расширяемости KDNET. Эта подпрограмма должна убедиться, что версия таблиц импорта и экспорта ожидается и поддерживается, а также завершится ошибкой, если нет. Он должен сделать копию таблицы импорта в собственной глобальной памяти. Он должен записывать подпрограммы, экспортируемые в структуру, на которую указывает поле "Экспорты" таблицы импорта. Он также должен задать поле Length структуры памяти, которая является частью указателя дескриптора устройства отладки, передаваемого в эту подпрограмму, с количеством байтов памяти, необходимых для поддержки аппаратного устройства.
Проверка количества экспортов импорта
Код должен проверить, соответствует ли функция Import FunctionCount, доступной в ОС, например, (KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS) и вернуть STATUS_INVALID_PARAMETER , если счетчик не соответствует.
Проверка счетчиков гарантирует совместимость между запущенной версией WINDOWS OS KDNET (например, загрузчиком загрузки, загрузчиком ОС, гипервизором, защищенным ядром или NT OS, все из которых связаны с библиотекой KDNET) и версией WDK, используемой для сборки текущего модуля расширяемости KDNET. WDK и версия ОС должны быть синхронизированы; В противном случае указанная выше проверка завершится ошибкой, если значение счетчика импорта и экспорта изменяется. Например, если интерфейс расширяемости KDNET добавил новую функцию функции, число больше не будет соответствовать. Чтобы убедиться, что они соответствуют, всегда используйте выпуск WDK, соответствующий ОС, в котором размещена версия KDNET.
Настройка требуемой памяти
Обратите внимание, что устройство будет заполнено оборудованием, выбранным для отладчика. При необходимости эта подпрограмма должна настроить объем памяти, необходимый для устройства. Например, модули расширяемости, поддерживающие оборудование 1Gig и 10Gig, могут увеличить размер памяти, который они запрашивают для устройств 10Gig. Они могут определить, какое устройство используется, проверив поле DeviceID дескриптора устройства отладки.
KdInitializeLibrary — единственный экспорт
Обратите внимание, что эта подпрограмма будет вызываться как winload, так и KDNET во время вызова KdInitSystem. Обратите внимание, что это подпрограмма ONLY, экспортируемая модулями расширяемости KDNET. Это единственная подпрограмма, помещенная в DEF-файл. Модули расширяемости KDNET имеют ровно один явный экспорт — эту подпрограмму и не импортируются.
KdSetHibernateRange
VOID
KdSetHibernateRange (
VOID
)
/*++
Routine Description:
This routine is called to mark the code in the KDNET extensiblity module
so that it can be properly handled during hibernate and resume from
hibernate.
Arguments:
None.
Return Value:
None.
--*/
Эта подпрограмма вызывается системой до гибернации, чтобы он смог правильно зарегистрировать код, используемый модулем расширяемости KDNET в системе. Это позволяет системе правильно управлять этой памятью во время гибернации и возобновления работы с гибернации. (Память сохраняется поздно и загружается рано, так как она будет вызываться очень рано во время возобновления.)
KdInitializeController
NTSTATUS
KdInitializeController(
__in PVOID Adapter
)
/*++
Routine Description:
This function initializes the Network controller. The controller is setup
to send and recieve packets at the fastest rate supported by the hardware
link. Packet send and receive will be functional on successful exit of
this routine. The controller will be initialized with Interrupts masked
since all debug devices must operate without interrupt support.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Return Value:
STATUS_SUCCESS on successful initialization. Appropriate failure code if
initialization fails.
--*/
Эта подпрограмма вызывается для инициализации оборудования. Он вызывается при инициализации системы и всякий раз, когда система просыпается из режима пониженного энергопотребления, для которого был вызван KdShutdownController. Эта подпрограмма должна гарантировать, что оборудование полностью завершено инициализации и готово к отправке пакетов ПЕРЕД возвратом. Эта подпрограмма должна ждать появления PHY и установления соединения. Обратите внимание, что если кабель не подключен, эта подпрограмма не должна останавливаться на неопределенный срок. Эта подпрограмма задает скорость связи и дуплекс в общей структуре данных KDNET, которая используется между KDNET и этим модулем расширяемости. Он также записывает MAC-адрес, используемый оборудованием, в расположение, на которое указывает TargetMacAddress в структуре общих данных KDNET.
KdShutdownController
VOID
KdShutdownController (
__in PVOID Adapter
)
/*++
Routine Description:
This function shuts down the Network controller. No further packets can
be sent or received until the controller is reinitialized.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Return Value:
None.
--*/
Крайне важно, чтобы эта подпрограмма ждала, пока все пакеты, которые по-прежнему ожидают, фактически отправлены по проводам. Эта подпрограмма должна ждать, пока все пакеты передачи не будут перемещены из основной памяти и переданы по сети, прежде чем завершить передачу на аппаратном обеспечении. После отправки всех ожидающих передачи пакетов эта подпрограмма должна полностью завершить работу оборудования. Эта процедура будет вызываться, когда система выключается, а также когда система решает перевести отладочный транспорт в состояние низкого энергопотребления. Это можно вызвать, когда система переходит в режим ожидания, гибернации, спящего режима и подключенного режима ожидания, а также при завершении работы системы.
KdGetHardwareContextSize
ULONG
KdGetHardwareContextSize (
__in PDEBUG_DEVICE_DESCRIPTOR Device
)
/*++
Routine Description:
This function returns the required size of the hardware context in bytes.
Arguments:
Device - Supplies a pointer to the debug device descriptor.
Return Value:
None.
--*/
Эта подпрограмма должна возвращать количество байтов, необходимых для всей памяти, необходимой для поддержки оборудования. Это включает структуру контекста и все буферы пакетов для получения и передачи, а также все дескрипторы пакетов оборудования и другие структуры. Размер всей необходимой памяти должен быть указан здесь. Включая любую дополнительную память, необходимую из-за ограничений выравнивания, которые могут быть у вашего оборудования, для пакетов, дескрипторов пакетов или других структур.
Обратите внимание, что эта подпрограмма должна вызываться подпрограммой KdInitializeLibrary при установке поля длины памяти в дескрипторе устройства отладки.
KdGetRxPacket
NTSTATUS
KdGetRxPacket (
__in PVOID Adapter,
__out PULONG Handle,
__out PVOID *Packet,
__out PULONG Length
)
/*++
Routine Description:
This function returns the next available received packet to the caller.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies a pointer to the handle for this packet. This handle
will be used to release the resources associated with this packet back
to the hardware.
Packet - Supplies a pointer that will be written with the address of the
start of the packet.
Length - Supplies a pointer that will be written with the length of the
received packet.
Return Value:
STATUS_SUCCESS when a packet has been received.
STATUS_IO_TIMEOUT otherwise.
--*/
Эта подпрограмма получает следующий доступный пакет, который был получен, но еще не обработан. Он возвращает дескриптор для этого пакета. Дескриптор будет использоваться для получения адреса пакета путем вызова KdGetPacketAddress, а также длины путем вызова KdGetPacketLength. Пакет и хендл должны оставаться доступными и действительными, пока пакет не будет освобожден путем вызова KdReleaseRxPacket. Эта подпрограмма также напрямую возвращает адрес пакета и его длину вызывающей стороне.
Если пакет в настоящее время недоступен, эта подпрограмма должна вернуться немедленно с STATUS_IO_TIMEOUT. Эта подпрограмма не должна ожидать получения пакета. Обратите внимание, что верхние 2 бита дескриптора зарезервированы. TRANSMIT_HANDLE и TRANSMIT_ASYNC должны быть понятными.
KdReleaseRxPacket
VOID
KdReleaseRxPacket (
__in PVOID Adapter,
ULONG Handle
)
/*++
Routine Description:
This function reclaims the hardware resources used for the packet
associated with the passed Handle. It reprograms the hardware to use those
resources to receive another packet.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies the handle of the packet whose resources should be
reclaimed to receive another packet.
Return Value:
None.
--*/
Эта подпрограмма освобождает ресурсы, связанные с дескриптором пакета, возвращая их в распоряжение оборудования, чтобы они могли быть использованы для получения другого пакета. Каждый успешный вызов KdGetRxPacket будет сопровождаться еще одним вызовом KdReleaseRxPacket с идентификатором, возвращенным вызовом KdGetRxPacket. Обратите внимание, что не гарантируется, что KdReleaseRxPacket будет вызываться сразу после успешного выполнения KdGetRxPacket. Возможно, сначала будет выполнен другой вызов KdGetRxPacket. Однако каждый успешный вызов KdGetRxPacket будет иметь свои ресурсы, выпущенные с помощью вызова KdReleaseRxPacket.
Эта подпрограмма должна правильно программировать оборудование, чтобы выпущенные ресурсы можно было использовать для получения другого пакета.
KdGetTxPacket
NTSTATUS
KdGetTxPacket (
__in PVOID Adapter,
__out PULONG Handle
)
/*++
Routine Description:
This function acquires the hardware resources needed to send a packet and
returns a handle to those resources.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies a pointer to the handle for the packet for which hardware
resources have been reserved.
Return Value:
STATUS_SUCCESS when hardware resources have been successfully reserved.
STATUS_IO_TIMEOUT if the hardware resources could not be reserved.
STATUS_INVALID_PARAMETER if an invalid Handle pointer or Adapter is passed.
--*/
Эта подпрограмма получает следующие доступные ресурсы передачи и возвращает дескриптор. Этот дескриптор будет использоваться для вызова KdGetPacketAddress и KdGetPacketLength. Адрес пакета, возвращаемый KdGetPacketAddress, будет использоваться для непосредственной записи содержимого пакета. Адрес пакета должен быть началом пакета, и длина должна быть максимальным числом байтов, которые можно записать в пакет. Обратите внимание, что если нет доступных аппаратных ресурсов, так как они были приобретены и еще не переданы, эта процедура должна немедленно вернуть STATUS_IO_TIMEOUT.
TRANSMIT_HANDLE необходимо задать в возвращаемом дескрипторе. Обратите внимание, что верхние два бита дескриптора зарезервированы для флагов TRANSMIT_ASYNC и TRANSMIT_HANDLE.
Отправка пакета данных через KdSendTxPacket
NTSTATUS
KdSendTxPacket (
__in PVOID Adapter,
ULONG Handle,
ULONG Length
)
/*++
Routine Description:
This function sends the packet associated with the passed Handle out to the
network. It does not return until the packet has been sent.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies the handle of the packet to send.
Length - Supplies the length of the packet to send.
Return Value:
STATUS_SUCCESS when a packet has been successfully sent.
STATUS_IO_TIMEOUT if the packet could not be sent within 100ms.
STATUS_INVALID_PARAMETER if an invalid Handle or Adapter is passed.
--*/
Эта подпрограмма отправляет пакет, связанный с переданным дескриптором, на провод. Обратите внимание, что Дескриптор может иметь дополнительный битовый набор в нем, который указывает, является ли отправка асинхронной передачей или нет. Если флаг TRANSMIT_ASYNC установлен в дескрипторе, эта подпрограмма должна программировать оборудование для отправки пакета, а затем немедленно вернуться, не ожидая завершения отправки оборудования. Это означает, что все ошибки, возникающие во время передачи, будут потеряны. Это нормально и так задумано, так как пакеты в любом случае могут теряться в сети. Если флаг TRANSMIT_ASYNC не задан в дескрипторе, эта подпрограмма должна ждать, пока пакет не будет отправлен на проводе, и должен возвращать любые ошибки, возникающие во время передачи, если таковые имеются. Обратите внимание, что при передаче файлов дампа на узел отладчика или при отправке сетевых пакетов Windows из KDNIC через KDNET будет установлено значение TRANSMIT_ASYNC. Когда все остальные пакеты отладчика отправляются, флаг TRANSMIT_ASYNC будет сброшен.
Если набор пакетов отправляется с установленным значением TRUE для TRANSMIT_ASYNC, а затем отправляется пакет, у которого TRANSMIT_ASYNC не установлен, оборудование должно ожидать фактической отправки пакета без установленного флага, даже если для этого придется дождаться отправки предыдущих асинхронных пакетов.
KdGetPacketAddress
PVOID
KdGetPacketAddress (
__in PVOID Adapter,
ULONG Handle
)
/*++
Routine Description:
This function returns a pointer to the first byte of a packet associated
with the passed handle.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies a handle to the packet for which to return the
starting address.
Return Value:
Pointer to the first byte of the packet.
--*/
Эта подпрограмма возвращает указатель на первый байт пакета, связанный с переданным дескриптором. Обратите внимание, что дескриптор будет иметь бит TRANSMIT_HANDLE установлен для передачи пакетов, а бит TRANSMIT_HANDLE сброшен для получения пакетов. Возвращаемый указатель должен быть виртуальным адресом Windows, который может быть прочитан или записан обработчиком. Этот адрес должен находиться в блоке памяти, зарезервированном для модуля расширяемости KDNET, который передается в структуру памяти дескриптора устройства отладки. (Обратите внимание, что модуль расширяемости KDNET никогда не должен использовать больше размера памяти, запрошенного в KdInitializeLibrary при доступе к этой памяти. Любая дополнительная память в конце блока зарезервирована для использования KDNET и не должна касаться модуля расширяемости KDNET.)
KdGetPacketLength
ULONG
KdGetPacketLength (
__in PVOID Adapter,
ULONG Handle
)
/*++
Routine Description:
This function returns the length of the packet associated with the passed
handle.
Arguments:
Adapter - Supplies a pointer to the debug adapter object.
Handle - Supplies a handle to the packet for which to return the
length.
Return Value:
The length of the packet.
--*/
Эта подпрограмма возвращает длину в байтах пакета, связанного с переданным дескриптором. Обратите внимание, что дескриптор будет иметь установленный бит TRANSMIT_HANDLE для передачи пакетов, а сброшенный бит TRANSMIT_HANDLE для получения пакетов. Для передачи пакетов эта длина должна быть максимальным числом байтов, которые можно записать в пакет. Для получения пакетов эта длина должна быть фактическим числом байтов в полученном пакете.
Отладка модулей расширяемости KDNET
Для отладки модуля расширяемости KDNET необходимо выполнить следующие команды bcdedit из командной строки с повышенными привилегиями на целевом компьютере.
Во-первых, и самое важное, необходимо выполнить следующие две команды, чтобы убедиться, что Winload позволит повторяться сбои загрузки, не снижая специальный путь сбоя, который разбивается на отладчик и предотвращает обычную загрузку. Выполнение этих команд позволит повторно перезагрузить компьютер с новыми битами и отлаживать эти новые биты без проблем.
Bcdedit -set {current} BootStatusPolicy IgnoreAllFailures
Bcdedit -set {current} RecoveryEnabled No
Если вы будете использовать последовательную отладку на com1 на целевом компьютере для отладки модуля расширяемости, выполните указанные ниже действия.
bcdedit -dbgsettings serial debugport:1 baudrate:115200
При этом транспорт отладки по умолчанию сериализуется на com1 в 115200 baud. Эти параметры также будут использоваться для отладки загрузки.
bcdedit -debug on
Это позволяет выполнять отладку ядра.
bcdedit -bootdebug on
Это позволяет выполнять отладку загрузочного процесса средствами winload.exe, которые вы будете использовать для отладки на этапе инициализации ядра, в том числе с помощью модуля расширяемости KDNET.
bcdedit -set kerneldebugtype net
Это заставляет тип отладки ядра на сеть, независимо от настроек транспорта отладки по умолчанию. Это приведет к тому, что winload.exe загрузит kdnet.dll в качестве средства отладки ядра.
bcdedit -set kernelbusparams b.d.f
Где b — номер шины, d — номер устройства, а f — номер функции — все десятичное — оборудования, для которого вы пишете модуль расширяемости KDNET. Эти числа будут зависеть от того, в каком слоте PCI находится оборудование. Их можно найти, найдя строку расположения на странице свойств устройства сетевого устройства в диспетчере устройств Windows. Откройте диспетчер устройств Windows, дважды щелкните по сетевым устройствам, найдите своё устройство, дважды щелкните на него, и в окне, которое откроется, должно быть поле 'Расположение', содержащее шину, устройство и функцию оборудования на шине PCI. Если у вас есть водитель автобуса, который приводит к скрытию этой информации, вам придется определить местоположение через ваших водителей или каким-то другим способом.
Это заставляет параметры шины ядра использовать формат b.d.f, что принуждает выбрать это конкретное устройство в качестве устройства отладки ядра.
bcdedit -set kernelhostip N
Где N определяется следующей формулой. Если на компьютере отладчика узла есть IPv4-адрес w.x.y.z, N = (w0x01000000) + (x0x00010000) + (y0x00000100) + (z0x00000001). N необходимо указать в командной строке в десятичной строке, а не шестнадцатеричной. Фактически вы принимаете каждый байт IPv4-адрес и объединяете его (в шестнадцатеричном виде), чтобы создать 32-разрядное число в шестнадцатеричном виде, а затем преобразовать его в десятичный.
bcdedit -set kernelport N
Где N составляет 50000 или другой порт, который не будет заблокирован во внутренней сети.
Это заставляет KDNET использовать порт N в качестве порта отладки сети.
bcdedit -set kernelkey 1.2.3.4
Это принудительно устанавливает ключ отладки KDNET на 1.2.3.4. 1.2.3.4 не является безопасным или уникальным в сетевом ключе. Чтобы обеспечить безопасность целевого компьютера, пакеты, передаваемые между узлом и целевыми компьютерами, должны быть зашифрованы. Настоятельно рекомендуется использовать автоматически созданный ключ шифрования. Дополнительные сведения см. в разделе "Настройка автоматической отладки сетевого ядра KDNET".
bcdedit -set kerneldhcp on
Это заставляет настройку DHCP ядра KDNET включиться.
Запустите отладчик на хост-компьютере отладчика со следующей командной строкой, если вы используете com1 в качестве порта последовательной отладки на хост-компьютере:
windbg -d -k com:port=com1,baud=115200
Это запустит отладчик и приведет к срабатыванию точки останова, когда загрузочный отладчик windbg впервые взаимодействует с хост-машиной.
Затем перезагрузите целевой компьютер, выполнив команду
shutdown -r -t 0
Когда отладчик входит в windbg, убедитесь, что символы загружены для winload. (может потребоваться задать .sympath и выполнить .reload). Затем выполните x winload!*deb*tra*. Один из перечисленных символов будет чем-то похожим на BdDebugTransitions.
Затем выполните команду ed winload!BdDebugTransitions 1, но обязательно используйте правильное имя символа.
Затем выполните команду, bu winload!blbdstop чтобы задать точку останова.
Затем нажмите g, чтобы продолжить.
Вы должны разбиться на winload! BlBdStop.
Затем выполните следующие команды.
bu nt!KdInitSystem
bu kdnet!KdInitialize
bu kdstub!KdInitializeLibrary
Обратите внимание, что, скорее всего, вы будете использовать kdstub при настройке точек останова в модуле расширяемости KDNET, если это не работает, используйте
bu kd_YY_XXXX!KdInitializeLibrary
Где Y — ваш класс PCI, а XXXX — ваш PCI VID. (т. е. используйте имя модуля расширяемости KDNET.)
Обычно в отладчике необходимо использовать kdstub вместо использования фактического имени модуля расширяемости.
Затем выполните команду bl , чтобы получить список точек останова. Убедитесь, что брейкпоинты находятся на месте (у каждого из них должна быть буква "e" рядом).
Затем нажмите g. Вы должны пересечь точку останова nt!KdInitSystem.
Нажмите g еще раз, и вы должны попасть в kdnet!KdInitialize
Снова нажмите g , и вы должны попасть в точку останова в собственном модуле в KdInitializeLibrary.
Затем можно установить точку останова в вашей подпрограмме InitializeController, а также в остальных подпрограммах, и пошагово просмотреть ваш код.
После выполнения команды в KdInitializeLibrary, нажмите g. Если вы установили точку останова в процедуре InitializeController, то она сработает следующей.
Убедитесь, что у вас установлены точки останова на подпрограммах KdGetTxPacket, KdSendTxPacket, KdGetRxPacket, KdReleaseRxPacket, затем снова нажмите g, и эти подпрограммы будут выполняться в процессе инициализации сети, которую выполняет KDNET во время загрузки.
Возможно, потребуется добавить временный код в подпрограммы KdInitializeLibrary или KdInitializeController, чтобы убедиться, что все ваши подпрограммы вызываются так, чтобы можно было выполнить все действия по всему коду. (Например, KdShutdownController не вызывается во время запуска, когда все работает нормально, поэтому вам потребуется явно вызвать его из временного кода, чтобы пройти по нему пошагово и убедиться, что он работает правильно.)
После того как вы проверили весь свой код и уверены, что он правильный, перезагрузите целевое устройство, но не устанавливайте флаг winload!BdDebugTransitions в true (оставьте его равным нулю по умолчанию).
Затем также запустите другой экземпляр отладчика ядра на компьютере отладчика узла.
Windbg -d -k net:port=50000,key=1.2.3.4
Пусть целевой компьютер загрузится, и он должен подключиться к другому экземпляру отладчика ядра по сети.
Затем выполните команды в отладчике ядра и убедитесь, что он работает, а затем позвольте системе продолжить загрузку, и убедитесь, что позже вы сможете войти в режим отладки и выполнить команды.
Примечание.
Задание флага переходов отладки в winload гарантирует, что Windows НЕ ЗАГРУЗИТСЯ. Если вы пытаетесь разрешить Windows завершить загрузку после установки этого флага, Windows просто завершит работу или зависнет. Если вы хотите, чтобы Windows успешно загрузилась, нельзя устанавливать флаг переходов отладки. Установка флага позволяет вам отлаживать код и проверять его корректность, пошагово проходя его с помощью отладчика, но в конечном итоге вам нужно будет снять флаг, чтобы убедиться, что отладка работает при обычной загрузке. Это означает, что при загрузке системы в обычном режиме невозможно выполнить пошаговое выполнение кода, а при обычном запуске Windows с включенной отладкой на оборудовании модуль расширяемости KDNET не может выполнять отладку. Любая попытка отладки с помощью отладчика ядра приведет к сбою компьютера. (Невозможно задать точки прерывания в коде, выполняемом в режиме отладки ядра, так как это приводит к бесконечному повторному входу, переполнению стека и перезагрузке.)
Несколько физических функций — 2PF
Помимо расширяемости KDNET, KDNET поддерживает отладку ядра с помощью нескольких физических функций (PFS) на поддерживаемых сетевых адаптерах путем секционирования пространства конфигурации PCI. Поставщики сетевых карт рекомендуется включить поддержку этой функции. Дополнительные сведения см. в разделе "Поддержка сетевого драйвера miniport для отладчика 2PF KDNET".
См. также
Автоматическая настройка отладки сетевого ядра KDNET
Настройка отладки сетевого ядра KDNET вручную
Поддержка сетевого драйвера miniport для отладчика 2PF KDNET