Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

15192
888
89788


[리눅스커널][인터럽트] /proc/interrupts 메시지로 인터럽트 속성 보기 5장. 인터럽트 핸들링

리눅스 proc 파일 시스템에서 인터럽트 동작을 출력하는 기능을 지원합니다. proc/interrupts란 파일을 읽으면 인터럽트의 개수와 종류를 바로 파악할 수 있습니다.

/proc/interrupts 메시지로 인터럽트 속성 분석하기

라즈베리파이에서 터미널을 열고 다음 명령어로 /proc/interrupts 파일을 읽어 인터럽트 종류와 실행 횟수를 확인합시다. 
root@raspberrypi:/home/pi# cat /proc/interrupts

위 명령어를 입력하면 터미널에서 다음과 같은 출력 결과를 확인할 수 있습니다.
CPU0       CPU1       CPU2       CPU3        
16:          0          0          0          0  bcm2836-timer   0 Edge      arch_timer 
17:     129951     132772     128401     128648  bcm2836-timer   1 Edge      arch_timer 
21:          0          0          0          0  bcm2836-pmu     9 Edge      arm-pmu 
23:       1264          0          0          0  ARMCTRL-level   1 Edge      3f00b880.mailbox 
24:       1710          0          0          0  ARMCTRL-level   2 Edge      VCHIQ doorbell 
46:        137          0          0          0  ARMCTRL-level  48 Edge      bcm2708_fb dma 
48:          0          0          0          0  ARMCTRL-level  50 Edge      DMA IRQ 
50:          0          0          0          0  ARMCTRL-level  52 Edge      DMA IRQ 
51:       2375          0          0          0  ARMCTRL-level  53 Edge      DMA IRQ 
54:      32325          0          0          0  ARMCTRL-level  56 Edge      DMA IRQ 
59:          0          0          0          0  ARMCTRL-level  61 Edge      bcm2835-auxirq 
62:    1355025          0          0          0  ARMCTRL-level  64 Edge      dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1 
86:       8025          0          0          0  ARMCTRL-level  88 Edge      mmc0 
87:       5121          0          0          0  ARMCTRL-level  89 Edge      uart-pl011 
92:      52579          0          0          0  ARMCTRL-level  94 Edge      mmc1FIQ:

위 출력 메시지는 라즈베리파이 전체 인터럽트 종류와 실행 횟수입니다.
여러 인터럽트 중 23번 인터럽트 "3f00b880.mailbox" 인터럽트를 살펴보겠습니다.
         CPU0       CPU1       CPU2       CPU3        
23:     1264          0          0          0  ARMCTRL-level   1 Edge      3f00b880.mailbox 

우선 23은 인터럽트 번호이고 CPU0부터 CPU3은 CPU 별로 인터럽트가 발생한 횟수를 보여줍니다. CPU0에서 1264번 나머지 CPU1~CPU3에서는 0번 인터럽트가 발생했습니다.

Edge는 이 인터럽트를 식별하는 방식 중 하나입니다. Edge는 인터럽트 신호가 High<->Low로 떨어질 때 인터럽트가 발생했다고 식별합니다. 마지막으로 "3f00b880.mailbox"은 인터럽트 이름입니다.

show_interrupts() 함수 분석

이번에는 /proc/interrupts 파일로 인터럽트 세부 속성을 출력하는 show_interrrupts() 함수를 열어 보겠습니다. 분석할 코드는 다음과 같습니다. 
[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/irq/proc.c]
01 int show_interrupts(struct seq_file *p, void *v)
02 {
03 static int prec;
04
05 unsigned long flags, any_count = 0;
06 int i = *(loff_t *) v, j;
07 struct irqaction *action;
08 struct irq_desc *desc;
...
09 rcu_read_lock();
10 desc = irq_to_desc(i);
...
11 seq_printf(p, "%*d: ", prec, i);
12 for_each_online_cpu(j)
13 seq_printf(p, "%10u ", desc->kstat_irqs ?
14 *per_cpu_ptr(desc->kstat_irqs, j) : 0);
...
15 #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
16 seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
17 #endif
18 if (desc->name)
19 seq_printf(p, "-%-8s", desc->name);
20
21 action = desc->action;
22 if (action) {
23 seq_printf(p, "  %s", action->name);
24 while ((action = action->next) != NULL)
25 seq_printf(p, ", %s", action->name);
26 }

먼저 10번째 줄 코드를 보겠습니다.
10 desc = irq_to_desc(i);

인터럽트 번호인 i 인자로 irq_to_desc() 함수를 호출해서 인터럽트 디스크립터를 desc 변수에 저장합니다. irq_to_desc() 함수를 호출하면 인터럽트 번호에 해당하는 인터럽트 디스크립터를 얻을 수 있습니다. 

11번째 줄 코드에서는 인터럽트 번호를 출력하고 12번째와 13번째 코드로 각 CPU별로 발생한 인터럽트 횟수를 출력합니다. 
11 seq_printf(p, "%*d: ", prec, i);
12 for_each_online_cpu(j)
13 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));

16번째 코드는 인터럽트를 식별 방법을 확인해서 출력합니다.
16 seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");

다음은 인터럽트 이름을 출력하는 코드입니다. 
21 if (action) {
22 seq_printf(p, "  %s", action->name);
23 while ((action = action->next) != NULL)
24 seq_printf(p, ", %s", action->name);
25 }

23번째부터 25번째 줄은 하나의 인터럽트를 여러 이름으로 등록했을 때 인터럽트 이름을 출력하는 코드입니다.

"cat /proc/interrupts" 명령어를 입력하면 /proc/interrupts 파일을 통해 인터럽트 종류별로 실행 횟수를 출력합니다. 이 메시지를 출력하는 코드는 show_interrupts() 함수이며 인터럽트 디스크립터로 인터럽트 정보를 출력합니다.

여기서 한 가지 기억해야 할 점이 있습니다. 우리가 분석하는 커널 메시지는 리눅스 커널 코드가 실행하면서 출력하는 것입니다. 커널 로그에서 어떤 메시지를 보면 이를 어떤 코드에서 실행하는지 확인하면 더 많은 것을 얻을 수 있습니다.

# Reference (인터럽트 처리)



핑백

덧글

댓글 입력 영역