460 likes | 648 Views
Ch 8. Interrupt I/O. Contents. Programed I/O 동작 방식 Driver Initialization and Cleanup Start I/O Routine 의 작성 Interrupt Service Routine 의 작성 DpcForIsr Routine 의 작성 Hardware Example : Parallel Port Example Code : Parallel Port Loopback Driver Testing The Parallel Port Loopback Driver
E N D
Contents • Programed I/O 동작 방식 • Driver Initialization and Cleanup • Start I/O Routine의 작성 • Interrupt Service Routine의 작성 • DpcForIsr Routine의 작성 • Hardware Example : Parallel Port • Example Code : Parallel Port Loopback Driver • Testing The Parallel Port Loopback Driver • Summary Ch 8. Interrupt I/O
Programmed I/O 동작(1) • IRP는 I/O Request처리를 위해 Device와 Data전송이 필요한지 판단 • Data 전송이 필요하면, Start I/O Routine에 전달하기 위한 IRP를 Queuing 함 • Start I/O Routine은 IRP의 Function Code에 기초해 전처리 작업과 설정작업 수행 후, I/O Process를 진행 • 수행후, Device는 Interrupt 발생, Kernel은 발생된 Interrupt를 Driver의 Interrupt Service Routine으로전달 • Device가 더 전송을 받아야 하면 ISR은 다음 전송 시작 모든 Data 전송이 끝날때 까지 3~4 지속적 반복 Ch 8. Interrupt I/O
Programmed I/O 동작(2) • 모든 전송이 끝나면, ISR은 DpcForIsr Routine을 시작하라는 Request를 DPC Queue에 삽입 • DPC Routine은 ISR보다 낮은 IRQL에서 실행 • I/O Manager의 DPC dispatcher는 ISR에 의해 예정된 DpcForIsr Routine을 실행 • DpcForIsr Routine은 IRP의 완료를 표시 • Queuing된 IRP를 Start I/O Routine에서 처리하도록 I/O Manager에게 통보 Ch 8. Interrupt I/O
Synchronization of Driver Routine ISR Start I/O DpcForIsr I/O Request Ch 8. Interrupt I/O
Synchronization of Driver Routine(3) • IRQL 기법에서는 Memory공유등의 상호배재를 해결해야함 • SynchCritSection Routine을 사용해 자원접근을 함 Ch 8. Interrupt I/O
Synchronization of Driver Routine(4) • KeSynchronizeExcution IRQL을 DIRQL까지 올리고, Spin Lock을 획득 • SynchCritSection Routine을 호출함 Ch 8. Interrupt I/O
Synchronization of Driver Routine(5) SynchCritSection 자원의 일시적인 독점 가능 DIRQL Context와 Routine add 전달 KeSynchronizeExecution SpinLock 획득 IRQL 상승 < DIRQL Ch 8. Interrupt I/O
Synchronization of Driver Routine(6) SynchCritSection DIRQL Return Value KeSynchronizeExecution SpinLock 반환 IRQL 복귀 < DIRQL Ch 8. Interrupt I/O
Initialization 해주지 않으면 IoStartPacket 호출시 접근위반 Error Initialize Start I/O Routine NTSTATUS DriverEntry(… … … … …) { : pDO->MajorFunction[ IRP_MJ_CREATE ] = DispCreate; : pDO->MajorFunction[ IRP_MJ_WRITE ] = DispWrite; : } NTSTATUS DriverEntry(… … … … …) { : pDO->FriverStartIO = StartIo; pDO->FriverUnload = DriverUnload; : pDO->MajorFunction[ IRP_MJ_WRITE ] = DispWrite; : } Ch 8. Interrupt I/O
Initialize DpcForIsr Routine • DPC Object와 각 Device Object를 연결시킬수 있음 • DpcForIsr • DpcForIsr 과 Device Object와 연관지을수 있음 • IoInitializeDpcRequest 호출 • 보통은 DriverEntry or AddDevice에서 해줌 • ISR Routine에서 Interrupt를 처리하는 동안 DPC를 Scheduling 함 • IoRequestDpc 호출 Ch 8. Interrupt I/O
Linking Interrupt Source to Kernel(1) • 실제 Interrupt Routine Address(ISR)를 Kernel에게 알림 • I/O Manager가 제공 • IoConnectInterrupt Function • ISR의 Address를 Parameter로 전달받음 • Interrupt Object를 Parameter로 전달받음 Ch 8. Interrupt I/O
Linking Interrupt Source to Kernel(2) • Interrupt Object 사용시 주의점 • ISR Routine이 하나이상의 Interrupt Vecter를 처리하거나 Driver가 하나 이상의 ISR을 가지고 있을 시 • Service Context 충돌을 피하기 위해 Spin Lock 사용 • SynchronizeIrql에 지정된 DIRQL Value는 Interrupt Vector가 가지는 DIRQL Value보다 커야함 • Driver Interrupt Routine은 IoConnectInterrupt 호출시 바로 실행가능한 상태로 준비되어 있어야함 • IoConnectInterrupt에서 지정된 IRQL에서 발생된 Interrupt는 Driver에 의해 수행되는 추가적인 초기화 작업을 선점할수도 있음 • ISR은 이러한 Interrupt를 제 때 처리할수 있어야 함 Ch 8. Interrupt I/O
Linking Interrupt Source to Kernel(3) • IoInitializeDpcRequest 호출후 DpcForIsr Routine 실행을 위한 초기화 작업 수행 • Device에서 Interrupt가 발생하지 않게 함 • Device에 적절한 Bit를 설정함 • Control register를 설정함 • ISR에서 요구하는 Driver의 초기화 수행 • IoConnectInterrupt를 호출 • ISR과 Interrupt Source를 연결 • Interrupt Object 주소를 Device Extension에 저장 • SynchCritSection Routine을 사용해 Device를 초기화 상태로 바꿈, Device가 Interrupt를 발생하게 함 Ch 8. Interrupt I/O
Unlinking Interrupt Source to Kernel • Driver가 Memory에서 Unload될 가능성이 있다면 • Memory에서 Unload 전에 Kernel과 Interrupt Souce연결 해제 • 만약 Unload 후에도 연결이 되어있다면, Device가 Interrupt 발생시 OS가 멈춤 • 두가지 절차를 따름 • KeSynchronizeExecution Function과 SynchCritSection Function을 사용해 Device를 정지 시킴. • Device에서 Interrupt 발생 불가 • IoDisconnectInterrupt Function 사용 • Device Interrupt Object를 Parameter로 넘겨주어 Kernel의 Interrupt Service Routine 목록에서 ISR 제거 Ch 8. Interrupt I/O
3. Start I/O Routine의 작성 Parallel Port 에서 사용되는 Programmed I/O Driver 개발에 관련
Execution Context • I/O Manager가 Start I/O 호출 • DISPATCH_LEVEL_IRQL에서 실행됨 • Paged Resource에 접근해 Page Fault를 발생하면 안됨 - StartIo Routine - Ch 8. Interrupt I/O
Start I/O Routine에서 하는 작업 • 현재 IRP의 Stack Location Pointer를 얻음 • IoGetCurrentIrpStackLocation 호출 • I/O Stack Location의 MajorFuntion Field를 확인하여 작업을 선택함 • IRP에 저장된 Bytes수와 System buffer Pointer를 저장 • Device Extension에 저장하면 좋음 • Device Extension에 Interrupt 발생 예상 Flag를 설정 • Device를 구동시킴 Ch 8. Interrupt I/O
Execution Context • Interrupt DIRQL과 관계된 Interrupt Object를 조사해 ISR을 찾아서 호출 • Kernel Interrupt dispatcher는 ISR을 호출 • 호출된 ISR은 IoConnectInterrupt를 호출할때 지정되었던 IRQL에서 수행 • ISR에서 해서는 안되는 작업(높은 IRQL때문에) • Page Fault 를 발생해서는 안됨 • System Resource를 할당,해제하려하면 안됨(ex. Memory) • 구지 해야한다면, DPC Routine에게 위임 Ch 8. Interrupt I/O
Interrupt Service Routine에서 하는 작업 • 발생된 Interrupt가 해당 Driver에 관련된것인지 확인 • Interrupt를 인식한 Device에 필요한 작업 요청 • 전송할 Data가 더 있으면, 다음 작업 시작 • 결국 다른 Interrupt를 발생시키는 결과 • Data 전송이 완료되거나 Error발생시 IoRequestDpc를 호출하여 DPC Request를 Queuing 함 • TRUE Return Ch 8. Interrupt I/O
Execution Context(1) • Driver에서의 DpcForIsr Routine의 임무 • 현재 IRP의 최종상태를 확인 • IRP를 완료후 다음 IRP 시작 • ISR이 IoRequestDpc를 호출하면 DpcForIsr Routine은 DPC Queue에 Queuing 됨 • DcpForIsr Routine은 DISPATCH_LEVEL_IRQL 수준에서 실행 • Paging되는 주소에 접근할수 없다는 의미가 됨 • I/O Manager는 DpcForIsr이 실행될때까지 주어진 Device에 대한 DPC Request(IoRequestDpc)를 무시 Ch 8. Interrupt I/O
Execution Context(2) - DpcForIsr Routine - Ch 8. Interrupt I/O
DpcForIsr Routine에서 처리하는 작업 • IRP의 I/O 상태를 설정, Status 변수 설정, Information변수에 실제 전송된 Bytes수를 설정 • 적절한 우선순위값 설정후 IoComplateRequest 호출 • IRP를 완료하게 됨 • IoComplateRequest가 호출되면 IRP에서는 어떤작업도 다시 수행해선 안됨 • Start I/O Routine에 다음 IRP를 전달하기 위해 IoStartNextPacket을 호출 Ch 8. Interrupt I/O
우선순위 증가 • Windows 2000의 Thread Manager는 효율적 운영을 위해 우선순위값 사용 • Starvation 방지를 위해 우선순위를 증가시켜줌 • IoComplateRequest 호출시 Parameter로 넘겨줌 • Mouse나 Keyboard같은 Device에 우선순위를 중시하여 가중치를 줌 Ch 8. Interrupt I/O
Parallel Port • RESET • Device를 초기화 시키고 싶을때 CPU가 이 Line을 통해 전송 • DATA • CPU가 정보를 parallel 하게 전송할수 있는 Line • STROBE# • CPU가 DATA Line에 보낼 정보가 있다는 신호를 보냄 Ch 8. Interrupt I/O
Parallel Port • BUSY • CPU에게 DATA를 받을수 없다는 것을 Device가 알림 • ACK# • Device가 BUSY 상태를 벗어났음을 알림 • Errors • Device가 CPU에게 준비상태 or Error상태를 알려지기 위한 몇 개의 Line Ch 8. Interrupt I/O
Parallel Port의 동작 순서 • CPU는 DATA Line에 data를 준비하고, 적어도 0.5ms을 기다림 • CPU는 STROBE# Line을 적어도 0.5ms정도 0을 유지한뒤 1로 올림 • Device에게 신호를 받으라는 신호임 • 새로운 Data가 오면 Device는 BUSY Line을 1로 바꿈 • Device가 전송을 받기 시작함 • 한 단위를 처리한뒤 BUSY Line을 0으로 ACK# Line을 1로 바꿈 Ch 8. Interrupt I/O
Device Register • 세개의 Register를 통해 정보를 주고 받음 • Data Register • Status Register • Control Register • Parallel Port 는 자동 설정을 지원함 • Configuration Manager가 Data Register의 기본주소를 찾아줌 Ch 8. Interrupt I/O
Interrupt의 발생 • Ex) Printer 가 Interrupt를 발생시키는 시기 • 초기화 작업을 마칠 때 • 한 문자를 처리하고 다음 문자를 처리할 준비가 되었을 때 • 전원이 변경되었을 때 • 종이가 없거나 연결이 되지 않았을 때 Ch 8. Interrupt I/O
Purpose of this Driver • Loopback Connector가 부착된 Parallel Port에 4Bits를 전송함 • Loopback Connector에 의해 Return 된 Data는 Driver의 임시 Buffer에 저장 • 때문에 읽기 작업은 전송한 4Bits와 동일함 • 추가로 4Bits를 Left Shift 한 상태로 Return 함 Ch 8. Interrupt I/O
Driver.h typedef struct _DEVICE_EXTENTION { PDEVICE_OBJECT pDevice; ULONG DeviceNumber; CUString ustrDeviceName; // 내부 Device Name CUString ustrSymLinkName; // SymbolicLinkName PUCHAR deviceBuffer; // 임시 Buffer ULONG deviceBufferSize; ULONG xferCount; // 현재 전송 Count ULONG maxXferCount; // 요청된 전송 Count ULONG portBase; // I/O register Addr ULONG Irq; // Parallel Port IRQPKINTERRUPT pIntObj; // Interrupt Object } DEVICE_EXTENSION, *PDEVICE_EXTENSION Ch 8. Interrupt I/O
Driver.cpp(1) • CREATEDEVICE • PnP 이전에 연결된 Device를 인식하기 위한 역할 • ClaimResources Function을 사용 • DISPATCHWRITE • Start I/O Routine에 진입할 IRP를 순서대로 대기열에 삽입 • DISPATCHREAD • Device Buffer의 Data를 사용자 Buffer에 Return Ch 8. Interrupt I/O
Driver.cpp(2) • STARTIO • IRP가 대기열에서 빠져나올때 마다 I/O Manager에 의해 호출 • DispatchWrite에서 시작된 작업을 완결시킴 • ISR • 사용자의 출력 buffer에 마지막 Bytes가 Printer Port에 전송되면 DpcForIsr Routine을 사용해 IRP를 완료 • DPCFORISR • ISR의 Request에 따라 I/O Request를 완료 Ch 8. Interrupt I/O
Conclusion of Testing • IRP를 dispatch Routine에서 Start I/O Routine으로 전송 • Device Interrupt에 반응 • Data를 성공적으로 전송 • Request를 완료 • Multiple User로 부터 Request를 관리 Ch 8. Interrupt I/O
Test Program 작성 절차 • 각각의 IRP가 도착하자마자 완료되는 단순한 Start I/O Routine을 작성 • Driver의dispatch Routine과 Start I/O Routine사이의 연결확인 • 실제 Start I/O, ISR 그리고 DpcForIsr Routine 작성 • Driver가 Read, Write를 모두 지원한다면 두 작업을 나누어 구현해 Test • Driver의 모든 Data전송 경로 Test • ReadFile , WriteFile 그리고 DeviceIoControl을 호출하는 간단한 Win32 프로그램을 사용 • 최대한 빨리 많은 수의 I/O Request를 발생시키는 Program을 이용해 Driver의 극단적인 상황을 Test Ch 8. Interrupt I/O
Test Program 작성 절차 • 한번에 여러 개의 Test Program을 실행 • Device가 여러 Program에서 공유된다면 다수의 Handle에서 작동이 원활해야함 • Driver가 다수의 Physical Device를 지원한다면 각 Device와 Test를 반복 • Multiprocessor 환경에서 4~6과정 반복 • SMP 동기화를 검증하기 위함 Ch 8. Interrupt I/O
Summary • 실제로 동작하는 Driver의 기본 골격을 제시 • Start I/O Routine은 각각의 Request을 초기화하고 ISR에서 Interrupt를 처리 • DpcForIsr Routine은 Device의 DIRQL이하에서 IRP를 올바르게 완료 Ch 8. Interrupt I/O