임베디드/임베디드 개념

ARM Mode, Register, Exception

fish9903 2023. 7. 14. 11:33

ARM을 다루는데 가장 기초적인 개념은 mode, register, exception일 것이다. 이 용어들에 대해 알아보자.

위 세 가지 용어들은 서로 연관되어 있어서 무엇을 먼저 설명하던지간에 용어가 섞여서 나온다. 여기선 mode, register, exception 순서로 진행해본다.

 

ARM operating mode

ARM에는 7가지 동작 모드가 존재한다. 각 모드에 대한 설명은 아래와 같다.

 

ARM 동작 모드(출처: ARM User Manual)

 

각 모드에 대한 추가적인 설명은 아래와 같다.

 

  • User(USR): 일반적으로 사용하는 모드로 ARM 상태와 Thumb 상태로 동작한다. 사용자 프로그램은 보통 이 모드에서 동작한다.
  • Fast Interrupt(FIQ): FIQ exception(high priority, fast)이 발생하면 이 모드로 전환된다. 
  • Interrupt Request(IRQ): IRQ exception(low priority, normal)이 발생하면 이 모드로 전환된다.
  • Supervisor(SVC): OS 등에서 시스템 코드를 수행하기 위한 보호 모드. OS에서 system call을 호출하면 SVC exception을 발생시켜 이 모드로 진입하고 동작을 수행한다. SVC exception은 순수 SWI(Software Interrupt)에 의해 발생한다.
  • Abort(ABT): Access 하려는 주소가 access 할 수 없는 주소이거나, 명령어 fetch 실패한 경우에 진입하는 모드. 또는 접근 보호된 메모리 주소에 접근하려고 할때 ABT exception이 발생한다.
  • Undefined(UND): 정의되지 않은(Undefined) 명령어를 만났을 때 진입한다. (Data abort, Prefetch abort 포함)
  • System(SYS): 사용자 프로세스나 OS에서 임시로 커널 모드를 획득해야 하는 경우(system resource 등) 이 모드 사용. Exception과 관련은 없고, 소프트웨어적으로 진입 가능하다.

 

이 모드들은 다시 2가지로 분류할 수 있다.

첫번째 User mode는 가장 일반적인 모드로, 대부분 응용 프로그램은 이 모드에서 동작한다.

두번째로 묶인 모드들은 Privileged Mode로, 이 모드들은 특정 exception이 발생했을 때 진입된다. Privileged라는 뜻이 붙은 이유는 cpsr register에 full read-write access를 가지고 있는 모드이기 때문이다.

 

cpsr register는 psr register 중 하나로, 이후 register 부분에서 등장한다. Processor는 cpsr regitser를 보고 mode를 결정하는데, 이 register에 접근하여 값을 변경할 수 있는 privileged mode들은 서로 스스로 mode를 변경할 수 있다는 것이다.

  • Privileged mode <--> Privileged mode (가능)
  • Privileged mode --> USR mode (가능)
  • USR mode --> Privileged mode (불가)

Privileged mode에서 SYS는 exception과 관련이 없는 mode이므로 이를 뺀 나머지를 exception mode로 부르기도 한다.

 

ARM의 default mode는 SVC mode이다. SVC mode에서 시작해야지 부팅시 ARM에 대한 모든 권한을 가지기 때문

 

ARM mode하면 동작 모드(operating mode) 말고 Thumb mode, ARM mode를 떠올릴 수도 있다. 간단히 보면, ARM은 두 종류의 명령어 집합을 가지고 있는데 하나는 32bit 명령어 집합(ARM mode)이고 다른 하나는 16bit 명령어 집합(Thumb mode)이다. 기본적으로 ARM은 32 bit RISC machine으로 word가 32bit이지만, Thumb mode는 32 bit ARM에서 돌아가는 16 bit 명령어인 것이다. 

 

ARM은 ARM mode와 Thumb mode를 섞어 사용하는 것을 허용한다. 따라서 런타임에 mode를 변경할 수 있어서 속도가 중요한 부분은 ARM mode로, 크기가 중요한 부분은 Thumb mode로 컴파일할 수 있다.

