Inflearn brand logo image

인프런 커뮤니티 질문&답변

동엽님의 프로필 이미지
동엽

작성한 질문수

시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리 - 1부 저자 직강 (2024년 버전)

5.4.3 실습: 어보트 모드(데이터 어보트)에서 슈퍼바이저 모드 변경 실습 (TRACE32)

5.4.3 실습에서 궁금한점이 있습니다.

작성

·

80

0

해당 실습을 진행하던 도중 궁금한점이 있어 이렇게 글 남기게 되었습니다!

data abort exception이 발생해서 vector_dabt라는 주소로 분기하게 된 상태에서는 SPSR_abt 레지스터에 이전 동작 모드인 user_mode bit encoding값이 설정이 되어있는 걸 볼 수 있었습니다.

 

그런데, Data abort를 처리하기 위해 supervisor mode로 진입하는 과정에서 movs pc, lr 명령어를 실행하면 supervisor mode로 진입은 하지만, SPSR_svc 레지스터에는 이전 동작 모드가 로드되지 않은 걸 볼 수 있었는데, 그렇다면 exception이 유발이 되어야만 SPSR_<mode>의 값이 갱신되는 것 인지 단순히 movs, subs와 같은 동작 모드를 변경하는 명령어로는 SPSR이 갱신되지 않는 것 인지 궁금합니다.

답변 2

0

김동현 (Austin Kim)님의 프로필 이미지
김동현 (Austin Kim)
지식공유자

질문하신 내용에 대해 직접 디버깅으로 확인하고 답신 드립니다.

혹시 이해가 가지 않는 부분이 있으면 다시 질문 부탁드립니다.

 

[User 모드에서 Data abort를 유발하는 동작 코드 리뷰]

1. Data abort 익셉션이 유발되면 0xFFFF0010 주소로 프로그램 카운터가 분기합니다.

NSR:FFFF0000|EA0003FF b 0xFFFF1004 ; vector_rst

NSR:FFFF0004|EA000465 b 0xFFFF11A0 ; vector_und

NSR:FFFF0008|E59FFFF0 ldr pc,0xFFFF1000

NSR:FFFF000C|EA000443 b 0xFFFF1120 ; vector_pabt

>> NSR:FFFF0010|EA000422 b 0xFFFF10A0 ; vector_dabt

이 때 CPSR과 SPSR_abt 레지스터의 값은 다음과 같습니다.

  • CPSR: 0x1D7 (현재 동작 모드는 Abort mode)

  • SPSR_abt: 0x10 (이전 동작 모드는 User mode)

NSR:FFFF10A0|vector_dabt: sub r14,r14,#0x8 ; r14,r14,#8

NSR:FFFF10A4| stm r13,{r0,r14} // r0와 r14 레지스터의 값을 프로세스의 스택에 푸시

// [1] 매우 중요한 동작

NSR:FFFF10A8| mrs r14,spsr // spsr의 값(spsr_abt과 같음)을 r14로 읽음

