제일 처음에 책을 읽으면서,
왜 DISPATCH_LEVEL에서 페이징이 불가능할까?
책에서는 모두 당연하다는 듯이 non-paged 메모리에 있어야 한다고 했다.
그리고는 전역변수에 동기화 객체를 선언했다.
참 알쏭달쏭했다. 전역변수 영역이 왜 페이징이 안되는가,
그리고 왜 DISPATCH_LEVEL에서는 페이징이 허용 안되는가?
이제 궁금증이 풀린 것 같다.
다음 코드를 보자. 이병오씨의 "윈도우 파일 시스템" 책에 있는 코드이다.
<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에 있다.
<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에 대해서 정리해봐야겠다.
왜 DISPATCH_LEVEL에서 페이징이 불가능할까?
책에서는 모두 당연하다는 듯이 non-paged 메모리에 있어야 한다고 했다.
그리고는 전역변수에 동기화 객체를 선언했다.
참 알쏭달쏭했다. 전역변수 영역이 왜 페이징이 안되는가,
그리고 왜 DISPATCH_LEVEL에서는 페이징이 허용 안되는가?
이제 궁금증이 풀린 것 같다.
다음 코드를 보자. 이병오씨의 "윈도우 파일 시스템" 책에 있는 코드이다.
- //스핀 록을 위한 변수를 전역 변수로 선언한다.
- KSPIN_LOCK CountMutex;
- ...
- NTSTATUS
- DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
- {
- ....
- // 스핀록을 초기화 한다.
- #if DBG
- KeInitializeSpinLock( &CountMutex );
- #endif
- ....
- }
그리고 책에 적혀있는 내용이다.
" 익스큐티브 스핀 록의 특징을 정리하면 다음과 같다.
● 스핀 록과 관련된 IRQL은 DISPATCHB_LEVEL IRQL이다.
● 스핀 록을 사용하기 위해서 드라이버는 스핀 록을 페이징 불가능한 영역에 할당해야만 한다.
● KeInitializeSpinLock() 함수를 사용하여 스핀 록을 초기화한다.
"
전역변수는 페이징이 불가능한 영역이다.
이런 결론이 나게 된다.
하지만 알아본 결과, 전역변수 영역도 데이터섹션에 올라가지만,
페이징이 될 수 있다.
라는 결론이 나왔다.
하지만, 드라이버는 커널에서 수행되기 때문에 왠만하면 전역변수가 페이징 되지 않는다.
확실한 non-paged 영역에 선언하는 방법은 DEVICE_EXTENSION에 있다.
- 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);
- ...
- }
이런 것이다.
결론을 알아보면, 어디에서든 드라이버가 이벤트 객체를 생성하는 사용 예를 흔하게 볼 수 있을텐데
만약 스와핑되어 버리면 ( SWAP-IN, SWAP-OUT을 의미한다. 페이징을 가리킨다 ) 이벤트 객체가 메모리
에 존재하지 않게 되어서, 상승된 IRQL에서 어떤 다른 스레드가 KeSetEvent()를 호출하려 하면, 버그 체크
가 발생하게 될 것이다.
즉, 자동 변수( auto-variable )로 선언하게 되면, 페이징이 되고, 함수 호출이 끝나버리면, 그 영역에 존재
하지 않게 된다. 즉 메모리에서 삭제 되거나, 물리메모리에서 디스크로 SWAP-OUT되버린 상태인 것이다.
흠, 좋아, 이제 머리가 쑥쑥 빨아들이는군,
다음에는 DISPATCH_LEVEL에 대해서 정리해봐야겠다.