토요일, 7월 13, 2013

기본 컨셉단계...

공부 및 개발을 위한 기본적인 컨셉을 이해 하기 위한 자료는 다 된것 같다.
이제 하나씩 만들어보기 시작할 단계인 것 같다.

2일간 무리해서 달린것 같은데.. 이젠 무리하지 말고 찬찬히.. 곱씹으면서 하나씩 맹그러 가면서 이해해야겠다.

데헷!(이건머지?)

Virtual address spaces

Processor가 메모리 영역을 읽거나 쓸때, 가상주소(virtual Address)를 이용한다.
Read/Write operation의 한부분으로 Process는 가상주소(virtual Address)를 물리주소(physical address)로 변환한다.
가상의 주소를 통한 메모리 접근은 다음과 같은 장점이 있다.
 - 프로그램은 큰 메모리 버퍼를 접근할때 비연속적인 물리메모리를 가 아닌 연속적인 가상 주소를 사용 할 수 있다.
 - 프로그램은 물리 메모리가 제공하는 크기보다 더 큰 메모리버퍼에 접근 할 수 있다.
   물리 메모라가 적게 제공될때, 메모리 메니저는 물리메모리의 Page들을(보통 4KB크기다.) disk file에 저장한다. 데이터 혹은 Code의 Page들은 필요에 따라 물리 메모리와 Disk에 옮겨진다.
 - 가상 주소는 다른 프로세서와 각각 따로이 사용된다. 하나의 Process에서 code는 다른 process가 사용하는 물리 메모리를 변경 할 수 없다.

 Process에서 사용 할수 있는 가상주소의 범위를 Process의 Virtual address space라 부른다.
 각각의 user-mode process는 개벌적인 virtual address space를 갖는다. 32bit process에서 virtual address space는 0x00000000~ 0x7FFFFFFF의 2GB이다. 64bit process에의 virtual address space는 0x00000000000 ~ 0x7FFFFFFFFFF 의 8TB 이다.
 가상주소의 범위는 가끔 가상 메모리의 범위라 부른다.

  아래의 그림은 Virtual address spaces의 핵심모양을 보여준다.



  위의 그림은 Notepad.exe와 MyApp.exe 2개의 64bit process를 위한 virtual address spaces를 보여준다.
  각 Process는 각각 0x00000000000 ~ 0x7FFFFFFFFFF의 virtual address space를 갖는다. 색칠된 block은 0x7F79..93950000에서 시작하는 가상 메모리 혹은 물리 메모리상의 Page(4KB)를 표시한다.
  메모장 process는 0X7f793950000에서 시작되는 가상주소의 연속된 3개의 page들을 사용함을 알수 있다.
  하지만, 이 3개의 연속작인 가상주소 page는 물리 메모리상 연속되지 않은 페이지들이 연결되어 있다. 또한 두 Process들은 똑같이 0X7f793950000에서 시작하는 가상메모리 page를 사용함을 알수 있다. 하지만 이 가상 page들은 서로 다른 물리 메모리의 page에 메핑되어 있다.

  사용자 공간과 시스템 공간(User space and system space)

  Notepad.exe와 MyApp.exe와 같은 Process들은 user mode에서 동작을 한다.(실행된다) 핵심OS 요소들과 많은 driver들은 더 특권적인 kernel mode에서 동작을 한다.
  32bit Windows에서 사용가능한 virtual address space 는 2^32 Bytes(4GB)이다. 보통 위쪽 2GB는 user space로 사용 되고 하래쪽 2GB는 System space로 사용된다.



  32Bit Windows에서 여러분은 부팅때 2GB이상의 user space를 사용 할지 지정 할수 있다.
 선택의 결과는 System space로 사용 가능한 공간 가상 주소가 줄어든다. 여러분은 user space의 크기를 3GB 까지 늘릴 수 있고 이 경우 단지 1GB의 System area으로 사용 가능하다.
 user space의 크기를 증가 시키려면 "BCDEdit/set increaseuseva"를 사용하라.

  64bit Windows에서 이론적으로 virtual address space의 양은 2^64(16ExaBytes)이지만 16 ExaBytes중에 적은 부분만이 실제 사용가능 하다.
  8TB(0X00000000000 ~ 0x7FFFFFFFFFF)가 User space로 사용 가능 하고 248TB(0XFFFF080000000000 ~ 0xFFFFFFFFFFFFFFFF)가 System space로 사용 가능하다.



  User mode에서 동작(실행)되는 Code는 System space에는 접근 할 수 없고 단지 user space에만 접근가능하다.
  이러한 제약은 user-mode code가 보호된(Protected) OS 자료구조를 읽거나 변경 하는 것을 방지 한다.
  Kernel mode에서 동작(실행)되는 Code는 System space와 User space 모두 접근이 가능하다.
  이는 kernel mode에서 동작 하는 code가 system space와 현재의 user-mode process의 virtual address space에 접근이 가능 함을 말한다.

  Kernel mode에서 동작하는 Driver는 user space의 주소에 직접 쓰거나(Write) 주소로부터 직접 읽을때 메우 조심해야 한다. 아래의 시나리오는 그 이유를 설명한다.
  1. user-mode program이 장치(device)로부터 어떤 데이터를 읽는 요청을 시작한다. 그 프로그램은 데이터를 받을 버퍼의 주소를 제공한다.
  2. kernel mode에서 실행중인 Device driver routine이 Read 명령을 시작하고 호출자에게 제어권을 반환 한다.
  3. 나중에, Read 명령이 완료됨을 알리기해 현제 실행중인 Thread가 머든 장치는 Interrupts를 발생시킨다. 그 Interrupt는 임의의 Process에 속한 임의의 Thread에서 실행중인 kernel-mode driver routine에 의해 처리된다.
  4. 이때, Driver는 1단계에서 user-mode 프로그램이 제공한 주소로 시작하는 곳에 데이터를 쓰기(write)를 하면 안된다. 이 주소는 현재 실행중인 Process는 다른 요청을 시작한 Process의 virtual address space에 속한 주소이다.

  Paged pool And Nonpaged pool

  user space에서 모든 물리 메모리 page들은 필요에 따라 disk file로 paged될 수 있지만 System space에 있는 어떤 물리적 Page는 그렇지 못하다.
  System space는 동적으로 할당되는 메모리를 위한 2영역(Paged pool, Nonpaged pool)이 있다. 64bit Windows에서 paged pool은 virtual address로 0xFFFFA80000000000~0xFFFFA81FFFFFFFFF의 128GB이다. Nonepaged pool은 virtual address로 0xFFFFAC0000000000 ~ 0xFFFFAC1FFFFFFFFF의 128GB이다.
  Paged pool에 할당된 메모리는 필요에 따라 Disk file을 Page될수 있지만, Nonpaged pool에 할당된 메모리는 disk file올 page될 수 없다.





Driver stacks

device driver로 보내지는 거의 모든 request(요청)들은 I/O request packet(IRPs)으로 보내진다.
각각의 device들은  device node들로 표현되어지고, 각 device node는 device stack을 갖는다.
보다 자세한 정보는 "Device nodes and device stacks"을 참조하라.

