Buffered I/O 방식
운영체제는 유저의 어플리케이션 버퍼와 같은 사이즈의 Non페이지한 시스템 버퍼를 할당한다. 쓰기 작업이 발생할 때는
드라이버 스택을 호출하기 전에 I/O 관리자는 유저의 데이터를 시스템 버퍼에 복사한다. 읽기 작업이 발생할 때는
드라이버 스택의 요청 작업이 완료된 후 시스템 버퍼를 유저 영역에 복사 한다
즉, 유저 영역의 데이터를 드라이버의 버퍼로 가져올 때, 드라이버 스택 전에 복사를 마친후 호출한다
[유저 -> 시스템 버퍼(IRP)]
반면에 시스템 드라이버의 버퍼에서 유저 영역의 버퍼로 데이터를 복사할 때는 드라이버에서의 활동이 모두 마친 후, 유저 영역의 데이터로 복사
[시스템 버퍼-> 유저]
서비스와 상호 동작하거나 느린 디바이스 또는 한번에 상대적으로 적은 양의 데이터를 주고받는 드라이버의 경우에
buffered I/O 전송 방식을 사용한다. 작은양의 buffered I/O 방식을 사용하면 상호 동작하는 전송에 있어서 적은 양의 물리 메모리를
소비해도 가능하다. 그 이유는 메모리 관리자는 이 buffed I/O 방식을 위해서 매번 통신 할 때 마다 할당된 메모리를 락(lock)할 필요가 없다.
direct I/O 방식과는 다르게 위와 같은 장점이 있다. 일반적으로 비디오, 키보드 마우스, 가상 드라이버들이 buffered I/O 방식을 사용
요약 : 데이터를 전달 할 때마다 페이지를 할당하고 lock(해당 데이터 전달을 위해서 메모리를 묶어 놓는 방식)하지 않고
적은양의 데이터 송/수신에 사용한다.
I/O Manager는 아래와 같은 상황일 때 I/O 작동이 buffered I/O 방식을 사용한다고 함.
- IRP_MJ_READ, IRP_MJ_WRITE 요청에 대해서 Device Object에서의 flag인 DO_BUFFERED_IO가
설정되어 있을 때 buffered I/O 방식 사용
- IRP_MJ_DEVICE_CONTROL 과 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청에 대해서 IOCTL의 전송 타입이
METHOD_BUFFERED일 때 buffered I/O 방식 사용
아래 설명하는 내용은 IRP_MJ_READ 요청에 대해서 설명하는 내용이다.
위의 그림은 Read 요청에 관해서 드라이버가 IRP에 존재하는 SytemBuffer를 이용해서 어떻게 데이터를 전송하는지 보여준다.
위의 드라이버가 생성한 디바이스 오브젝트의 Flag의 값은 DO_BUFFERED_IO이다.
1. 유저 영역의 가상 메모리는 현재의 스레드 버퍼를 가지고 있을 것이다. 해당 스레드 버퍼의 데이터일 경우
페이징 기반 물리 주소의 범위 내에 존재할 것이다.
2. I/O 관리자는 현재 스레드의 읽기 요청을 도와준다(Service). 스레드는 현재 버퍼의 유저 메모리 영역의 주소를 I/O 관리자에게 넘겨준다.
3. I/O 관리자는 유저가 제공한 버퍼에 접근가능 한지 확인 한 후, ExAllocatePoolWithTag함수를 호출해서 논 페이지한 시스템 버퍼인
SystemBuffer를 할당한다. 이때 사이즈의 크기는 유저에서의 버퍼 크기와 동일하다.
4. I/O 관리자는 드라이버에 전송된 IRP가 할당되어 있는 시스템 버퍼에 접근 할 수 있게한다.
[위에서 할당한 시스템 버퍼와 IRP의 System Buffer의 연결 개념]
5. 드라이버는 디바이스에 존재하는 데이터를 시스템 버퍼로 데이터를 읽어 들인다. 해당 시스템 버퍼의 경우
Non 페이징하고 해당 메모리에 lock 없이 안전하게 접근할 수 있다.
그리고 해당 읽기 과정이 끝이 나면, 드라이버는 IRP에 IoCompleteRequet를 호출한다.
6. 이제 유저 영역의 스레드가 동작할 때, I/O 관리자는 시스템 버퍼로부터 유저 버퍼로 데이터를 읽어들인다.
그리고 ExFreePool 함수를 호출해서 시스템 버퍼를 해체한다.
[출처] https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/methods-for-accessing-data-buffers
'reversing > Windows Driver' 카테고리의 다른 글
I/O Control Codes [IOCTL] 정리 (0) | 2017.08.09 |
---|---|
MDL(Memory Descriptor List)[1] (1) | 2017.08.08 |
WinDBG 명령어 [CallStack] (0) | 2017.08.08 |
IRP, I/O Stack 관련 내용 정리 [3] (0) | 2017.08.04 |
IRP, I/O Stack 관련 내용 정리 [2] (0) | 2017.08.04 |