본문 바로가기

카테고리 없음

[가상화-virtualization] HCR_EL2 레지스터에 접근하는 어셈블리 코드 분석

이번에는 HCR_EL2 레지스터를 읽는 예시 코드를 소개합니다. 다음은 XEN 하이퍼바이저에서 호출되는 _show_registers 함수의 어셈블리 명령어입니다.

01 0x25c550 <_show_registers.isra.14>:
02  0x25c550:    stp    x19, x20, [sp, #-96]!
03  0x25c554:    and    w20, w2, #0xff
...
04  0x25c62c:    mrs    x1, hcr_el2
05  0x25c630:    adrp    x0, 284000 <symbols_token_index+0x9700>
06  0x25c634:    add    x0, x0, #0x908
07  0x25c638:     bl    0x23bee0 <printk>

먼저 04번째 줄에 있는 'mrs x1, hcr_el2' 명령어를 분석하겠습니다. 이것은 HCR_EL2 레지스터의 값을 x1 레지스터에 로딩하는 동작입니다. 07번째 줄은 printk 함수를 호출해 HCR_EL2 레지스터의 값을 저장한 x1 레지스터를 출력합니다.
 
이번에는 HCR_EL2 레지스터를 설정하는 예제 코드를 소개합니다. 다음은 XEN 하이퍼바이저가 부팅할 때 호출되는 init_traps 함수의 어셈블리 명령어입니다.

01 0x25c8a0 <init_traps>:
02  0x25c8a0:    adrp    x0, 0x26a000 <guest_irq_compat+0x70>
03  0x25c8a4:    add    x0, x0, #0x800
04  0x25c8a8:    msr    vbar_el2, x0
...
05  0x25c8c8:    mov    x0, #0x38 // #56
06  0x25c8cc:    msr    hcr_el2, x0
07  0x25c8d0:    isb
08  0x25c8d4:    ret
    
먼저 05번째 줄을 보겠습니다. 0x38이란 값을 x0 레지스터에 이동하는 동작입니다. 06번째 줄은 x0 레지스터의 값을 hcr_el2 레지스터에 설정하는 명령어입니다.

 

---
[중요] HCR_EL2 레지스터에 설정하는 0x38의 정체는?

위 코드에서 0x38은 무엇을 의미할까요? 0x38을 2진수인 0b111000으로 표기할 수 있는데, 이는 HCR_EL2 레지스터를 구성하는 비트 필드에 대응됩니다.

HCR_EL2의 3번째 비트는 FMO, 4번째 비트는 IMO, 그리고 5번째 비트는 AMO인데, 이를 이진수로 0b111000으로 표기할 수 있습니다. 해당 비트 필드를 1로 설정하면 비트 필드의 기능을 활성화하게 됩니다. 이 방식으로 HCR_EL2 레지스터를 설정합니다.

참고로 HCR_EL2.IMO와 HCR_EL2.FMO는 IRQ와 FIQ를 가상 인터럽트로 설정하는 비트 필드입니다. HCR_EL2.IMO와 HCR_EL2.FMO 비트 필드인데 1로 설정되면 EL2나 EL1에서 IRQ나 FIQ가 유발되면 EL2에 존재하는 익셉션 핸들러(VBAR_EL2)가 받아 처리합니다. 또한 HCR_EL2.AMO는 EL1 혹은 EL2에서 SError가 유발되면 EL2에서 받아 처리할 수 있는 기능을 제공합니다.

정리하면 HCR_EL2 레지스터에 존재하는 IMO, FMO, AMO 비트 필드는 EL1에서 인터럽트나 SError가 유발되면 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번째 줄을 봅시다. WRITE_SYSREG 매크로 함수를 사용해 HCR_AMO, HCR_FMO, HCR_IMO를 비트 OR 연산한 결과를 HCR_EL2 레지스터에 쓰는 동작입니다.

HCR_EL2 시스템 레지스터 이외의 다른 시스템 레지스터도 이와 유사한 방식으로 설정합니다.

---

 

< '시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 저자>