device로 읽기,쓰기 혹은 제어의 요청을 보내기위하여 I/O manager는 장치를 위한 device node를 찾는다 그리고 IRP를 그 Node의 device stack에 낸다.
때론 하나 이상의 device stack이 I/O request를 처리하는데에 관여되기도 한다.
Device stack의 수와 관계없이 I/O요청과 연관된 driver들은 모두 요청에 대한 driver stack이라 부른다.(발번역 ㅠㅠ)
우리는 driver stack이란 용어를 특정 technology를 위한 driver의 계층화된(Layered)잡합들을 가리킬때도 사용한다.

몇몇  device stack이 처리하는 I/O request

어떤 경우, 하나 이상의 device stack은 IRP를 처리하는데에 관여된다. 아래의 그림은 4개의 device stack이 하나의 IRP를 처리하는데 관여되는 경우를 보여준다.



자~ 아래에 어떻게 IRP가 처리 되는지 그림에 표시된 번호별로 설명한다.
 1. IRP는 My USB Storage Device node를 위한 device stack에 있는 function driver인 Disk.sys에 의해 생성된다.
    Disk.sys는 IRP를  drvice stack의 아래쪽인 Usbstor.sys에 전달 한다.
 2. Usbstor.sys는 My USE Storage Device node의 PDO driver이고 USB Mass Storage Device node의 FDO임을 기억하자.
    여기에서  IRP가 (PDO, Usbstor.sys)의 것인지 (FDO Usbstor.sys)의 것인지 결정하는것인 중요하지 않다. IRP는 dirver(Usbstor.sys)의 것이고 이 driver는  PDF와 FDO 양쪽다 접근(access)이 가능하다.
 3. Usbstor.sys가 IRP처리를 마쳤을때, IRP는 Usbhub.sys로 전해진다.
    USBhub.sys는 USB Mass Storage Deivce node의 PDO driver이며 또한 USB Root Hub node의 FDO driver이다.    IRP가 PDO에 있는지 FDO에 있는지는 중요하지 않다. IRP는 driver(Usbhub.sys)에 있고 이 driver는 PDO와 FDO 양쪽 모두 접근이 가능하다.
 4. Usbhub.sys가 IRP의 처리를 마쳤을때, IRP는 (Usbuhci.sys, Usbport.sys)pair으로 전달된다.
    Usbuhci.sys는 miniport driver이고 Usbposrt.sys는 port driver이다. 이 pair(miniport, port)는 한나의 driver역학을 한다. 이경우, miniport dirver와 port driver 모두 Micro$oft가 작성한 것이다.
(pair-Usbuhci.sys, Usbport.sys)쌍은 USB Root Hub node의 PDO dirver이며 동시에 USB Host Controller node의 FDO driver이다.
(pair-Usbuhci.sys, Usbport.sys)쌍은 Host controller H/W와 통신을 하고 그다음 실제 물리적 USB storage device와 통신을 한다.

 I/O request를 위한 driver stack

  위 그림에서 I/O request에 참여한 4개의 driver의 순서를 고려하라.
  우린 device node와 각각의 device stack이 아닌 driver들에 초점을 둔 순서에 관점을 얻을 수 있다.
  아래의 그림은 위로부터 아래에 이르는 순서로 driver를 보여준다.
  Disk.sys는 하나의 device object에 연결됨을 보여주지만, 다른 3개의 드라이버는 2개의 device object들과 연결됨을 보여준다.
 


  I/O 요청에 관여된 driver들의 순서들은 driver stack for I/O request라 부른다.
  I/O 요청에 관한 driver stack을 설명하려면, 우리는 요청에 참여한 순서대로 위로부터 아래로 driver들을 그린다.
 
  Driver stack for I/O Request은 device node를 위한 device stack과는 매우 다르다는 것을 알 수 있다. 또한 The driver stack for an I/O request는 device tree의 한지점에 남아 있지 않음을 알 수 있다.
 
  Technology driver stacks
 
 일단 앞서본 그림중에 Driver stack for the I/O request를 기억하자. 만약 우리가 위의 그램에서 driver에 익숙한 이름을 지어주고 약간의 약간의 변경을 해준다만. 우리는 Windows Driver Kit(WDK)문서에서 볼수 있었던 익순간 블록다이어그램을 얻을 수 있을 것이다.
 
 
 
 이 그림에서 driver stack은 3부분으로 나뉘어져 있다. 우린 각 부분을 특정 technology나 O/S의 일부분 혹은 특정 요소에 대임된다고 생각 할 수 있다.
예를 들어, 우리는 driver stack의 제일 쥐에 있는 첫 부분이 Volume manager에 속한다고 말할 수 있고, 두번째 부분을 O/S의 저장장치(요소)에 속한다고 말할 수 있다. 그리고 세번째 부분을 O/S의 핵심 USB부분에 속한다고 말할 수있다.
 세번째 영역에 있는 driver들을 고려해보자. 이 driver들은 다양한 USB 요청들과 USB H/W를 처리하기위해 Micro$oft가 제공하는 핵심 USB driver 집합의 일부분이다.
 아래의 그림은 전체 USB core 블럭 다이어그램의 모양세를 보여준다.

 

  위 그림은 특정 기술에 대한 모든 driver들을 보여주거나  O/S의 일부분 혹은 특정 구성요소를 보여주는 a technology driver stack라 불리는 블럭 다이어 그렘이다.
  일반적으로, technology driver stacks은 USB Core Driver Stack, Storage Stack, 1394 Driver Stack 그리고 Audio Driver Stack과 같은 이름이 붙여진다.
 
  Note : 이 주제에서 USB Core block diagram은 USB 1,0 및 2,0에 대한 technology driver stacks을 설명하는 여러 방법중 하나를 보여준다.
  the USB 1.0, 2.0, and 3.0 driver stack의 공식적인(실제) 다이어그램은 "USB Driver Stack Architecture"를 참조하라.
 
 

Minidrivers, Miniport drivers, and driver pairs

이번 주제에서 우린 miniport, port같은 driver들을 어떻게 쉽게 개발 할 것인지 설명하고자 한다.
dirver의 쌍에서 하나의 driver는 전체 drive정보를 수집하는 등의 일반적일 일을 처리 하고 다른 driver는 개별 device의 특별한 일을 처리한다.
이 driver들은 miniport driver, miniclass driver, minidriver등의 많은 이름을 갖으며, drive의 특별한 일을 처리 한다.

대게 Micro$oft는 일반적인 driver를 제공 하고 개별 H/W vendor들은 특벽한 일을 처리하는 driver를 제공한다.
이번 주제를 읽기 전에 먼저 당신은 "Device nodes and device stack" 과 "I/O requst packets"에 대한 개념을 이해하고 있길 바란다.

모든 Kernel-mode driver는 드라이버가 로드된후 가장 먼저 호출 되는 DriverEntry라는 이름의 함수를 구현해놔야한다.
DriverEntry함수는 driver에 구현된 몇몇 함수들의 포인터로 DRIVER_OBJECT 자료구조의 특정 Member를 체워운다.
예를 들어, DriverEntry 함수는 다음 그림에서와 같이, Driver의 unload 함수에 대한 포인터로 DRIVER_OBJECT 구조체의 unload member를 채 운다.



