'handling'에 해당되는 글 2건

  1. 2010.03.10 hotplug signal handling in linux (4)
  2. 2008.06.05 ARM9 Exception handling에 대한 또다른 이야기

Linux kernel에서 usb-storage 등을 꽂으면 자동으로 인식되어 mount까지 되는 것을 볼 수 있는데, 이것을 hotplug라고 한다.  Hotplug가 일어나는 과정은 대략 다음과 같이 기술할 수 있다.

1. 장비 꽂음

2. Kernel의 interrupt routine을 거친 후 kobject에서 인식

3. uevent가 발생하고 user application인 hotplug routine 실행

따라서 이러한 hotplug signal을 받아낼 수 있다면 새로운 장치가 인식되었을 때에 원하는 작업을 수행할 수 있게 된다.  이 문서에서는 이를 가능하게 하는 방법을 기술하는 것을 목표로 한다.

Kernel 2.6.17에서 uevent에 관련된 정보는 lib/kobject_uevent.c에서 찾아볼 수 있다.

void kobject_uevent (struct kobject *kobj, enum kobject_action action)

{

  char **envp;

  char *buffer;

  char *scratch;

  const char *action_string;

  const char *devpath = NULL;

  const char *subsystem;


  ...

 

  /* call uevent_helper, usually only enabled during early boot */

  if (uevent_helper[0]) {

    char *argv[3];

  

    argv[0] = uevent_helper;

    argv[1] = (char *) subsystem;

    argv[2] = NULL;

    call_usermodehelper (argv[0], argv, envp, 0);

    /* send signal to detect daemon routine end */.

  }

  

  ...

}


모든 routine이 실행되고 마지막으로 call_usermodehelper ()를 호출하여 user 영역의 application을 실행한다.  현재 uevent_helper는 “/sbin/hotplug”이다.

따라서, signal을 받기 원하는 daemon에게 이러한 signal을 전달해줄 user application을 작성하고, 이 uevent_helper에 등록하면 실행될 것이다.  여기서는 이러한 user application이 /root/detect_test라고 가정하도록 하겠다.

...


  /* call uvent_helper, usually only enabled during early boot */

  if (uevent_helper[0]) {

    char *argv[3];


    argv[0] = uevent_helper;

    argv[1] = (char *) subsystem;

    argv[2] = NULL;

    call_usermodehelper (argv[0], argv, envp, 0);


    /* edit part start */

    if (0 == strcmp (“mount”, action_string) || 0 == strcmp (“unmount”, action_string)) {

      argv[0] = “/root/detect_test”;

      call_usermodehelper (argv[0], argv, envp, 0);

    }

    /* edit part end */


    /* send signal to detect daemon routine end */

  }

  

  ...

}


이렇게 작성한다면 장비를 꽂거나 제거할 때에 /root/detect_test라는 user application이 호출된다.  이때 /root/detect_test에 전달된 argv와 envp를 사용하면 여러가지 정보를 알 수 있다.

/root/detect_test

block


HOME=/

PATH=/sbin;/bin;/usr/sbin;/usr/bin;

ACTION=mount

DEVPATH=/block/sda/sda1

SUBSYSTEM=block

SEQNUM=706

MINOR=1

MAJOR=8

PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0

PHYSDEVBUS=scsi

PHYSDEVDRIVER=sd


2010년 3월 10일에 추가함
============================================
2.6.23.17 kernel에서 확인한 결과, user helper를 사용하지 않고도 kernel과 user app을 연결시키는 방법이 아래와 같다.

   
    int ns = -1;
    struct sockaddr_nl sa;
    char buf[1024];
    struct iovec iov = { buf, sizeof(buf) };
    struct msghdr msg = { &sa, sizeof(sa),&iov, 1, NULL, 0, 0};
    int len;

    (void)params;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;

    ns = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if(ns < 0)
    {
        PrintError("[%s]%d socket()",__func__,__LINE__);
        return;
    }

    if(bind(ns, (struct sockaddr *)&sa, sizeof(sa)))
    {
        PrintError("[%s]%d bind()",__func__,__LINE__);
        close(ns);
        return;
    }

    while(1) {
        len = recvmsg(ns, &msg, 0);
        ...
    }

    close(ns);

RAW socket을 이용하여 recv가 가능하구나... 이제야 알았다... -.-;;

Posted by 강군님

