Objectives
- 주변장치와의 소통
- Interrupt Handler 구현
- Synchronizing interrupts with Process Context
Intro
Background Information
I/O Ports
- Definition: set of I/O addresses
- can be mapped to physical memory addresses → communicate directly with the device through instructions
- port is differentiated by the number of bits: 8, 16, 32 bit ports
- Types
- Control registers: receive device commands
- Status registers: contains device’s internal status information
- Input registers: data is taken from the device
- Output registers: data is written to transmit it to the device
- Example
- Parallel Port has eight ports (each port: 8bits).
- Data Log @base:
0x378
- both entry & exit log
- Status Register @base+1:
0x379
- Control Register @base+2:
0x37a
IRQ (Interrupt ReQuest)
-
I/O ports or Special memory areas can be insufficient to control the device
-
Polling Inefficiency: interrogating the device status repeatedly
-
Objective: 특정 event가 일어났을 때, hardware가 event가 일어났음을 알려줌
-
To make use..
- Interrupt Handlers must be implemented
- Interrupts must be requested before use and released after use.
- Device Drivers must
- share an interrupt or
- synchronize with interrupts
-
Accessing shared resources
- between an interrupt routine
Accessing the hardware
1. Request Access to I/O Ports
Example
- COM1
- Base Address:
0x3F8
- has 8 ports
- Base Address:
Requesting access
Releasing access
List Port Requests
$ sudo cat /proc/ioports
0000-001f : dma1
0020-0021 : pic1
0040-005f : timer
0060-006f : keyboard
0070-0077 : rtc
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : ide1
01f0-01f7 : ide0
0376-0376 : ide1
0378-037a : parport0
037b-037f : parport0
03c0-03df : vga+
03f6-03f6 : ide0
03f8-03ff : serial
...
2. Accessing I/O Ports (Kernel Space)
asm/io.h
signature | comments |
---|---|
unsigned inb(int port) | reads one byte (8 bits) from port |
void outb(unsigned char byte, int port) | writes one byte (8 bits) to port |
unsigned inw(int port) | reads two bytes (16-bit) ports |
void outw(unsigned short word, int port) | writes two bytes (16-bits) to port |
unsigned inl (int port) | reads four bytes (32-bits) from port |
void outl(unsigned long word, int port) | writes four bytes (32-bits) to port |
- To insert delay (in case I/O operations transferring data too fast which occurs problems), insert
_p
such asinb_p
,outb_p
, etc.
Example
3. Accessing I/O ports (User Space)
sys/io.h
Example
Interrupt Handling
Requesting an interrupt
request_irq
& free_irq
handler function is executed in interrupt context..
- we can’t call blocking APIs(
mutex_lock()
ormsleep()
) - avoid doing a lot of work & use deferred work if needed
- read the device register to get the status of the device and acknowledge the interrupt
- operations that most of the time can be performed with non-blocking calls
request_threaded_irq
device에서 interrupt 발생해도 non-blocking mode에서 device register 읽을 수 없는 상황 존재..
이런 경우에 work-in-process action (ex. work queue, kernel thread)를 이용하여 device register에 접근해야 함.
request_threaded_irq
이용하면 process-phase 혹은 interrupt context phase에서 interrupt handling 을 수행할 수 있음.
handler
: interrupt context에서 수행할 functionthread_fn
: process context에서 수행할 function
flags
IRQF_SHARED
: interrupt can be shared with other devices.- if not set, if there’s already a handler associated with the requested interrupt, the request for interrupt will fail
- all the associated interrupt handlers will be executed until the device that genet
IRQF_ONESHOT
:
Reference
Implementing an interrupt handler
Interrupt Handler Function Signature
Reference
Locking
- interrupt handler들은 interrupt context에서 실행되기 때문에 다음과 같은 실행 가능한 동작들이 제한된다.
- user space memory 접근 불가
- blocking function 호출 불가
- spinlock 이용한 synchronization 까다롭고 deadlock 만들 수 있음 (spinlock used is already acquired by a process that has been interrupted by the running handler)
- 하지만, spinlock 이용하는 경우 있음…
- interrupt handler - process context 사이에서 데이터 공유
- interrupt handler - bottom-half handler 사이에서 데이터 공유
- 이런 경우에는 interrupt를 끄고 spinlock을 써야됨..
- Disabling Interrupts
- processor level에서 모든 interrupt 끄기.. faster & preferred
- interrupt controller level에서 특정 interrupt 끄기
Disabling All Interrupts at Processor level
-
read_lock_irqsave()
-
read_unlock_irqrestore()
-
read_lock_irq()
-
read_unlock_irq
-
write_lock_irqsave()
-
write_unlock_irqrestore()
-
write_lock_irq()
-
write_unlock_irq()
Disabling Particular Interrupt at Interrupt Controller level
disable_irq()
disable_irq_nosync()
: async versionenable_irq()