DRIVER_OBJECT 구조체의 주요함수 Member는 아래 그림에서 볼 수 있듯이 I/O request packets(IRPs)를 처리하는 함수의 포인터들 이다.
일반적으로 driver는  IRPs의 다양한 종류를 처리 하는 함수들의 포인터들로 주요함수의 Member를 체운다.



IRP는 IRP_MJ_READ, IRP_MJ_WRITE 혹은 IRP_MJ_PNP와 같은 상수로 구분뒤는 주요함수 코드로 분류 할 수 있다.
주요 함수를 구분하는 이러한 상수들은 주요함수 배열의 index역할을 한다.
예를 들어, IRP_MJ_WIRTE 를 가지고 IRPs를 처리하는 Driver의 주요 기능을 구현하고자 한다고 가정해보자
이 경우 driver는 MajorFunxtion[IRP_MJ_WRITE]에 Dispatch 함수 포인터를 체울 것이다.
일반적으로 driver는 일부가 I/O manager에서 제공되는 기본값으로 남겨지고 나머지는 주요 함수들의 요소가 체운다.
(다시 말해보자면 함수 포인터로 체우고 나머지 는 default값으로 체운다는 말인듯)
아래의 예제는 parport driver를 위한 함수 포인터를 보기위한 !drvobj 디버거의 사용법을 보여준다.

0: kd> !drvobj parport 2
Driver object (fffffa80048d9e70) is for:
 \Driver\Parport
DriverEntry:   fffff880065ea070 parport!GsDriverEntry
DriverStartIo: 00000000
DriverUnload:  fffff880065e131c parport!PptUnload
AddDevice:     fffff880065d2008 parport!P5AddDevice

Dispatch routines:
[00] IRP_MJ_CREATE                      fffff880065d49d0 parport!PptDispatchCreateOpen
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fffff880065d4a78 parport!PptDispatchClose
[03] IRP_MJ_READ                        fffff880065d4bac parport!PptDispatchRead
[04] IRP_MJ_WRITE                       fffff880065d4bac parport!PptDispatchRead
[05] IRP_MJ_QUERY_INFORMATION           fffff880065d4c40 parport!PptDispatchQueryInformation
[06] IRP_MJ_SET_INFORMATION             fffff880065d4ce4 parport!PptDispatchSetInformation
[07] IRP_MJ_QUERY_EA                    fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              fffff880065d4be8 parport!PptDispatchDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff880065d4c24 parport!PptDispatchInternalDeviceControl
[10] IRP_MJ_SHUTDOWN                    fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     fffff880065d4af4 parport!PptDispatchCleanup
[13] IRP_MJ_CREATE_MAILSLOT             fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       fffff880065d491c parport!PptDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL              fffff880065d4d4c parport!PptDispatchSystemControl
[18] IRP_MJ_DEVICE_CHANGE               fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         fffff880065d4840 parport!PptDispatchPnp

디버거의 출력 내용에서 여러분은 parport.sys가 GsDriverEntry를 구현한 것을 볼수 있다.
driver가 생성될때 자동적으로 생선된 GsDriverEntry는 초기화를 하고 driver개발자가 구현한 DriverEntry를 호출한다.

여러분은 DriverEntry 함수에 있는 parport driver가 아래의 주요함수들이 dispatch 하기 위한 포인터를 볼수 있다.

 - IRP_MJ_CREATE
 - IRP_MJ_CLOSE
 - IRP_MJ_READ
 - IRP_MJ_WRITE
 - IRP_MJ_QUERY_INFORMATION
 - IRP_MJ_SET_INFORMATION
 - IRP_MJ_DEVICE_CONTROL
 - IRP_MJ_INTERNAL_DEVICE_CONTROL
 - IRP_MJ_CLEANUP
 - IRP_MJ_POWER
 - IRP_MJ_SYSTEM_CONTROL
 - IRP_MJ_PNP

 나머지 주요함수의 요소들은 기본 dispatch함수(nt!IopInvalidDeviceRequst)로 남겨진다.

 디버거의 결과에서 여러분은 parport dirver가 Unload와 AddDevice의 함수 포인터를 볼수 있다.
 AddDevice 함수는 DRIVER_OBJECT 구조에체 포인터가 저장되지 않기 때문에 이래적이다.(?모르겠다.. 어떻게 해석 할지....)
 대신, DRIVER_OBJECT 구조체의 확장 member가 AddDevice에 저장된다.
 아래의 그림은 parport driver가 DriverEntry 함수에 제공한 함수 표인터를 나열하고 있다.
 (parport 가 제공한 함수포인터는 색이 칠해저 있다.)

 

 Driver paris를 사용해서 쉽게 만들기
 오린 기간 동안  Windows Driver Model(WDM)에 익숙해져 있는 Micro$oft 내/외부의 드라이버 개발자들은 dispatch 함수에 관하여 몇가지를 깨달았다.
 - Dispatch 함수들은 대게 상용구들이다. 예를들면, IRP_MJ_PNP dispatch 함수 코드는 모든 Driver가 동일하다. 이 코드들은 H/W의 각 부분을 제어하는 개별 driver에 고유 Plug and Play(PnP)의 일부분이다.
 - Dispatch 함수는 바로 얻는 것은 어렵고 힘들다. Thread 동기화나 IRP queueing, IRP 취소 같은 기능을 구현하는 것은 O/S가 어떻게 작동하는지에 대한 깊은 이해가 필요하다.
 
 Driver개발자가 쉽게 이들을 만는것을 돕기 위해 Micro$oft는  몇몇의 Technology-specific driver model을 만들었다.
언뜻, Technology-specific model은 서로 꽤나 다르게 보이지만, 이것들을 자세히 뜯어보면 상당부분 많은 것들이 이 Paradigm에 근거 함을 볼수 있다.
 - Driver는 2부분으로 나뉘어진다. 하나는 일반적인 것을 처리 하는 부분이고 또 하나는 특정 device의 특정 일을 처리하는 부분이다.
 - 일반적인 부분은 Mirco$oft가 만들어준다.
 - 특정 부분은 Micro$oft혹은 개발 H/W vendor가 만들어준다.

Proseware와 Contoso 회사가 WDM driver를 요구하는 장난감 로버트를 만든다고 가정해보자. 또 Micro$oft가 GenralRobot.sys라는 일반적인 Robot driver를 제공 한다고 가정하자.
Proseware와 Contoso는 각각 그들의 로봇이 필요로하는 처리를 위한 작은 Driver를 작성 할 수 있다.
예를 들자면 Preseware는 ProsewareRobot.sys를 만들 수 있고 이를 가지고 ProsewareRobot.sys과 GeneralRobot.sys의 쌍으로 하나의 WDM Driver를 만들 수 있다.
비슷하게 ContosRobot.sys과 GeneralRobot.sys는 하나의 WDM driver를 만들 수 있겠다.
가장 일반적은 형태의 Idea는 Specifix.sys와 general.sys의 쌍을 이용하여 driver를 만들수 있다는 것이다.

Driver Pairs 에서의 함수 포인터

