Armv8

레지스터 셋

justbagmeg 2023. 7. 21. 14:05

https://developer.arm.com/documentation/den0024/a/ARMv8-Registers

AARCH64 범용 레지스터

모든 예외 레벨에서 언제든지 접근할 수 있는 64bit의 범용 레지스터 31개를 제공한다. 각 레지스터는 64bit며 X0 ~ X30까지 존재한다.

 

각 64bit 범용 레지스터는 32bit W 레지스터를 포함하며, W 레지스터는 X 레지스터의 하위 워드에 매핑된다. -> 그러면 armv8은 한 번에 처리하는 단위가 32bit라는건가? 

W레지스터에서 값을 읽는다면 상위 X레지스터의 값은 읽지 않고 W 레지스터에 쓴다면 X레지스터의 값은 00000000으로 쓰여진다. W 레지스터에 0xFFFFFFFF을 쓴다면, X레지스터는 0x00000000FFFFFFFF 이 된다.

 

 

 

 

 

 

31개의 핵심 레지스터 외에도 특별 레지스터가 존재한다. 

X31, W31 레지스터는 존재하지 않는다. 다만 명령어들은 31이 ZERO 레지스터를 가리키도록 인코딩되어 있다.하나 이상의 인수가 숫자 31이 스택 포인터(SP)를 나타내도록 인코딩되는 제한된 명령어 그룹도 있습니다.

제로 레지스터에 접근할 때 모든 쓰기는 무시되고(레지스터에 아무것도 작성이 안된다는 거겠지??) 모든 읽기는 0을 반환합니다. 64비트 형식의 스택 포인터 레지스터는 X 접두사를 사용하지 않는다는 점에 유의하자. (X 접두사를 안쓴다는거는 X29 이렇게 접근하는게 아니라 29 이런식으로 접근한다는건가?) ㄴㄴ 밑에 그림을 보면, 32bit, 64bit를 나누기 위해서 32bit SP인 경우 앞에 W 접두사를 붙인다.

 

 

 

 

ARMv8 아키텍처에서 AARCH64로 실행할 때, 각 예외 레벨에서 반환된 상태 값은 다음 특정 레지스터들에 저장된다.

- Exception Link Register (ELR) -> 예외 반환 주소 저장

- Saved Processor State Register (SPSR)

예외 레벨마다 지정된 SP가 있지만, 반환 상태를 저장하기 위한 것은 아니다.

 

 

 

 

 

 

 

Zero Register

제로 레지스터는 소스 레지스터로 사용될 때는 0으로 읽고, 목적지 레지스터로 사용될 경우는 값을 버린다. 모든 명령어에서 사용할 수 있는 것은 아니지만 대부분의 명령어에서 사용 가능한다.

스택 포인터

ARMv8 구조에서 스택 포인터는 예외 레벨과 어느 정도 구분되어 있다. (구분되어 있다는 말이 예외 레벨에 종속되지 않고 따로따로 존재한다?? 이런 느낌인가). 아무튼 기본적으로 예외를 발생시키면 예외 레벨에 맞는 스택 포인터 SP_ELn이 선택된다. 예를 들어 예외 레벨 1을 발생시키면, SP_EL1이 선택된다. (선택한다는게 무슨 말이야? 스택 포인터가 예외 처리 후 돌아올 위치를 가리키는 거잖아. 그러니까 어떤 예외가 발생했을 때 예외 처리가 끝난 후 돌아올 위치를 지정한다. 이렇게 이해하면 될까?? ) 각 예외 레벨은 스택 포인터를 가지고 있다. SP_EL0, SP_EL1, SP_EL2, SP_EL3. 

SP_EL0 이외의 레벨에서 프로세서는 다음 것(?)들을 사용할 수 있다.

- 해당 예외 레벨 전용 스택 포인터 SP_ELn

- EL0의 스택 포인터 SP_EL0

그러니까 EL0 외의 예외 레벨에서는 EL0의 스택 포인터까지 사용할 수 있다는거지. 불쌍한 EL0은 자기거를 나눠주면서 자기는 자기거밖에 못쓰고...

