커널 산책 - SWI와 시스템 콜 (4)

저번 산책 때

SWI 명령을 통해서 

함수 번호(인덱스)를 넘기는 부분을 살펴 보았습니다. 

그렇다면...

커널은 이 번호를 어떻게 얻을까요?

ARM 어셈블러 명령에 이런 번호를 얻는 명령이나 코프로세서 명령이 따로 있을까요?

불행하게도 그런 것 없습니다. 

그래서 

ARM의 입셉션에 대한 사전 지식이 필요합니다. 

왜냐?

ARM에서 SWI 명령에 대한 입셉션이 발생했을 때

처리 되는 상태를 이용해서 시스템 콜 함수 인덱스를 얻거든요..

실제로 커널 코드는 좀 복잡하니깐 

먼저

간단한 ARM 어셈블러를 이용해서 설명하기로 하죠..

전에 open() 시스템 콜을 호출하기 위해서는 

swi __NR_SYSCALL_BASE(==0x900000)+1

로 명령을 만들고 호출 한다고 했죠?

이 명령이 수행되는 순간 Software Interrupt 입셉션이 발생합니다. 

ARM 프로세서는 이 순간에 하드웨어적인 처리 방식으로 

다음과 같은 일을 합니다. 

1) PC 값을 LR 레지스터에 넣습니다. 

LR 은 Link Register 의 약자인데  R14 레지스터의 별칭입니다. 
PC 는 Program Counter 의 약자인데 R15 레지스터의 별칭입니다.
이때 PC 값은 SWI 명령 다음에 수행할 명령 주소 값을 가지고 있게 됩니다.
 
SWI 명령의 입셉션을 수행하고 난 후 원래 위치로 올 필요는 없죠.. 
발생했을 당시의 명령이 SWI 명령인데 이 위치로 돌아 오면 무한 반복 하잖아요..
그래서 SWI 명령 다음에 수행할 명령의 주소가 PC 에 있게 되고 
이 값을 LR 에 저장하므로써
나중에 LR 값을 PC  에 지정하면 
그 순간 SWI 명령 다음의 명령을 수행하게 되는 거죠.
이거 무척 중요합니다. 
꼭! 기억하세요..
2) CPSR  을 SPSR 에 넣습니다. 

CPSR 은 현재 프로세스 상태 레지스터인데 
이것을 SPSR 에 저장하므로써 복귀할때 이 저장된 값을 복구하면 
입셉션 발생 전 상태로 쉽게 돌아 올 수 있지요..
3) PC 에 입셉션 벡터 테이블의 소프트웨어 인터럽트 테이블 주소를 넣습니다. 

   이때 하이벡터 상태가 아니면 
   
   PC 에 0x00000008 을 지정하게 되고요
   
   하이벡터 상태이면 
   
   PC 에 0xFFFF0008 을 지정하게 됩니다. 
   
이전에 익셉션 벡터 테이블에 대한 설명 기억 나시나요?

이렇게 해서 소프트웨어 인터럽트 핸들러가 수행되게 됩니다. 

이제 인터럽트 핸들러는 시스템 콜을 처리해야 겠죠?

그런데 문제는 시스템 콜 함수를 구별해야 하잖아요?

어떻게 시스템 콜 함수 인덱스를 구할까요?

위에서 제가 꼭 기억하라고 한 것 있었죠?

예..

LR  레지스터에 저장된 값이 있죠...

이 값에 들어 있는 주소가 무슨 주소라고 했죠?

SWI 명령 다음 주소라고 했죠...

그러면 SWI 명령이 있는 주소는 ?

맞아요...

LR 레지스터에서 4 를 빼주면 됩니다. 

예를 들어 SWI 명령 자체를 R0 에 넣고 싶다면 이렇게 하면 됩니다. 

ldr R0, [LR-4]
이 명령을 통해서 R0 에는SWI 명령 자체가 들어 있습니다 .

이제 R0를 가공해서 시스템 콜 함수 인덱스를 얻어 오면 됩니다. 

시스템 콜 할 때 다음과 같이 사용했죠?

swi __NR_SYSCALL_BASE(==0x900000)+1

그리고 SWI 명령은 다음과 같은 구조라고 했죠?

수행 조건(4비트) + SWI 명령(4비트) + 임의값(24비트)
이중 임의값 24 비트가 __NR_SYSCALL_BASE(==0x900000)+1 부분입니다. 

그러면 R0 에서 먼저 24비트 값만 구해야 겠죠?

그리고 0x900000을 빼버리면 +1 한 값만 남겠죠?

이렇게 하면 시스템 콜 함수 번호를 얻게 됩니다. 

실제 커널 소스가 이걸 구현하는 가는 조금 있다 봐야 하구요...

오늘은 시간도 늦었고

( 아시나요? 이 글쓰는 이시간 즉 저녁 11시에 전 회사에 있고 오늘은 개천절 즉 공휴일이라는 사실 ㅠㅠ )

다음 산책 시간엔 

시스템 콜을 호출하는 최신 방식에 대해서 알아 보려구요..

그럼... 

여기서 잠깐! -----------------------------------------------------

ARM 에 대해서 공부하다보면 

APCS 라는 것이 있다는 것을 알게 될 수도 있습니다. 

APCS 는 ARM Procedure Call Standard 의 약자인데 

이 말을 한글로 하면 흠... 영어가 딸리는 군요..

ARM 에서 권장하는 C 언어 함수 호출에 대한 몇 가지 규칙입니다. 

이 규칙은 gcc 같은 컴파일러가 따르게 됩니다. 

이 규칙은 ARM 의 레지스터의 별칭을 지칭하고 

어떻게 C 의 변수들을 사용하는 지 

레지스터는 어떤 용도로 사용하면 좋은지를 권장합니다.  

다음과 같은 규칙이 있습니다.  

r0 a1 argument 1/scratch register/result
r1 a2 argument 2/scratch register/result
r2 a3 argument 3/scratch register/result
r3 a4 argument 4/scratch register/result
r4 v1 register variable
r5 v2 register variable
r6 v3 register variable
r7 v4 register variable
r8 v5 register variable
r9 v6/sb register variable/static base
r10 v7/sl register variable/stack limit/stack chunk handle
r11 fp register variable/frame pointer
r12 ip new-sb in inter-link-unit call/sscratch register
r13 sp stack pointer
r14 lr link register/scratch register
r15 pc program counter

이에 대한 정확한 뜻은 시스템 콜 산책을 하다보면 좀 더 자세하게 알게 됩니다. 

이 규칙은 여러 곳에서 필요하거든요..

ARM 커널을 이해하기 위한 지식 중 꼭 필요한 것중 하나 입니다. 

-----------------------------------------------------------------------

어떤 분이 글 보기가 너무 어지럽고 텍스트만 있어서 읽기 어렵다고 하네요

흠 ...

제가 봐도 그래요...

그런데 그냥 이렇게 살다 죽을래요...

저도 짬내서 쓰는 글인데다가 

보통...

글 꾸미는 시간이 

글쓰는 시간 만큼 걸려요...

나중에 혹시라도 책으로 쓰면 그때 정리 할래요..

저 무척 게으르거든요...

그리고 글쓰는 것이 노동으로 느껴지면 글 안쓰게 돼요 ㅠㅠ

이해해 주세용..