(Specific.sys, General.sys) Pair에서 Windows는 Specific.sys를 로드하고 해당 File의 DriverEntry함수를 호출 할 것이다.
Specific.sys 의 DriverEntry 함수는 DIRVER_OBJECT 구조체의 포인터를 받는다.
일반적으로 여러분은 주요 함수 배열의 몇몇 요소가 Dipatch 함수의 포인터로 체워진 DriverEntry를 기대할 것이다.
또한 여러분은 AddDevice member(driver object extion)와 DRIVER_OBJECT의 member(아마도 StartIo member일 것이다.)가 체워진 DriverEntry를 기대 할것이다.
하지만 Driver pair model의 DriverEntry는 그렇지 않다. 대신 specific.sys의 DriverEntry 함수는 General.sys에 구현된 초기화 함수에 따라 DRIVER_OBJECT 구조체를 전달한다.
아래의 예제 코드는 이 pair에서 호출되는 초기화 함수가 어떻게 호출되는지 보여준다.

PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback};

// DriverEntry function in ProsewareRobot.sys
NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
   // Call the initialization function implemented by GeneralRobot.sys.
   return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks);
}

GeneralRobot.sys에서 초기화 함수는 DRIVER_OBJECT 구조체(그리고 확장)의 member에 접근하고 주요함수의 요소에 접근하는  함수 포인터를 작성한다.
I/O manager가 driver pair 에 IRP를 보낼때, IRP는 우선 GeneralRobots.sys에 구현된 Dispatch함수로 간다.
만약 GeneralRobot.sys가 스스로 IRP를 처리 한다면, ProsewareRobot.sys같은 특정 Driver는 연관될 필요가 없다.
만약 GeneralRobot.sys가 IRP의 전부가 아닌 일부분을 처리한다면, ProsewareRobot.sys에 구현된 callback 함수중 하나로부터 나머지 부분을 처리할 것이다.
GeneralRobot.sys는 GenerelRobotInit를 호출 할때 ProsewareRobot callback함수의 포인터 받는다.

DriverEntry가 반환된 후(실행을 마친 뒤), Proseware Robot device node를 위한 Device stack이 생성(구성)된다.
그 Device stack은 아마도 아래와 같을 것이다.



위 그림에서 볼수 있듯이. Proseware Robot의 device stack은 3 device object를 갖는다.
최상위의 Device object는 AfterThought.sys Filter driver와 연결된 filter device object(Filter DO)이다.
가운데이 있는 Device object는  Driver pair(ProsewareRobot.sys와 GeneralRobot.sys)와 연결된 functinoal Device object이다. 이 Device pair는 device stack에서  function device의 역할을 한다.
바닥에 있는 device object는 Pci.sys와 연결된 Physical device object(PDO)이다.
Device pair는 device stack에서 한 level에만 속하고 오직 하나의 device object (FDO)와 연결됨을 나타낸다.
GeneralRobot.sys가 IRP를 처리 할때, 부가적으로 ProsewareRobot.sys을 호출 할것이지만, device stack의 아래로 요청(request)를 전달하는 것과는 다르다.
( 주] GeneralRobot.sys가 IRP를 처리 할때 ProsewareRobot.sys를 호출 하지만 이건 기존에 살펴 보았던 Stack의 하부로 요청을 전달 하는 것과는 다른의미이다.)
Driver pair은 하나의 WDM driver를 형성하는데 이는 device stack에서 오직 한 level에 존재 한다.
( 주] 두개의 deivce pair는 비록 두개의 driver이지만 stack구조를 바탕으로 보면 하나의 device driver의 역할을 한다는 말이지 싶다.)
Driver pair는 IRP를 처리 하거나 IRP를 device stack의 하부에 있는 PDO(여기에선 pci.sys)로 전달한다.

Driver pair의 예

만약 여러분의 Laptop 컴퓨터에 무선 네트워크 카드가 있고, Device Manager를 살펴보고 네트워크 카드 드라이버가 newwlv64.sys임을 알았다고 하자(의역 만빵)
 netwlv64.sys를 위한 function pointer를 살펴보기위해 !drvobj debugger extension을 사용 할 수 있다.

 1: kd> !drvobj netwlv64 2
Driver object (fffffa8002e5f420) is for:
 \Driver\netwlv64
DriverEntry:   fffff8800482f064 netwlv64!GsDriverEntry
DriverStartIo: 00000000
DriverUnload:  fffff8800195c5f4 ndis!ndisMUnloadEx
AddDevice:     fffff88001940d30 ndis!ndisPnPAddDevice
Dispatch routines:
[00] IRP_MJ_CREATE                      fffff880018b5530 ndis!ndisCreateIrpHandler
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff88001936f00 ndis!ndisDummyIrpHandler
[02] IRP_MJ_CLOSE                       fffff880018b5870 ndis!ndisCloseIrpHandler
[03] IRP_MJ_READ                        fffff88001936f00 ndis!ndisDummyIrpHandler
[04] IRP_MJ_WRITE                       fffff88001936f00 ndis!ndisDummyIrpHandler
[05] IRP_MJ_QUERY_INFORMATION           fffff88001936f00 ndis!ndisDummyIrpHandler
[06] IRP_MJ_SET_INFORMATION             fffff88001936f00 ndis!ndisDummyIrpHandler
[07] IRP_MJ_QUERY_EA                    fffff88001936f00 ndis!ndisDummyIrpHandler
[08] IRP_MJ_SET_EA                      fffff88001936f00 ndis!ndisDummyIrpHandler
[09] IRP_MJ_FLUSH_BUFFERS               fffff88001936f00 ndis!ndisDummyIrpHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff88001936f00 ndis!ndisDummyIrpHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff88001936f00 ndis!ndisDummyIrpHandler
[0c] IRP_MJ_DIRECTORY_CONTROL           fffff88001936f00 ndis!ndisDummyIrpHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff88001936f00 ndis!ndisDummyIrpHandler
[0e] IRP_MJ_DEVICE_CONTROL              fffff8800193696c ndis!ndisDeviceControlIrpHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch
[10] IRP_MJ_SHUTDOWN                    fffff88001936f00 ndis!ndisDummyIrpHandler
[11] IRP_MJ_LOCK_CONTROL                fffff88001936f00 ndis!ndisDummyIrpHandler
[12] IRP_MJ_CLEANUP                     fffff88001936f00 ndis!ndisDummyIrpHandler
[13] IRP_MJ_CREATE_MAILSLOT             fffff88001936f00 ndis!ndisDummyIrpHandler
[14] IRP_MJ_QUERY_SECURITY              fffff88001936f00 ndis!ndisDummyIrpHandler
[15] IRP_MJ_SET_SECURITY                fffff88001936f00 ndis!ndisDummyIrpHandler
[16] IRP_MJ_POWER                       fffff880018c35e8 ndis!ndisPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL              fffff880019392c8 ndis!ndisWMIDispatch
[18] IRP_MJ_DEVICE_CHANGE               fffff88001936f00 ndis!ndisDummyIrpHandler
[19] IRP_MJ_QUERY_QUOTA                 fffff88001936f00 ndis!ndisDummyIrpHandler
[1a] IRP_MJ_SET_QUOTA                   fffff88001936f00 ndis!ndisDummyIrpHandler
[1b] IRP_MJ_PNP                         fffff8800193e518 ndis!ndisPnPDispatch

