4 분 소요

Device Nodes and Device Stacks(원본 Microsoft Learn 링크)


Windows에서 디바이스는 PnP(Plug and Play) 디바이스 트리의 디바이스 노드로 표현된다. 일반적으로, I/O 요청이 디바이스로 전송되면 여러 드라이버가 요청을 처리하는 데 도움을 준다. 이러한 드라이버 각각은 디바이스 오브젝트와 연결되며, 디바이스 오브젝트는 스택으로 배열된다. 디바이스 오브젝트와 해당 드라이버들의 순서가 바로 디바이스 스택이라고 하며, 각 디바이스 노드는 고유한 디바이스 스택을 가진다.

디바이스 노드와 PnP 디바이스 트리

Windows는 디바이스를 Plug and Play 디바이스 트리 또는 간단히 디바이스 트리라고 부르는 트리 구조로 구성한다. 일반적으로 디바이스 트리의 노드는 디바이스 또는 복합 디바이스의 개별 기능을 나타낸다. 그러나 일부 노드는 물리적 디바이스와 관련이 없는 소프트웨어 구성 요소를 나타내기도 한다.

디바이스 트리의 노드를 디바이스 노드라고 한다. 디바이스 트리의 루트 노드를 루트 디바이스 노드라고 한다. 관례적으로, 루트 디바이스 노드는 아래 그림에서 보듯이 디바이스 트리의 맨 아래에 그려진다.

devicetree

디바이스 트리는 PnP 환경에 내재된 부모/자식 관계를 보여준다. 디바이스 트리의 여러 노드는 버스를 나타내며, 해당 버스에 연결된 자식 디바이스들을 가진다. 예를 들어, PCI Bus 노드는 마더보드의 물리적 PCI 버스를 나타낸다. 시작 시에 PnP 매니저는 PCI 버스 드라이버에게 PCI 버스에 연결된 디바이스를 열거하라고 요청한다. 이러한 디바이스는 PCI Bus 노드의 자식 노드로 표현된다. 위의 그림에서 PCI Bus 노드는 USB 호스트 컨트롤러, 오디오 컨트롤러, PCI Express 포트 등 PCI 버스에 연결된 여러 디바이스의 자식 노드를 가지고 있다.

PCI 버스에 연결된 일부 디바이스는 그 자체로 버스이기도 하다. PnP 매니저는 이러한 버스 각각에 대해 그 버스에 연결된 디바이스를 열거하도록 요청한다. 위의 그림에서 오디오 컨트롤러는 그 아래에 오디오 디바이스가 있는 버스로 표현되어 있다. 또한 PCI Express 포트는 그 아래에 디스플레이 어댑터가 있는 버스이고, 디스플레이 어댑터는 그 아래에 모니터가 연결된 버스로 볼 수 있다.

노드를 디바이스로 볼지 버스로 볼지는 관점에 따라 달라진다. 예를 들어 디스플레이 어댑터는 화면에 나타날 프레임을 준비하는 데 핵심적인 역할을 하는 디바이스로 볼 수 있다. 하지만 연결된 모니터를 감지하고 열거할 수 있는 버스로 생각할 수도 있다.

디바이스 오브젝트와 디바이스 스택

디바이스 오브젝트는 DEVICE_OBJECT 구조체의 인스턴스다. PnP 디바이스 트리의 각 디바이스 노드는 디바이스 오브젝트의 순서 목록을 가지며, 각 디바이스 오브젝트는 드라이버와 연결된다. 이러한 디바이스 오브젝트의 순서 목록과 해당 드라이버를 합쳐 디바이스 스택이라고 한다.

디바이스 스택을 여러 방식으로 생각할 수 있다. 가장 형식적으로는 디바이스 스택은 (디바이스 오브젝트, 드라이버) 쌍의 정렬된 목록이다. 그러나 특정 상황에서는 디바이스 스택을 디바이스 오브젝트의 순서 목록으로 생각하는 것이 더 유용할 수 있다. 다른 상황에서는 드라이버의 순서 목록으로 생각하는 것이 더 유용할 수 있다.

관례적으로 디바이스 스택에는 위와 아래가 있다. 디바이스 스택에서 처음 생성된 디바이스 오브젝트는 맨 아래에 위치하며, 마지막으로 생성되어 스택에 첨부된 디바이스 오브젝트는 맨 위에 위치한다.

아래 그림에서는 Proseware Gizmo 디바이스 노드가 세 개의 (디바이스 오브젝트, 드라이버) 쌍으로 구성된 디바이스 스택을 가진다. 맨 위의 디바이스 오브젝트는 AfterThought.sys 드라이버와 연결되어 있고, 중간 디바이스 오브젝트는 Proseware.sys 드라이버와, 맨 아래는 Pci.sys 드라이버와 연결되어 있다. 다이어그램 중앙의 PCI Bus 노드는 두 개의 (디바이스 오브젝트, 드라이버) 쌍을 가진 디바이스 스택을 가지며, 하나는 Pci.sys, 하나는 Acpi.sys와 연결된다.

proseware

디바이스 스택은 어떻게 구성되는가?