(Thumb mode는 16 bit 명령어라 크기가 작지만, 32 bit 명령어보단 느리다)

 

또 중요한 점은 Thumb mode에서 exception이 발생하여 exception handler로 들어갈 때는 ARM 모드로 전환된다는 것이다. 따라서 exception handler는 ARM mode로 컴파일되어야 한다.

 

ARM register

ARM core는 동작 모드가 바뀌면 사용하는 register set도 바뀐다. ARM core는 한 mode당 R0~R15까지 16개에 CPSR과 SPSR까지 더하면 18개의 register를 가진다. ARM 동작 모드는 총 7개이므로 단순히 계산해보면 18 * 7 = 126개의 register가 있을 것으로 예상할 수 있다. 하지만 실제로는 그렇지 않다.

 

ARM core에는 37개의 register가 존재하는데, 아래는 각 모드별로 사용가능한 register들을 나타내는 표이다. 

ARM core의 register(출처: ARM user manual)

각 열은 ARM 동작 모드와 그 모드에서 사용하는 register를 나타낸다. 왼쪽 아래 삼각형이 있는 register는 해당 열의 모드에서만 사용가능한 전용 register(banked register)이다. 

 

이를 바탕으로 ARM core에 있는 register 개수를 계산해보자.

 

 USR와 SYS --> R0~R15 + CPSR = 17개

 SVC --> R13_svc, R14_svc + SPSR_svc = 3개

 ABT --> R13_abt, R14_abt + SPSR_abt = 3개

 UND --> R13_und, R14_und + SPSR_und = 3개

 IRQ --> R13_irq, R14_irq + SPSR_irq = 3개

 FIQ --> R8_fiq~R14_fiq + SPSR_fiq = 8개

총 37개 register가 존재한다.

 

즉, 여러 모드가 공유하는 register(R0~R12, R15, CPSR)와 한 모드 전용 banked register(Rn_<mode>, SPSR_<mode>)가 존재한다.

 

ARM core에는 R0~R15, CPSR, SPSR의 3가지 종류의 register가 존재한다.

이중 R0~R12는 범용 레지스터(general purpose register), R13은 스택 포인터(Stack Pointer, SP), R14는 링크 레지스터(Link Register, LR), R15는 프로그램 카운터(Program Counter, PC)라고 부른다.

(R13~R15, CPSR, SPSR은 특별한 용도에 사용되는 register라 Special Purpose Register라고도 한다.)

 

추가로 general purpose register도 사용 용도를 정한 약속이 있는데, PCS(Procedure Call Standared)라고 한다. (이름은 계속 변경중... APCS --> ... --> AAPCS)

 

특히 FIQ mode를 보면 banked register가 R8~R14까지로, 다른 모드보다 많은 것을 확인할 수 있다. 이는 FIQ mode만의 특징으로, 전용 register 개수가 많아서 모드 전환시 FIQ 모드에서는 R8~R12까지는 이전 모드의 레지스터 값을 백업할 필요가 없어 빠르다. 이게 Fast Interrupt Request(FIQ)라고 부르는 이유이다.

 

다른 특징으론 USR와 SYS 모드는 완전히 동일한 register를 공유하면서 사용한다는 것이다. 차이는 CPSR register의 mode bit의 값에서 난다. 또한 SPSR가 없다.

SPSR가 없는 이유는 system, user mode로 들어가는 exception이 없기 때문이다. (Exception 부분 참고)

 

CPSRSPSR은 PSR(Program Status Register)로, 상태를 관리한다.

여기서 상태(status)는 계산 결과(음수, 양수, 0), ARM 모드(Thumb, ARM, ...), ARM 동작 모드 등을 정보를 의미한다.

CPSR은 Current PSR(현재 상태를 저장), SPSR은 Saved PSR(상태를 저장)하는 register이다.

 

아래는 PSR register 구성이다.

CPSR, SPSR(출처: ARM user manual)