디버거의 출력에서 여러분은 netwlv64.sys에 GsDriverEntry가 구현되어 있음을 볼수 있다.
Driver가 제작될때 자동으로 생성된 GsDriverEntry는 초기화를 하고 Driver 개발자가 작성한 DriverEntry를 호출 할 것이다.

예제에서 netwlv64.sys는 DriverEntry를 구현되어 있고 ndis.sys는 AddDevice, Unload 그리고 몇몇 dispatch함수가 구현되어있다.
Netwlv64.sts는 NDIS miniport driver라 부르고 ndis.sys는 NDIS라이브러리라 부른다. 이 두 모듈은 모두(NDIS miniport, NDIS Library)쌍을 형성한다.

아래의 그림은 무선 렌카드의 device stack을 보여준다. Device pair(netwlv64.sys, ndis.sys)는 device stack에서 오직 한 level에만 관련되어 있고 그것은 오직 한device object(FDO)와 연결되어 있음을 나타낸다.



유효한 driver pair들
또 다른 technology-specific driver model들은 Driver pair의 일반적인 부분과 특정 부분을 구현할때 다양한 이름을 사용한다.(의역이다.)
많은 경우 이 pair의 특정 부분은 "mini" 접두어를 갖는다. 아래에 몇가지 pairs를 보여주겠다.
 - (display miniport driver, display port driver)
 - (audio miniport driver, audio port driver)
 - (storage miniport driver, storage port driver)
 - (battery miniclass driver, battery class driver)
 - (HID minidriver, HID class driver)
 - (changer miniclass driver, changer port driver)
 - (NDIS miniport driver, NDIS library)

 목록에서 볼수 있듯이, 몇몇 model들은 dirver pair의 일반적인 부분(port라고 쓴 부분들)을 class driver라는 용어로 사용한다.
 이 class driver들은 standalone class driver와 다르고, class filter dirver와 다르다.

I/O requst packet


대부분의 요청(Request)은  device driver에서 보내고 이러한 요청들은 I/O request packets(IRPs)의 형태를 갖는다.
O/S 구성요소 혹은 driver는 IoCallDriver를 호출 함으로서 driver에 IRP를 보낸다.
IoCallDriver는  2개의 매게변수(DEVICE_OBJECT 포인터와, IRP포인터)를 갖는다.
DEVICE_OBJECT는  DRIVER_OBJECT와 연결된 포인터를 갖는다.
O/S 구성요서가 IoCallDriver를 호출 하면, 여러분은 O/S 구성요소가 device에 혹은 Device object와 연결된 Driver에 IRP를 보낸다고 말한다.
가끔 여러분은  IRP를 보낸다(Send)는 말 대신 IRP를 전송(forward) 혹은 구문전송(the phrase passes)이라고 말할 것이다.

일반적으로 IRP는 stack에 나열된 몇몇의 driver에서 처리된다. stack안의 각각의 driver는 device object와 연결되어 있다.
보다 많은 정보를 알고 싶으면 "Device nodes and device stacks"을 참조 하라. IRP가 stack device에서 처리 될때 IRP는 대게  device stack의 최상위에 있는 device object에 보내진다.
예를 들어 만약 IRP가 아래의 그림과 같은 device stack에서 처리 된다면, IRP는 우선 device stack의 최상위에 있는 filter device object(Filter DO)에 보내질 것이다.




device stack아래로 IRP전달 하기

I/O manager가 위 그림의 Filter DO에 IRP를 보냈다고 가정하자.
Filter DO와 연결된 driver(AfterThought.sys)는 IRP를 처리 하고
이를  device stack구조상 아래에 있는 functional device object(FDO)로 보낼 것이다.
driver가 device stack상 바로 아래쪽 device object에 IRP를 를 보낼때, 여러분은  driver가 IRP를 device stack 밑으로 내려보낸다고 말할것이다.
어떤 IRP들은 deice stack의 물리적 device object로 보내질 것이다.(해석하기 까다롭다.)
또 어떤 IRP들은 PDO상위의 driver에서 처리를 완료 하기 때문에 PDO까지 보내지 않을 것이다.

IRPs are self-contained

IRP 구조체는 driver가 I/O request 처리를 하는데 필요한 모든 정보를 포함하고 있다.
IRP 구조체의 어떤 부분은 stack내에 있는 driver에 공통적인 정보를 포함하고 있고, 또 IRP의 다른 부분에는 Stack에 있는 일부 driver에 필요한 특별한 정보를 포함하고 있다.

금요일, 7월 12, 2013

Choosing a driver model

Driver model 선택하기

Micro$soft Windows는 여러분들이 driver를 만들때, 다양한 Driver model을 제공하고 있다.
최고의 Driver모델의 선택 전략은 여러분이 작성하려는 driver의 형태에 따라 틀려질 것이다.
아래에 선택 사항이 있다.
 - Device function driver
 - Device filter driver
 - Software driver
 - File System filter driver
 - File System driver

 다양한 Driver간의 차이점을 알고자 한다면 "What is a driver"와 "Device nodes and device stack"을 찾아보아라.
 아래에선 각 driver model을 선택하는 방법에 대하여 설명하고자 한다.

 Device function driver model 선택 하기

 여러분이 H/W device를 설계한다고 치자, 제일 먼저 고려해야 할 것은 function driver를 작성해야 한다는 것이다.
 아래의 질문들에 대하여 답해보라.
  - 당신은 driver를 작성할 필요가 없는가?(아 이거 어렵다..... 해석이 안되네..)
  - 만약 여러분이 function driver를 작성한다면 사용해야할 최고의 device model은 무엇인가?

 이 질문들의 대답은 당신의 device가 Device and driver technologies에 기술된 기술의 list에 부합하는 것을 결정한다.
 각각의 기술을 위한 문서를 보고 당신이 작성해야 할 function driver를 결정 하고 당신의 장치에 유요한 driver model에 대하여 연구하라.
 어떤 개별적인 Technology은 minidriver models을 가지고 있다. minidriver model에서 device driver는 두 부분을 포함하고 있다. 하나는
General tasks 처리이고 다른 하나는 Device-specific task 처리 부분이다. 일반적으로 Micro$oft는 General portion을 작성하고
장치 제작사들은 device-specific porting을 작성한다. Device-specific 부분은 많은 이름을 가지고 있으며, 대부분 mini접두어를 사용한다.
여기에 minidriver model에서 사용되는 이름을 보여주고자 한다.
  - Display minoport driver
  - Audio miniport driver
  - Battery miniport driver
  - Bluetooth protocol driver
  - HID minidirver
  - WIA minidirver
  - NDIS miniport dirver
  - Storage miniport driver
  - Streaming minidriver

minidirver model에 대하여 살펴보고자 한다면 "Minidrivers and driver pairs"를 보도록 하자.
Device and driver technologies에 나열된 technology들은 전용 minidriver model이 없다.
특정 technology 에 관한 문서에는 Kernel-Mode Driver Framework(KMDF)를 사용하라 조언할 것이다.
다른 Technology에 관한 문서는 User-Mode Driver Framework(UMDF)를 사용 하라 조언할 것이다.
중요한 것은 여러분이 특정 장치를 위한 문서를 연구해야한다는 것이다.
만약 여러분의 Device technology가 minidriver가 있다면 여러분은 minidirver model을 사용해야한다.
혹은 minidirver가 없다면  UMDF, KMDF 또는 Windows Driver Model(WDM)을 사용할지 여부는 여러분의
Technology-specific 설명서에있는 지침을 따르십시오.

