이번에는 HCR_EL2 레지스터를 읽은 예시 코드를 소개합니다.
다음은 XEN 하이퍼바이저에서 호출되는 _show_registers() 함수의 어셈블리 명령어입니다.
01 000000000025c550 <_show_registers.isra.14>:
02 25c550: a9ba53f3 stp x19, x20, [sp, #-96]!
03 25c554: 12001c54 and w20, w2, #0xff
...
04 25c62c: d53c1101 mrs x1, hcr_el2
05 25c630: 90000140 adrp x0, 284000 <symbols_token_index+0x9700>
06 25c634: 91242000 add x0, x0, #0x908
07 25c638: 97ff7e2a bl 23bee0 <printk>
04번째 줄을 보면 'mrs x1, hcr_el2' 명령어를 실행해 HCR_EL2 레지스터의 값을 x1 레지스터에 로딩합니다. 07번째 줄은 printk() 함수를 호출해 HCR_EL2 레지스터의 값을 담고 있는 x1 레지스터를 출력합니다.
이번에는 HCR_EL2 레지스터에 값을 써서 설정하는 예시 코드를 소개합니다.
다음은 XEN 하이퍼바이저가 부팅할 때 호출되는 init_traps() 함수의 어셈블리 명령어입니다.
01 000000000025c8a0 <init_traps>:
02 25c8a0: d0000060 adrp x0, 26a000 <guest_irq_compat+0x70>
03 25c8a4: 91200000 add x0, x0, #0x800
04 25c8a8: d51cc000 msr vbar_el2, x0
...
05 25c8c8: d2800700 mov x0, #0x38 // #56
06 25c8cc: d51c1100 msr hcr_el2, x0
07 25c8d0: d5033fdf isb
08 25c8d4: d65f03c0 ret
먼저 05번째 줄을 보겠습니다. 0x38이란 값을 x0 레지스터에 이동하는 동작입니다. 06번째 줄은 x0 레지스터의 값을 hcr_el2 레지스터에 설정하는 명령어입니다.
[중요]
위 코드에서 0x38는 무엇을 의미할까요? 0x38을 2진수로는 111000로 표기할 수 있는데, 이는 HCR_EL2 레지스터를 구성하는 비트 맵에 대응됩니다.
HCR_EL2의 3번째 비트는 FMO, 4번째 비트는 IMO 그리고 5번째 비트는 AMO인데, 해당 비트를 1로 설정하면 비트 맵의 기능을 활성화하게 됩니다. 이 방식으로 HCR_EL2 레지스터를 설정합니다.
위에서 설명한 어셈블리 명령어에 대응되는 C 코드는 다음과 같습니다.
https://github.com/xen-project/xen/blob/stable-4.15/xen/arch/arm/traps.c
01 void init_traps(void)
02 {
...
03 /*
04 * Configure HCR_EL2 with the bare minimum to run Xen until a guest
05 * is scheduled. {A,I,F}MO bits are set to allow EL2 receiving
06 * interrupts.
07 */
08 WRITE_SYSREG(HCR_AMO | HCR_FMO | HCR_IMO, HCR_EL2);
09 isb();
10 }
08번째 줄은 HCR_EL2 레지스터에 첫 번째에 인자로 지정된 매크로 값을 써주는 WRITE_SYSREG() 매크로 함수를 사용합니다. HCR_AMO, HCR_FMO 그리고 HCR_IMO의 값을 OR 비트 연산할 결과를 HCR_EL2 레지스터에 써주는 동작입니다.



최근 덧글