← ARMv9 해설DUJINLABS.COM

Source deep dive 06 · KVM_RUN · EL2 · VTTBR · guest abort

ARM64 KVM vCPU와 Stage-2 fault 소스 분석

VM이 “CPU를 빌려 쓴다”는 설명에서 시작해 QEMU의 KVM_RUN이 guest register를 EL2에 적재하고, Stage-2 translation fault가 memslot과 host page를 거쳐 새 PTE로 해결되는 실제 경로를 분석한다.

Kernel
Linux v6.18.37
Entry
KVM_RUN
EL2
VHE · nVHE
MMU
Stage 2

KVM은 guest CPU 상태와 memory 번역을 번갈아 실행한다

QEMU는 장치와 VM 생명주기를 관리하고, KVM kernel module은 guest CPU가 native에 가깝게 실행되도록 EL2를 설정한다. guest가 스스로 처리할 수 있는 instruction은 계속 실행되고, privileged operation·Stage-2 fault·interrupt·MMIO 같은 사건에서 host로 나온다.

vCPU

guest register와 pending exception을 담는 실행 단위.

Memslot

guest physical address 범위를 userspace virtual memory와 연결한다.

Stage-2 MMU

guest IPA를 host PA로 번역하고 권한을 제한한다.

Exit

host가 처리해야 하는 사건과 userspace까지 전달할 사건을 구분한다.

struct kvm, kvm_vcpu, kvm_s2_mmu를 먼저 잡는다

객체범위arm64 핵심 field
struct kvmVM 전체arch.mmu, memslots, vgic와 VMID.
struct kvm_vcpu가상 CPU 하나arch.hw_mmu, sysregs, fault info, pending IRQ.
struct kvm_s2_mmuStage-2 translationpage-table object, VTCR, VMID와 nested MMU 관계.
struct kvm_runKernel↔QEMU 공유 ABIexit_reason, MMIO data, system event와 debug 정보.

struct kvm_s2_mmustruct kvm_vcpu_arch가 architecture state의 중심이다.

KVM_RUN에서 guest 진입까지

Host userspace → guest

QEMU ioctl(vcpu_fd, KVM_RUN)
→ kvm_arch_vcpu_ioctl_run(vcpu)
→ pending signal·timer·request 처리
→ vgic state와 guest sysreg 준비
→ kvm_arm_vcpu_enter_exit(vcpu)
→ kvm_call_hyp_ret(__kvm_vcpu_run)
→ guest world entry

메인 loop는 kvm_arch_vcpu_ioctl_run()에 있다. guest에 한 번 들어갔다가 끝나는 함수가 아니라 exit를 처리하고 다시 들어가는 loop다.

VHE와 nVHE는 같은 목표를 다른 경계로 구현한다

ModeHost kernel 위치__kvm_vcpu_run
VHEEL2 host register view 사용arch/arm64/kvm/hyp/vhe/switch.c
nVHEhost kernel은 EL1, 작은 hyp code는 EL2arch/arm64/kvm/hyp/nvhe/switch.c
pKVMprotected nVHE에서 host와 hyp 격리 강화hyp/nvhe/mem_protect.c

kvm_arm_vcpu_enter_exit()은 mode별 hyp call 세부를 감추고 공통 run loop에 반환한다.

Guest exit는 ESR의 EC를 handler table로 보낸다

guest가 trap되면 EL2는 ESR_EL2, FAR_EL2, HPFAR_EL2와 guest state를 저장한다. host의 handle_exit()은 exception index와 ESR EC를 보고 sysreg trap, WFx, HVC, instruction/data abort 등의 handler를 선택한다.

ExitKernel 처리Userspace exit 여부
WFI/WFEblock·yield 또는 조건부 재진입대개 kernel 안에서 처리.
System registeremulation 또는 virtual state 갱신대개 kernel 안에서 처리.
Stage-2 RAM faulthost page와 Stage-2 PTE 준비해결되면 즉시 재진입.
Emulated MMIOkvm_run에 주소·길이·방향 기록KVM_EXIT_MMIO로 QEMU 복귀 가능.