Device filter driver를 위한 driver model 선택하기

상당히 많은 몇몇 Driver들이 장치로부터 데이터를 읽는 것과 같은 하나의 I/O요청에 대응 한다. Driver들은 스택안에 존재한다.
그리고 앞서 보여준바와 같이 Stack에서 첫 Driver는 위에있고 마지막 Driver 는 하단에 있다.
스택은 하나의 function driver와 몇몇의 filter driver를 포함할 수 있다. Function driver와 filter driver에 대하여 알고 싶다면
"What is a driver?"와 "Device nodes and device stacks"을 보도록 하자.

만약 여러분이 device를 위한 filter driver를 만들 준비중이라면,  "Device and driver technologies"에 기술된 Technologies들의
 나열 중에 당신의 device와 부함하는 것을 결정하시오
 특정 device technology 문서에 Filter driver model 선택에 대한 지침이 있는지 여부를 확인합니다.
 만약 기술 문서에 해당 내용에 대한 지침이 없을 경우 먼제 UMDF(User-mode driver framework) Model을 사용하는 것이 좋다.
 만약 당신의 Filter driver가 UMDF로 접근 할 수 없는 데이터 구조를 접근 해야 할 경우,
 Driver model로 KMDF(Kernel-mode driver framework)를 사용하는 것이 좋다.
 아주 드문 경우지만 당신의 driver 가  KMDF(Kernel-mode driver framework)에 유요하지 않은 자로에 접근 할 필요가 있다면,
 WDM을 당신의 driver model로 사용해라.

 software driver를 위한 driver model 선택하기

 Device와  연결되지 않은 Driver를 softwaare driver라 한다. Software dirver에 대하여 더 알고 싶다면, "What is a driver?"를 참조하라.
 Software driver는 Kernel-mode에서 동작하며, protected OS Data에 접근 할수 있기 때문에 매우 유용하다.
 processor mode에 관현 정보를 알고 싶다면 "User mode and kernel mode."를 참조하라.

 software driver는 KMDF(Kernel-mode driver framwork)와 기존의 Windows NT driver model의 2가지 종류가 있다.
KMDF와 기존의 Windows NT model은 둘 모두 PnP(Plug and Play) 및 전원 관리에 대하여 신결 쓰지 않고 Driver를 작성 할 수 있다.
때문에 당신은 단신의 Driver의 기본 작업에 더 집중 할 수 있습니다. KMDF(Kernel-mode driver framework)로 작성한다면
framework가 PnP및 전원처리를 하기 때문에 여러분은이들에 신경 쓸 필요가 없다.
기존의 Windows NT model로 작성한다면, 기존 Windows NT model은 PnP와 전력처리에 완전히 독립적이므로 신경쓸 필요가 없다.
 우리는 만약 당신이 KMDF에 익숙하다면 KMDF로 작업하길 권장한다.
 만약 당신이 제작 하려는 driver가 전원관리와 PnP에 독립적이라면, 기존의 Windows NT model을 이용하라.
 만약 단신이 제낙 하려는 Driver가 PnP Event나 전원 관리를 신경 써야 한다면 기존의 Windows NT model을 사용 할 수 없다.  KMDF를 사용하라.
 매우 드문 경우지만, PnP나 전원관리를 신경 쓰거나 KMDF에 유효하지 않은 데이터에 접근 하는 software driver를 작성해야 한다면 WDM을 사용하라.

 File system filter driver를 위한 driver model 선택하기

 이 모델을 선택하는데 도움을 얻고자 한다면 "File system filter drivers"를 살펴보기바란다.

 File system driver를 위한 driver model 선택하기

 이 모델의 선택에 도움을 얻고자 한다면 "File System Minifilter drivers"를 살펴 보기 바란다.

What is a driver?

드라이버란 무엇인가?

Driver라는 용어를 짧게 정의 하는 것은 매우 힘들다. 기본적으로, 드라이버는 OS와 장치가 대화(통신)를 하게하는 소프트웨어의 구성 요소다. 예를 들어, Application이 장치로부터 어떤 데이터를 읽어야 한다고 가정하자면. OS는 Driver에 기술된(구현된) 함수를 호출 할 것이다. 특정 회사에서 제작된 Driver는 OS에 그 데이터를 반환 할 것이고 OS는 다시 Application에게 줄 반환 할 것이다.



확장된 정의

 위의 설명은 몇가지방법으로 다시 말해 볼 수 있다.(정말 이건 의역의 극치..아마 틀렸을것이다.)
  ● 모든 Driver들이 꼭 그 장치들을 생산한 회사에서 작성 되는 것은 아니다.
       - 대부분 장치들은 H/W 표준규격에 맞추어 제작된다. 이는 즉 그 Driver는 Macro$oft에서 작성되기도 하고, 장치 개발사(자)는 드라이버를 제공하지 않기도 함을 의미한다.
  ● 모든 Driver가 직접 장치와 통신하는 것은 아니다.
       - 특정 I/O 요청(장치로부터 데이터를 읽어오는 것등)에 대하여 계층구조를 이루며 동작하는  몇몇 Driver들이 있다. 아래 그림에서 볼 수 있듯이 Stack구조를 이루며 해당 요청에 응답을 하기도 한다. Stack구조 상의 어떤 Driver는 한 구조(형식)에서 다른 구조(형식)로의 변환(형 변환이나 좌표계 변환 등의 변환)에 관여하는 것도 있다. 이 Driver들은 장치와 직접 통신하지 않는다. 그것들은 단지 요청을 조작하고 Stack구조상 낮은 위치의 Driver에 요청을 전달한다.


       Stack구조상에서 Device와 직접 통신하는 Driver를 function driver라 말하고, 그외에 연산기능을 수행하는 것을 Filter driver라 부른다.
  ● 어떤 Filter Driver는 직접적으로 해당 I/O요청에 관여하지 않고 I/O 요청에 대한 정보를 관찰하고 기록하기도 한다. 예를 들어  특정 Filter driver들은 Stack구조상에 있는 다른 Driver들이 I/O 요청에 제대로 동작하는지를 감시하는 역할을 하기도 한다.

다시 말해 Driver란, OS와 장치간에 통신에 있어서 참여하고나 혹은 감시하는 Software 구성요소 즘으로 확장해 말할 수 있겠다.

소프트웨어 Driver

우리의 확장된 정의는 일부 Driver가 꼭 장치에 연결되어 있지 않기 때문에 아직 정확하지 않은것 같다. 예를 들어, 당신은 OS 핵심 자료구조의 데이터(이 데이터는 Kernel mode에서 동작 하는 코드만이 접근이 가능하다.)에 접근하는 Tool을 만들어야 한다고 치자. 당신은 이 Tool을 두 부분으로 나움으로서 이를 가능하게 할 수 있다. 한 부분은 User mode에서 동작는 User Interface를 보여주는 부분을 말하며 다른 부분으로 Kernel mode에서 동작 하는 OS 핵심 데이터에 접근하는 부분을 말한다.  user mode에서 동작 하는 부분을 Application이라 부르고 Kernel mode에서 동작하는 부분을 software driver라 부른다. software driver는 하드웨어 장치와 관련되지 않는다. 프로세서의 동작 Mode에 대한 더 많은 정보를 보고자 한다면 User mode and Kernel Mode를 참조하길 바란다.