32개 bit중 여기서 볼 것들은 다음과 같다.

  • N: 계산 결과가 음수면 1, 아니면 0
  • Z: 계산 결과가 0이면 1
  • C: 계산에 carry, borrow이 발생하면 1
  • V: 계산 결과에 overflow가 발생하면 1
  • J: Jazelle 상태로 전환 시 1 (ARM mode, Thumb mode같은 ARM의 또다른 모드, JAVA 바이트 코드 실행 지원)
  • I: IRQ를 disable할 때 1(일반적인 interrupt를 disable할 때 1)
  • F: FIQ를 disable할 때 1
  • T: Thumb mode일 때 1
  • M[4:0]: mode bit, ARM 동작 모드를 표현
    • 0b10000: USR
    • 0b10001: FIQ
    • 0b10010: IRQ
    • 0b10011: SVC
    • 0b10111: ABT
    • 0b11011: UND
    • 0b11111: SYS

CPSR, SPSR은 위와 같은 정보를 저장하고 있기때문에 이것을 보면 특정 시점의 프로세서의 상태(context)를 알 수 있다.

따라서 ARM 동작 모드가 변경될 때는 각 모드별 context를 전용 SPSP register에 저장해 두고 전환이 된다.

 

 이는 TCB를 이용한 context switching과 비슷한데, 다음 Exception 설명에서 추가적으로 설명한다.

 

CPSR, SPSR의 N, Z, C, V와 같은 계산 결과 상태를 저장하는 bit는 condition flag라고 한다.

것이 있는 이유는 ARM의 명령어의 특징을 보면 알 수 있다.

ARM core는 명령어를 fetch하자마자 실행하는 것이 아니고, condition flag를 보고 실행할지 말지 결정한다.

이를 conditional execution이라고 한다.

(ex. 다음과 같은 접미사가 붙은 명령어 --> XXXeq(equal하면 = Z bit가 1이면 XXX실행) )

 

ARM exception

앞서 봤듯이, ARM에는 7가지 동작 모드가 있고 프로그램이 실행되면서 모드가 바뀔 수 있다. 

어떻게 동작 모드가 바뀌고, 이때 레지스터들(특히 공유하는)은 어떻게 관리되는지 알아보자.

 

ARM 동작 모드를 바꾸는(바뀌는) 방법은 exception을 사용하는 것이다. Exception과 interrupt는 종종 동일한 의미로 사용되곤 하는데, 의미적으로 구분해보면 interrupt는 외부적인 요인(외부 장치 등)으로 발생하여 명령어 실행 흐름을 가로채는 것이다. Exception은 프로세서 내부에서 발생하여 명령어 실행 흐름을 가로채는 것이다.

Exception 중에서 비동기적으로 발생하는 것이 interrupt, 동기적으로 발생하는 것을 그냥 exception이라고 한다.

(Interrupt는 exception의 한 종류)

 

이 exception이라는 사건이 발생하면 진행하던 동작(명령어)를 멈추고, exception 종류에 맞는 mode에 진입하고 exception 에 맞는 주소로 jump한 뒤에 exception handler에서 이를 처리를 한다. 

이를 정해놓은 것을 exception vector table이라고 하고, 아래와 같다.

ARM의 Exception vector table(출처: ARM user manual)

 

Exception 종류별로 발생시 진입하는 모드와 jump하는 주소가 적혀있다. 해당 주소로 jump한다는 것은 그 주소에 있는 명령어를 처리한다는 것이고, 이 주소에 있는 것이 exception(interrupt) handler이다.

 

Exception이 발생하는 상황을 다시 보면 다음과 같다.

  • SVC mode: 전원이 들어오거나 리셋이 일어난 경우 진입, SWI 발생시 진입
  • IRQ mode: 하드웨어적인 interrupt가 발생하면 진입
  • FIQ mode: Interrupt중 fast Interrupt가 발생하면 진입
  • ABT mode: 접근하려는 주소가 유효하지 않을 때, 명령어 fetch 실패했을 때 진입
  • UND mode: 명령어를 decode했는데 ARM이 모르는 명령어 일 때 진입

