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

vector table의 구현과 실제

twoweeks-within 2024. 11. 26. 19:24


Vector Table: 각각의 Exception이 일어 났을 때 정해진 곳으로 branch
> 그 용도에 맞는 처리 routine들이 들어 있으면 됨.
  
Low Vector를 기준
;----------------------------------------------------------------------------;
; ADDRESS EXCEPTION MODE ON ENTRY
;----------------------------------------------------------------------------;

; 0x00000000   Reset               Supervisor
; 0x00000004   Undefined Exception Undefined
; 0x00000008   Software Interrupt  Supervisor
; 0x0000000C   Abort (prefetch)    Abort
; 0x00000010   Abort (data)        Abort
; 0x00000014   Nothing             Nothing
; 0x00000018   IRQ                 IRQ

;----------------------------------------------------------------------------;


Reset > 0x0, Undef Exception 나면 0x4 뭐 이런 식으로 32bit씩 자리 차지 
 4byte씩만 가지고 Exception을 처리하기에는 너무 비좁음
   > Instruction 한 개 들어갈만한 공간 가지고 Exception을 처리하기에는 너무나 버거움.

AREA INIT_VECTOR, CODE, READONLY → INIT_VECTOR라는 부분 기억
   
CODE32                ; 32-bit ARM instruction set
ENTRY

; Vector Table
0x00   B   Reset_Handler        ; 0x0
0x04   LDR PC, 0x30             ; 0x4
0x08   LDR PC, 0x34             ; 0x8
0x0C   LDR PC, 0x38             ; 0xC
0x10   LDR


각 주소별로 어디론가 branch하는 코드가 들어 있음. : 각각의 Handler로 Jump 
4byte씩 ARM mode에서 돌게 하기 위해 > 위에 CODE32가 자리 잡음.
 Exception에 진입 > ARM의 기본 state = ARM state. 

Reset > Reset_Handler,
Data Abort > Abort_Handler로 Jump! 

다른 곳에 각각의 Handler를 구현 > Exception Vector에서 Jump하도록 구현. 

 어떻게 0x0부터 차례로 메모리에 자리잡게 할지?
      : Scatter Loading을 이용 > 컴파일 할 때 0x0부터 자리잡게 하고서, Flash에 저장할 때 0x0부터 차례대로
 or  SDRAM이 0x0부터 시작하는 거라면 0x0부터 복사 Vector Table을 vectors.s에 만들어 놓고서 컴파일한 후
    > Scatter Loading File에 아래와 같이 적어주면 0x0부터 만들어짐

BOOT_ROM 0x0 {
       BOOT_RAM 0x0 0x4000 ; 0x0부터 시작 {
            vectors.o (INIT_VECTOR, +FIRST) ; vectors.s를 컴파일하는데, INIT_VECTOR AREA를 맨 앞에 두어라.

(참고 +LAST는 맨 마지막에 놓으라는뜻 ) ..........
     }
}

 High Vector로 만들고 싶으면?

BOOT_ROM 0x0 {
         BOOT_RAM 0xFFFF0000 0x4000 ; 0xFFFF0000 부터 시작 {

              vectors.o (INIT_VECTOR, +FIRST) ; vectors.s를 컴파일하는데, INIT_VECTOR AREA를 맨 앞에 
      }
}

각 Handler들을 그때 그때 막 바꾸고 싶을땐..
branch하라는 명령어 말고 다른 거 넣으면됨

0x00   B   Reset_Handler         ; 0x0
0x04   LDR PC, 0x30              ; 0x4
0x08   LDR PC, 0x34              ; 0x8
0x0C   LDR PC, 0x38              ; 0xC
0x10   LDR PC, 0x3C              ; 0x10
0x14   LDR PC, 0x40              ; 0x14
0x18   LDR PC, 0x44              ; 0x18
0x1C   LDR PC, 0x48              ; 0x1C

; Handlers Address (Data)
0x30   DCD 0x1000                ; Undefined Handler
0x34   DCD 0x2000                ; SWI Handler
0x38   DCD 0x3000                ; Prefetch Handler
0x3C   DCD 0x4000                ; Abort Handler
0x44   DCD 0x6000                ; IRQ Handler
0x48   DCD 0x7000                ; FIQ Handler


 0x30, 0x34, 0x38, 0x3C, 0x44, 0x48에 들어 있는 값을 바꿔주면 그때 그때 상황에 맞추어 handler를 바꿀 수 있음.
 Reset Handler는 그대로 쓴이유 > Entry point니까, 그냥 두는 매너

 Handler에 무엇을 채워 넣으면 될까? 

1. Reset Handler : Power On이 되면 진입하게 되는 Default Handler  처리X