댓글을 달아 주세요

  1. Sunny 2012.02.13 11:39  댓글주소  수정/삭제  댓글쓰기

    올려주신 post잘 보았습니다. uevent_helper를 사용하지 않고 socket으로 kobject_uevent를 받아서 처리해보려고 하는데, 막상 recvmsg()까지 와서 kobject까지 얻어내는 방안이 묘연합니다.
    예를 들어 usb가 꽂혔을 때 uevent가 발생하고 난 후 "/sbin/hotplug"를 실행시키고자 하는데,(물론 default로 들어가있긴하지만 만약 없다고 가정하면) 이를 실행시키려면 subsystem을 넣어줘야 다음과 같이 호출이 가능합니다.

    call_usermodehelper ("/sbin/hotplug", (char *)subsystem, NULL, 0); (linux/lib/kobject_uevent.c참고)
    여기서 subsystem은 kobject로부터 받아오게 되는데요.
    recvmsg로 uevent를 받고서 msghdr로부터 kobject를 받아와야 되는걸로 보이는데, 방법이 잘 찾아지지 않네요. .ㅠ.ㅠ 도움 부탁드립니다

  2. Favicon of https://kangun.tistory.com 강군님 2012.02.15 10:09 신고  댓글주소  수정/삭제  댓글쓰기

    출장지라서 답글을 늦게 보았습니다 ^^;; 그런데 무엇을 원하시는 것인지요?

    지금 올리신 내용으로는 잘 이해가 안되서요.. 알고 계시겠지만 위쪽에 있는 code는 kernel space에서의 것이고, 아래쪽에 새로 넣은 것은 user space에서의 code입니다.

    무엇을 원하시는 것인지 잘 이해를 못해서... 뭐라고 말씀드리기가 힘드네요 ^^

  3. Sunny 2012.02.17 15:40  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. 답글 감사드립니다.
    제가 두 개의 구현 방법을 참고삼아, 보던중에, 실제 구현은 아래 user space의 code를 작업하던 중이었는데, 하다가 막히는 바람에 글을 올리게 되었습니다. 실제 kernel space에서 작업을 하게 되면 관련 환경 변수들(envp)이 넘어가게 되니까 문제가 없는데, user space에서 recvmsg로 받고 난 후에 이 envp를 얻는 것에서 막혔습니다. 실제 envp가 넘어가질 않으니 제가 user space에서 user event를 받아도 제대로 처리가 되지 않더군요.

    아 참고로 제가 작업하데 된 background는 proc/sys/kernel/hotplug에 sbin/hotplug를 넣지 않는 상황에서 user event를 받아 이 sbin/hotplug를 trigger하려는 것입니다.

  4. Favicon of https://kangun.tistory.com 강군님 2012.03.14 09:20 신고  댓글주소  수정/삭제  댓글쓰기

    헐~ 답글이 굉장히 많이 늦어졌네요.. ^^;;; 아직도 출장지에 있습니다.. ㅎㅎ 집이 그립네요 -.-

    실제로 말씀하신 것처럼 envp가 넘어오지는 않습니다만, 넘어온 정보들로 sdXn인지 block device인지 등등을 알 수 있습니다. 넘겨진 정보들을 사용하여 /sys의 값들을 활용하여도 찾을 수가 있고요..

    다만 kernel space에서 바로 넘겨준 것처럼 보기 쉽게(?) 정리가 되지는 않긴 하네요.. 방법을 한번 찾아봐야겠군요.. ㅎㅎ (이글을 보실지도 의문입니다만... ^^)

아래의 내용들은 모두 exception ARM mode일 때 발생하였다고 가정한 것입니다.  Thumb mode에서 발생할 경우에 대해서는 LR에 저장되는 값이 차이가 있으니 염두에 두시고 참고하시면 될 것 같습니다.

 

1.     Reset exception handling

 

순서

동작

동작 설명

1

SPSR_svc = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 1

FIQ 비활성화

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10011

SVC 모드로 전환

3

LR_svc = 알 수 없는 주소 (의미 없음)

 

4

PC = 0x00

Reset vector

 

-       Reset exception ARM으로 reset 신호가 입력되면 발생하며, reset 신호가 입력되는 경우는 전원이 인가되거나 reset 스위치를 누르는 경우입니다. 0x0번지는 ARM 시스템이 시작하는 번지로 이 위치에 부트스트랩 코드가 들어가게 됩니다따라서 전원이 인가되거나 reset을 눌렀을 때에 지정된 (ADS cc에서 Entry 지정어로 지정) 부트스트랩 코드가 실행되게 됩니다.

 

2.     Undefined Instruction exception handling

 

순서

동작

동작 설명

1

SPSR_undef = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 0

 

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b11011