NSR:FFFF10AC| str r14,[r13,#0x8] // r14의 값(spsr_abt)을 프로세스의 스택에 푸시 // [2] 매우 중요한 동작

NSR:FFFF10B0| mrs r0,cpsr

NSR:FFFF10B4| eor r0,r0,#0x4 ; r0,r0,#4

NSR:FFFF10B8| msr spsr_cxsf,r0 // spsr.m를 supervisor 모드 필드로 변경

// spsr는 뱅크드 레지스터이므로, 어보트 모드에서

// spsr을 변경하면 spsr_abt가 함께 변경

NSR:FFFF10BC| and r14,r14,#0x0F ; r14,r14,#15

NSR:FFFF10C0| cpy r0,r13

NSR:FFFF10C4| ldr r14,[pc,+r14,lsl #0x2] // r14 레지스터에 분기할 레이브를 저장

// 이전 동작 모드가 user 모드이면: __dabt_usr로 분기

NSR:FFFF10C8| movs pc,r14

NSP:FFFF10CC| dcd 0xC0201CE0 ; __dabt_usr

NSP:FFFF10D0| dcd 0xC0201910 ; __dabt_invalid

__dabt_usr 레이블의 동작

NSR:C0201CE0|__dabt_usr: sub r13,r13,#0x48 ; r13,r13,#72

NSR:C0201CE4| stmib r13,{r1-r12}

NSR:C0201CE8| mrc p15,#0x0,r7,c1,c0,#0x0 ; p15,#0,r7,c1,c0,#0 (system control)

NSR:C0201CEC| ldr r8,0xC0201C20

...

NSR:C0201D1C| cpy r2,r13

NSR:C0201D20| bl 0xC021BB20 ; v7_early_abort

NSR:C0201D24| b 0xC0201FA4 ; ret_from_exception

v7_early_abort 함수를 호출한 다음에 ret_from_exception 레이블로 분기

여기서 v7_early_abort는 data abort에 대한 서비스 루틴을 실행

 

ret_from_exception 레이블은 r9와 r8 레지스터를 업데이트한 다음에 ret_to_user 레이블 분기

NSR:C0201FA4|ret_from_exception: lsr r9,r13,#0x0D

NSR:C0201FA8| lsl r9,r9,#0x0D

NSR:C0201FAC| mov r8,#0x0 ; r8,#0

NSR:C0201FB0| b 0xC0201048 ; ret_to_user

ret_to_user 레이블에서는 유저 모드로 복귀

NSR:C0201048|ret_to_user: cpsid i

...

NSR:C0201068| cpy r2,r13

NSR:C020106C| ldr r1,[r2,#0x40] // '[2] 매우 중요한 동작'으로 위에 명시한 프로세스의 스택 주소에 이전에 저장된 spsr_abt의 값(0x10, 이전 동작 모드는 user 모드)을 r1레지스터로 읽음

NSR:C0201070| ldr r14,[r2,#0x3C]!

NSR:C0201074| tst r1,#0x8F ; r1,#143 // 예외 처리 확인

NSR:C0201078| bne 0xC0201094

NSR:C020107C| msr spsr_cxsf,r1 // spsr(spsr_svc)에 r1 레지스터를 저장

NSR:C0201080| strex r1,r2,[r2]

NSR:C0201084| ldmdb r2,{r0-r14}^ // 스택에 푸시된 값을 로딩해서 r0~r14 레지스터 업데이트, 스택에 되돌아갈 주소가 저장된 r14 값이 이미 푸시됨 - '[1] 매우 중요한 동작'으로 표기

NSR:C0201088| nop

NSR:C020108C| add r13,r13,#0x48 ; r13,r13,#72

NSR:C0201090| movs pc,r14 // 유저 모드로 복귀하면서 data abort가 유발된 프로그램 카운터로 분기

 

[질문에 대해 정리]

  • SPSR 레지스터의 값은 익셉션이 유발될 때 Arm 프로세서가 하드웨어적으로 업데이트합니다. 즉 익셉션이 유발된 시점의 CPSR의 값을 SPSR_<mode>에 업데이트합니다.

  • movs, subs와 같은 동작 모드를 변경하는 명령어를 실행하면, movs 혹은 subs 명령어를 실행한 시점의 CPSR의 값이 SPSR_<mode>로 복사되지는 않습니다.

  • SPSR 레지스터의 값은 msr spsr_cxsf,r0 명령어와 같이 어셈블리 명령어로 변경할 수 있습니다. 대부분 동작 모드를 변경하기 직전에 spsr 레지스터의 값을 변경합니다.

언제든 궁금한 점이 있으면 질문해주세요.

감사합니다.

동엽님의 프로필 이미지
동엽
질문자

답변 감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다. 동엽님.

ARM 아키텍처에서 예외가 발생하면, 다루고 있는 모드에 따라 특정한 예외 처리 동작을 수행하게 됩니다. 이 과정에서 사용되는 레지스터에 대한 질문을 주셨습니다. 구체적으로는 예외 발생 시와 동작 모드 전환 시의 SPSR 레지스터에 대해 궁금해 하셨네요.

예외 및 SPSR 동작 이해

  1. 예외 발생 시:

    • SPSR: 예외가 발생하면, 해당 예외 모드의 SPSR 레지스터에는 예외가 발생하기 직전에 실행 중이던 상태 정보가 저장됩니다. 예를 들어, user mode에서 data abort가 발생하면, SPSR_abt에는 user mode의 CPSR 값이 저장됩니다.
    • 이때 예외 벡터는 예외가 발생한 상황에 따라 해당 주소로 분기합니다.
  2. 동작 모드 전환 시:

    • MOVS 명령어: movs pc, lr과 같은 명령어는 예외 처리 모델이 아닌 일반적인 명령어로 사용될 때 CPSR 이하의 레지스터 값만을 갱신하며, SPSR에는 영향을 주지 않습니다.
    • 따라서, 단순히 모드 전환 자체로는 SPSR이 갱신되지 않으며, 예외 발생에 의해서만 SPSR_가 업데이트됩니다.

이와 같은 특성으로 인해 내리신 결론처럼, 예외 상황에서의 전환이 아닌 단순한 명령어로는 SPSR의 갱신이 이루어지지 않는 것입니다.

관련하여 더 심층적인 이해를 돕기 위해 리눅스 커널 동작 모드별 스택 포인터 초기화 관련 유사 질문 보기를 참조하시면, 추가적인 사례와 설명을 확인할 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

동엽님의 프로필 이미지
동엽

작성한 질문수

질문하기