Linux Kernel(4.14) Hacks

rousalome.egloos.com

포토로그 Kernel Crash




[라즈베리파이] 인터럽트 디버깅 - proc/interrupts #CS [라즈베리파이][커널]인터럽트

새로운 리눅스 시스템을 접했을 때 인터럽트의 개수와 종류를 바로 파악하려면 proc 파일 시스템을 활용할 필요가 있습니다.

그럼 라즈베리안에서 인터럽트 종류와 개수를 바로 알려면 어떤 명령어를 입력해야 할까요? 우선 리눅스 커널 proc 파일 시스템이 알려주는 인터럽트 정보(/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번 인터럽트가 발생했다고 말해주는군요.

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

그럼 위와 같은 정보를 출력하는 함수는 어디일까요? 정답은 show_interrupts 함수입니다. 그럼 show_interrupts 함수에서 어떻게 위와 같은 정보를 출력하는지 예외 처리 코드를 제외하고 핵심 코드만 살펴볼까요?
[kernel/irq/proc.c]
1 int show_interrupts(struct seq_file *p, void *v)
2 {
static int prec;
4
5 unsigned long flags, any_count = 0;
6 int i = *(loff_t *) v, j;
7 struct irqaction *action;
8 struct irq_desc *desc;
//..
9 irq_lock_sparse();
10 desc = irq_to_desc(i);
//..
11 seq_printf(p, "%*d: ", prec, i);
12 for_each_online_cpu(j)
13 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
14
//...
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 if (action) {
22 seq_printf(p, "  %s", action->name);
23 while ((action = action->next) != NULL)
24 seq_printf(p, ", %s", action->name);
25 }

다음 코드는 인터럽트 번호인 i 인자를 받아 인터럽트 디스크립터를 받습니다. irq_to_desc 함수는 인터럽트 번호로 해당 인터럽트 디스크립터를 알아낼 수 있으니 참 유용한 일을 하네요.
10 desc = irq_to_desc(i);
 
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");
 
다음은 인터럽트 이름을 출력하는 코드입니다. 
23번째부터 25번째 줄 코드는 하나의 인터럽트를 여러 이름으로 등록할 수 있는데 이 정보를 확인하기 위한 코드입니다.
21 if (action) {
22 seq_printf(p, "  %s", action->name);
23 while ((action = action->next) != NULL)
24 seq_printf(p, ", %s", action->name);
25 }

/proc/interrupts 파일에서 인터럽트 정보를 확인했습니다. 여기서 한 가지 기억해야 할 점이 있는데요. 우리가 보는 커널 메시지나 디버깅 정보는 리눅스 커널 코드에서 출력해주는 것입니다. 따라서 해당 로그가 메시지를 리눅스 커널의 어떤 코드가 실행하면서 출력하는지 살펴보면 더 많은 것을 얻을 수 있습니다.


핑백

덧글

댓글 입력 영역