다음을 통해 공유


디바이스 확장

대부분의 중간 및 최저 수준 드라이버의 경우 디바이스 확장은 디바이스 개체와 연결된 가장 중요한 데이터 구조입니다. 내부 구조는 드라이버 정의이며 일반적으로 다음을 위해 사용됩니다.

  • 디바이스 상태 정보를 유지 관리합니다.

  • 드라이버에서 사용하는 커널 정의 개체 또는 스핀 잠금과 같은 기타 시스템 리소스에 대한 스토리지를 제공합니다.

  • I/O 작업을 수행하기 위해 드라이버에 상주하고 시스템 공간에 있어야 하는 모든 데이터를 보유합니다.

대부분의 버스, 함수 및 필터 드라이버(최하위 수준 및 중간 드라이버)는 임의 스레드 컨텍스트(현재 스레드가 발생하는 경우)에서 실행되므로 디바이스 확장은 각 드라이버의 기본 위치로 디바이스 상태 및 드라이버에 필요한 다른 모든 디바이스 관련 데이터를 유지 관리합니다. 예를 들어 CustomTimerDpc 또는 CustomDpc 루틴을 구현하는 모든 드라이버는 일반적으로 디바이스 확장에서 필요한 커널 정의 타이머 및/또는 DPC 개체에 대한 스토리지를 제공합니다.

ISR이 있는 모든 드라이버는 커널 정의 인터럽트 개체 집합에 대한 포인터에 대한 스토리지를 제공해야 하며, 대부분의 디바이스 드라이버는 이 포인터를 디바이스 확장에 저장합니다. 각 드라이버는 디바이스 개체를 만들 때 디바이스 확장의 크기를 결정하고 각 드라이버는 자체 디바이스 확장의 내용과 구조를 정의합니다.

I/O 관리자의 IoCreateDeviceIoCreateDeviceSecure 루틴은 비페이지 메모리 풀에서 디바이스 개체 및 확장에 대한 메모리를 할당합니다.

IRP를 수신하는 모든 표준 드라이버 루틴은 요청된 I/O 작업에 대한 대상 디바이스를 나타내는 디바이스 개체에 대한 포인터도 받습니다. 이러한 드라이버 루틴은 이 포인터를 통해 해당 디바이스 확장에 액세스할 수 있습니다. 일반적으로 DeviceObject 포인터는 가장 낮은 수준의 드라이버 ISR에 대한 입력 매개 변수이기도 합니다.

다음 그림에서는 최하위 수준의 드라이버 디바이스 개체의 디바이스 확장에 대한 드라이버 정의 데이터의 대표적인 집합을 보여줍니다. 상위 수준 드라이버는 IoConnectInterrupt 에서 반환되고 KeSynchronizeExecutionIoDisconnectInterrupt에 전달된 인터럽트 개체 포인터에 대한 스토리지를 제공하지 않습니다. 그러나 상위 수준 드라이버는 드라이버에 CustomTimerDpc 루틴이 있는 경우 다음 그림에 표시된 타이머 및 DPC 개체에 대한 스토리지를 제공합니다. 상위 수준 드라이버는 임원 스핀 잠금 및 연동 작업 큐에 대한 스토리지를 제공할 수도 있습니다.

최하위 수준 드라이버에 대한 예제 디바이스 확장을 보여 주는 다이어그램.

인터럽트 개체 포인터에 대한 스토리지를 제공하는 것 외에도, 가장 낮은 수준의 디바이스 드라이버는 ISR이 서로 다른 벡터에서 둘 이상의 디바이스에 대해 인터럽트를 처리하거나 둘 이상의 ISR이 있는 경우 인터럽트 스핀 잠금에 대한 스토리지를 제공해야 합니다. ISR 등록에 대한 자세한 내용은 ISR 등록을 참조하세요.

일반적으로 드라이버는 그림과 같이 디바이스 확장에 디바이스 개체에 대한 포인터를 저장합니다. 또한 드라이버는 확장에서 디바이스에 대한 리소스 목록의 복사본을 유지할 수도 있습니다.

상위 수준 드라이버는 일반적으로 디바이스 확장에 다음 하위 드라이버의 디바이스 개체에 대한 포인터를 저장합니다. IRP에서 IRP에서 다음 하위 드라이버의 I/O 스택 위치를 설정한 후 상위 수준 드라이버는 IRP 처리에 설명된 대로 다음 하위 드라이버의 디바이스 개체에 대한 포인터IoCallDriver에 전달해야 합니다.

또한 하위 수준 드라이버에 대해 IRP를 할당하는 상위 수준 드라이버는 새 IRP에 있어야 하는 스택 위치 수를 지정해야 합니다. 특히 상위 수준 드라이버가 IoMakeAssociatedIrp, IoAllocateIrp 또는 IoInitializeIrp를 호출하는 경우 이러한 지원 루틴에 올바른 StackSize를 인수로 제공하려면 다음 하위 수준 드라이버의 대상 디바이스 개체에 액세스하여 StackSize 값을 읽어야 합니다.

상위 수준 드라이버는 IoAttachDeviceToDeviceStack에서 반환된 포인터를 통해 다음 하위 수준 드라이버의 디바이스 개체에서 데이터를 읽을 수 있지만 이러한 드라이버는 다음 구현 지침을 따라야 합니다.

  • 하위 드라이버의 디바이스 개체에 데이터를 쓰려고 시도하지 않습니다.

    이 지침의 유일한 예외는 하위 수준 이동식 미디어 드라이버의 디바이스 개체 플래그 에서 DO_VERIFY_VOLUME 설정하고 지우는 파일 시스템입니다.

  • 다음과 같은 이유로 낮은 드라이버의 디바이스 확장에 액세스하려고 시도하지 마세요.

    • 두 드라이버 간에 단일 디바이스 확장에 대한 액세스를 동기화하는 안전한 방법은 없습니다.

    • 이러한 백도어 통신 체계를 구현하는 드라이버 쌍은 개별적으로 업그레이드할 수 없으며, 기존 드라이버 원본을 변경하지 않고는 중간 드라이버를 삽입할 수 없으며, 한 Windows 플랫폼에서 다음 플랫폼으로 쉽게 다시 컴파일하고 이동할 수 없습니다.

한 Windows 플랫폼 또는 버전에서 다음 버전으로 하위 수준 드라이버와의 상호 운용성을 유지하려면 상위 수준 드라이버가 제공된 IRP를 다시 사용하거나 새 IRP를 만들어야 하며 , IoCallDriver 를 사용하여 하위 수준 드라이버에 요청을 전달해야 합니다.