KDNET 전송 확장성 모듈 개발
이 항목에서는 별도의 하드웨어 드라이버 확장성 모듈 dll을 사용하여 모든 하드웨어에서 KDNET 전송을 확장하여 실행할 수 있는 방법을 설명합니다. KDNET 전송 확장성 모듈은 네트워크 카드 공급업체에서 개발하여 특정 네트워크 카드에 커널 디버깅 지원을 추가합니다.
KDNET 개요
KDNET은 네트워크를 통해 창의 커널 디버깅을 가능하게 하는 커널 디버그 전송입니다. 처음에는 이더넷 NIC를 사용하여 커널 디버깅을 지원하는 데 사용되었습니다. 하드웨어 지원 계층이 네트워크 패킷 처리 및 커널 인터페이스 계층과는 별도의 모듈에 기본 제공되도록 설계되었습니다. 이 하드웨어 드라이버 지원 계층을 KDNET 확장성 모듈이라고 합니다.
KDNET은 별도의 하드웨어 드라이버 확장성 모듈 dll을 사용하여 모든 하드웨어에서 실행되도록 확장할 수 있는 유일한 전송입니다. KDNET 및 KDNET 확장성 모듈을 통해 Windows의 모든 디버깅을 지원하는 것이 목표입니다. 다른 모든 커널 전송 DLL(kdcom.dll, kd1394.dll, kdusb.dll 등)은 결국 더 이상 사용되지 않으며 Windows에서 제거됩니다.
KDNET에서 KDNET 확장성 모듈과 통신하는 데 사용하는 인터페이스에는 두 가지 유형이 있습니다. 하나는 NIC, USB 및 무선 하드웨어에 사용되는 패킷 기반 인터페이스이고, 다른 하나는 직렬 하드웨어를 통해 KDNET을 지원하는 데 사용되는 바이트 기반 인터페이스입니다.
KDNET 확장성 모듈은 올바르게 작동하려면 매우 엄격한 요구 사항을 따라야 합니다. 커널 디버깅에 사용되므로 시스템에서 코드의 추가 실행을 보류할 때 호출되고 실행됩니다. 일반적으로 시스템의 모든 프로세서는 커널 디버그 전송을 통해 호스트 머신에서 실행되는 디버거 애플리케이션과 통신하는 프로세서를 제외하고 IPI에서 회전하는 상태로 잠깁니다. 해당 프로세서는 일반적으로 인터럽트(인터럽트)를 완전히 사용하지 않도록 설정하여 실행되며, 디버거에서 명령이 나오기를 기다리는 디버그 전송 하드웨어에서 기본적으로 회전합니다.
가져오기 및 내보내기
KDNET 확장성 모듈에는 정확히 하나의 명시적 내보내기인 KdInitializeLibrary가 있습니다. 명시적 가져오기도 없습니다. KDNET 확장성 모듈은 KdInitializeLibrary를 호출할 때 KDNET에서 호출할 수 있는 루틴 목록이 포함된 구조체에 대한 포인터를 전달합니다. 다른 루틴을 호출할 수 없습니다. 네, 가져오기가 있는 KDNET 확장성 모듈은 잘못 설계되었으며 지원되지 않습니다.
링크 /dump /exports 및 링크 /dump /imports를 사용하여 KDNET 확장성 모듈의 가져오기 및 내보내기를 덤프하면 내보내기(KdInitializeLibrary)가 하나만 있고 가져오기가 없는 것을 볼 수 있습니다. KDNET 확장성 모듈은 KdInitializeLibrary가 호출될 때 KDNET이 포인터를 전달하는 내보내기 함수 구조에 함수 포인터를 입력하여 KDNET에 대한 추가 내보내기를 보고합니다. 그런 다음 KDNET은 해당 구조의 함수 포인터를 사용하여 확장성 모듈을 호출하고 모듈에서 지원하는 하드웨어를 사용하여 데이터 전송에 영향을 줍니다. KDNET은 모듈이 구조의 내보내기 함수 테이블에서 채우는 특정 함수를 확인하여 모듈이 패킷 기반 모듈인지 바이트 기반 모듈인지 여부를 결정합니다. 이러한 함수 중 일부는 패킷 기반 하드웨어를 지원하기 위한 것이며, 다른 함수는 직렬 기반 하드웨어용입니다. 테이블의 일부 함수는 직렬 및 패킷 기반 하드웨어(KdInitializeController, KdShutdownController, KdGetHardwareContextSize)에서 사용됩니다.
코드 디자인
KDNET 확장성 모듈은 단일 스레드 코드로 작성해야 합니다. 동기화를 수행해서는 안 됩니다. 모든 커널 디버그 전송은 디버거를 입력할 때 적절한 동기화를 수행하도록 Windows 커널에 따라 달라집니다. 커널에는 커널 디버거에 들어갈 때 걸리는 디버거 잠금이 있으며 디버거를 입력할 때 IPI에서 시스템의 다른 프로세서도 잠급니다. 이러한 프로세서는 호스트에서 실행되는 커널 디버거가 대상 컴퓨터에 실행을 계속하도록 지시하는 경우에만 릴리스됩니다. 커널은 이 동기화를 수행하므로 KDNET 확장성 모듈은 코드에서 스핀 잠금, 뮤텍스, 게이트 또는 기타 Windows 동기화 메커니즘을 절대로 사용하지 않아야 합니다. 패킷 및 바이트를 보내고 받기 위해 해당 하드웨어를 직접 프로그래밍하도록 작성해야 합니다.
KDNET 확장성 모듈 코드는 가능한 한 간단하게 만들어야 합니다. 이렇게 하면 하드웨어 디버거를 사용하지 않고는 컴퓨터에 KDNET 확장성 모듈 코드를 라이브로 디버깅할 수 없으므로 가능한 한 버그가 없는지 확인할 수 있습니다. 커널 디버거를 사용하여 커널 디버그 전송 코드를 디버그할 수 없습니다. 이렇게 하면 커널 스택(일반적으로 이중 오류 및 다시 부팅으로 종료됨)으로 인해 컴퓨터가 다시 부팅되거나, 전송이 다시 입력되어 대부분의 경우 전송이 제대로 작동하지 않습니다.
KDNET 확장성 모듈 명명 규칙
커널 디버그 전송 모듈은 KDNET 확장성 모듈에 대한 두 가지 명명 규칙 중 하나를 따라야 합니다. 모듈이 PCI 기반 하드웨어를 지원하는 경우 XXXX가 16진수로 하드웨어의 PCI 공급업체 ID이고 YY가 하드웨어의 PCI 클래스인 kd_YY_XXXX.dll 이름이 지정되어야 합니다. PCI 기반 하드웨어를 지원하는 창의 상자에 제공되는 몇 가지 KDNET 확장성 모듈이 있습니다. 예를 들어 Intel의 kd_02_8086.dll, Broadcom의 kd_02_14e4.dll 및 Realtek의 kd_02_10ec.dll. 모든 PCI 기반 KDNET 확장성 모듈에서 https://www.pcisig.com/membership/member-companies 등록된 PCI 공급업체 ID를 조회할 수 있습니다. 이 모듈의 이름에 있는 마지막 4자로 16진수로 지원하는 하드웨어의 공급업체 VID를 사용합니다. 대부분의 in box 모듈에 대한 클래스 코드는 네트워크 클래스 디바이스이므로 PCI 구성 공간에 PCI 클래스의 0x02 02입니다. Winload.exe PCI 구성 공간에서 PCI 디바이스 클래스 및 선택한 디버그 디바이스의 PCI VID를 읽어 PCI 기반 KDNET 확장성 모듈의 이름을 빌드하고 이름에 해당 식별자가 있는 모듈을 로드하려고 시도합니다. 디바이스에 네트워크 0x02 클래스가 아닌 PCI 클래스 코드가 있는 경우 KDNET 확장성 모듈의 이름으로 디바이스에 대해 올바른 PCI 클래스 코드를 16진수로 사용해야 합니다. 그렇지 않으면 모듈이 winload에 의해 올바르게 로드되지 않습니다. _02_
각 이름에는 16진수의 네트워크 클래스 디바이스에 대한 PCI 클래스 코드가 있습니다. 이 코드는 디버그 디바이스의 PCI 구성 공간에서도 찾아서 읽습니다.
DBG2 테이블 항목이 있고 PCI 기반 디바이스가 아닌 디바이스가 있는 경우 모듈에 대한 명명 규칙이 다릅니다. DBG2 테이블 디버그 디바이스에 대한 명명 규칙은 kd_XXXX_YYYY.dll 여기서 XXXX는 16진수 DBG2 테이블 PortType이고 YYYY는 DBG2 테이블 항목의 16진수 DBG2 테이블 PortSubtype입니다. Kd_8003_5143.dll 0x5143 하위 형식의 net(0x8003) PortType을 지원하기 위한 받은 편지함 DLL입니다. 이 경우 5143은 퀄컴 PCI vid입니다. 이는 퀄컴 USB 컨트롤러에서 KDNET을 지원하기 위한 것이고, Net DBG2 테이블 항목의 경우 PortSubtype은 하드웨어 공급업체의 PCI VID로 정의됩니다. 이 명명 규칙을 사용하여 직렬, USB 및 기타 DBG2 테이블 디바이스를 지원할 수 있습니다. 현재 지원되는 PortType 값은 직렬 디바이스의 경우 8000, 1394 디바이스의 경우 8001, USB 디바이스의 경우 8002, NET 디바이스의 경우 8003입니다. 직렬 및 USB 디바이스의 하위 형식은 Microsoft와 함께 예약되어야 합니다. Microsoft는 할당된 직렬 및 USB 하위 형식 목록을 유지 관리합니다. 기존 지원되는 형식이 하드웨어에서 작동하지 않는 경우 직렬 또는 USB 하위 형식을 예약하려면 메일 kdnet@microsoft.com 을 보내주세요.
KDNET 확장성 가져오기
다음은 KDNET 확장성 모듈에서 호출할 수 있는 루틴 목록입니다. 이러한 모든 루틴은 KdInitializeLibrary 루틴에 전달되고 kdnetextensibility.h 헤더는 이러한 루틴에 대한 일반 호출을 다시 매핑하여 가져오기 테이블을 통과합니다. 모듈에 가져오기가 없도록 코드는 가져오기 테이블을 통해 호출해야 합니다. 커널, HAL 또는 다른 커널 모듈에서 내보낸 다른 루틴은 호출할 수 없습니다. 이러한 루틴만 호출할 수 있습니다. 이 루틴 집합은 모든 기본 KDNET 확장성 모듈을 개발하기에 충분한 것으로 입증되었으며 일반적인 시나리오에 적합합니다. 커널에서 내보내지만 이 목록에 없는 추가 루틴이 필요한 경우 시나리오와 필요한 추가 루틴 및 이유를 설명하는 메일 kdnet@microsoft.com 을 보내주세요. 이 목록은 주요 Windows 릴리스 주기(있는 경우)에만 추가됩니다. 이러한 루틴의 대부분은 커널 또는 HAL에서 지원하는 Windows 커널 API에 직접 해당합니다. 하나 또는 두 개의 사용자 지정 KDNET 전용 루틴입니다.
가져오기 테이블을 통한 루틴의 올바른 다시 매핑이 발생할 수 있도록 헤더에 kdnetextensibility.h를 올바르게 포함하는 것이 중요합니다. 이 작업이 수행되지 않으면 모듈에 가져오기가 있으며 지원되지 않습니다.
쓰기 메모리 루틴 읽기
메모리 매핑된 디바이스 메모리를 읽고 쓰는 데 다음 루틴을 사용해야 합니다. 이러한 호출 규칙은 동일한 호출 규칙을 가지며 해당 커널 루틴(READ_REGISTER_UCHAR, READ_REGISTER_USHORT, READ_REGISTER_ULONG, WRITE_REGISTER_UCHAR, WRITE_REGISTER_USHORT, WRITE_REGISTER_ULONG 및 READ_REGISTER_ULONG64 및 WRITE_REGISTER_ULONG64 64비트 플랫폼에서만 매핑됩니다. 모든 디바이스 메모리 액세스는 프로세서에서 읽기 및 쓰기를 다시 정렬하지 않도록 하기 때문에 이러한 루틴을 통해 수행해야 합니다. 이 msdn.microsoft.com 이러한 루틴에 대한 호출 규칙에 해당하는 Windows CE Compact 2013 루틴을 문서화합니다. 아쉽게도 NT 루틴이 문서화되지 않은 것처럼 보이지만 호출 규칙은 동일합니다.
IO 포트 루틴 읽기
디바이스 IO 포트를 읽고 쓰는 데 다음 루틴을 사용해야 합니다. 이러한 호출 규칙은 동일한 호출 규칙을 가지며 해당 커널 루틴(READ_PORT_UCHAR, READ_PORT_USHORT, READ_PORT_ULONG, WRITE_PORT_UCHAR, WRITE_PORT_USHORT 및 WRITE_PORT_ULONG 매핑됩니다. 모든 디바이스 IO 포트 액세스는 이러한 루틴을 통해 수행해야 합니다. 이 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 확장성 모듈은 디바이스 DMA 엔진을 프로그래밍하는 데 필요한 물리적 메모리 주소를 가져오기 위해 KdGetPhysicalAddress를 호출해야 하며, 많은 모듈은 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 확장성 모듈 간에 가져오기 및 내보내기 루틴을 전달하기 위해 호출됩니다. 이 루틴은 가져오기 및 내보내기 테이블의 버전이 예상 및 지원되는지 유효성을 검사해야 하며, 그렇지 않은 경우 실패합니다. 가져오기 테이블의 복사본을 자체 전역 메모리에 만들어야 합니다. 가져오기 테이블의 내보내기 필드가 가리키는 구조체로 내보내는 루틴을 작성해야 합니다. 또한 하드웨어 디바이스를 지원하는 데 필요한 메모리 바이트 수와 함께 이 루틴에 전달된 디버그 디바이스 설명자 포인터의 일부인 메모리 구조의 길이 필드를 설정해야 합니다.
가져오기 내보내기 수 유효성 검사
코드는 Imports FunctionCount가 OS (KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS)
에서 사용할 수 있는 항목과 일치하는지 확인하고 개수가 일치하지 않는 경우 반환 STATUS_INVALID_PARAMETER
해야 합니다.
개수를 확인하면 실행 중인 Windows OS KDNET 버전(예: 부팅 관리자/OS 로더/하이퍼바이저/보안 커널/NT OS, KDNET 라이브러리에 대한 모든 링크) 및 현재 KDNET 확장성 모듈을 빌드하는 데 사용되는 WDK 버전 간의 호환성이 보장됩니다. WDK 및 OS 버전을 동기화해야 합니다. 그렇지 않으면 가져오기/내보내기 카운터 값이 변경되면 위의 확인이 실패합니다. 예를 들어 KDNET 확장성 인터페이스가 새 기능 함수를 추가한 경우 개수는 더 이상 일치하지 않습니다. 일치하는지 확인하려면 항상 KDNET 버전을 호스팅하는 OS와 일치하는 WDK 릴리스를 사용합니다.
필요한 메모리 사용자 지정
디바이스는 디버거에 대해 선택된 하드웨어로 채워집니다. 이 루틴은 필요한 경우 디바이스에 따라 필요한 메모리 양을 사용자 지정해야 합니다. 예를 들어 1Gig 및 10Gig 하드웨어를 모두 지원하는 확장성 모듈은 10Gig 디바이스에 대해 요청하는 메모리 크기를 늘릴 수 있습니다. 디버그 디바이스 설명자의 DeviceID 필드를 검사하여 사용 중인 디바이스를 확인할 수 있습니다.
KdInitializeLibrary는 유일한 내보내기입니다.
이 루틴은 KdInitSystem 호출 중에 winload 및 KDNET에서 모두 호출됩니다. 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 주소를 KDNET 공유 데이터 구조의 TargetMacAddress가 가리키는 위치에 씁니다.
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.
--*/
보류 중인 모든 전송 패킷이 실제로 유선으로 전송될 때까지 이 루틴 WAIT가 중요합니다. 이 루틴은 모든 전송 패킷이 주 메모리에서 DMA로 전송되고 하드웨어에서 전송을 종료하기 전에 와이어에 있을 때까지 기다려야 합니다. 보류 중인 모든 전송 패킷이 전송되면 이 루틴은 하드웨어를 완전히 종료해야 합니다. 이 루틴은 시스템이 종료될 때와 시스템이 디버그 전송을 저전력 상태로 관리하도록 결정할 때 호출됩니다. 시스템이 종료될 때 외에도 시스템이 대기, 최대 절전 모드, 절전 모드 및 연결된 대기 상태로 전환될 때 호출할 수 있습니다.
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에 대한 모든 호출 다음에는 KdGetRxPacket에서 반환된 핸들을 사용하여 KdReleaseRxPacket에 대한 또 다른 호출이 수행됩니다. KdGetRxPacket이 성공한 직후에 KdReleaseRxPacket이 호출된다는 보장은 없습니다. 다른 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 플래그가 핸들에 설정되지 않은 경우 이 루틴은 패킷이 유선으로 전송될 때까지 기다려야 하며 전송 중에 발생하는 오류가 있는 경우 반환해야 합니다. 덤프 파일을 디버거 호스트로 보내거나 KDNIC에서 KDNET을 통해 Windows 네트워킹 패킷을 보내는 경우 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
그러면 기본 디버그 전송이 115200 baud의 com1에서 직렬로 설정됩니다. 이러한 설정은 부팅 디버깅에도 사용됩니다.
bcdedit -debug on
이렇게 하면 커널 디버깅이 가능합니다.
bcdedit -bootdebug on
이렇게 하면 winload.exe 부팅 디버깅이 가능하며, KDNET 확장성 모듈을 포함하여 초기 커널 초기화로 디버그하는 데 사용합니다.
bcdedit -set kerneldebugtype net
이렇게 하면 기본 디버그 전송 설정에 관계없이 커널 디버그 형식이 net으로 강제 적용됩니다. 이로 인해 winload.exe 커널 디버그 전송으로 kdnet.dll 로드합니다.
bcdedit -set kernelbusparams b.d.f
여기서 b는 버스 번호이고 d는 디바이스 번호이고 f는 KDNET 확장 모듈을 작성하는 하드웨어의 함수 번호(모두 10진수)입니다. 이러한 숫자는 하드웨어가 있는 PCI 슬롯에 따라 달라집니다. Windows 디바이스 관리자에서 네트워크 디바이스의 디바이스 속성 페이지에서 위치 문자열을 찾아서 찾을 수 있습니다. Windows 디바이스 관리자를 열고, 네트워크 디바이스를 두 번 클릭하고, 디바이스를 찾고, 두 번 클릭하고, 열리는 창에는 PCI 버스에서 하드웨어의 버스, 디바이스 및 기능을 포함하는 위치 필드가 있어야 합니다. 해당 정보를 마스킹하는 버스 드라이버가 있는 경우 드라이버의 위치 또는 다른 방법을 확인해야 합니다.
이렇게 하면 커널 busparams가 b.d.f로 강제 적용되어 특정 디바이스를 커널 디버그 디바이스로 선택해야 합니다.
bcdedit -set kernelhostip N
여기서 N은 다음 수식에 의해 결정됩니다. 호스트 디버거 컴퓨터에 iPv4 주소가 w.x.y.z인 경우 N = (w0x01000000) + (x0x00010000) + (y0x00000100) + (z0x00000001). N은 16진수가 아니라 10진수로 명령줄에 지정해야 합니다. 실제로 IPv4 주소의 각 바이트를 가져와서 16진수로 32비트 숫자를 빌드하기 위해 연결한 다음 10진수로 변환합니다.
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
이렇게 하면 KDNET 커널 dhcp 설정이 켜지게 합니다.
호스트 컴퓨터에서 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
다.
당신은 윈로드에 침입해야한다! BlBdStop.
그런 다음, 다음 명령을 실행합니다.
bu nt!KdInitSystem
bu kdnet!KdInitialize
bu kdstub!KdInitializeLibrary
KDNET 확장성 모듈에서 중단점을 설정할 때 kdstub를 사용할 가능성이 가장 높습니다. 그렇지 않으면 다음을 사용합니다.
bu kd_YY_XXXX!KdInitializeLibrary
여기서 YY는 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로 설정합니다(기본값은 0으로 유지).
그런 다음 호스트 디버거 머신에서 커널 디버거의 다른 인스턴스도 실행합니다.
Windbg -d -k net:port=50000,key=1.2.3.4
대상 머신 부팅을 허용하고 네트워크를 통해 커널 디버거의 다른 인스턴스에 연결해야 합니다.
그런 다음 커널 디버거에서 명령을 실행하고 작동하는지 확인한 다음 대상 부팅을 계속하도록 하고 나중에 중단하고 명령을 실행할 수 있는지 확인합니다.
참고 항목
Winload에서 디버그 전환 플래그를 설정하면 Windows가 부팅되지 않습니다. 해당 플래그를 설정한 후 Windows에서 부팅을 완료하도록 허용하려는 경우 Windows는 단순히 작동이 중단되거나 중단됩니다. Windows가 성공적으로 부팅되도록 하려면 해당 디버그 전환 플래그를 설정할 수 없습니다. 플래그를 설정하면 디버거에서 코드를 단계별로 실행하여 코드를 디버그하고 올바른지 확인할 수 있지만, 궁극적으로는 정상적으로 부팅할 때 디버깅이 작동하는지 확인할 수 있도록 플래그를 설정하지 않아도 됩니다. 즉, 시스템을 정상적으로 부팅할 때 코드를 단계별로 실행할 수 없으며 실제로 Windows가 정상적으로 실행되는 경우 하드웨어에서 디버깅을 사용하도록 설정하면 KDNET 확장성 모듈이 디버그할 수 없습니다. 커널 디버거를 사용하여 디버그하려고 하면 컴퓨터가 충돌합니다. (커널 디버그 경로에서 실행되는 코드에서는 무한 재진입, 날려버린 스택 및 다시 부팅이 발생하므로 중단점을 설정할 수 없습니다.)
여러 물리적 함수 - 2PF
KDNET 확장성 외에도 KDNET은 PCI 구성 공간을 분할하여 지원되는 NIC에서 여러 PF(물리적 함수)를 사용하여 커널 디버깅을 지원합니다. 네트워크 카드 공급업체는 이 기능을 지원하는 것이 좋습니다. 자세한 내용은 디버거 2PF KDNET Miniport 네트워크 드라이버 지원을 참조 하세요.