ISLab Flash Team Ch 12 DMA Drivers Ch
ISLab Flash Team Ch 12. DMA Drivers Ch 7. Driver Dispatch Routines
ISLab Flash Team Win 2 K 상에서 DMA가 동작하는 방법 Ch 7. Driver Dispatch Routines
Using DMA and Virtual Memory • DMA에 있어서 가상 메모리 사용 문제 – DMAC의 물리주소로의 맵핑(MDL: Memory Descriptor List) – Scatter/Gather 하드웨어 지원 문제 이것은 DMA 논리적 주소(Logical space)와 맵핑 레지스터로 해결 가상 메모리 공간 물리 메모리 공간 페이지 테이블 맵 레지 스터 Buffer DMA Controller Buffer 주소 카운트 ISLab Flash Team Ch 7. Driver Dispatch Routines 5 Made By ICEUNI
Memory Descriptor List(1) • MDL(Memory Descriptor List) 구조체 맵핑 레지스터에 물리적 주소 로드의 문제 해결 • I/O Manager에 의해 관리 – 디바이스 객체 Flags DO_DIRECT_IO – IRP Mdl. Address – 디바이스에게 IRP를 넘긴다. ISLab Flash Team Ch 7. Driver Dispatch Routines 7 Made By ICEUNI
Memory Descriptor List(2) 물리 메모리 가상 메모리 MDL Start. Va ` Byte. Offset ` Byte. Count Size Process Mapped. System. Va Phys Addr 1 Phys Addr 2 Phys Addr 3 <MDL의 구조체> ISLab Flash Team Ch 7. Driver Dispatch Routines 8 Made By ICEUNI
캐쉬의 일관성 유지(2) • CPU 데이터 캐쉬 Processor Control On-chip Caches Registers Speed: Fastest Size: Smallest Cost: Highest Off-chip Level Caches (SRAM) Main Memory (DRAM) Secondary storage • CPU 캐쉬 컨트롤러와 DMA 하드웨어가 서로 인식하지 못함. Inconsistency (Disk) Slowest • CPU 캐쉬상의 DMA 버퍼 일정 부분을 Flush Ke. Flush. Io. Buffers Biggest Lowest ISLab Flash Team Ch 7. Driver Dispatch Routines 11 Made By ICEUNI
패킷 기반과 공통 버퍼 DMA • 패킷 기반의 DMA : Direct I/O 관련 DMA • 공통 버퍼 방식의 DMA : nonpaged 버퍼를 사용 DMA • 패킷 기반의 DMA와 공통 버퍼 방식 DMA은 상호 연관적 – (예) Adaptec Ultra 160 계열 SCSI 호스트 어댑터 ISLab Flash Team Ch 7. Driver Dispatch Routines 13 Made By ICEUNI
ISLab Flash Team 어댑터 객체를 이용하여 작업하기 Ch 7. Driver Dispatch Routines
올바른 어댑터 객체 찾기(1) • Io. Get. Dma. Adapter함수를 호출 • PDMA_ADAPTER Io. Get. Dma. Adapter(pdo, p. Device. Description, Number. Of. Map. Registers) PDMA_ADAPTER Io. Get. Dma. Adapter IRQL == PASSIVE_LEVEL 인자 설명 IN PDEVICE_OBJECT pdo 디바이스를 위한 물리적 디바이스 객체에 대한 포 인터 IN PDEVICE_DESCRIPTION p. Device. Description DEVICE_DESCRIPTION 구조체에 대한 포인터 IN OUT PULONG Number. Of. Map. Registers 입력 : 요구되는 맵핑 레지스터들의 개수 출력 : 드라이버가 어떤 DMA 전송 동작을 위해 할당할 수 있는 맵핑 레지스터들의 최대 개수 리턴 값 DMA_ADAPTER에 대한 포인터 <Io. Get. Dma. Adapter 함수> ISLab Flash Team Ch 7. Driver Dispatch Routines 16 Made By ICEUNI
어댑터 객체를 얻어오고 해제하기(2) NTSTATUS Allocate. Adapter. Channel IRQL == DISPATCH_LEVEL 인자 설명 IN PDMA_ADAPTER p. Dma. Adapter Io. Get. Dma. Adapter에 의해 리턴되는 DMA 어댑터 객체 대한 포인터 IN PDEVICE_OBJECT p. Device. Object 타겟 DMA 디바이스 객체에 대한 포인터 IN ULONG Number. Of. Map. Registers 전송에 사용될 맵핑 레지스터들의 개수를 지정 IN PDRIVER_CONTROL Execution. Routine 시스템 DMA 컨트롤러나 버스 마스터 어댑터가 사용 가능할 때 바로 호출될 수 있는 드라이버가 제공하는 Adapter. Control 루틴에 대한 포 인터 IN PVOID p. Context Adapter. Control 루틴에 전달될 드라이버가 결정한 컨택스트에 대한 포 인터 Return STATUS_SUCCESS 또는 STATUS_INSUFFICIENT_RESOURCES <Allocate. Adapter. Channel의 함수 원형> IO_ALLOCATION_ACTION Adapter. Control IRQL == DISPATCH_LEVEL 인자 설명 IN PDEVICE_OBJECT p. Device. Object DMA 동작을 위한 타겟 디바이스 IN PIRP p. Irp 이 동작을 기술하는 IRP IN PVOID Map. Register. Base 맵핑된 레지스터들의 그룹에 대한 핸들 IN PVOID p. Context 드라이버가 결정한 컨텍스트 Return • Deallocate. Object. Keep. Registers • Keep. Object <Adapter. Control 루틴의 함수 원형> ISLab Flash Team Ch 7. Driver Dispatch Routines 19 Made By ICEUNI
어댑터 객체 캐쉬 플러쉬하기 • 데이터 전송의 마지막 단계 Flush. Adapter. Buffers BOOLEAN Flush. Adapter. Buffers IRQL <= DISPATCH_LEVEL 인자 설명 IN PDMA_ADAPTER p. Dma. Adapter Io. Get. Dma. Adapter에 의해 리턴되는 DMA 어댑터 객체에 대한 포인터 IN PMDL p. Mdl 버퍼를 기술하는 MDL IN PVOID Map. Register. Base Adapter. Control 에 전달되는 핸들 IN PVOID Current. VA 버퍼가 시작하는 가상 주소 IN ULONG Length 버퍼의 길이 IN BOOLEAN Write. To. Device TRUE – 동작이 출력일 때 FALSE – 동작이 입력일 때 Return TRUE – 어댑터 객체가 플러쉬되었을 때 FALSE – 에러가 발생했을 때 <Flush. Adapter. Buffers의 함수 원형> ISLab Flash Team Ch 7. Driver Dispatch Routines 21 Made By ICEUNI
ISLab Flash Team 패킷 기반의 슬레이브 DMA 드라이버 작성 Ch 7. Driver Dispatch Routines
패킷 기반의 슬래이브 DMA(1) • IRP_MN_START_DEVICE – DMA 채널을 획득. IRP stack Parameters. Start. Device. Allocated. Resources. Translated – DEVICE_DESCRIPTION 구조체 구성 – Io. Get. Dma. Adapter 호출 – Io. Get. Dma. Adapter 리턴된 DMA_OBJECT 포인터 디바이스 익스텐션 – 디바이스 객체의 Flags • if(Flags == DO_DIRECT_IO) then MDL 생성 ISLab Flash Team Ch 7. Driver Dispatch Routines 24 Made By ICEUNI
DMA 전송 나누기(1) • 첫번째 전송 p. Dev. Ext->transfer. VA = (PUCHAR)Mm. Get. Mdl. Virtual. Address(p. Irp->Mdl. Address); p. Dev. Ext->bytes. Remaining = (PUCHAR)Mm. Get. Mdl. Byte. Count(p. Irp->Mdl. Address); p. Dev. Ext->transfer. Size = p. Dev. Ext->byte. Remaining; map. Regs. Needed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(. . , . . ); p. Dev. Ext->transfer. VA, p. Dev. Ext->transfer. Size if(map. Regs. Needed > p. Dev. Ext->map. Regs. Available){ map. Regs. Needed = p. Dev. Ext->map. Regs. Available; p. Dev. Ext->transfer. Size = map. Regs. Needed * PAGE_SIZE - Mm. Get. Mdl. Byte. Offset(p. Irp->Mdl. Address); } //어댑터 객체의 사용을 주목 – Dma. Adapter //어댑터 동작을 위한 함수 포인터들을 갖고 있는 //Io. Get. Dma. Adapter에 의해 리턴되는 포인터 p. Dev. Ext->p. Dma. Adapter->Dma. Operations->Allocate. Adapter. Channel( p. Dev. Obj, map. Regs. Needed, Adapter. Control, p. Dev. Ext); Ch 7. Driver Dispatch Routines ISLab Flash Team 30 Made By ICEUNI
DMA 전송 나누기(2) • 추가 전송 p. Dev. Ext->bytes. Remaining -= p. Dev. Ext->transfer. Size; if(p. Dev. Ext->byte. Remaining > 0) { p. Dev. Ext->transfer. VA += p. Dev. Ext->transfer. Size; p. Dev. Ext->transfer. Size = p. Dev. Ext->byte. Remaining; map. Regs. Needed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(. . , . . ); p. Dev. Ext->transfer. VA, p. Dev. Ext->transfer. Size if(map. Regs. Needed > p. Dev. Ext->map. Regs. Available){ map. Regs. Needed = p. Dev. Ext->map. Regs. Available; p. Dev. Ext->transfer. Size = map. Regs. Needed * PAGE_SIZE - BYTE_OFFSET(p. Dev. Ext->transfer. VA); } p. Dev. Ext->p. Dma. Adapter->Dma. Operations ->Map. Transfer(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, p. Dev. Ext->transfer. VA, transfer. Size, p. Dev. Ext->b. Writing); } ISLab Flash Team Ch 7. Driver Dispatch Routines 31 Made By ICEUNI
ISLab Flash Team 예제 코드 : 패킷 기반의 슬레이브 DMA 드라이버 Ch 7. Driver Dispatch Routines
DRIVER. H typedef struct _DEVICE_EXTENSION {. . . PDMA_ADAPTER p. Dma. Adapter; ULONG map. Register. Count; ULONG dma. Channel; // Adapter. Control 콜백되었을 때 // 맵핑 레지스터들에게 할당된 핸들이다. PVOID map. Register. Base; ULONG byte. Requested; ULONG byte. Remaining; ULONG transfer. Size; PUCHAR transfer. VA; // 쓰기일 때는 이 플래그가 TRUE, 읽기는 FALSE BOOLEAN b. Writing; . . . } DEVICE_EXTENSION, *PDEVICE_EXTENSION; #define MAX_DMA_LENGTH 4096 ISLab Flash Team Ch 7. Driver Dispatch Routines 33 Made By ICEUNI
Get. Dma. Info 루틴 • Get. Dma. Info 에서 Io. Get. Dma. Adapter를 호출 • DEVICE_DESCRIPTION 구조체 설정 NTSTATUS Get. Dma. Info(IN INTERFACE_TYPE bus. Type, IN PDEVICE_OBJECT p. Dev. Obj){ PDEVICE_EXTENSION p. Dev. Ext = (PDEVICE_EXTENSION) p. Dev. Obj->Device. Extension; DEVICE_DESCRIPTION dd; // DEVICE_DESCRIPTION 구조체 선언 // DEVICE_DESCRIPTION 구조체의 값을 설정 Rtl. Zero. Memory(&dd, sizeof(dd)); dd. version = DEVICE_DESCRIPTION_VERSION 1; : // 이 디바이스가 필요로 할 수 있는 맵핑 레지스터들의 최대 개수를 계산한다. // 전송 데이터가 페이지 정렬이 되어있지 않을 수 있으므로 // 1을 더해서 최대 전송 크기를 한 페이지 크기만큼 늘린다. p. Dev. Ext->map. Register. Count = (MAX_DMA_LENGTH /PAGE_SIZE)+1; p. Dev. Ext->p. Dma. Adapter = Io. Get. Dma. Adapter(p. Dev. Obj, &dd, &p. Dev. Ext->map. Register. Count); : } ISLab Flash Team Ch 7. Driver Dispatch Routines 34 Made By ICEUNI
ISLab Flash Team 패킷 기반의 버스 마스터 DMA 드라이버 작성 Ch 7. Driver Dispatch Routines
버스 마스터 하드웨어 설정(1) • Adapter. Control 루틴 PHYSICAL_ADDRESS Dma. Address; PMDL p. Mdl = p. Irp-> Mdl. Address; p. Dev. Ext->transfer. VA = (PUCHAR) Mm. Get. Mdl. Virtual. Address(p. Mdl); p. Dev. Ext->transfer. Size = p. Dev. Ext->byte. Remaining = Mm. Get. Mdl. Byte. Count(p. Mdl); Dma. Address = p. Dev. Ext->p. Dma. Adapter->Dma. Operations-> map. Transfer(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, p. Dev. Ext->transfer. VA, &p. Dev. Ext->transfer. Size, p. Dev. Ext->b. Writing); // transfer. Size는 첫번째 세그먼트에 대한 최대 연속적인 길이 값으로 리셋된다. // write. Dma. Address는 DMA 주소 레지스터를 프로그램하는 디바이스 전용 루틴이다. write. Dma. Address(p. Dev. Ext, Dma. Address. Low. Part); // 비슷하게, Write. Dma. Count도 디바이스 전용이다. write. Dma. Count(p. Dev. Ext, p. Dev. Ext->transfer. Size); // 지금 디바이스를 시작 Start. Device(p. Dev. Ext); // 반드시 버스 마스터가 작업중이라고 표시하고 리턴 return Deallocate. Object. Keep. Registers; ISLab Flash Team Ch 7. Driver Dispatch Routines 37 Made By ICEUNI
버스 마스터 하드웨어 설정(2) • Dpc. For. Isr 루틴 PHYSICAL_ADDRESS Dma. Address; PMDL p. Mdl = p. Irp-> Mdl. Address; p. Dev. Ext->p. Dma. Adapter->Dma. Operations-> Flush. Adapter. Buffers(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, p. Dev. Ext->transfer. VA, &p. Dev. Ext->transfer. Size, p. Dev. Ext->b. Writing); p. Dev. Ext->bytes. Remaining -= p. Dev. Ext->transfer. Size; if(p. Dev. Ext->bytes. Remaining > 0) { p. Dev. Ext->transfer. VA += p. Dev. Ext->transfer. Size; p. Dev. Ext->transfer. Size = p. Dev. Ext->bytes. Remaining; Dma. Address = p. Dev. Ext->p. Dma. Adapter->Dma. Operations-> Map. Transfer(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, p. Dev. Ext->transfer. VA, & p. Dev. Ext->transfer. Size, p. Dev. Ext->b. Writing); Write. Dma. Address(p. Dev. Ext, Dma. Address. Low. Part); Write. Dma. Count(p. Dev. Ext, p. Dev. Ext->transfer. Size); // 지금 디바이스를 재시작 Start. Device(p. Dev. Ext); } ISLab Flash Team Ch 7. Driver Dispatch Routines 38 Made By ICEUNI
Scatter/Gather 지원 하드웨어 • Scatter/Gather 리스트 • 개별적인 Page table 하드웨어 <Scatter/gather 하드웨어를 가진 버스마스터 디바이스> 물리적 메모리 가상 메모리 C 버스 마스터 Scatter/Gather C 하드웨어 B B 주소 길이 : A+B A A 주소 길이 : C ISLab Flash Team Ch 7. Driver Dispatch Routines 39 Made By ICEUNI
Map. Transfer를 사용 Scatter/Gather 리스트 작성 • Adapter. Control 루틴(1) PHYSICAL_ADDRESS Dma. Address; ULONG bytes. Left. In. Buffer; ULONG segment. Size; ULONG map. Register. Index; PUCHAR segment. VA; PMDL p. Mdl = p. Irp->Mdl. Address; p. Dev. Ext->transfer. VA = Mm. Get. Mdl. Virtual. Address(p. Mdl); p. Dev. Ext->bytes. Remaining = Mm. Get. Mdl. Byte. Count(p. Mdl); p. Dev. Ext->transfer. Size = 0; byte. Left. In. Buffer = p. Dev. Ext->bytes. Remaining; segment. VA = p. Dev. Ext->transfer. VA; map. Register. Index = 0; ISLab Flash Team Ch 7. Driver Dispatch Routines 40 Made By ICEUNI
Map. Transfer를 사용 Scatter/Gather 리스트 작성 • Adapter. Control 루틴(2) while(map. Register. Index > p. Dev. Ext->map. Register. Count && bytes. Left. In. Buffer > 0){ // 전체를 위해 시도 segment. Size = bytes. Left. In. Buffer; Dma. Address = p. Dev. Ext->p. Dma. Adapter->Dma. Operations-> Map. Transfer(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, segment. VA, &segment. Size, p. Dev. Ext->b. Writing); // Write. Map. Register 디바이스 전용의 메소드이다. // scatter/gather 레지스터 한쌍을 프로그램 Write. Map. Register(p. Dev. Ext, map. Register. Index, Dma. Address. Low. Part, segment. Size); map. Register. Index++; // 다음 번 scatter/gather 쌍으로 이동 p. Dev. Ext->transfer. Size += segment. Size; segment. VA +=segment. Size; bytes. Leftin. Buffer -= segment. Size; } // 지금 디바이스를 시작 Start. Device(p. Dev. Ext); // 그리고 scatter/gather 레지스터가 사용중이라고 표시 return Deallocate. Object. Keep. Registers; Ch 7. Driver Dispatch Routines ISLab Flash Team 41 Made By ICEUNI
Map. Transfer를 사용 Scatter/Gather 리스트 작성 • Dpc. For. Isr 루틴(1) PHYSICAL_ADDRESS Dma. Address; ULONG bytes. Left. In. Buffer; ULONG segment. Size; ULONG map. Register. Index; PUCHAR segment. VA; PMDL p. Mdl = p. Irp->Mdl. Address; // 어댑터 객체 버퍼를 정리한다. Dma. Address = p. Dev. Ext->p. Dma. Adapter->Dma. Operations-> Flush. Adapter. Buffers(p. Dev. Ext->p. Dma. Adapter, p. Mdl, p. Dev. Ext->map. Register. Base, segment. VA, &segment. Size, p. Dev. Ext->b. Writing); p. Dev. Ext->byte. Remaining -= p. Dev. Ext->transfer. Size; ISLab Flash Team Ch 7. Driver Dispatch Routines 42 Made By ICEUNI
Map. Transfer를 사용 Scatter/Gather 리스트 작성 • Dpc. For. Isr 루틴(2) if(p. Dev. Ext->byte. Remaining > 0){ p. Dev. Ext->transfer. VA += p. Dev. Ext->transfer. Size; p. Dev. Ext->transfer. Size = 0; bytes. Left. In. Buffer = p. Dev. Ext->bytes. Remaining; segment. VA = p. Dev. Ext->transfer. VA; map. Register. Index = 0; while(map. Register. Index > p. Dev. Ext->map. Register. Count && bytes. Left. In. Buffer > 0){ : } // 그런 후 디바이스를 시작 Start. Device(p. Dev. Ext); } else { // 마지막 전송 동작이 완료된 후 맵핑 레지스터를 해제 p. Dev. Ext->p. Dma. Adapter->Dma. Operations->Free. Map. Registers(. . . ); // 그리고 IRP를 완료 Io. Complete. Request(. . . ); Io. Start. Next. Packet(. . . ); } ISLab Flash Team Ch 7. Driver Dispatch Routines 43 Made By ICEUNI
ISLab Flash Team 공통 버퍼 슬레이브 DMA 드라이버 작성 Ch 7. Driver Dispatch Routines
공통 버퍼 할당하기 • 공통 버퍼를 위한 메모리는 물리적으로 연속적이고 특정 디바이스의 DMA 논리적 영역 상에서 볼 수 있어야 한다. Allocate. Common. Buffer PVOID Allocate. Common. Buffer IRQL == PASSIVE_LEVEL 인자 설명 IN PDMA_ADAPTER p. Dma. Adapter Io. Get. Dma. Adapter에 의해 리턴되는 DMA_ADAPTER 구조체에 대한 포인터 IN ULONG Length 요구되는 버퍼에 대한 바이트 크기 OUT PPHYSICAL_ADDRESS Logical. Address DMA 컨트롤러의 논리적 공간 상에서의 공통 버퍼에 대한 주소 IN BOOLEAN Cache. Enabled TRUE – 메모리 캐쉬가 가능 FALSE – 메모리 캐쉬가 불가능 Return NULL이 아닌 경우 – 공통 버퍼에 대한 VA FALSE - 에러 <Allocate. Common. Buffer의 함수 원형> ISLab Flash Team Ch 7. Driver Dispatch Routines 45 Made By ICEUNI
ISLab Flash Team 공통 버퍼 버스 마스터 DMA 드라이버 작 성 Ch 7. Driver Dispatch Routines
ISLab Flash Team Summary Ch 7. Driver Dispatch Routines
Summary ISLab Flash Team Ch 7. Driver Dispatch Routines 56 Made By ICEUNI
- Slides: 56