A.1.1 익셉션 벡터 테이블
익셉션이 발생하면 해당하는 익셉션에 맞춰 프로그램 카운터(PC)를 익셉션 벡터 테이블에 정의된 오프셋 주소로 점프해 핸들러를 실행합니다.
아래는 익셉션 벡터 테이블입니다.
예를 들어, 정의되지 않는 명령어를 만나면 Undefined Instruction 벡터 테이블로 이동해 Undefined Instruction 핸들러를 수행하고 돌아옵니다. 이것을 이용해 Undefined Instruction 핸들러에 정의되지 않는 추가 명령어를 삽입해 소프트웨어 적으로 명령어를 확장시킬 수 있습니다.
각 익셉션 테이블에는 그냥 핸들러의 주소만 담고 있습니다. 이유는 각 하드웨어, 펌웨어마다 핸들러의 코드가 다르기 때문입니다.
정리
1. 익셉션 발생 시 프로그램 카운터(PC)를 익셉션 벡터 테이블을 이용해 핸들러로 이동한다.
2. 익셉션 테이블은 핸들러의 주소만 담고있다. 이유는 기기마다 사람마다 코드와 특성이 다르기 때문이다.
A.1.2 익셉션의 종류
익셉션(exception)은 주변장치(peripheral) 등에서 발생한 신호를 처리하기 위해 순차적으로 진행하던 프로그램의 수행을 끊는 것을 말합니다. 프로그램의 수행을 끊을 때 단순히 PC값을 바꾸는 것과는 다릅니다. PC는 항상 순차적으로 PC + (명령어 한 개 사이즈) 만큼 증가하다가 branch 나 jump를 만나면 PC값이 확 바뀝니다. 하지만 익셉션의 경우 PC값이 바뀔 뿐만 아니라 돌아갈 주소의 값도 저장을 해야 합니다.
진행 중이었던 프로그램의 흐름(context)을 복귀하려면 R14(Link register)에 복귀할 주소의 값을 저장하는 것입니다.
예를 들어, USR모드에서 익셉션이 발생해 IRQ모드로 변경하는 상황이라면 다음과 같습니다.
책에 익셉션 별로 다른 복귀 주소(표 A.2)를 볼 수 있는데. ARM은 파이프라인 이므로 각 익셉션 별로 정상 복귀를 하기 위해서는 R14에 각기 다른 동작을 해주어야 합니다. 익셉션이 발생했을 때 나오는 용어 CPSR, SPSR와 ARM이 자동으로 수행하는 동작의 순서는 책을 참고해주시길 바랍니다.
정리
1. 익셉션에 따라 PC의 주소와 CPSR를 익셉션에 맞게 각 LR와 SPSR에 저장 후 PC값 익셉션 벡터 테이블로 옮기고 핸들러를 수행한다.
2. 핸들러를 수행하고 돌아올 때는 백업 해놨던 레지스터의 값을 그대로 넣으면 흐름이 끊겼던 위치로 연결된다.
A.1.3 인터럽트
인터럽트(interrupt)는 가로채다 라는 의미를 가지고 있습니다. 즉, 프로그램의 흐름을 가로채는 것과 동일합니다. 앞서 배운 익셉션과 유사한데, ARM에서는 인터럽트와 익셉션이 구분되지 않고 동작한다고 합니다. 그래서 익셉션 핸들러나 인터럽트 핸들러나 같은 개념입니다. 하지만 이후에 x86 계열 데스크탑 OS 프로젝트를 위해 용어 정리를 해보겠습니다.
인터럽트는 CPU의 외부 요인에서 발생된 것입니다. 키보드를 눌렀다거나, 마우스, 스마트폰 터치 등을 의미합니다. 혹은 시간이 지남에 따라 인터럽트가 발생하기도 합니다. 이처럼 정해진 기준 없이 예측 불가(Asynchronous Interrupt)하게 이벤트가 발생 하는 것을 인터럽트라고 합니다. 운영체제 내부에서는 수많은 인터럽트들이 발생됩니다. 그리고 인터럽트는 필연적으로 지연(latency)을 발생합니다. 그래서 지연을 줄이기 위해 VIC 등 별도 하드웨어로 인터럽트의 지연을 최소화합니다.
익셉션은 주로 CPU의 내부 요인에 의해 발생된 것입니다. 어떤 수를 0으로 나누거나(divided by zero), system call이 발생 했거나 overflow가 일어났을 때 발생합니다. 익셉션은 이처럼 정해진 기준이 있고 이를 어기면 발생하는(Synchronous Interrupt) 인터럽트를 말합니다.
출처 : http://melonicedlatte.com/computerarchitecture/2019/02/12/213856.html
인터럽트(interrupt), 예외(exception), 트랩(trap)의 비교 - Easy is Perfect
여러 가지 블로그를 찾아 보던 중에 좋은 자료가 있어서 간결하게 하여 포스팅하여 정리하였습니다. - 인터럽트 (인터럽트에는 비동기와 동기가 있다. 비동기는 interrupt, 동기는 exception) > Asynchron
melonicedlatte.com
ARM인터럽트의 종류는 IRQ와 FIQ, 2가지로 나뉩니다. F는 fast를 의미합니다. FIQ는 IRQ보다 빠른 인터럽트 처리를 위해 존재합니다. 아래는 인터럽트의 대한 개념 5가지입니다.
- Interrupt Request(IRQ) : 일반적인 인터럽트가 발생할 경우에 이 쪽으로 처리가 된다.
- Fast Interrupt Request(FIQ) : IRQ보다 우선순위가 높고 별도의 인터럽트 처리를 위한 레지스터가 있어 빠르다. 인터럽트 레이턴시를 줄이기 위해 어떤 인터럽트들은 FIQ로 처리해야 할 경우가 있다.
- Non-Maskable Fast Interrupt(NMFI) : NMFI를 켜면 FIQ를 비활성화할 수 없다.
- Low Interrupt Latency(LIL) : 인터럽트 지연을 줄이기 위한 동작, 인터럽트 발생 시 현재 수행 중인 명령의 실행이 끝나지 않아도 취소해 SUBS PC, r14, #4로 발생 시점 한 발 뒤로 가 인터럽트의 지연을 줄이고 그 시간을 인터럽트 처리 후에 보상한다. (strongly ordered인 경우에는 중간에 명령어 취소가 불가능 하기에 multiword의 load/store 명령은 가급적 피해야 한다.
- Interrupt Controller(IC) : VIC를 포함하는 인터럽트를 처리하는 부분, ARM의 인터럽트 종류는 IRQ, FIQ 2가지 이므로 어떤 인터럽트가 발생했는지는 알 수 없다. 그래서 인터럽트 컨트롤러에 어떤 인터럽트가 발생했는지 물어봐야 한다.
<인터럽트 컨트롤러(IC)가 하는 일은>
1. 인터럽트 발생 시 어떤 인터럽트가 발생 했는지 레지스터에 등록
2. 인터럽트 발생 시 IRQ or FIQ에 맞춰 인터럽트 신호 줌
3. 특정 인터럽트를 마스킹(인터럽트 비활성화) 기능
4. 인터럽트 간 우선순위 설정
결국에, 인터럽트가 발생하면 펌웨어가 크게 3단계로 인터럽트를 처리합니다.
<인터럽트 처리 3단계>
1. 인터럽트 컨트롤러(IC)가 인터럽트 소스를 판별
2. 인터럽트에 따라 인터럽트 서비스 루틴을 선택
3. 해당 인터럽트 소스 비활성화 후 서비스 루틴 진입
VIC는 위의 3단계를 하드웨어가 모드 처리 후 펌웨어의 인터럽트 서비스 루틴으로 진입합니다. 그리고 VIC는 인터럽트 서비스 루틴의 "시작 주소"를 가지고 있습니다. 시작 주소는 펌웨어가 직접 명시해줍니다.
정리
1. ARM에서 익셉션과 인터럽트는 구분되지 않고 동작한다. 그래도 의미를 나누자면 인터럽트는 외부 요인 (키보드...)에 의한 것이다.
2. 인터럽트의 종류는 IRQ, FIQ 2가지이다.
3. 인터럽트 레이턴시를 줄이기 위해 하드웨어를 붙인다.
4. strongly ordered인 경우에는 multiword의 load/store 명령은 가급적 피한다.
추가
1. 인터럽트는 정해진 기준 없이 예측 불가하게 이벤트 발생, 즉 하드웨어 적인 키보드, 입출력, 네트워크, 타이머,..
2. 익셉션은 어떤 기준을 어기면 발생해 예측 가능한 이벤트, 즉 어떤 수를 0으로 나누었을 경우, system call, overflow,..
A.1.4 Abort (강제 종료)
ARM에서 Abort는 인터럽트(익셉션)의 한 종류입니다. 인터럽트와 Abort를 나누자면
인터럽트 : 데이터 처리를 위해 정상적인 프로그램 흐름 끊음
Abort : 비정상적인 동작으로 인해 정상적인 프로그램 흐름 끊음 (강제 종료)
ARM의 경우에 3가지 경우로 Abort가 걸립니다.
1. 접근 권한 없이 MPU로 보호되는 메모리 접근
2. AMBA 메모리 버스가 에러 응답
3. ECC 로직에서 에러 발생
주로 "메모리" 관련 에러입니다. ARM이 메모리에 접근하는 방법은 명령어 읽기, 데이터 읽기입니다. 명령어 읽기에 실패한다면 prefetch abort, 데이터 읽기에 실패하면 data abort에 걸립니다. 혹은 메모리는 정상인데 읽어온 명령어를 모르는 경우가 있습니다. 이경우를 undefined instruction exception이라고 합니다. 이것 또한 일종의 abort입니다.
BUT!! undefined instruction exception(정의되지 않은 명령어)의 핸들러에서 정의 되지 않은 명령어를 소프트웨어적으로 처리 할 수 있습니다. 혹은 co-processor( 보조 프로세서)를 연결해 기능을 확장 할 수 있습니다.
정리
1. Abort는 인터럽트(익셉션)의 한 종류이다.
2. Abort는 주로 메모리 관련 에러인데 메모리가 정상인 경우 undefined instruction (정의 되지 않은 명령어)이다.
A.1.5 동작 모드와 뱅크드 레지스터
ARM의 동작 모드(operating mode)는 익셉션과 관련되어 있습니다. A.1.1의 이미지를 보시면 익셉션 벡터 테이블 별 동작 모드를 볼 수 있습니다. (간혹 익셉션과 상관없는 동작 모드도 존재합니다.)
뱅크드 레지스터는 어떤 전용의 레지스터가 있는 경우를 의미합니다. 동작 모드는 아래와 같이 7개 입니다. 하드웨어 마다 추가된 동작모드도 있습니다.
일반적으로는 색이 칠해지지 않은 영역 (범용 레지스터)들은 레지스터들을 공유하면서 사용합니다. 하지만 색을 칠해진 곳은 뱅크드 레지스터이며 공유하지 않는다는 것이 특징입니다. 만약 범용 레지스터가 공유하지 않는다면 많은 수의 레지스터들을 필요로 하기 때문에 공유합니다. 동작 모드별 설명은
- User mode : 일반적인 모드, ARM/Thumb 상태
- FIQ : FIQ 익셉션 발생 시 전환, ARM 상태일 때만 동작하고 빠른 처리를 위해 별도의 뱅크드 레지스터(R7_fiq~R14_fiq)가 있음
- IRQ : IRQ 익셉션 발생시 전환, ARM/Thumb 상태 모두 동작
- SVC : 운영체제에서 시스템 코드 수행을 위한 보호 모드, system call시 SVC 익셉션과 함께 SVC 모드로 전환 후 커널 동작 수행
- ABT : Data Abort, Prefetch Abort가 발생 시 ABT모드로 전환
- SYS : 사용자 프로세서가 임시로 커널 모드 획득 시 SYS모드로 전환, 혹은 사용자/커널 모드를 구분하지 않는 운영체제는 기본으로 SYS 모드인 경우가 많아 익셉션과 연관되어 있지 않고 소프트웨어로 모드 전환 후 진입 가능
동작 모드 별로 사용할 수 있는 범용/상태 레지스터의 최대 개수는 정해져 있어 다른 동작 모드라도 공유해서 사용해야 합니다. 공유하는 R0~R15 그리고 CPSR레지스터 이름에 의미가 있습니다.
- R0~R12 : 범용 레지스터(general purpose register)
- R13 : 스택 포인터(stack pointer, SP) 대부분의 프로그램은 스택을 기반으로 동작함
- R14 : 링크 레지스터(Link Register, LR) 서브 루틴 혹은 함수 호출이 끝난 후 리턴할 주소 (return address)를 저장함
- R15 : 프로그램 카운터(Program Counter, PC) 다음 명령어의 주소를 담음 혹은 branch or jump시 해당 명령어의 주소를 담음 ARM모드이면 4바이트 증가 Thumb모드이면 2바이트 증가
- CPSR : 프로그램 상태 레지스터(Current Program Status Register) 현재 ARM의 상태를 나타내는 레지스터
- SPSR : 백업된 상태 레지스터(Saved Program Status Register) CPSR의 백업 레지스터
FIQ모드를 보면 R8~R12까지는 공유하는 것이 아닌 FIQ모드 본인의 레지스터입니다. 이렇게 자기만의 레지스터가 있으면 context switch (저장 - 복원) 시 굳이 저장 및 복원을 할 필요가 없어 레이턴시가 줄어듭니다. 그래서 Fast가 붙은 것입니다. 그리고 각 동작 모드 별로 R13(SP), R14(LR)도 자신들만의 독립된 공간이 있습니다. 이렇게 각 동작모드 별로 공유하지 않고 자신만의 레지스터가 있는 경우를 뱅크드 레지스터(banked register)라고 합니다. 저는 bank를 은행으로 보았고 미리 예약 혹은 예금한다는 의미로 받아들였습니다. CPSR과 SPSR은 A.1.7에서 더 나옵니다.
정리
1. ARM에서 익셉션은 동작 모드과 관련이 있음, 그리고 각 동작모드 별 자신만 가지고 있는 뱅크드 레지스터가 있다.
2. R0~R12는 범용 레지스터라고 부르고 R13~R15 특수 목적으로 사용되는 레지스터이다.
A.1.6 ARM 모드와 Thumb 모드
ARM은 32비트와 16비트 명령어 집합이 있습니다. 이것을 ARM/Thumb 모드 명령어 집합이라고 합니다. Thumb 모드의 크기가 대략 ARM 모드에 비교해 70% 작다고 합니다.
Thumb 모드는 사이즈가 작은 대신에 속도가 느리고 ARM 모드는 사이즈가 큰 대신에 속도가 빠릅니다. 그래서 ARM은 두 모두 섞어 쓰는 것을 허용합니다. 즉, 펌웨어가 제어해 ARM/Thumb 모드를 런타임에 변경 가능합니다. 그리고 ARM/Thumb 명령어를 섞어 최종 바이너리를 만들 수도 있습니다.
ARM 모드와 Thumb 모드는 동작 모드에 따라 자동으로 바뀌기도 합니다. Thumb 모드가 동작 중이여도 익셉션이 발생 해 익셉션 핸들러로 들어갈 때는 ARM 모드로 전환됩니다. 그래서 익셉션 핸들러는 ARM 모드로 컴파일되어야 합니다. 그리고 Thumb 모드에서는 R8 이상의 높은 번호의 레지스터 사용이 제한됩니다. SP, LR, PC는 사용한데 반면 범용 레지스터 R8~R12는 몇 가지 명령어에서만 사용이 가능합니다.
정리
1. ARM에서는 ARM(32bit)/Thumb(16bit) 명령어 집합이 있다.
2. 속도가 중요하다면 ARM모드를 속도는 상관이 없지만 사이즈가 중요할 때는 Thumb를 적절히 사용한다.
A.1.7 프로그램 상태 레지스터
앞서 ARM의 동작 모드와 이것에 연결되어 있는 익셉션들의 상태(A.1.1 익셉션 벡터 이미지)를 보았습니다. 또, ARM이 처리하는 명령어 모드(ARM/Thumb)도 살펴보았습니다. 앞에 언급한 것들은 프로세서의 상태입니다.
프로세서 상태 외에도 프로그램이 동작하면서 생기는 많은 상태가 있습니다. 예를 들면 계산 값이 음수, 0, 양수가 나온다거나 오버플로가 발생했을 경우 이러한 프로그램의 상태를 저장하는 레지스터가 필요합니다. 이런 프로그램의 현재 상태를 저장하는 레지스터를 프로그램 상태 레지스터(Current Program Status Register, CPSR)라고 합니다. 반면에 상태를 백업하는 레지스터를 (Saved PSR, SPSR)이라고 합니다. 그렇기 때문에 CPSR, SPSR은 구조가 같습니다.
각 비트의 의미는
- N(Negative) : 계산 결과가 음수일 때 1로
- Z(Zero) : 계산 결과가 0일 때 1로
- C(Carry) : 계산 결과에 carry나 borrow 발생 시 1로
- V(oVerflow) : 계산 결과에 overflow 발생 시 1로 변경
- Q : 곱셈 시 32비트 넘어가면 올림수에 이용
- J(Jazelle) : Cortex-A 이상 프로세서에서 Jazelle 상태로 전환 시 1로, Jazelle는 하드웨어에서 Java 바이트 코드를 실행할 수 있도록 하는 확장 모드임
- DNM(Do Not Modify) : 확장을 위해 비워둠
- GE [3:0] : SIMD(Single Instruction Multi Data) 명령을 사용해서 연산을 할 때 하프 워드 단위로 크거나 같은지 표시함
- IT [7:2] : ITSTATE, Thumb-2에 포함된 IT(if-then) 명령을 처리할 때 참조함, 원래 Thumb 모드 명령어는 조건부 실행이 안되지만 IT비트 영역으로 조건부 실행이 가능하도록 만듦
- E(Endian) : 엔디안 표시
- A(Abort) : 예측 가능한 data abort만 발생, 비트 끄면 예측 불가능한 비동기 데이터 abort 허용
- I(IRQ) : 1이면 IRQ 비활성화
- F(FIQ) : 1이면 FIQ 비활성화
- T(Thumb) : 1이면 Thumb모드
- M [4:0](Mode) : 모드 비트
10000 : USR
10001 : FIQ
10010 : IRQ
10011 : SVC
10111 : ABT
11011 : UND
11111 : SYS
익셉션 발생 시 하드웨어가 익셉션에 연결되어 있는 해당 동작 모드로 M 영역 값을 바꿉니다. 만약 IRQ가 발생하면 하드웨어가 값을 0x12로 바꾸고 익셉션 핸들러로 진입합니다.
정리
1. ARM은 프로세서 상태(익셉션과 동작 모드)와 프로그램 상태(CPSR과 SPSR)라는 개념이 있다.
'OS > Embedded OS' 카테고리의 다른 글
부록 A.5 Makefile을 짜보자 (0) | 2021.08.24 |
---|---|
부록 A.4 gcc 사용법 (0) | 2021.08.24 |
부록 A.3 실행 파일 형식 (0) | 2021.08.24 |
부록 A.2 ABI (0) | 2021.08.24 |
2장 개발 환경 구성하기 (0) | 2021.08.14 |