[DDK] DISPATCH_LEVEL 에서 Paging 이 불가능한 이유

제일 처음에 책을 읽으면서,

왜 DISPATCH_LEVEL에서 페이징이 불가능할까?

책에서는 모두 당연하다는 듯이 non-paged 메모리에 있어야 한다고 했다.

그리고는 전역변수에 동기화 객체를 선언했다.

참 알쏭달쏭했다. 전역변수 영역이 왜 페이징이 안되는가,

그리고 왜 DISPATCH_LEVEL에서는 페이징이 허용 안되는가?

이제 궁금증이 풀린 것 같다.

다음 코드를 보자. 이병오씨의 "윈도우 파일 시스템" 책에 있는 코드이다.

  1. //스핀 록을 위한 변수를 전역 변수로 선언한다.  
  2. KSPIN_LOCK     CountMutex;  
  3.  
  4. ...  
  5.  
  6. NTSTATUS  
  7. DriverEntry(  
  8.     IN PDRIVER_OBJECT DriverObject,  
  9.     IN PUNICODE_STRING RegistryPath  
  10.     )  
  11. {  
  12.     ....  
  13.     // 스핀록을 초기화 한다.  
  14.     #if DBG  
  15.         KeInitializeSpinLock( &CountMutex );  
  16.     #endif  
  17.  
  18.     ....  
  19.  
  20. }  
<TEXTAREA class="cpp" style="DISPLAY: none" name=code rows=10 cols=60>//스핀 록을 위한 변수를 전역 변수로 선언한다. KSPIN_LOCK CountMutex; ... NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { .... // 스핀록을 초기화 한다. #if DBG KeInitializeSpinLock( &CountMutex ); #endif .... } </TEXTAREA>

그리고 책에 적혀있는 내용이다.

" 익스큐티브 스핀 록의 특징을 정리하면 다음과 같다.

 ● 스핀 록과 관련된 IRQL은 DISPATCHB_LEVEL IRQL이다.
 ●
스핀 록을 사용하기 위해서 드라이버는 스핀 록을 페이징 불가능한 영역에 할당해야만 한다.
 ● KeInitializeSpinLock() 함수를 사용하여 스핀 록을 초기화한다.
"
 전역변수는 페이징이 불가능한 영역이다.

이런 결론이 나게 된다.

 하지만 알아본 결과, 전역변수 영역도 데이터섹션에 올라가지만,

        페이징이 될 수 있다.

 라는 결론이 나왔다.

 하지만, 드라이버는 커널에서 수행되기 때문에 왠만하면 전역변수가 페이징 되지 않는다.

 확실한 non-paged 영역에 선언하는 방법은 DEVICE_EXTENSION에 있다.
 
  1. typedef struct _DEVICE_EXTENSION {  
  2.     ...  
  3.     KSPIN_LOCK QLock;  
  4. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;  
  5.  
  6. ...  
  7.  
  8. NTSTATUS  
  9. AddDevice(  
  10.     PDRIVER_OBJECT pDriverObject,  
  11.     PDEVICE_OBJECT pPhysicalDeviceObject  
  12.     )  
  13. {  
  14.     ...  
  15.     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pPhysicalDevcieObejct->DeviceExtension;  
  16.       
  17.     KeInitializeSpinLock(&pdx->QLock);  
  18.  
  19.     ...  
  20.  
  21. }  
<TEXTAREA class="cpp" style="DISPLAY: none" name=code rows=10 cols=60>typedef struct _DEVICE_EXTENSION { ... KSPIN_LOCK QLock; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; ... NTSTATUS AddDevice( PDRIVER_OBJECT pDriverObject, PDEVICE_OBJECT pPhysicalDeviceObject ) { ... PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pPhysicalDevcieObejct->DeviceExtension; KeInitializeSpinLock(&pdx->QLock); ... } </TEXTAREA>

이런 것이다.

 결론을 알아보면, 어디에서든 드라이버가 이벤트 객체를 생성하는 사용 예를 흔하게 볼 수 있을텐데

만약 스와핑되어 버리면 ( SWAP-IN, SWAP-OUT을 의미한다. 페이징을 가리킨다 ) 이벤트 객체가 메모리

에 존재하지 않게 되어서, 상승된 IRQL에서 어떤 다른 스레드가 KeSetEvent()를 호출하려 하면, 버그 체크

가 발생하게 될 것이다.

 즉, 자동 변수( auto-variable )로 선언하게 되면, 페이징이 되고, 함수 호출이 끝나버리면, 그 영역에 존재

하지 않게 된다. 즉 메모리에서 삭제 되거나, 물리메모리에서 디스크로 SWAP-OUT되버린 상태인 것이다.

 흠, 좋아, 이제 머리가 쑥쑥 빨아들이는군,

 다음에는 DISPATCH_LEVEL에 대해서 정리해봐야겠다.
위로 스크롤