2. Undefined Handler 
 Undefined Exception이 발생하는 이유:  ARM core가 Memory에서 Op code를 decode했더니 모르는 Op code더라.. 라는 상황
     > a) XIP Memory, Software가 실행되고 있는 Memory, 가 Corrupt 되었거나, Software가 저장된 저장 매체가 Corrupt될때.
   >> Design Review부터 다시 -> Memory를 제대로 control 하고 있는 것인지 timing이 적당한 건지 확인
     > b) 일부러 Undefined Exception
   ex) ARM Core 혼자 만으로는 Computing Power가 다 나오지 않을 때 
        > Co processor를 달아서 ARM이 혼자 해야 할 일을 덜어줌
      > Co processor에게 뭔가 명령을 내려주고 싶을 때,

      > Undef Exception의 경우 자기 전용 Register가 R13_und, R14_und, SPSR_und 뿐,  -> backup 
                >> UNDEF_Handler stmfd sp!, {r0-r12, r14} ;                       구현해 넣고 싶은 내용들~~~
     ldmfd sp!, {r0-12, pc}^ ; Register들을 다시 Restore.
     Undef Exception: LR에 Undef exception이 난 명령어 바로 다음을 가리키는 값이 들어감 
 > Handler에 들어와서 현재 Register들만 backup하면됨

3. Prefetch Abort Handler : 
  문제가 발생했다는 것을 외부에 알리는 일, information을 남겨놓는 일을 남겨 놓음.
    > 안 만나면 좋은 Exception이니까 어떻게든 만천하에 알려서 문제가 수정될 수 있도록 하는 routine 끼워놓음.
       > Debugging 용도의 Code들이 삽입
   MMU를 쓰는 경우에서 Prefetch Abort의 경우 : 스와핑으로 잘 알려진 Demand Loading을 사용하느라 발생
         Demand Loading : XIP를 하는 Memory가 너무 작음, Software를 모두 Loading X , 실제 실행 해야 하는 부분만 XIP Memory에 Loading 
PAbort : 진입했다가 복귀할 때는 Undef Exception과 같은 처리를 하면 됨

PAbort_Handler stmfd sp!, {r0-r12, r14} ;   Register들을 backup 해

구현해 넣고 싶은 내용들

ldmfd sp!, {r0-12, pc}^ ; Register들을 다시 Restore-

4. Data Abort Handler DAbort : Align이 안 맞는 Data를 Access할 때 발생,
     >강제로 맞춰서 원상 복구하는 형태의 Handler를 넣어놓음.
 Abort mode : 자기 전용 Register가 R13_abt, R14_abt, SPSR_abt 3개,
    > Handler 진입 시 R0~R12를 bakcup하고요, 이전 mode로 돌아가기 위하여 LR을 backup
DAbort Handler : 임무를 마치고 돌아갈 시점이 LR - 8 >  맨 앞에 lr을 교정하는 명령어가 하나.

 DAbort_Handler sub lr, lr, #8 ; 돌아갈 주소 교정
 stmfd sp!, {r0-r12, r14} ; Register들을 backup 해 두고요. 
구현해 넣고 싶은 내용들~
ldmfd sp!, {r0-12, pc}^ ; Register들을 다시 Restore

5. FIQ :  IRQ는 FIQ, 
    IRQ : LR-8를 해주면, Exception이 발생한 시점에 처리된 명령어의 알아 낼 수 있음
             > Handler에 진입하자마자 LR을 가공. 
     >  Exception 발생 당시에 처리된 명령어의 다음 바로 주소가 Interrupt를 처리하고 난 후에 계속 진행되어야 할 명령어
  > LR-4 : 다음 처리할 명령어를 찾을 수 있음.
    FIQ : R8~R14하고 SPSR 갖고있음 
          >진입 : R0~R7까지만 backup 
    IRQ :  R13, R14, SPSR 갖고 있음, R0~R12를 backup
> FIQ,IRQ : 돌아갈 주소 LR을 backup

 IRQ_Handler sub lr, lr, #4 
  stmfd sp!, {r0-r12, r14} ; Register들을 backup 
 구현해 넣고 싶은 내용들~
 ldmfd sp!, {r0-r12, r14}^ 

FIQ_Handler sub lr, lr, #4 
stmfd sp!, {r0-r7,lr} 구현해 넣고 싶은 내용들~
ldmfd sp!, {r0-r7,pc}^ 

6. SWI SWI_Handler는 Undef Exception Handler랑 똑같이 처리

7. SWI_Handler

stmfd sp!, {r0-r12, r14} ; Register들을 backup 
 구현해 넣고 싶은 내용들~
ldmfd sp!, {r0-12, pc}^ ; Register들을 다시 Restore

 Pipe line과 Exception관계에서의 Table을 수시로 보시고 생각해 봐야함..
 

// R14는 레지스터 예외 발생시 사용하려고 안전하게 백업