Поделиться через


Разработка модулей расширяемости транспорта KDNET

В этом разделе описывается, как транспорт KDNET можно расширить для запуска на любом оборудовании с помощью отдельной библиотеки dll модуля расширения драйвера оборудования. Модули расширяемости транспорта KDNET разрабатываются поставщиками сетевых карт для добавления поддержки отладки ядра в определенные сетевые карты.

Обзор KDNET

KDNET — это отладочный транспорт ядра, который обеспечивает отладку ядер окон через сеть. Первоначально она использовалась для поддержки отладки ядра с сетевыми адаптерами Ethernet. Он разработан таким образом, чтобы уровень поддержки оборудования был встроен в отдельный модуль от сетевой обработки пакетов и уровня интерфейса ядра. Этот уровень поддержки драйвера оборудования называется модулем расширяемости KDNET.

KDNET — это единственный транспорт, который можно расширить для запуска на любом оборудовании с помощью отдельной библиотеки dll модуля расширения драйвера оборудования. Это цель поддерживать все отладки Windows через KDNET и модули расширяемости KDNET. Все остальные библиотеки DLL транспорта ядра (kdcom.dll, kd1394.dll, kdusb.dll и т. д.) в конечном итоге будут устаревшими и удалены из Windows.

Существует два типа интерфейсов, которые KDNET использует для взаимодействия с модулями расширяемости KDNET. Один из них — это интерфейс на основе пакетов, используемый для сетевых адаптеров, USB и беспроводного оборудования, а другой — интерфейс на основе байтов, который используется для поддержки KDNET через последовательное оборудование.

Модули расширяемости KDNET должны соответствовать очень строгим требованиям, чтобы правильно работать. Так как они используются для отладки ядра, они будут вызываться и выполняться, когда система задерживает дальнейшее выполнение кода. Как правило, все процессоры в системе блокируются в IPI, за исключением процессора, который взаимодействует с приложением отладчика, работающим на хост-компьютере через транспорт отладки ядра. Этот процессор обычно работает с прерываниями полностью отключен, и, по сути, спиннинг на отладочном транспортном оборудовании, ожидающем выполнения команд от отладчика.

Импорт и экспорт

Модули расширяемости KDNET имеют ровно один явный экспорт — KdInitializeLibrary. Они также не имеют явных импортов. Модули расширяемости KDNET передают указатель на структуру со списком подпрограмм, которые они могут вызывать KDNET при вызове KdInitializeLibrary. Другие подпрограммы не могут быть вызваны. Период. Модули расширяемости 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 — это шестнадцатеричная таблица DBG2 PortType, а YYY — это шестнадцатеричная таблица DBG2 PortSubtype из записи таблицы DBG2. Kd_8003_5143.dll — это библиотека DLL в папке "Входящие" для поддержки net (0x8003) PortType с подтипом 0x5143. В этом случае 5143 — это vid-код Qualcomm PCI, так как он предназначен для поддержки KDNET на USB-контроллерах Qualcomm, а для записей таблицы Net DBG2 портSubtype определяется как PCI VID для поставщика оборудования. Обратите внимание, что вы можете поддерживать последовательные, 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. Ниже приведены экспорты модуля расширяемости пакета 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 будут сняты.

Если набор пакетов отправляется с TRANSMIT_ASYNC задать TRUE, а затем пакет, который не имеет 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. (может потребоваться задать симпат и выполнить перезагрузку). Затем выполните 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