Stage-2 Data Abort는 IPA를 복원해 memslot을 찾는다

Guest memory fault

guest VA → Stage-1 IPA 성공
→ Stage-2 IPA → PA 실패
→ ESR_EL2 DABT/IABT + HPFAR_EL2
→ handle_exit
→ kvm_handle_guest_abort
→ fault IPA 계산
→ memslot·HVA·VMA 검사
→ user_mem_abort 또는 MMIO

kvm_handle_guest_abort()은 abort 종류, IPA 범위, nested 여부와 memslot을 검사한다.

guest VA나 FAR만으로 host physical page를 알 수 없다. HPFAR와 page offset, VTCR의 IPA 범위, memslot과 host VMA를 차례로 연결해야 한다.

user_mem_abort()가 host page와 Stage-2 PTE를 연결한다

  1. fault IPA를 GFN으로 바꾸고 memslot에서 HVA를 찾는다.
  2. host VMA와 fault type을 검사해 page size, writable·executable protection을 정한다.
  3. 필요하면 GUP나 fault-in으로 host physical page를 pin·resolve한다.
  4. huge mapping 가능 여부와 dirty logging·read-only 정책을 반영한다.
  5. kvm_pgtable_stage2_map()으로 IPA→PA descriptor를 설치한다.
  6. 필요한 cache maintenance와 Stage-2 TLB synchronization 뒤 guest를 재실행한다.

user_mem_abort()kvm_pgtable_stage2_map()을 이어서 읽는다.

RAM이 아닌 IPA는 QEMU device emulation으로 나갈 수 있다

memslot이 없거나 I/O bus에 등록된 영역이면 KVM이 load/store instruction의 size·direction·register를 해석한다. kernel 내 irqchip·timer처럼 처리 가능한 device는 안에서 끝나고, userspace device는 KVM_EXIT_MMIO로 QEMU에 전달된다.

QEMU가 read 값을 kvm_run.mmio.data에 채우고 다시 KVM_RUN하면 KVM이 guest register에 결과를 반영하고 fault instruction 다음으로 진행한다.

Dirty logging은 write permission을 이용해 변경 page를 찾는다

live migration 시작 시 Stage-2를 write-protect하고 첫 write fault에서 dirty bit를 기록하는 방식이 기본이다. hardware dirty-bit 기능이 있으면 trap 횟수를 줄일 수 있지만 log를 읽고 clear하는 ordering과 TLB invalidation이 필요하다.

HDBSS 같은 architecture 확장은 hardware가 Stage-2 dirty 상태를 기록하도록 돕는다. feature 존재, KVM 구현, userspace migration protocol 지원을 각각 확인해야 한다.

Linux v6.18.37 소스 지도

파일심볼책임
arch/arm64/kvm/arm.ckvm_arch_vcpu_ioctl_run, kvm_arm_vcpu_enter_exitvCPU run loop
kvm/hyp/*/switch.c__kvm_vcpu_runEL2 state switch와 guest entry
kvm/handle_exit.chandle_exitESR EC별 dispatch
kvm/mmu.ckvm_handle_guest_abort, user_mem_abortStage-2 fault 해결
kvm/hyp/pgtable.ckvm_pgtable_stage2_map/unmapStage-2 descriptor 관리
asm/kvm_host.hkvm_s2_mmu, kvm_vcpu_archarm64 KVM 상태 구조

KVM exit와 fault를 직접 추적한다

Host 관찰

sudo trace-cmd record -e kvm -e kvmmmu -e irq ./run-vm.sh
sudo trace-cmd report
sudo perf kvm stat live
cat /sys/kernel/debug/kvm/* 2>/dev/null
qemu-system-aarch64 ... -d guest_errors

exit reason, fault IPA, memslot, userspace MMIO 여부를 같은 시간축으로 본다. exit 횟수가 많다는 사실만으로 KVM bug라고 판단하지 말고 WFI, timer, MMIO, Stage-2 fault 비율을 나눈다.

근거 자료