이렇게 exception이 발생하면 동작 모드가 변경된다. 여기서 중요한 점은 ARM 동작 모드들은 몇몇 register들을 공유한다는 것이다. 따라서 모드가 변경될 때 다음과 같은 점들을 고려해야 한다.

 

1. Exception 처리 후, 이전 mode로 복귀

2. 변경 전 mode에서 쓰던 register값들을 복원(context를 온전히 복원, 교체)

 

context란 프로세서의 상태를 의미한다. 특정 시점의 프로세서의 상태는 특정 시점의 register들의 값을 보면 되므로 context란 register들의 값, 상태를 의미한다고 볼 수 있다.

 

이 조건들을 만족하기 위해 앞에서 설명했던 CPSR, SPSR와 special purpose register가 사용된다.

위의 register들을 이용하여 mode를 변경하는(context switching) 과정은 다음과 같다.

 

1. Exception에 따라 PC+4 또는 PC+8(Thumb mode일 경우는 PC+2 또는 PC+4)을 R14_<mode>에 저장

2. CPSR을 SPSP_<mode>에 저장

3. CPSR의 동작 mode bit와 I, F, T bit를 exception과 동작 mode에 따라 변경

4. PC 값을 exception vector로 변경

 

예시) USR mode에서 IRQ exception 발생

출처: ARM user manual

Exception 처리(mode 변경)

1. R14_irq에 PC+4를 저장

2. CPSR register를 SPSR_irq에 저장(백업)

3. CPSR register의 동작 mode를 IRQ 로 변경(진입) --> stack pointer도 IRQ mode의 stack을 가리키게 됨

4. CPSR의 T bit를 ARM mode에서 exception 처리하므로, ARM mode로 변경

5. CPSR의 I bit를 disable(IRQ 요청을 받았다는 뜻)

6. Exception vector table에 따라 PC를 0x18주소로 변경(low vector인 경우)

7. R0~R12를 R13_riq(stack pointer)가 가리키는 stack에 저장

8. Exception 처리

 

mode 복귀

1. CPSR에 SPSR_irq를 넣음(이전 mode인 USR mode로 복귀)

2. Stack에 저장했던 register 복원

3. PC = R14_irq - 4 연산(SUBS PC, R14, #4)으로 이전 실행 흐름 복귀

 

Exception 발생 시 R14_<mode> register에 저장하는 값(PC+4, PC+8, ..)과 복귀 주소 연산을 하는 이유는 ARM의 pipeline을 보면 알 수 있다.

간단히 보면, pipeline을 사용하면 PC는 현재 실행중인 명령어보다 몇 단계(cycle) 앞을 가리키고 있다. 따라서 exception이 발생하면 다시 돌아와야 하는데, 각 exception별로 pipeline에서 exception이 발생한 단계가 다르기 때문에, 복귀하기 위한 계산이 다르고 이 계산을 R14값에 해줘야 한다.

Cycle 단위로 동작하기 때문에 ARM mode인지 Thumb mode인지에 따라도 달라진다.

 

Low vector, High vector

Low vector는 low address에 vector table이 존재하는 방식, high vector는 high address에 vector table이 존재하는 방식이다.

 

Exception vector table을 보면 system, user mode로 진입하는 exception이 없다. SYS와 USR 전용 SPSR가 없는 이유이다. 그렇다면 SYS, USR mode에는 어떻게 들어갈까? 

CPSR의 mode bit를 변경하는 코드를 작성하여 진입할 수 있다. CPSR을 다루는 전용 명령어가 존재한다.

사실 SYS, USR mode말고 다른 mode들도 CPSR의 mode bit를 변경하여 진입할 수 있다.


참고한 자료

 

ARM user manual

https://documentation-service.arm.com/static/5f8dacc8f86e16515cdb865a

 

'임베디드 OS 만들기'  4, 6, 8, 10 장과 A.1 부록