Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

9365
557
421924


[리눅스커널] softirq: SOFTIRQ_MASK의 정체 6. 인터럽트 후반부 처리

SOFTIRQ_MASK 분석하기 

SOFTIRQ_MASK 가 어떤 값인지 알아보기 위해 이 플래그의 선언부를 확인해봤습니다.
다음은 SOFTIRQ_MASK의 선언부입니다.

https://elixir.bootlin.com/linux/v4.19.30/source/include/linux/preempt.h
#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)

#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)

보시다시피 SOFTIRQ_MASK 매크로는 __IRQ_MASK, SOFTIRQ_BITS, SOFTIRQ_SHIFT와 같이 생소한 매크로로 구성돼 있어 바로 어떤 값인지 확인하기 어렵습니다.
그래서 각각의 매크로의 선언부를 따라 가다 보면 시간이 오래 걸리는 경우가 많습니다.

SOFTIRQ_MASK 매크로를 확인하기 위한 패치 코드

그래서 SOFTIRQ_MASK 매크로의 정체를 빨리 확인하기 위해 다음과 같은 패치 코드를 생성해봤습니다.

diff --git a/kernel/softirq.c b/kernel/softirq.c
index 6f58486..acde648 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -246,6 +246,15 @@ static inline bool lockdep_softirq_start(void) { return false; }
 static inline void lockdep_softirq_end(bool in_hardirq) { }
 #endif

+int __find_softirq_mask(int param)
+{
+       int result = 0;
+
+       result = param & SOFTIRQ_MASK;
+
+       return result;
+}
+
 asmlinkage __visible void __softirq_entry __do_softirq(void)
 {
        unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -256,6 +265,9 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
        __u32 pending;
        int softirq_bit;

+       if (__find_softirq_mask(max_restart))
+                       return;
+
        /*
         * Mask out PF_MEMALLOC s current task context is borrowed for the
         * softirq. A softirq handled such as network RX might set PF_MEMALLOC

여기서 주의 사항은 소스를 빌드한 후 리눅스 시스템에는 절대 설치하면 안됩니다.  
 
SOFTIRQ_MASK 매크로를 전처리 코드에서 확인하기 
 
위에서 보이는 패치를 반영한 후 커널을 빌드해서 전처리 파일을 확인해 봤습니다. 
다음 코드를 같이 볼까요?

out/kernel/.tmp_softirq.i
int __find_softirq_mask(int param)
{
 int result = 0;

 result = param & (((1UL << (8))-1) << (0 + 8));

 return result;
}

위 코드에서 보이듯 SOFTIRQ_MASK의 정체는 '(((1UL << (8))-1) << (0 + 8))' 임을 알 수 있습니다.
(((1UL << (8))-1) << (0 + 8)) 구문을 계산하려고 하니 짜증이 나는군요.

SOFTIRQ_MASK 매크로를 어셈블리 코드로 확인하기 

이번에는 __find_softirq_mask() 함수를 어셈블리 코드로 분석해보겠습니다. 다음 코드를 같이 보겠습니다. 

______addr/line|code______|label_________________|mnemonic________________|comment
01   NSR:801244AC|E1A0C00D   __find_softirq_mask:   cpy     r12,r13
02   NSR:801244B0|E92DD800                          push    {r11-r12,r14,pc}
03   NSR:801244B4|E24CB004                          sub     r11,r12,#0x4     ; r11,r12,#4
04   NSR:801244B8|E52DE004                          push    {r14}
05   NSR:801244BC|EBFFAE15                          bl      0x8010FD18       ; __gnu_mcount_nc
06   NSR:801244C0|E2000CFF                          and     r0,r0,#0xFF00    ; r0,r0,#65280
07   NSR:801244C4|E89DA800                          ldm     r13,{r11,r13,pc}

06번째 줄을 보면 'and     r0,r0,#0xFF00' 구문이 보입니다. 즉, SOFTIRQ_MASK의 정체는 0xFF00입니다.
'param & SOFTIRQ_MASK' 구문은 어셈블리 코드 포멧으로 'and     r0,r0,#0xFF00' 명령어이기 때문입니다.

결론 

C 포멧의 소스 코드보다 어셈블리 코드를 분석할 때 매크로의 정체를 빨리 파악할 수 있습니다.
이처럼 어셈블리 코드를 읽으면 더 빨리 코드를 읽을 때도 있습니다.


덧글

댓글 입력 영역