이 다이어 그램은 user-mode application과 kernel-mode software driver간의 통신을 보여준다.

추가~!
Software driver들은 항상 kernel mode에서 동작을 한다. software driver를 작성하는 주된 이유는 보호되는 데이터(Protected data)는 꼭 kernel mode에서만 접근이 가능 하기 때문이다. 하지만, Device Driver는 항상 Kernel-mode 데이터 및 resources 에 접근 하는 건 아니기 때문에 어떤 Device Driver는 user-mode에서 동작을 하기도 한다.

아직 우리가 다루지 않은 드라이버의 종류인 Bus driver가 있다. bus driver를 이애 하려면  Device Node와 Device tree에 대하여 이해할 필요가 있다. Device tree, node, bus driver에 대한 보다 자세한 정보는 Device Nodes and Device Stacks를 참고하길 바란다.

우리는 function dirver의 정의에 대해 간략히 살펴보았다. 장치에게 function driver란장치와 직접적으로 통신을 하는 스택에 있는 driver의 하나라 말할 수 있겠다. 이는 PCI (Peripheral Componet Interface) bus에 직접적으로 연결된 장치에 있어서는 정확한 말이다.
function driver는 PC장치를 위한 장치의 메모리 resource와 port에 메핑된 주소를 가지고 있다. 하지만, 대부분, 장치의 장치들은 PIC bus에 직접적으로 연결되어 있지 않고 PCI bus에 연결된 Host bus adapter에 연결되어 있다.  예를 들자면, USB toaster는 (USB host controller라 불리는)Host bus adapter에 연결되어 있다. USB toaster는 function driver를 가지고 있으며, USB Host controller역시 function driver를 가지고 있다. Toaster의 function driver는  USB host controller의 function driver에 요청을 보냄으로서 Toaster와 간접적으로 통신을 한다. USB shot controller 의 function driver는 Toaster와 통신하는 USB Host controller 하드웨어와 직접 통신합니다.


Device nodes and device stacks

Device nodes and device stacks

Windows에서 장치들은 Pnp Device tree의 Device node로 구성된다.
일반적으로 I/O Request이 Device로 보내졌을때, 몇몇 driver들이 해당 Request를 처리를 한다.
이들 driver들은 각각 device object와 연계되어 있어고 이 연계된 device object들은 Stack구조를 이루고 있다.
관련된 driver들이 속한 device object들의 나열을 device stack이라 부른다. 각 device node들은 각각의 device stack을 갖는다.
=> Device node는 device Stack을 갖으며, 이 Deice stack은 몇몇의 driver들로 구성된다.(device node => Device stack > Device object >= Driver)

device node들과 the Plug and Play device tree
Windows는 장치들을 the Plug and Play device tree(혹은 단순히 device tree라 부른다)라 불리우는 tree 구조로 구성한다.
일반적으로, Device tree에서 node는 장치 또는 복합 장치의 개별 기능(function)을 나타낸다.
하지만, 어떤 node들은 물리적 장치와 관련 없는 software들로 구성된다.

Device tree에서 Node는 device node라 불린다. Device tree에서 최상위 Node는  root device node라 부른다.
대게 root device node는 아래의 그림과 같이 device tree의 제일 아래에 그린다.



Device tree는 PnP환경하에서 부/자 관계로 표시된다.
Device tree에서 어떤 node는 그들과 연결된 하위 device들을 갖는 버스(Bus)들로 표시된다.
예를 들어,  PCI Bus node는 메인보드의 물리적 PCI Bus를 나타낸다.
시스템이 시작을 하면, PnP 메니저가 PCI bus에 연결된 장치들을 나열 하도록 PCI bus driver에 요청을 한다. 이러한 장치들은 PCI Bus node의 하위로 표시된다.
위의 그림에서 PCI Bus node는 USB Host controller, Audio controller, PCI Express port등 PCI Bus node와 연결된 많은 하위 노드를 갖는다.
PCI Bus에 연결된 어떤 장치들은 그 자체가 Bus다. PnP manager가 이들 버스에 그 버스와 연결된 장치들을 나열 하도록 요청한다.
위 그림에서 우리는 Audio controller가 Audio 장치들과 연결된 Bus임을 볼 수 있다.
우리는 PCI Express port가 Display adapter와 연결된 Bus임을 볼수 있다. 그리고 display dapter는 2개의 모니터(실제 모니터는 하나만 표시됨 이거 오류임)와 연결된 bus임을 볼 수 있다.
Node는 당신이 보는 시점에 따라 장치 일수도 있고 버스 일수도 있다.
예를들어 Display adapter를 화면에 표시되는 영상을 구성하는 핵심 기능으로서 장치라 생각 할수 있다.
하지만 당신은  연결된 모니터들을 나열하고 검출하는 능력(기능)으로서 Display adapter를 버스라 생각 할수도 있는 것이다.

Device Objects와 device stacks
Device Object는 DEVICE_OBJECT 구조체의 instance이다.
PnP device tree에서 각 device node는 device oject들을 갖을 수 있고, 이들 device object들은 각각  driver와 연관되어 진다.
당신은 device stack을 여러형태로 생각 할 수 잇다. 아주 일반적으로, device stack은 device object/driver들로 이루어 져있다.
그러나 특정 상황에서 그 Device object의 정렬 된 목록으로 Device stack을 생각하는 것이 더 효율 적일 것이다.
일반적으로 Device stack은 상하위 구조를 갖는다. 첫번째 device object는 Device stack의 바닥에 만들어지고, 나중에 만들어진(혹은 부착된) device object는 device stack의 최상위에 위치한다.
아래의 그림에서 Proseware Gizmo device node는 device object/driver등이 3개으로 구성된 device stack을 가지고 있다. 가장 위에 위치한 device object는 AfterThought.sys driver와 연결되어 있고,
가운데에 위치한 device object는 Proseware.sys driver와 연결되어 있으며, 최하위에 위치한 Device object는 Pci.sys driver와 연결되어 있다.
그림 중앙에 위치한 PCI BuS node는 device object/driver등이 하나는 Pci.sys와 다른 하나는 Acpi.sys와 연결되어져 있는 2개로 구성되어 있다.



Device stack이 어떻게 만들어질까
시스템이 시작을 하면 PnP Manager는  버스와 연결된 하위 장치들을 나열 도록 각 각 Bus Driver에 요청을 한다. 예를 들어 PnP Manager는  PCI버스에 연결된 장치들을 나열 하도록 PCI Bus driver(Pci.sys)에 요청을 한다. 이러한 요청의 결과로, Pci.sys는 PCI Bus와 연결된 각 장치들의 Device Object를 생성한다. 이 장치 Object들은 각각 Physical Device Object(PDO)라 불린다. 다시말해, Pci.sys는 아래의 그림에서 볼는 바와 같이 PDO들의 집합을 생성한다.



 PnP manager는 새로이 만들어진 PDO(physical Device Object)를 연결하고 어떤 driver가 그 Node의 device stack에 필요지 결정하기위해 Registry를 검색한다.