시작 시에 PnP 매니저는 각 버스의 드라이버에게 해당 버스에 연결된 자식 디바이스를 열거하라고 요청한다. 예를 들어 PnP 매니저는 PCI 버스 드라이버(Pci.sys)에게 PCI 버스에 연결된 디바이스를 열거하라고 요청한다. 이에 응답하여 Pci.sys는 PCI 버스에 연결된 각 디바이스마다 디바이스 오브젝트를 생성한다. 이러한 디바이스 오브젝트를 PDO(Physical Device Object)라고 한다. Pci.sys가 PDO 세트를 생성한 직후 디바이스 트리는 아래 그림처럼 보인다.

pcinode

PnP 매니저는 새로 생성된 각 PDO에 대해 디바이스 노드를 연결하고, 해당 노드의 디바이스 스택에 어떤 드라이버가 포함되어야 하는지를 레지스트리에서 조회한다. 디바이스 스택은 하나의 함수 드라이버(function driver)만을 가져야 하며, 선택적으로 하나 이상의 필터 드라이버를 가질 수 있다. 함수 드라이버는 디바이스 스택의 주요 드라이버이며 read, write, device control 요청을 처리한다. 필터 드라이버는 이러한 요청을 처리하는 데 보조적인 역할을 한다. 함수 및 필터 드라이버가 로드될 때마다 디바이스 오브젝트를 생성하고 디바이스 스택에 첨부한다. 함수 드라이버가 생성한 디바이스 오브젝트를 FDO(Functional Device Object), 필터 드라이버가 생성한 디바이스 오브젝트를 Filter DO라고 한다. 이제 디바이스 트리는 다음과 같은 모습이 된다.

devicenode

그림에서 한 노드에서는 필터 드라이버가 함수 드라이버 위에 있고, 다른 노드에서는 함수 드라이버 아래에 있다. 함수 드라이버 위에 있는 필터 드라이버를 Upper filter driver, 아래에 있는 필터 드라이버를 Lower filter driver라고 한다.

PDO는 디바이스 스택의 맨 아래에 항상 위치한다. 이는 디바이스 스택이 구성되는 방식 때문이다. PDO가 먼저 생성되고 추가 디바이스 오브젝트는 기존 스택의 맨 위에 첨부되기 때문이다.

참고: 디바이스에 대한 드라이버가 설치될 때, 설치 프로그램은 INF 파일의 정보를 사용해 어떤 드라이버가 함수 드라이버이고, 어떤 드라이버가 필터 드라이버인지를 결정한다. INF 파일은 일반적으로 Microsoft 또는 하드웨어 벤더가 제공한다. 드라이버 설치 후에는 PnP 매니저가 레지스트리를 조회해 디바이스의 함수 및 필터 드라이버를 확인할 수 있다.

버스 드라이버

위의 그림을 보면 Pci.sys 드라이버가 두 가지 역할을 수행함을 알 수 있다. 첫째, Pci.sys는 PCI Bus 디바이스 노드의 FDO와 연결된다. 사실 Pci.sys는 해당 FDO를 생성한다. 즉 Pci.sys는 PCI 버스의 함수 드라이버다. 둘째, Pci.sys는 PCI Bus 노드의 모든 자식 노드의 PDO와 연결된다. Pci.sys는 자식 디바이스의 PDO를 생성했기 때문이다. 디바이스 노드의 PDO를 생성하는 드라이버를 그 노드의 버스 드라이버라고 한다.

관점이 PCI 버스라면 Pci.sys는 함수 드라이버다. 그러나 Proseware Gizmo 디바이스 관점에서는 Pci.sys는 버스 드라이버다. 이러한 이중 역할은 PnP 디바이스 트리에서 매우 일반적이다. 버스의 함수 드라이버로 동작하는 드라이버는 자식 디바이스의 버스 드라이버 역할도 한다.

User-mode 디바이스 스택

지금까지 논의한 것은 커널 모드 디바이스 스택이다. 즉 스택의 드라이버는 커널 모드에서 실행되며, 디바이스 오브젝트는 시스템 공간에 매핑되어 커널 모드 코드에서만 접근 가능하다. 커널 모드와 유저 모드의 차이에 대한 정보는 유저 모드와 커널 모드 참고.

일부 경우에는 디바이스가 커널 모드 디바이스 스택 외에 유저 모드 디바이스 스택도 가진다. 유저 모드 드라이버는 종종 UMDF(User-Mode Driver Framework)에 기반하며, 이는 Windows Driver Frameworks(WDF)가 제공하는 드라이버 모델 중 하나다. UMDF에서 드라이버는 유저 모드 DLL이며, 디바이스 오브젝트는 IWDFDevice 인터페이스를 구현하는 COM 객체다. UMDF 디바이스 스택의 디바이스 오브젝트를 WDF 디바이스 오브젝트(WDF DO)라고 한다.

아래 그림은 USB-FX-2 디바이스의 디바이스 노드, 커널 모드 디바이스 스택, 그리고 유저 모드 디바이스 스택을 보여준다. 유저 모드 스택과 커널 모드 스택의 드라이버 모두 USB-FX-2 디바이스로 향하는 I/O 요청 처리에 참여한다.

usbfx2

댓글남기기