접미사 t는 SP_EL0이 선택될 걸 의미하고, h는 SP_ELn이 선택될 걸 의미한다. (그럼 굳이 ELnt 이렇게 숫자 넣은 이유가 뭐지? 그냥 EL 구분하는건가?)

 

 

SP는 대부분의 명령어에서 참조할 수 없다. 하지만 ADD 같은 명령어같은 일부 산술 명령어에서 현재 스택 포인터를 읽고 쓰면서 함수의 스택 포인터를 조정할 수 있다. 

  ADD SP, SP, #0x10      // Adjust SP to be 0x10 bytes before its current value

PC

원래 ARMV7 명령어 세트의 특징 중 하나는 범용 레지스터로 프로그램 카운터인 R15를 사용한 것이다. PC는 몇 가지 영리한 프로그래밍 트릭을 가능하게 했지만 컴파일러와 복잡한 파이프라인 설계를 어렵게 만들었다. ARMv8은 PC에 대한 직접적인 접근을 제거함으로서 반환 예측이 더 쉬워지고 ABI 사양이 단순화됐다. (반환 예측은 또 뭘까.. 반환이 어떤 반환을 말하는거지? ABI가 뭐지?)
PC는 네임드 레지스터로 액세스할 수 없다. (네임드 레지스터라는게 범용 레지스터를 말하는건가?) PC 상대 로드 및 주소 생성과 같은 특정 명령어에 암시적으로 사용되며 PC를 데이터 처리 명령 또는 로드 명령의 대상으로 지정할 수 없다.

SPSR

예외를 처리할 때 프로세스의 상태는 연관된 SPSR에 저장된다. SPSR은 예외를 처리하기 전의 PSTATE를 저장하고, 예외 처리가 끝나면 이전의 PSTATE를 복원한다.

https://developer.arm.com/documentation/den0024/a/ARMv8-Registers/AArch64-special-registers/Saved-Process-Status-Register

각 비트는 AARCH64의 다음 값들을 나타낸다.

- N: negative result 

- Z: zero result

- C: carry out

- V: overflow 

- SS: Software Step. 예외 처리 시 software step이 활성화 됐는지 나타냄. (software step이 뭐야?)

- IL: Illigal Execution State Bit. 예외 처리 직전의 PSTATE.IL 값 (PSTATE.IL이 뭐야?)

- D: Process state Debug mask. 예외가 발생한 예외 레벨을 대상으로 하는 watchpoint, breakpoint 및 소프트웨어 단계 디버그 이벤트의 디버그 예외가 마스킹되었는지 여부를 나타낸다. 

- A: SError mask bit (system error)

- I: IRQ mask bit

- F: FIQ mask bit

- M[4]: 예외가 발생한 곳의 예외 상태( ??). 0은 AARCH64를 나타낸다. (이게 무슨 말이지?? )

- M[3:0]: 예외가 발생한 모드 또는 수준. (수준이라는게 레벨을 말하는건가?)

AARMv8 에서 SPSR은 발생한 예외 레벨에 따라 달라진다. EL1에서 발생하면 SPSR_EL1을 사용하고 ELn에서 발생하면 SPSR_ELn을 사용한다.

The register pairs ELR_ELn and SPSR_ELn that are associated with an Exception level retain their state during execution at a lower Exception level.

프로세스 상태 (PSTATE)

AArch64에는 ARMv7의 현재 프로그램 상태 레지스터(CPSR)와 직접적으로 대응하는 것이 없다. AArch64에서는 기존 CPSR의 구성 요소가 독립적으로 액세스할 수 있는 필드로 제공한다. 이를 통칭하여 프로세서 상태(PSTATE)라고 한다.

https://developer.arm.com/documentation/den0024/a/ARMv8-Registers/Processor-state