그 Device stack은 필히 하나의 Function driver와 선택적으로 하나 혹은 그이상의 filter driver를 갖을 수 있다. Function driver는 device stack의 main driver이고 device control 요청 및 Read/Write를 처리해야한다.
이 function/filter driver가 Load됨으로서 device stack을 만들고 device object들을 생성한다. function driver가 생성한 device object는 FDO(functional device object)라 불리우고, filter driver가 생성한 device object는 Filter DO)filter device Object가 불린다.
Device tree는 아래 그림과 같다.



그림에서 보는 봐와같이 하나의 node는 function driver위에 filter driver가 있다. 그리고 다른 node안에는 filter driver가 function driver 아래에 있다.
device stack에서 function driver위에 있는 filter driver는 upper filter driver가 하고, function driver 밑에 있는 filter driver는 lower filter driver가 한다.

PDO는 항상 device stack에서 가장 아래에 존재하는 device object이다. 이것은 device stack의 생성의 결과다. PDO는 가장 처음 생성되고 추가적인 device들은 stack의 위쪽에 추가된다.
(PDO는 항상 device stack의 가장 아래에 존재하고 나머지 device object(Driver)들은 그위에 추가된다. 그리고 그 위에 다른 device들이 앞서 본봐와 같은 구조로 추가적으로 생성된다. 라고 의역해본다.)

Note
장치를 위한 driver가 install될때  installer는 어떤 driver가 function driver인지 filter인지 결정하기 위해 INF file의 정보를 이용한다.
일반적으로 INF file은 Micro$oft 혹은 Hardware vendor들에 의해 제공된다. 장치 driver가 install된후 PnP Manager는 Registry 검색을 통하여 장치의 filter/function driver를 결정 한다.

Bus Drivers
위의 그림에서, 당신은 Pci.sts driver의 두가지 역할을 볼 수 있다. 하나는 PCI Bus device node의 FDO와 결합되어져 있다. 사실 PCI Bus drivce node에서 FDO로 생성된다. 따라서 Pci.sys는 PCI Bus의 function driver이다.
두번째로, Pci.sys는 PCI Bus node에 연결된 하위 Device의 PDO와 결합되어져 있다. 즉, 하위 device를 위한 PDO로서 생성되어질때 호출 된다. Device node의 PDO로서 생성된 driver는 그 node의 Bus dirver로서 불리운다.
당신의 보는 관점이 PCI Bus라면 , Pci.sys는 Functino driver일것이지만, 당신이 보는 관점이 Proseware Gizmo device라면 Pci.sys는 Bus dirver이다. Pnp Device tree에서 이러한 두가지 역할은 일반적이다.
드라이버는 Bus에서 function driver의 역할을 수행할 뿐만 아니라. Bus의 하위 장치의 Bus driver역할을 수행한다.

User-mode deivce stacks
위에서 우리는 kernel-mode device stack에 대하여 언급하였다. 즉, kernel-mode에서 실행되는 스택에 존재 하는 driver나 device object들은 커널 모드에서 실행되는 코드에게만 유요한 시스템 영역에 메핑된다.
kernel-mode와 user-mode의 차이에 관한 정보는 User mode and Kenel mode를 참조하라.
어쩔땐, 장치들은 kernel-mode stack과 더블어 user-mode device stack을 갖기도 한다. user-mode driver는 windows driver framework에서 제공하는 driver의 한 종류인 (UMFM)User-Mode Driver Framework를 기반으로 한다.
UMDF에서 이 driver들은 user-mode DLL이다. 그리고 device object들은 IWDFDevice interface를 구현한 COM Object이다. UMDF device stack에 있는 device object는 WDF device object(WDF DO)라 부른다.
아래의 그림은 USB-FX-2 장치를 위한 user-mode device 와 kernel-mode device 및 device node를 보여주고 있다. user-mode 및 kernel-mode stack에 존재하는 driver들은 USB-FX-2 장치의 I/O요청에 모두 참여가 가능하다.




User mode and Kernel mode

User mode and Kernel mode

Windows가 동작하는 컴퓨터에의 프로세서는 두가지 의 다른 mode(user mode/kernel mode)에서 동작한다.
프로세서는 실행 중인 코드의 종류에 따라 두 mode들을 구분(변경)하며 실행 한다.
Application은 user mode에서 동작을 하고 핵심OS 요소들은 Kernel mode에서 동작을 한다.
대부분의 Driver들은 kernel mode에서 동작을 하지만 어떤 Driver들은 user mode에서 동작을 한다.

Use-mode Application을 시작 할때 Windows는 application을 위한 pocess를 생성한다.
process는 Application을 위하여 private virtual adress space와 private hanle table을 제공한다.
Application의 virtual addresss space는 private이기 때문의 하나의 application은 다른 application에 속한 데이터를 변경할 수 없다.
각 application은 고립(독자적으로)되어 실행된다. 그래서 만약 applicatino이 작살나면, 그 파급은 하나의 application에 국한된다.
다른 applicatino들과 OS는 그 파장효과에 영향을 받지 않는다.

private이 된다는 것은 use-mode application 의 virtual addresss space에 제한적이다.
user-mode상에서 동작하는 process는 OS를 위해 예약된 virtual address에 접근 할 수 없다.
user-mode application의 virtual address space 제약은 OS data의 심각한 파과의 가능성이나 변경을 방지 한다.

Kernel-mode에서 모든 code들은  하나의 virtual address space를 공유한다.
이는 kernel-mode dirver는 다른 드라이버와 OS 로부터 독립되어 실행되지 않는다는것을 위미한다.
만약 kernel-mode driver가 잘못된 virtual address에 wirte를 한다면, OS 혹은 다른 driver에 속한 데이터를 손상 시킬 수 있다.
만약 kernel-mode driver가 뻑난다면, OS를 뻑낼수도 있다.

아래의 그림은 user-mode와 kernel-mode 요소간의 통신을 보여주고 있다.


목요일, 7월 11, 2013

Getting started with drivers

이 글에서, 우리는 드라이버 개발의 시작에 도움을 주는 주제를 제공한다.
우리는 개념적 기반을 설명하고 당신이 Visual Stdio개발 환경을을 이용하여 드라이버를 작성하는 방법을 제시하고자 합니다.

시작전에, 당신은 C언어에 친숙해야하고 Callback함수와 Event handler 그리고 Function Pointer의 개념을 숙지 하고 있어야 한다. 만약 User-Mode Driver Framework를 기반으로 하는 드라이버를 작성하고자 한다면, 당신은 C++ 및 COM에 대하여 숙지하고 있어야 한다.

아래의 주제들은 당신이 드라이버 개발 환경과 드라이버에 대한 기본적 지식들을 배우개 될 것이다. 또한 당신은 당신의 첫 드라이버의 제작과 작성의 시작을 위한 실습을 하게 될 것이다.

 - 드라이버란 무엇인가
 - 드라이버 모델 택하기
 - 당신의 첫 드라이버 작성