임베디드/임베디드 레시피

SWI 의 진실

twoweeks-within 2024. 11. 26. 20:18

Hardware없이 interrupt를 거는 방법? 

SoftWare Interrupt :  Asynchronous(비동기식) 하게 암때나 걸리는 게 Interrupt 
     Software Interrupt != Interrupt
          > Software적으로 Exception을 거는것임.
        > User mode에 있던 System > Supervisor mode로 전환,
        > Software Interrupt를 거는 순간부터는 Privileged Mode로 전환 System을 마음대로 주무를 수 있는 권한이 생김.

왜 이런 SWI( software interrupt) 사용? : compatibility. 
    > kernel service를 이용할 때 많이 사용
      a)  Privileged mode로 들어갈 수 있음,
      b)  Kernel service : 입구가 하나로 한정
        > Kernel 입장에서는 SWI 부분만 수정을 잘하면 되는 장점.

SWI가 이용 예
1. System Call (Kernel)
2. Semi hosting

1. System Call : Kernel등에서 많이 사용되는 개념
        >Kernel: SVC mode에서 동작
       <>일반 application : User Mode에서 동작
  > User Mode의 일반 application이 Kernel에게 service를 요청할 때 사용.
 SWI를 > Kernel Mode로 System mode를 바꾸는것

2. Semi hosting : 
    Target에서의  I/O에 관련된 것들을 경로를 바꿈
        >  Target에서 실행되어야 하는 I/O 
     > Debugger를 실행하고 있는 Host system에서 대신 수행하게함
ex) UART로 Message를 뿌리던 target의 routine > Semi hosting routine
       > UART가 아닌 Debugger로 target의 Reporting을 직접 받을 수 있음

 SWI, Handler 어떻게 구현?

1. Software Interrupt를 걸려면 ?
  SWI {condition} ;
 assembly를 삽입 : SWI 명령어를 만나는 순간 Exception 발생
       > SWI Exception Vector (0x0008)번지로 branch.
 이렇게 SWI 명령어 자체로 Exception을 걸어 User mode에서 강제로 SVC mode로 갈 수 있음

SWI {condition} ;
  > SWI에 대해서 여러 가지 종류의 SWI를 걸 수 있음,
 SWI 뒤에 number >  Handler에서 뒤에 parameter로 준 condition을 switch  >  여러 가지 case 처리

ARM에서는 Exception이 발생 > Exception Vector로 jump해서 곧바로 Handler로 branch
      > 어떻게 parameter를 줌??

 SWI 명령자체가 답. 
SWI 명령어의 32bit binary 형태

cond 1111 24bit (interrupted) immediate

MSB 4bit : 조건을 나타내는 명령어 (EQ, NEQ 등) > condition flag에 대한 조건 명령 
1111 : SWI 명령.
24bit : parameter가 들어감 >여러 가지 종류의 SWI 
// 순수하게 System Software Engineer가 구현해야 하는 몫 
LSB 24bit와는 아무 상관없이 일단 1111 (SWI)가 있으면
  >Processor : Exception 발생

 Software Interrupt >  R14_SVC에 돌아갈 주소가 저장

돌아갈 주소를 안다 == 돌아갈 주소에서 한 칸만 이전을 가져올 수만 있다면 SWI가 걸린 위치를 가져올 수 있음.
 그러면 SWI가 걸린 위치를 가져와서 LSB 24bit만 Masking해내면 끝

LDR r0, [r14, #-4]
BIC r0, r0, #0xFF000000 // 8*4 = 32byte , 32- 8 = 24

r14 에서 그 전 주소를 뺌 ( -4 byte) 그걸 하위 24bit 에 저장

ex) 
1.  SWI 호출과 Handler의 구현
2.  C Level의 SWI 의 직접 호출 구현

1. 일반적인 SWI 호출하는 방법

c file에서 SWI를 호출,  

SWI_OOOPS()
{
.............
SWI_Exception();   SWI_OOOPS()라는 함수에서 SWI 호출
.............
}

Assembly file 하나에서 SWI_Exception 함수를 구현
    > SWI {condition} 명령어를 사용하기 위해
 

SWI_Exception
     SWI 0x121212  // SWI에 parameter 0x121212 할당

SWI 0x121212 를 만나면 SWI_EXception >  Exception Vector로 branch

0x8번지에 쓰여진 형태  // Vector Table
b SWI_Handler   // b : branch

 C Level의 SWI Handler를 부르기 위한 Handler를 만듬 + 여기에서 LSB 24 bit도 건짐

SWI_Handler
    STMFD sp!, {lr} ; 돌아갈 주소 저장
    LDR r0, [lr, #-4] ; SWI 주소의 값을 가져옴.
    BIC r0, r0, #0xFF000000 ; LSB 24bit 건져냄.  // 0x12121212
    BL SWI_C_Handler ; r0에 넣었으니까, AAPCS에 의하여 첫번째 argument로
             //r0에 SWI 인자값(하위 24비트)이 들어 있음 > 이를 첫 번째 인자로 하여 SWI_C_Handler를 호출
    LDMFD sp!, {lr} ; 다 처리하고 왔으면 돌아가야지~

SWI_C_Handler만 잘 구현하면 됨

void SWI_C_Handler (int OPTion)
{
    switch(option)
    {
      case 0x123432:
          UART_MESSAGE ("SWI 0x123432");
      break ;
      case 0x121212 :
         LCD_MESSAGE ("SWI 0x121212");
      break ;
      case 0x654321:
         USB_MESSAGE ("SWI 0x654321");
      break ;
     }
}

r0에 LSB 24 bit를 넣었음 > 그 값은 int option으로 넘어오게 되고, 그 option에 대해서 switch를 걸었음
    >  결국 LCD_MESSAGE 를 찍음

2. 다른 종류의 LSB 24bit를 걸기 위해서 SWI_Exception() 함수를 Assembly로 따로따로 구현해야 하느냐!
    >함수를 SWI와 번호로 선언할 수 있음

__swi(0x123432) void UART_OUT (void)라고 선언

SWI_OOOPS()
{
      .............
      SWI_Exception();
      UART_OUT();
      .............
}

 LCD MESSAGE와 UART MESSAGE가 실행
   > UART_OUT() 함수 자체가 SWI 0x123432으로 compile 

결국 SWI_OOOPS()함수는

SWI_OOOPS
    ........
    SWI 0x121212
    SWI 0x123432
    .........

이런 식으로 컴파일됨