AArch64에서는 ERET 명령을 실행하여 예외에서 돌아오면 SPSR_ELn이 PSTATE에 복사된다. 이렇게 하면 ALU 플래그, 실행 상태, 예외 수준 및 프로세서 분기(branch)가 복원된다. 여기서부터 ELR_ELn의 주소에서 실행을 계속한다.
PSTATE.{N, Z, C, V} 필드는 EL0에서 액세스할 수 있다. 다른 모든 PSTATE 필드는 EL1 이상에서 실행할 수 있으며 EL0에서는 정의되지 앟는다.

시스템 레지스터

AArch64에서 시스템 구성은 시스템 레지스터를 통해 제어되며, MSR 및 MRS 명령어를 사용하여 액세스한다.

MSR, MRS 명령어 설명 페이지

https://developer.arm.com/documentation/den0024/a/The-A64-instruction-set/System-control-and-other-instructions/System-register-access

 

Documentation – Arm Developer

 

developer.arm.com

레지스터 이름은 해당 레지스터가 접근할 수 있는 가장 낮은 예외 수준을 알려준다.

예를 들어, 

- TTBR0_EL1은 EL1, EL2, EL3에서 접근할 수 있다.

- TTBR0_EL2는 EL2, EL2에서 접근할 수 있다.

접미사 _ELn이 붙은 레지스터는 일부 또는 모든 레벨에 별도의 뱅크 복사본이 있지만 일반적으로 EL0은 아니다. EL0에서 액세스할 수 있는 시스템 레지스터는 거의 없지만, 캐시 유형 레지스터(CTR_EL0)는 액세스할 수 있는 레지스터 중 하나다.

MRS  x0, TTBR0_EL1          // Move TTBR0_EL1 into x0
MSR  TTBR0_EL1, x0          // Move x0 into TTBR0_EL1

이전 버전의 ARM 아키텍처는 시스템 구성에 코프로세서(coprocess 가 뭘까? 뭔가 같이 하는 프로세스 그런 느낌인데.. )를 사용했지만 AArch64에는 코프로세서에 대한 지원이 포함되어 있지 않다.
표에는 각 레지스터의 복사본이 별도로 있는 예외 레벨이 나와 있다. 예를 들어 별도의 보조 제어 레지스터(ACTLR)는 ACTLR_EL1, ACTLR_EL2 및 ACTLR_EL3으로 존재한다.

시스템 컨트롤 레지스터 SCTLR

시스템 제어 레지스터(SCTLR)는 표준 메모리, 시스템 기능을 제어하고 코어에서 구현되는 기능에 대한 상태 정보를 제공하는 레지스터다.

https://developer.arm.com/documentation/den0024/a/ARMv8-Registers/System-registers/The-system-control-register

https://developer.arm.com/documentation/den0024/a/ARMv8-Registers/System-registers/The-system-control-register

 

Documentation – Arm Developer

 

developer.arm.com

Endianness

우왓 이건 또 뭐야.

메모리의 바이트를 리틀 엔디안(LE) 또는 빅 엔디안(BE) 라고 보는 두 가지 방법이 있다. 빅 엔디안에서는 MSB가 가장 낮은 주소, 즉 0에 가까운 주소에 저장된다. 반면 리틀 엔디안에서는 LSB가 가장 낮은 주소에 저장된다. 엔디안 대신 바이트 순서라고 해도 된다.

이 데이터 바이트 순서(엔디안)은 예외 수준별로 독립적으로 제어된다. (오... 그럼 하나의 아키텍처에서 여러 엔디안을 사용한다는거!>?!?!?!?!?!) EL1, EL2, EL3 에서는 SCTLR_ELn.EE 레지스터가 엔디안을 설정한다. 

EL1의 추가 비트인 SCTLR_EL1.E0E는 EL0의 데이터 엔디안 설정을 제어한다. AArch64 실행 상태에서 데이터 액세스는 LE 또는 BE가 될 수 있지만 명령어 페치는 항상 LE가 된다.

프로세서가 LE와 BE를 모두 지원하는지 여부는 프로세서 구현에 따라 다르다. 리틀 엔디안만 지원되는 경우 EE 및 E0E 비트는 항상 0이고, 빅 엔디안만 지원되는 경우 EE 및 E0E 비트는 정적 1 이다.