본문 바로가기

Programming/Linux_Kernel

local_irq_disable(), local_irq_save(flags) 분석

두 함수를 비교하고, local_irq_disable()대신 local_irq_save(flags)를 쓰는 이유를 알아보자.


local_irq_disable

#define local_irq_disable() \

       do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)


#define raw_local_irq_disable()                arch_local_irq_disable()


static inline void arch_local_irq_disable(void)

{

       unsigned long temp;

       asm volatile(

               "        mrs        %0, cpsr        @ arch_local_irq_disable\n" // cpsr 을 읽어서 %0 에 저장

               "        orr        %0, %0, #128\n"                                // 7번째비트(128)를 or 시킴

               "        msr        cpsr_c, %0"                                        // %0 값을 다시 cpsr_c 에 저장

               : "=r" (temp)                                                        // %0 은 temp 를 사용 (확실치 않음)

               :

               : "memory", "cc");

}



local_irq_save(flags)

#define local_irq_save(flags)                                \

       do {                                                \

               raw_local_irq_save(flags);                \

               trace_hardirqs_off();                        \

       } while (0)

       

#define raw_local_irq_save(flags)                        \

       do {                                                \

               typecheck(unsigned long, flags);        \

               flags = arch_local_irq_save();                \

       } while (0)

       

static inline unsigned long arch_local_irq_save(void)

{

       unsigned long flags, temp;


       asm volatile(

               "        mrs        %0, cpsr        @ arch_local_irq_save\n" // cpsr 을 읽어서 %0 에 저장

               "        orr        %1, %0, #128\n"                     // 7번째비트(128)를 or 시킨 값을 %1에 저장 

               "        msr        cpsr_c, %1"                           // %1의 값을 cpsr_c 에 저장

               : "=r" (flags), "=r" (temp)                               // %0 은 flags 를 사용, %1 은 temp 를 사용

               :

               : "memory", "cc");

       return flags;

}


쓰는 이유에 대해 설명한 글

원문 : http://kldp.org/node/29163


질문 1의 답변임다. 혹 틀리더라도 비난은 자제 -.-
local_irq_save() 함수를 알기전에 cli()라는 함수를 알아야 합니다.

cli 는 clear Interrupt 의 약자로서 CPU 가 interrupt signal을 받더라도
이를 무시하도록 하는 것입니다. 하드웨어 인터럽트와 소프트웨어 모두다
입니다.

이를 통해 synchronization 문제를 해결합니다.
data corruption 을 막는 거죠.

cli 로 critical region 을 보호한 후 sti 로 interrupt signal 받아들이도록
세팅해주어야 합니다.

문제는 sti 로 인터럽트를 받아들이기로 세팅하면 cli 호출
전에 인터럽트를 받아
들이기로 한것인지 아닌지를 깡그리 무시한채 sti 세팅합니다.
cli 호출 전에 인터럽트를 받아들이는 상태였다면 다행이지만
인터럽트 무시 상태였다면 sti 호출후 상태가 틀려지게 되죠.
즉 cli 함수 사용전의 인터럽트 관련 세팅 상태가 원상복귀
되지 않는거죠.

그래서 사용하는 것이 local_irq_save() 함수 입니다.

패러미터로 들어가는
flag 변수(스택에 존재)에 
현재 인터럽트 관련 플래그를 저장하는 IF 라는 레지스터
정보를 저장합니다.

cli 가 sti 와 짝을 이루듯 local_irq_save 는 local_irq_restore 와
짝을 이룹니다. local_irq_restore 함수가 호출되면서
flag 변수에 저장되었던 것을
다시 IF 레지스터에 넣는거죠.

그러면 local_irq_save 전의 인터럽트 관련 세팅 상태로 원상복귀됩니다.



즉, irq 를 disable 했다가 다시 enable 할건데,

그전의 상태로 원복해야 하기 때문에, enable/disable 상태를 cpsr 로 부터 read 해서 flags 에 저장한 후 원복시킴


'Programming > Linux_Kernel' 카테고리의 다른 글

__builtin_return_address(0)  (0) 2013.11.28
kernel log back ground 로 저장하기  (0) 2013.11.27
CPSR  (0) 2013.10.31
arm 에서의 linux process 와 thread  (0) 2013.10.23
linux process memory usage  (0) 2013.10.22