Undefined 모드로 전환

3

LR_undef = 발생 당시의 PC - 4

 

4

PC = 0x04

Undefined vector

 

-       Undefined Instruction exception ARM에서 정의되지 않은 명령을 수행하려고 하거나 co-processor에서 응답이 없으면 발생합니다 (흔히 사용하는 co-processor로는 MMU cache를 제어하는 CP15를 들 수 있겠습니다).  명령을 수행하려고 하는 단계에서 발생한다는 것은 곧 파이프라인의 decode단계가 마무리된 직후에 인식된다는 의미입니다.  Handling이 끝난 후 돌아갈 지점은 그 다음 명령어가 위치한 지점이 되겠습니다

 

주소

명령

PC 위치

비고

0x8000

ADD R1, R0, R2

 

 

0x8004

MOV R0, R1

PC 12

 

0x8008

WHAT_INSTRUCTION

PC 8

인식되는 지점

0x800C

XOR R2, R0, R1

PC 4

LR_undef에 저장되는 위치, 되돌아올 위치

0x8010

AND R1, R2, R1

PC

 

 

-       만약 STB에서 Undefined Instruction exception이 발생하였다면 LR_undef에서 한 WORD를 뺀 주소, LR_undef 4 에 어떤 명령이 수행되고 있는지를 찾아가보면 해당 exception을 발생시킨 명령어 (해당 아키텍처에서 지원하지 않는 명령어라거나)를 찾을 수 있겠습니다.

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 다음 명령어이기 때문에 LR_undef PC를 맞춰주시면 됩니다.

 

3.     Software Interrupt (SWI) exception handling

 

순서

동작

동작 설명

1

SPSR_svc = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] =

 

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10011

SVC 모드로 전환

3

LR_undef = 발생 당시의 PC - 4

 

4

PC = 0x08

SWI vector

 

-       SWI exception은 다른 exception들과는 다르게 사용자의 요청에 의해서 발생합니다흔히 사용자 응용프로그램 레벨 (USER)에서 운영체제의 레벨(SVC)로 진입하기 위한 용도로 쓰이게 되며, linux에서는 시스템 콜을 예로 들 수 있습니다.  Decode 단계가 마무리된 직후에 인식이 됩니다.  Handling이 끝난 후 돌아갈 지점은 그 다음 명령어가 위치한 지점이 되겠습니다

 

주소

명령

PC 위치

비고

0x8000

SWI 0x03

PC 8

인식되는 지점

0x8004

MOV R0, R1

PC 4

LR_svc에 저장되는 위치, 되돌아올 위치

0x8008

ADD R1, R0, R2

PC

 

0x800C

XOR R2, R0, R1

 

 

0x8010

AND R1, R2, R1

 

 

 

-       SWI exception은 사용자의 요청에 의해서만 발생하는 것이기 때문에 시점을 확인하는 것은 어렵지 않을 것이라고 생각이 됩니다.

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 다음 명령어이기 때문에 LR_svc PC를 맞춰주시면 됩니다.

 

4.     Prefetch Abort exception handling

 

순서

동작

동작 설명

1

SPSR_abort = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 0

 

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10111

Abort 모드로 전환

3

LR_abort = 발생 당시의 PC 4

 

4

PC = 0x0C

Prefetch Abort vector

 

-       Prefetch Abort exception은 잘못된 address 공간에서 명령을 읽으려고 할 때 MMU나 기타 memory controller에 의해서 발생하게 됩니다여기서 말하는 잘못된 address 공간이 의미하는 것은 정렬이 잘못되었거나, 권한이 없거나, 해당 주소를 나타내는 디스크립터에 유효하지 않다는 flag set되어 있을 때를 나타냅니다.  Execute 단계에 인식하게 되며, handling이 끝난 후 돌아갈 지점은 실행중이던 명령의 위치가 있던 지점이 되겠습니다.

 

주소

명령

PC 위치

비고

0x8000

SUB R1, R1, #1

PC 8

인식되는 지점, 되돌아올 위치

0x8004

MOV R0, R1

PC 4

LR_abort에 저장되는 위치

0x8008

ADD R0, R1, R2

PC

 

0x800C

XOR R2, R0, R1

 

 

0x8010

AND R1, R2, R1

 

 

 

-       만약 STB에서 Prefetch Abort exception이 발생하였다면 LR_abort에서 한 WORD를 뺀 주소, LR_abort 4 에 어떤 명령이 수행되고 있는지를 찾아가보면 해당 exception을 발생시킨 명령어를 찾을 수 있겠습니다.

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 지점이 되므로 LR_abort 4 PC를 맞춰주면 되겠습니다.

 

5.     Data Abort exception handling

 

순서

동작

동작 설명

1

SPSR_abort = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 0

 

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10111

Abort 모드로 전환

3

LR_abort = 발생 당시의 PC 4

 

4

PC = 0x10

Data Abort vector

 

-       Data Abort exception은 잘못된 address 공간에 데이터를 R/W 하려고 할 때 MMU나 기타 memory controller에 의해서 발생하게 됩니다여기서 말하는 잘못된 address 공간이 의미하는 것은 정렬이 잘못되었거나, 권한이 없거나, 해당 주소를 나타내는 디스크립터에 유효하지 않다는 flag set되어 있을 때를 나타냅니다.  (NULL pointer를 간접접근 한다던지 하는 경우) Memory access 단계에서 인식하게 되며, handling이 끝난 후 돌아갈 지점은 실행중이던 명령의 위치가 있던 지점이 되겠습니다.

 

주소

명령

PC 위치

비고

0x8000

LDR R0, [R3]

PC 12

인식되는 지점, 되돌아올 위치

0x8004

MOV R0, R1

PC 8

 

0x8008

ADD R0, R1, R2

PC 4

LR_abort에 저장되는 위치

0x800C

XOR R2, R0, R1

PC

 

0x8010

AND R1, R2, R1

 

 

 

-       만약 STB에서 Prefetch Abort exception이 발생하였다면 LR_abort에서 두 WORD를 뺀 주소, LR_abort 8 에 어떤 명령이 수행되었는지를 찾아가보면 해당 exception을 발생시킨 명령어를 찾을 수 있겠습니다.

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 지점이 되므로 LR_abort 8 PC를 맞춰주면 되겠습니다.

 

6.     Interrupt request (IRQ) exception handling

 

순서

동작

동작 설명

1

SPSR_irq = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 0

 

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10010

IRQ 모드로 전환

3

LR_irq = 발생 당시의 PC 4

 

4

PC = 0x18

IRQ vector

 

-       IRQ exception은 외부의 장치에서 발생된 interrupt 신호가 ARM에 입력되면 발생합니다.  Execute 단계에서 인식하게 되며, handling이 끝난 후 돌아갈 지점은 실행중이던 명령의 다음 위치가 되겠습니다.

 

주소

명령

PC 위치

비고

0x8000

SUB R1, R1, #1

PC 12

인식되는 지점

0x8004

MOV R0, R1

PC 8

되돌아올 위치

0x8008

ADD R0, R1, R2

PC 4

LR_irq에 저장되는 위치

0x800C

XOR R2, R0, R1

PC

 

0x8010

AND R1, R2, R1

 

 

 

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 다음 명령어가 위치한 지점이 되므로 LR_irq 4 PC를 맞춰주면 되겠습니다.

 

7.     Fast Interrupt request (FIQ) exception handling

 

순서

동작

동작 설명

1

SPSR_fiq = CPSR

상태 레지스터 저장

2

CPSR 값 변경

CPSR[5] = 0

ARM 상태로 전환

CPSR[6] = 1

FIQ 비활성화

CPSR[7] = 1

IRQ 비활성화

CPSR[4:0] = 0b10001

FIQ 모드로 전환

3

LR_fiq = 발생 당시의 PC 4

 

4

PC = 0x1C

FIQ vector

 

-       FIQ exception은 외부의 장치에서 발생된 interrupt 신호가 ARM에 입력되면 발생합니다.  Execute 단계에서 인식하게 되며, handling이 끝난 후 돌아갈 지점은 실행중이던 명령의 다음 위치가 되겠습니다.

 

주소

명령

PC 위치

비고

0x8000

SUB R1, R1, #1

PC 12

인식되는 지점

0x8004

MOV R0, R1

PC 8

되돌아올 위치

0x8008

ADD R0, R1, R2

PC 4

LR_irq에 저장되는 위치

0x800C

XOR R2, R0, R1

PC

 

0x8010

AND R1, R2, R1

 

 

 

-       리턴되어야 할 지점은 앞서 말씀드린 것과 같이 해당 exception을 발생시킨 다음 명령어가 위치한 지점이 되므로 LR_irq 4 PC를 맞춰주면 되겠습니다.

 

그리고 제가 세미나에서 ARM un-aligned access를 지원하지 않는다고 하였는데, ARMv6부터는 un-aligned access support한다고 합니다.

Posted by 강군님

댓글을 달아 주세요