가상화 (Virtualization)

Linux 가상화(KVM/QEMU)를 CPU 가상화, 메모리 가상화, 장치 가상화가 결합된 시스템 관점에서 심층 분석합니다. VMX/SVM 기반 VMCS/VMCB 실행 모델, EPT/NPT 2단계 페이지(Page) 변환과 TLB 비용, virtio split/packed ring 및 vhost 가속 경로, irqfd/ioeventfd 이벤트 전달, VFIO 패스스루와 IOMMU 격리(Isolation), OVMF/Secure Boot/TPM 실습, SEV/TDX 같은 기밀 컴퓨팅(Confidential Computing) 확장, 라이브 마이그레이션 일관성 포인트, NUMA·hugepage·pinning 기반 성능 튜닝, 트레이싱과 장애 복구까지 클라우드 운영 핵심을 다룹니다.

전제 조건: 커널 아키텍처CPU 토폴로지(Topology) 문서를 먼저 읽으세요. KVM 기반 가상화는 vCPU 스케줄링과 메모리 매핑(EPT/NPT)의 결합이 핵심이므로, 실행 경계와 VM-Exit 경로를 먼저 고정해야 합니다.
일상 비유: 이 주제는 공유 공연장의 타임슬롯 운영과 비슷합니다. 무대는 하나지만 팀별 사용 슬롯과 장비 맵핑을 분리하듯이, 하이퍼바이저(Hypervisor)는 물리 자원을 VM 단위로 중재합니다.

핵심 요약

  • 격리 모델 — 관측 범위와 자원 한계를 분리해 이해합니다.
  • 자원 회계 — cgroups 제한과 스케줄링 효과를 함께 봅니다.
  • 가상화 경계 — 호스트/게스트 전환 비용을 파악합니다.
  • 시간/상태 일관성 — 체크포인트(Checkpoint)/복원 시 기준값을 점검합니다.
  • 운영 정책 — 격리 강도와 성능 비용의 균형을 맞춥니다.

단계별 이해

  1. 경계 정의
    무엇을 공유하고 무엇을 분리할지 먼저 정합니다.
  2. 제한 적용
    CPU/메모리/IO 제한을 단계적으로 설정합니다.
  3. 관측 검증
    네임스페이스(Namespace)/가상화 경계에서 보이는 값을 확인합니다.
  4. 장애 복구 점검
    마이그레이션/재시작(Reboot) 시 일관성을 검증합니다.
관련 표준: Intel VT-x (VMX, VMCS, EPT), AMD-V (SVM, VMCB, NPT), virtio Specification 1.2 (가상 I/O 디바이스) — KVM이 구현하는 하드웨어 가상화 및 반가상화(Paravirtualization) 규격입니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.

UEFI 가상 실습 기준선

SEV, TDX, VFIO 같은 고급 주제를 보기 전에, 일반 KVM/QEMU 환경에서 OVMF + TPM 2.0 + Secure Boot 기준선을 먼저 재현해 두는 편이 좋습니다. 이 조합은 "UEFI 부팅이 되는가", "Secure Boot 키가 실제로 적용되는가", "TPM PCR 측정이 잡히는가"를 분리해서 확인할 수 있게 해 주므로, 기밀 VM이나 네트워크 부팅 실험의 최소 비교군 역할을 합니다.

실습 축핵심 구성왜 먼저 필요한가
UEFI 펌웨어(Firmware)Q35 머신 + OVMF CODE/VARS 분리NVRAM 부트 엔트리, Secure Boot 키, MokManager 상태를 VM별로 재현 가능하게 유지합니다.
Secure Bootpre-enrolled keys 또는 shim/GRUB 체인서명 검증(Signature Verification) 실패와 단순 UEFI 부팅 실패를 구분할 수 있습니다.
TPM 2.0swtpm + tpm-tisPCR 7/11 같은 측정 상태를 잡아 기밀 VM 전후 비교 기준을 만듭니다.
부트 아티팩트shim/GRUB, UKI, EFIStub를 각각 분리 테스트같은 VM에서도 "전송 경로", "신뢰 체인(Chain of Trust)", "측정 경로"가 다를 수 있음을 확인할 수 있습니다.
실무 순서: 일반 UEFI VM → Secure Boot 활성 VM → TPM 측정 확인 VM → 그 다음에 SEV/TDX나 서명된 iPXE/HTTP Boot를 얹는 순서가 디버깅(Debugging)하기 가장 쉽습니다. 앞단 기준선이 없으면 기밀 컴퓨팅 실패와 단순 펌웨어/부트로더(Bootloader) 실수를 구분하기 어렵습니다.

가상화 개요

Linux의 KVM(Kernel-based Virtual Machine)은 커널을 Type-1 하이퍼바이저로 변환합니다. 하드웨어 가상화 확장(Intel VT-x, AMD-V)을 활용하여 게스트 OS를 네이티브에 가까운 속도로 실행합니다.

KVM/QEMU 아키텍처 상세 유저스페이스 (User Space) Guest VM 1 vCPU 0 vCPU 1 Guest Memory (GPA) Guest VM 2 vCPU 0 vCPU 1 Guest Memory (GPA) QEMU (Device Emulation) virtio-net virtio-blk e1000/rtl8139 IDE/AHCI Display Memory Regions (RAM, ROM) vCPU Threads (ioctl/KVM_RUN) ioctl 커널스페이스 (Kernel Space) KVM Module (/dev/kvm) VM 관리 | vCPU 스케줄링 | EPT/NPT kvm.ko 공통 인프라 kvm-intel.ko VMX/VMCS/EPT kvm-amd.ko SVM/VMCB/NPT vfio.ko PCI passthrough 하드웨어 (Hardware) CPU Virtualization Intel VT-x (VMX) / AMD-V (SVM) VM Entry/Exit | VPID | TSC scaling Memory Virtualization EPT (Intel) / NPT (AMD) 2D Page Walk | PML | IOMMU I/O Virtualization VT-d / AMD-Vi (IOMMU) SR-IOV | PASID | PRI Interrupt Virtualization APICv (Intel) / AVIC (AMD) Posted Interrupts
KVM: 커널 모듈(Kernel Module)이 하드웨어 가상화를 관리, QEMU가 디바이스 에뮬레이션 담당

KVM API (/dev/kvm)

#include <linux/kvm.h>

/* 1. KVM 파일 열기 */
int kvm_fd = open("/dev/kvm", O_RDWR);

/* 2. VM 생성 */
int vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0);

/* 3. 메모리 설정 */
struct kvm_userspace_memory_region region = {
    .slot = 0,
    .guest_phys_addr = 0,
    .memory_size = 0x10000000,  /* 256MB */
    .userspace_addr = (__u64)mem,
};
ioctl(vm_fd, KVM_SET_USER_MEMORY_REGION, ®ion);

/* 4. vCPU 생성 */
int vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);

/* 5. 실행 루프 */
while (1) {
    ioctl(vcpu_fd, KVM_RUN, 0);
    switch (run->exit_reason) {
    case KVM_EXIT_IO:    /* I/O 처리 */ break;
    case KVM_EXIT_MMIO:  /* MMIO 처리 */ break;
    case KVM_EXIT_HLT:   goto done;
    }
}

KVM ioctl 계층 구조

레벨FD주요 ioctl설명
System/dev/kvmKVM_CREATE_VM, KVM_GET_API_VERSION, KVM_CHECK_EXTENSION전역 KVM 기능 조회, VM 생성
VMvm_fdKVM_CREATE_VCPU, KVM_SET_USER_MEMORY_REGION, KVM_CREATE_IRQCHIP, KVM_IRQFD, KVM_IOEVENTFDVM 단위 메모리/인터럽트(Interrupt)/디바이스 설정
vCPUvcpu_fdKVM_RUN, KVM_GET_REGS, KVM_SET_REGS, KVM_GET_SREGS, KVM_SET_CPUID2vCPU 실행, 레지스터(Register) 조작
Devicedev_fdKVM_CREATE_DEVICE, KVM_SET_DEVICE_ATTR커널 내 디바이스 (GIC, VFIO 등)

kvm_run 공유 메모리 구조체(Struct)

/* QEMU와 커널이 mmap으로 공유하는 구조체
 * vcpu_fd에서 mmap(NULL, mmap_size, ..., vcpu_fd, 0)으로 매핑
 * KVM_RUN 후 exit_reason을 확인하여 처리 */

struct kvm_run {
    /* in */
    __u8  request_interrupt_window;  /* 인터럽트 윈도우 요청 */
    __u8  immediate_exit;            /* 즉시 exit (시그널 처리용) */

    /* out */
    __u32 exit_reason;               /* VM Exit 사유 */
    __u8  ready_for_interrupt_injection; /* 인터럽트 주입 가능 여부 */
    __u64 cr8;                       /* TPR (Task Priority Register) */

    /* exit_reason별 union */
    union {
        /* KVM_EXIT_IO */
        struct {
            __u8  direction;    /* KVM_EXIT_IO_IN / KVM_EXIT_IO_OUT */
            __u8  size;         /* 1, 2, 4 바이트 */
            __u16 port;         /* I/O 포트 번호 */
            __u32 count;        /* REP 접두사 시 반복 횟수 */
            __u64 data_offset;  /* kvm_run 내 데이터 오프셋 */
        } io;

        /* KVM_EXIT_MMIO */
        struct {
            __u64 phys_addr;    /* 게스트 물리 주소 */
            __u8  data[8];      /* 읽기/쓰기 데이터 */
            __u32 len;          /* 접근 크기 */
            __u8  is_write;     /* 쓰기 여부 */
        } mmio;

        /* KVM_EXIT_INTERNAL_ERROR */
        struct {
            __u32 suberror;     /* 에뮬레이션 실패 등 */
            __u32 ndata;
            __u64 data[16];
        } internal;
    };
};

QEMU-KVM 상호작용 상세 흐름

/* QEMU의 vCPU 스레드 실행 루프 (실제 흐름) */
/* accel/kvm/kvm-accel-ops.c */

static void *kvm_vcpu_thread_fn(void *arg)
{
    struct CPUState *cpu = arg;

    kvm_init_vcpu(cpu);  /* KVM_CREATE_VCPU + mmap kvm_run */

    while (!cpu->unplug) {
        /* 1. 인터럽트 주입 준비 */
        if (cpu->interrupt_request) {
            kvm_cpu_synchronize_state(cpu);
            kvm_arch_put_registers(cpu);  /* KVM_SET_REGS */
        }

        /* 2. KVM_RUN → 게스트 실행 (커널로 진입) */
        ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);

        /* 3. VM Exit 처리 */
        switch (run->exit_reason) {
        case KVM_EXIT_IO:
            kvm_handle_io(run->io.port, ...);
            /* → QEMU 디바이스 모델로 I/O 디스패치 */
            break;
        case KVM_EXIT_MMIO:
            address_space_rw(&address_space_memory,
                run->mmio.phys_addr, ...);
            /* → QEMU MemoryRegion으로 MMIO 디스패치 */
            break;
        case KVM_EXIT_SHUTDOWN:
            qemu_system_reset_request();
            break;
        }
    }
}

/*
 * 전체 흐름 요약:
 *
 * QEMU (유저)            KVM (커널)              하드웨어
 * ─────────────────────────────────────────────────────────
 * ioctl(KVM_RUN) ──→ vcpu_run() ──→ VMLAUNCH/VMRESUME
 *                                        │
 *                                   [게스트 실행]
 *                                        │
 *                                   VM Exit 발생
 *                                        │
 *                    vmx_handle_exit() ←──┘
 *                        │
 *                   커널에서 처리 가능?
 *                   ├─ YES → 즉시 재진입 (fast path)
 *                   └─ NO  → QEMU로 exit_reason 전달
 *                                │
 * exit_reason 처리 ←─────────────┘
 * (I/O, MMIO 에뮬레이션)
 * 다시 ioctl(KVM_RUN) → ...
 */
QEMU-KVM 실행 흐름 (KVM_RUN ioctl) QEMU (유저스페이스) KVM (커널) 하드웨어 (CPU) ① ioctl(KVM_RUN) vcpu_run() ② VMLAUNCH/VMRESUME 게스트 실행 ③ VM Exit 발생 ④ handle_exit() 커널에서 처리 가능? YES (fast path) 즉시 재진입 → NO (slow path) ⑤ exit_reason 전달 I/O/MMIO 에뮬레이션 ⑥ 다시 ioctl(KVM_RUN) 반복 Fast Path: MSR/CPUID 등 커널 단독 처리 가능 → QEMU 복귀 없이 즉시 재진입 Slow Path: I/O/MMIO 에뮬레이션 필요 → QEMU에 exit_reason 전달 후 처리

커널 내부 vcpu_run 흐름

/* virt/kvm/kvm_main.c — KVM_RUN ioctl 커널 처리 */
static long kvm_vcpu_ioctl(struct file *filp,
    unsigned int ioctl, unsigned long arg)
{
    case KVM_RUN:
        return kvm_arch_vcpu_ioctl_run(vcpu);
}

/* arch/x86/kvm/x86.c */
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
{
    struct kvm_run *run = vcpu->run;

    vcpu_load(vcpu);  /* vCPU를 현재 pCPU에 바인딩 */

    for (;;) {
        /* 1. 시그널 체크 */
        if (signal_pending(current)) {
            run->exit_reason = KVM_EXIT_INTR;
            break;
        }

        /* 2. 인터럽트 주입 */
        kvm_inject_pending_events(vcpu);

        /* 3. 게스트 진입 준비 + VMLAUNCH/VMRESUME */
        r = vcpu_enter_guest(vcpu);

        /* 4. VM Exit 처리 */
        if (r <= 0) break;      /* QEMU로 반환 */
        /* r > 0: 커널에서 처리 완료 → 즉시 재진입 (fast path) */

        /* 5. 스케줄링 포인트 */
        if (need_resched()) {
            cond_resched();  /* 다른 태스크에 CPU 양보 */
        }
    }

    vcpu_put(vcpu);
    return r;
}

/* vcpu_enter_guest(): 실제 VM 진입/탈출 */
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
    /* 게스트 상태를 VMCS/VMCB에 로드 */
    kvm_x86_ops.prepare_switch_to_guest(vcpu);

    /* preempt, IRQ 비활성화 */
    preempt_disable();
    local_irq_disable();

    /* ★ VM Entry: VMLAUNCH/VMRESUME (Intel) 또는 VMRUN (AMD) */
    kvm_x86_ops.vcpu_run(vcpu);

    /* VM Exit 후 복귀 */
    local_irq_enable();
    preempt_enable();

    /* Exit reason 처리 */
    r = kvm_x86_ops.handle_exit(vcpu, exit_fastpath);
    return r;
}
ℹ️

Fast Path vs Slow Path: 커널에서 처리 가능한 VM Exit (예: MSR 읽기, CPUID, 일부 EPT violation)는 QEMU로 돌아가지 않고 즉시 재진입합니다. 이를 fast path라 하며, QEMU-커널 컨텍스트 스위칭(Context Switching)을 제거하여 성능을 크게 향상시킵니다. I/O 에뮬레이션이 필요한 경우만 slow path로 QEMU에 전달됩니다.

virtio 프레임워크

virtio는 가상화 환경에서 디바이스 I/O 성능을 최적화하는 준가상화(paravirtualization) 프레임워크입니다. 게스트가 가상화 환경임을 인지하고 하이퍼바이저와 효율적으로 통신합니다.

virtio 디바이스용도
virtio-net네트워크
virtio-blk블록 스토리지
virtio-scsiSCSI 스토리지
virtio-gpu그래픽
virtio-fs파일시스템(Filesystem) 공유
virtio-mem메모리 핫플러그(Hotplug)
virtio-balloon동적 메모리 조정
virtio-rng하드웨어 난수 전달
virtio-vsock호스트-게스트 소켓(Socket) 통신
virtio-crypto암호화(Encryption) 가속

Virtqueue 및 내용

모든 virtio 디바이스는 virtqueue를 통해 게스트↔호스트 데이터를 교환합니다. virtqueue는 게스트 메모리에 위치한 링 버퍼(Ring Buffer)로, Split Virtqueue(레거시)와 Packed Virtqueue(v1.1+) 두 가지 형식이 있습니다.

참고: Split/Packed Virtqueue 구조, virtio 드라이버 작성법, vhost 커널 백엔드, vDPA 하드웨어 가속, Feature Negotiation, virtio-mem/virtio-balloon 동적 메모리 관리(Memory Management) 등 상세 내용은 virtio/vhost/vDPA 프레임워크 페이지에서 다룹니다.

EPT/NPT (확장 페이지 테이블(Page Table))

EPT(Extended Page Table, Intel) / NPT(Nested Page Table, AMD)는 게스트 물리 주소(GPA) → 호스트 물리 주소(HPA) 변환을 하드웨어에서 수행합니다. 소프트웨어 섀도 페이지 테이블보다 훨씬 효율적입니다.

2차원 페이지 워크

/*
 * 가상화 환경의 주소 변환 (2D Page Walk):
 *
 * 게스트 가상 주소 (GVA)
 *   │ ← 게스트 페이지 테이블 (GPT, 게스트 CR3)
 *   ▼
 * 게스트 물리 주소 (GPA)
 *   │ ← EPT/NPT (호스트 관리, EPTP/nCR3)
 *   ▼
 * 호스트 물리 주소 (HPA)
 *
 * 최악의 경우 페이지 워크 비용:
 * - 4-level GPT × 4-level EPT = 최대 24회 메모리 접근
 *   (GPT 각 레벨마다 EPT 4-level 워크 필요 + 최종 데이터 접근)
 * - 5-level (LA57) GPT × 4-level EPT = 최대 30회
 * - TLB 미스 시 성능 영향 큼 → VPID로 TLB 격리하여 완화
 */

/* EPT 페이지 테이블 엔트리 (Intel) */
/*
 * 비트 레이아웃 (4KB 페이지):
 * [0]     Read access
 * [1]     Write access
 * [2]     Execute access (XD 비트와 반대 의미)
 * [5:3]   EPT Memory Type (WB=6, UC=0, WT=4)
 * [6]     Ignore PAT (1이면 EPT의 Memory Type 우선)
 * [7]     1=Large page (2MB/1GB), 0=다음 레벨 포인터
 * [8]     Accessed bit (CPU가 자동 설정)
 * [9]     Dirty bit (CPU가 자동 설정, PML 활성화 시)
 * [10]    Execute access for usermode (MBEC)
 * [N-1:12] 물리 프레임 번호 (HPA >> 12)
 * [63]    Suppress #VE (Virtualization Exception)
 */

/* EPT Violation 처리 — arch/x86/kvm/mmu/mmu.c */
static int kvm_mmu_page_fault(struct kvm_vcpu *vcpu,
    gpa_t gpa, u64 error_code)
{
    /* 1. memslot에서 GPA → HVA 매핑 조회 */
    slot = kvm_vcpu_gfn_to_memslot(vcpu, gpa >> PAGE_SHIFT);

    /* 2. HVA → HPA 변환 (호스트 페이지 테이블 워크) */
    pfn = gfn_to_pfn(kvm, gpa >> PAGE_SHIFT);

    /* 3. EPT 엔트리 설정 (GPA → HPA 매핑 추가) */
    kvm_mmu_map_page(vcpu, gpa, pfn, ...);

    /* 4. 게스트 재진입 (다음 VM Entry에서 자동 적용) */
    return 1;  /* 커널에서 처리 완료 → fast path */
}
EPT/NPT 2차원 페이지 워크 (2D Page Walk) Guest Virtual Address (GVA) Guest CR3 GPT L4 (GPA addr) EPT 워크 GPT L3 (GPA addr) EPT 워크 GPT L2 (GPA addr) EPT 워크 GPT L1 (GPA addr) EPT 워크 GPA (물리) EPT 워크 EPT/NPT (Extended/Nested Page Table) EPT L4 (HPA) EPT L3 (HPA) EPT L2 (HPA) EPT L1 (HPA) EPTP (Extended Page Table Pointer) 레지스터가 EPT L4 base 가리킴 HPA (호스트) 페이지 워크 비용 계산 GPT 각 레벨 접근 시 EPT 4-level 워크 필요 → 4 (GPT) × 4 (EPT) = 16회 메모리 접근 최종 데이터 페이지 접근에도 EPT 워크 필요 → +4회 총 최대 24회 메모리 접근 (TLB 미스 시) 성능 최적화: VPID (Virtual Processor ID) vCPU별 TLB 엔트리 태깅으로 VM Exit/Entry 시 TLB flush 불필요 → 실제 워크로드에서는 TLB 히트율이 높아 2D 워크 비용 크게 완화

EPT 고급 기능

기능설명용도
VPIDVirtual Processor IDentifier. TLB에 vCPU 태그 부여VM Exit/Entry 시 TLB 플러시(Flush) 불필요 → 성능 향상
PMLPage Modification Logging. dirty page를 CPU가 로그 버퍼(Buffer)에 자동 기록라이브 마이그레이션 dirty tracking 가속
MBECMode-Based Execute Control. 유저/커널 모드별 실행 권한게스트 커널 보호 (SMEP 에뮬레이션 없이)
SPPSub-Page Protection. 128바이트 단위 쓰기 보호(Write Protection)VM introspection, 악성코드 분석
2MB/1GB 페이지EPT 대형 페이지 매핑TLB 미스 감소, 게스트 메모리 대용량 시 필수
💡

vhost-net은 네트워크 I/O를 커널 내에서 직접 처리하여 QEMU ↔ 커널 간 컨텍스트 스위칭을 제거합니다. 네트워크 처리량(Throughput)이 크게 향상됩니다.

VMCS (Virtual Machine Control Structure)

VMCS는 Intel VT-x에서 게스트-호스트 전환 시 CPU 상태를 저장하는 구조체입니다. 각 vCPU마다 하나의 VMCS가 할당됩니다.

/* VMCS 주요 필드 영역 */
/* Guest-state area: 게스트 진입 시 로드 */
GUEST_CS_SELECTOR, GUEST_RIP, GUEST_RSP, GUEST_RFLAGS,
GUEST_CR0, GUEST_CR3, GUEST_CR4,
GUEST_GDTR_BASE, GUEST_IDTR_BASE,

/* Host-state area: VM Exit 시 로드 */
HOST_CS_SELECTOR, HOST_RIP, HOST_RSP,
HOST_CR0, HOST_CR3, HOST_CR4,

/* VM-execution control fields */
PIN_BASED_VM_EXEC_CONTROL,    /* 외부 인터럽트, NMI */
CPU_BASED_VM_EXEC_CONTROL,    /* HLT, I/O, MSR 감시 */
SECONDARY_VM_EXEC_CONTROL,    /* EPT, VPID, unrestricted guest */
VM_EXIT_CONTROLS,             /* exit 동작 */
VM_ENTRY_CONTROLS,            /* entry 동작 */

/* VM-exit information fields */
VM_EXIT_REASON, EXIT_QUALIFICATION, GUEST_LINEAR_ADDRESS

VM Exit 처리 흐름

/* arch/x86/kvm/vmx/vmx.c */
static int vmx_handle_exit(struct kvm_vcpu *vcpu,
    enum exit_fastpath_completion exit_fastpath)
{
    u32 exit_reason = vmx->exit_reason.full;

    switch (exit_reason) {
    case EXIT_REASON_EPT_VIOLATION:
        return handle_ept_violation(vcpu);
    case EXIT_REASON_IO_INSTRUCTION:
        return handle_io(vcpu);
    case EXIT_REASON_MSR_READ:
        return handle_rdmsr(vcpu);
    case EXIT_REASON_MSR_WRITE:
        return handle_wrmsr(vcpu);
    case EXIT_REASON_CPUID:
        return handle_cpuid(vcpu);
    case EXIT_REASON_HLT:
        return kvm_emulate_halt(vcpu);
    /* ... 약 60가지 exit reason ... */
    }
}

AMD VMCB (Virtual Machine Control Block)

/* AMD SVM의 제어 구조체 — Intel VMCS에 대응
 * VMCB는 일반 메모리 페이지 (4KB)에 위치 (VMCS는 CPU 내부 캐시)
 * VMRUN 명령어가 VMCB 물리 주소를 인자로 받음 */

struct vmcb_control_area {          /* 오프셋 0x000~0x3FF */
    u32 intercepts[5];              /* CR/DR/Exception/명령어 인터셉트 비트맵 */
    u16 pause_filter_thresh;        /* PAUSE 루프 exit 임계값 */
    u16 pause_filter_count;
    u64 iopm_base_pa;               /* I/O Permission Map 물리 주소 */
    u64 msrpm_base_pa;              /* MSR Permission Map 물리 주소 */
    u64 tsc_offset;                 /* 게스트 TSC 오프셋 */
    u32 asid;                       /* Address Space IDentifier (VPID 역할) */
    u8  tlb_ctl;                    /* TLB 플러시 제어 */
    u64 exitcode;                   /* #VMEXIT 사유 코드 */
    u64 exitinfo1, exitinfo2;       /* exit 추가 정보 */
    u64 nested_ctl;                 /* NPT 활성화 비트 */
    u64 nested_cr3;                 /* NPT 페이지 테이블 루트 (nCR3) */
    u64 virt_ext;                   /* LBR 가상화 등 */
    u64 vmcb_clean;                 /* clean bits: 변경 안 된 필드 표시 */
    u64 next_rip;                   /* NRIP Save: 다음 명령어 RIP */
};

struct vmcb_save_area {             /* 오프셋 0x400~0xFFF */
    /* 세그먼트 레지스터, CR0-CR4, EFER, RIP, RSP, RFLAGS, ... */
    /* 게스트의 전체 CPU 상태 저장/복원 */
};

Intel VT-x vs AMD-V (SVM) 비교

항목Intel VT-x (VMX)AMD-V (SVM)
제어 구조체VMCS (CPU 내부 캐시(Cache), VMREAD/VMWRITE)VMCB (일반 메모리, 직접 접근)
VM 진입VMLAUNCH / VMRESUMEVMRUN
VM 탈출자동 (VM_EXIT_REASON)#VMEXIT (exitcode)
2차 페이지 테이블EPT (EPTP)NPT (nCR3)
TLB 태깅VPID (16-bit)ASID (32-bit)
인터럽트 가상화Posted Interrupts (PI)AVIC (AMD Virtual Interrupt Controller)
MSR 비트맵(Bitmap)VMCS 내 포인터MSRPM (8KB)
NRIP 자동 저장지원 (VM Exit 시 자동)NRIP Save 기능 (선택적)
Unrestricted GuestSecondary 컨트롤 비트기본 지원 (Real Mode 직접 실행)
Clean Bits 최적화없음 (항상 전체 로드)VMCB Clean Field (변경 안 된 부분 스킵)
Confidential VMTDX (Trust Domain Extensions)SEV / SEV-ES / SEV-SNP
커널 모듈kvm_intelkvm_amd
커널 소스arch/x86/kvm/vmx/arch/x86/kvm/svm/

인터럽트 가상화

게스트에 인터럽트를 효율적으로 전달하는 것은 KVM 성능의 핵심입니다. KVM은 커널 내에서 가상 인터럽트 컨트롤러(Interrupt Controller)를 에뮬레이션하고, Posted Interrupts/AVIC로 VM Exit 없이 직접 전달합니다.

디바이스 IRQ/MSI KVM IRQ 라우팅 vIOAPIC / vLAPIC 게스트 IDT Posted Interrupts(Intel) / AVIC(AMD): VM Exit 없이 vCPU에 직접 주입 CPU가 root 모드면 다음 VM Entry 시 자동 주입 irqfd 경로: vhost/eventfd - KVM 주입 (QEMU 우회)
설명 요약:
  • KVM 인터럽트 전달 경로 */
  • 가상 PIC (i8259): 레거시 IRQ 0-15
  • → 현대 게스트에서는 거의 사용 안 함
  • 가상 IOAPIC: IRQ 라우팅 테이블(Routing Table) 기반
  • → KVM_CREATE_IRQCHIP으로 커널 내 에뮬레이션 활성화
  • 가상 LAPIC: vCPU당 하나, 타이머(Timer) + IPI
  • → KVM_CREATE_IRQCHIP에 포함
  • MSI/MSI-X: PCI 디바이스의 직접 인터럽트
  • → QEMU가 KVM_SIGNAL_MSI 또는 irqfd로 주입
  • Posted Interrupts (Intel):
  • → VM Exit 없이 게스트에 직접 인터럽트 전달
  • → 256비트 Posted Interrupt Descriptor (PID)
  • → 특별한 notification vector가 CPU에 알림
  • Posted Interrupt 흐름 (Intel VT-x) */
  • 디바이스 인터럽트 발생
  • → IOMMU Interrupt Remapping → PID에 비트 설정
  • → Notification Vector를 물리 CPU에 전송
  • → CPU가 비root 모드(게스트)면:
  • 게스트 IDT로 바로 전달 (VM Exit 없음!)
  • → CPU가 root 모드(호스트)면:
  • 다음 VM Entry 시 자동 주입
  • irqfd를 통한 인터럽트 주입 최적화 */
  • vhost-net → eventfd 쓰기 → irqfd → KVM 인터럽트 주입
  • 이 경로는 QEMU를 완전히 우회 → 낮은 지연(Latency)시간 */

KVM 메모리 관리

/* KVM의 메모리 관리 핵심 개념 */

/* 1. Memory Slots: 게스트 물리 주소 공간을 호스트 가상 메모리에 매핑 */
struct kvm_userspace_memory_region {
    __u32 slot;              /* 슬롯 번호 (0~N) */
    __u32 flags;             /* KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_READONLY */
    __u64 guest_phys_addr;   /* 게스트 물리 시작 주소 */
    __u64 memory_size;       /* 바이트 크기 */
    __u64 userspace_addr;    /* 호스트 가상 주소 (QEMU mmap) */
};
/* 게스트 RAM은 QEMU의 mmap 영역 → KVM이 EPT에 on-demand 매핑
 * 게스트가 GPA 접근 → EPT miss → KVM이 HVA→HPA 변환하여 EPT 추가 */

/* 2. Dirty Page Tracking: 라이브 마이그레이션 핵심 */
/* KVM_MEM_LOG_DIRTY_PAGES 플래그 → EPT dirty bit 활용 */
/* KVM_GET_DIRTY_LOG ioctl → 변경된 페이지 비트맵 반환 */
/*
 * PML (Page Modification Logging, Intel):
 *   dirty page 발생 시 CPU가 자동으로 GPA를 PML 로그 버퍼에 기록
 *   버퍼가 가득 차면 VM Exit → KVM이 비트맵 업데이트
 *   소프트웨어 EPT 스캔 대비 오버헤드 대폭 감소
 */

/* 3. KSM (Kernel Same-page Merging): 동일 페이지 공유 */
/* 여러 VM의 동일한 메모리 페이지를 하나의 물리 프레임으로 통합
 * echo 1 > /sys/kernel/mm/ksm/run
 * → 동일한 OS를 실행하는 다수 VM에서 메모리 30-50% 절감 가능
 * → COW (Copy-On-Write)로 투명하게 분리 */

/* 4. Huge Pages: TLB 효율 극대화 */
/* QEMU에서 -mem-path /dev/hugepages → 2MB/1GB 대형 페이지 사용
 * EPT도 2MB/1GB 매핑 → TLB 미스 감소, 페이지 워크 레벨 감소 */

/* 5. Memory Ballooning: 동적 메모리 조정 */
/* virtio-balloon: 게스트에 "풍선"을 부풀려 사용하지 않는 페이지를 회수
 * 호스트가 메모리 부족 시 → 게스트 balloon inflate → 페이지 반환
 * 호스트 여유 시 → 게스트 balloon deflate → 페이지 재할당 */

KVM 내부 커널 API

KVM의 사용자 공간 ioctl API (/dev/kvm)와 별개로, 커널 내부에서 VM과 vCPU를 관리하는 핵심 함수들이 있습니다. 이들은 KVM 아키텍처의 실제 구현을 이해하는 데 필수적입니다.

함수위치역할
kvm_create_vm()virt/kvm/kvm_main.cVM 인스턴스 생성 (KVM_CREATE_VM ioctl 처리)
kvm_arch_vcpu_create()arch/x86/kvm/x86.c아키텍처별 vCPU 초기화 (VMCS/VMCB 할당)
kvm_set_memory_region()virt/kvm/kvm_main.c게스트 물리 메모리 슬롯 등록/변경
vcpu_enter_guest()arch/x86/kvm/x86.cVMLAUNCH/VMRESUME 실행 (게스트 진입)
kvm_emulate_io()arch/x86/kvm/x86.cIN/OUT 명령어 에뮬레이션
kvm_set_irq()virt/kvm/irqchip.c게스트에 인터럽트 주입
kvm_flush_remote_tlbs()virt/kvm/kvm_main.c모든 vCPU의 TLB 무효화 (EPT 변경 후)
kvm_make_request()include/linux/kvm_host.hvCPU에 비동기 작업 요청 (TLB flush, APIC 등)
kvm_vcpu_kick()virt/kvm/kvm_main.csleep 중인 vCPU를 깨워 요청 처리 강제
kvm_get_dirty_log()virt/kvm/kvm_main.cdirty 페이지 비트맵 반환 (라이브 마이그레이션)
/* kvm_create_vm — VM 인스턴스 생성 흐름 */
static struct kvm *kvm_create_vm(unsigned long type,
                                   const char *fdname)
{
    struct kvm *kvm = kvm_arch_alloc_vm();
    /* 1. 메모리 슬롯 배열 초기화 */
    kvm_init_memslots_id(kvm);
    /* 2. 아키텍처별 초기화 (EPT root, APIC 등) */
    kvm_arch_init_vm(kvm, type);
    /* 3. MMU notifier 등록 (호스트 페이지 변경 추적) */
    kvm_init_mmu_notifier(kvm);
    return kvm;
}

/* kvm_set_irq — 게스트 인터럽트 주입 */
int kvm_set_irq(struct kvm *kvm, int irq_source_id,
                u32 irq, int level, bool line_status)
{
    /* irqchip 라우팅 테이블에 따라 PIC/IOAPIC/MSI로 전달 */
    return kvm_irq_delivery_to_apic(kvm, NULL, &irq_entry,
                                       NULL);
}

/* kvm_make_request + kvm_vcpu_kick — 비동기 vCPU 요청 패턴 */
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);  /* 플래그 설정 */
kvm_vcpu_kick(vcpu);  /* sleep 중이면 IPI로 깨움 */
/* → vcpu_enter_guest() 진입 시 request를 확인하고 TLB flush 수행 */
  1. kvm_create_vm()사용자 공간의 ioctl(KVM_CREATE_VM)이 최종적으로 호출하는 커널 함수입니다. MMU notifier를 등록하여 호스트의 페이지 회수/이동 시 EPT를 자동 갱신합니다.
  2. kvm_set_irq()irqfd, ioeventfd와 연동되어 vhost-net 등에서 QEMU를 경유하지 않고 직접 게스트에 인터럽트를 주입합니다.
  3. kvm_make_request() + kvm_vcpu_kick()vCPU 간 비동기 통신 패턴입니다. EPT 변경, APIC 재구성 등 다른 vCPU에 영향을 주는 작업 후 사용됩니다. kvm_vcpu_kick()은 대상 vCPU가 게스트 실행 중이면 IPI로 VM Exit을 유발합니다.

vhost: 커널 내 virtio 백엔드

vhost는 QEMU의 디바이스 에뮬레이션 일부를 커널로 옮겨 성능을 극대화합니다. 특히 vhost-net은 네트워크 패킷(Packet)이 유저스페이스를 거치지 않고 커널에서 직접 처리됩니다.

구성요소위치역할
virtio 프론트엔드게스트 커널게스트의 virtio 드라이버
virtqueue공유 메모리게스트-호스트 간 링 버퍼 통신
vhost 백엔드호스트 커널패킷 처리 (커널 스레드(Kernel Thread))
QEMU호스트 유저제어 경로, 초기 설정
/* vhost-net: virtqueue 폴링 루프 (커널 스레드) */
static void handle_tx(struct vhost_net *net)
{
    struct vhost_virtqueue *vq = &net->vqs[VHOST_NET_VQ_TX];
    struct msghdr msg = { .msg_flags = MSG_DONTWAIT };

    for (;;) {
        head = vhost_get_vq_desc(vq, vq->iov,
            ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL);
        if (head < 0) break;

        /* 게스트의 TX 버퍼를 호스트 소켓으로 전송 */
        len = sock_sendmsg(sock, &msg);
        vhost_add_used_and_signal(vq, head, len);
    }
}

irqfd와 ioeventfd

KVM은 이벤트 기반 통신으로 VM Exit를 최소화합니다:

메커니즘방향용도
irqfd호스트 → 게스트eventfd를 통해 게스트에 인터럽트 주입
ioeventfd게스트 → 호스트특정 MMIO/PIO 주소 write 시 eventfd 시그널(Signal)
/* irqfd: eventfd에 쓰면 게스트에 인터럽트 전달 */
struct kvm_irqfd irqfd = {
    .fd  = eventfd_fd,
    .gsi = 24,       /* 게스트 IRQ 번호 */
};
ioctl(vm_fd, KVM_IRQFD, &irqfd);

/* 호스트에서 인터럽트 트리거 */
uint64_t val = 1;
write(eventfd_fd, &val, sizeof(val));  /* → 게스트 IRQ 24 발생 */

중첩 가상화 (Nested Virtualization)

L0 호스트 위의 L1 게스트에서 다시 하이퍼바이저를 실행하는 기술입니다. KVM은 VMCS shadowing과 EPT의 중첩 처리를 지원합니다.

# 중첩 가상화 활성화
modprobe kvm_intel nested=1
# 또는
echo "options kvm_intel nested=1" > /etc/modprobe.d/kvm.conf

# 확인
cat /sys/module/kvm_intel/parameters/nested   # Y
ℹ️

중첩 가상화 시 성능 오버헤드(Overhead)가 있습니다 (EPT violation 처리가 2단계). 프로덕션보다는 개발/테스트 환경에서 주로 사용합니다. AMD의 경우 kvm_amd nested=1을 사용합니다.

라이브 마이그레이션

VM을 중단 없이 다른 호스트로 이전하는 기술입니다. KVM의 dirty page tracking이 핵심 메커니즘입니다.

단계동작KVM 인터페이스
1. Pre-copy전체 메모리를 대상 호스트로 복사KVM_GET_DIRTY_LOG
2. Iterative copy변경된 페이지만 반복 전송dirty bitmap 조회
3. Stop & copyVM 정지, 나머지 상태 전송KVM_GET_REGS/SREGS
4. Resume대상에서 VM 재개KVM_SET_REGS/SREGS

Confidential VM (SEV / TDX)

클라우드 환경에서 호스트/하이퍼바이저로부터 게스트 메모리를 보호하는 하드웨어 기반 보안 기술입니다. 게스트 메모리가 암호화되어 호스트 관리자도 내용을 읽을 수 없습니다.

기술벤더메모리 암호화무결성(Integrity) 검증커널 지원
SEV-SNPAMDAES-128 (VM별 키)RMP (역방향 맵)5.19+
TDXIntelAES-128 (TME-MK)SEPT + EPT 무결성6.2+ (게스트), 6.16+ (호스트)
Arm CCAArmRealm 메모리 암호화GPT (Granule Protection Table)6.13+
💡

참고: SEV→SEV-ES→SEV-SNP 진화, TDX Module/SEAMCALL/TDCALL 아키텍처, ARM CCA Realm 관리, 공유/개인 메모리 모델, 증명 프로토콜, SVSM, 기밀 컨테이너(Kata), GPU TEE, CSP별 구현, 성능 오버헤드 분석 등의 상세 내용은 기밀 컴퓨팅 문서를 참조하세요.

기준선 실습부터 고정: SEV/TDX/CCA 실험 전에 일반 KVM VM에서 OVMF 부팅, Secure Boot 키 적용, swtpm 기반 TPM 2.0이 먼저 안정적으로 동작해야 합니다. 구체 명령은 QEMU의 OVMF + Secure Boot + swtpm 실습을 참조하세요.

KVM/QEMU 성능 튜닝

CPU 최적화

# vCPU 핀닝: vCPU 스레드를 물리 CPU에 고정
# NUMA 로컬리티 보장 → 캐시/메모리 지연시간 최소화
virsh vcpupin myvm 0 2       # vCPU 0 → pCPU 2
virsh vcpupin myvm 1 3       # vCPU 1 → pCPU 3

# 에뮬레이터 스레드 격리 (QEMU I/O 스레드)
virsh emulatorpin myvm 0-1   # QEMU 워커를 pCPU 0-1에 제한

# NUMA 토폴로지 매칭
virsh numatune myvm --nodeset 0 --mode strict
# 게스트 메모리를 NUMA 노드 0에 한정 → 원격 메모리 접근 제거

# CPU 호스트 패스스루 (최대 성능)
# QEMU: -cpu host (호스트 CPUID 그대로 전달)
# → 라이브 마이그레이션 시 동일 CPU 모델 필요

# halt-polling: vCPU가 HLT 후 즉시 sleep 하지 않고 일정 시간 대기
echo 200000 > /sys/module/kvm/parameters/halt_poll_ns
# 200μs 동안 바쁜 대기 → 짧은 idle 구간에서 VM Exit/Entry 감소
# 레이턴시 민감한 워크로드에 유효, CPU 전력은 증가

메모리 최적화

# Huge Pages 사용 (대표 최적화)
# 2MB Huge Pages:
echo 4096 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
mount -t hugetlbfs hugetlbfs /dev/hugepages

# QEMU에서 Huge Pages 사용:
# -mem-path /dev/hugepages -mem-prealloc
# 또는 libvirt: <memoryBacking><hugepages/></memoryBacking>

# 1GB Huge Pages (부트 파라미터로만 가능):
# hugepagesz=1G hugepages=32  (GRUB 부트 파라미터)

# Transparent Huge Pages (THP): 자동 대형 페이지
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
# QEMU가 madvise(MADV_HUGEPAGE)로 요청 시에만 적용

# KSM (동일 페이지 병합):
echo 1 > /sys/kernel/mm/ksm/run
echo 200 > /sys/kernel/mm/ksm/sleep_millisecs  # 스캔 주기
# 동일 OS의 다수 VM에서 메모리 30-50% 절감
# CPU 오버헤드 있음, 사이드 채널 취약 가능성

I/O 최적화

구성방식성능비고
virtio-blkvirtio 블록 드라이버좋음기본 블록 디바이스
virtio-scsivirtio SCSI 컨트롤러좋음핫플러그, 다수 디스크에 유리
vhost-user-blk유저 공간 블록 백엔드매우 좋음SPDK와 조합
NVMe 패스스루VFIO 직접 할당최고 (네이티브)마이그레이션 불가
virtio-net (기본)QEMU 백엔드보통유저 공간 I/O 경로
vhost-net커널 백엔드좋음-netdev tap,vhost=on
vhost-user-netDPDK/OVS 백엔드매우 좋음유저 공간 스위칭
SR-IOV VF 패스스루VFIO 직접 할당최고 (네이티브)마이그레이션 불가
# I/O 스레드 활성화 (QEMU): 메인 루프에서 I/O 분리
# -object iothread,id=io1 -device virtio-blk-pci,iothread=io1,...

# 디스크 I/O 스케줄러: 게스트 내 none 권장 (호스트가 스케줄링)
echo none > /sys/block/vda/queue/scheduler   # 게스트 내부

# virtio-net 멀티큐: 다중 vCPU에서 네트워크 처리 병렬화
# -device virtio-net-pci,mq=on,vectors=10,netdev=net0
# 게스트에서: ethtool -L eth0 combined 4

KVM/QEMU 디버깅

# KVM 통계 확인
cat /sys/kernel/debug/kvm/vm*/vcpu*/stats
# 또는 perf kvm stat live (실시간 VM Exit 통계)
perf kvm stat live
# 출력 예시:
#  Event             Count  Median
#  EPT_VIOLATION      1523   1.2us
#  IO_INSTRUCTION      892   3.5us
#  HLT                 456  12.1us
#  EXTERNAL_INTERRUPT  234   0.8us

# VM Exit 이유별 카운터
perf kvm stat report

# KVM tracepoint 활성화
echo 1 > /sys/kernel/debug/tracing/events/kvm/enable
cat /sys/kernel/debug/tracing/trace_pipe
# kvm_entry, kvm_exit, kvm_mmio, kvm_pio, kvm_msr 등

# 특정 tracepoint만 활성화
echo 1 > /sys/kernel/debug/tracing/events/kvm/kvm_exit/enable
echo 1 > /sys/kernel/debug/tracing/events/kvm/kvm_entry/enable

# QEMU Monitor (디버그 콘솔)
# QEMU 실행 시 -monitor stdio 또는 -monitor telnet::4444,server
# 주요 명령어:
(qemu) info registers       # vCPU 레지스터
(qemu) info mem              # 메모리 매핑
(qemu) info mtree            # 메모리 토폴로지 트리
(qemu) info qtree            # 디바이스 트리
(qemu) info irq              # 인터럽트 통계
(qemu) info kvm              # KVM 상태
(qemu) xp /16xg 0x1000       # 게스트 물리 메모리 덤프

# GDB로 게스트 커널 디버깅
# QEMU: -s -S (GDB 서버 :1234, 시작 시 중지)
gdb vmlinux
(gdb) target remote :1234
(gdb) hbreak start_kernel    # 하드웨어 브레이크포인트 */
(gdb) continue

KVM 커널 소스 구조

경로설명
virt/kvm/kvm_main.cKVM 코어: ioctl 디스패치(Dispatch), 메모리 슬롯, vCPU 관리
arch/x86/kvm/x86.cx86 공통: CPUID, MSR, 인터럽트, 에뮬레이션
arch/x86/kvm/vmx/Intel VT-x: VMCS, VM Entry/Exit, Posted Interrupts
arch/x86/kvm/svm/AMD SVM: VMCB, NPT, AVIC, SEV
arch/x86/kvm/mmu/MMU: EPT/NPT 관리, 섀도 페이지 테이블, TDP
arch/x86/kvm/lapic.c가상 LAPIC 에뮬레이션
arch/x86/kvm/ioapic.c가상 IOAPIC 에뮬레이션
arch/x86/kvm/irq_comm.cIRQ 라우팅(Routing), MSI 전달
arch/x86/kvm/emulate.cx86 명령어 에뮬레이터 (MMIO 등)
drivers/vhost/vhost 커널 백엔드 (net, scsi, vsock)
drivers/vfio/VFIO 프레임워크 (PCI, mdev, IOMMU)
arch/arm64/kvm/ARM64 KVM (EL2 하이퍼바이저)

VFIO (Virtual Function I/O)

VFIO는 유저 공간에서 직접 디바이스를 안전하게 제어할 수 있게 하는 커널 프레임워크입니다. IOMMU를 활용하여 DMA 격리를 보장하면서 디바이스를 VM(KVM)이나 유저 공간 드라이버(DPDK, SPDK)에 할당합니다. 과거 UIO(Userspace I/O)는 DMA 격리 없이 디바이스를 노출했지만, VFIO는 IOMMU 기반 격리를 통해 멀티테넌트 환경에서도 안전한 디바이스 패스스루를 제공합니다.

VFIO 아키텍처

VFIO는 Container → Group → Device 3계층 모델로 디바이스를 관리합니다.

User Kernel HW QEMU / libvirt VM 패스스루 DPDK / SPDK 유저 공간 드라이버 사용자 어플리케이션 ioctl(/dev/vfio/*) /dev/vfio/vfio Container FD /dev/vfio/N Group FD Device FD BAR/IRQ/Config VFIO Core drivers/vfio/vfio_main.c VFIO-PCI drivers/vfio/pci/ VFIO-mdev drivers/vfio/mdev/ IOMMU Subsystem drivers/iommu/ Type1 IOMMU DMA Mapping PCI Device (GPU, NIC, NVMe) BAR, MSI-X, Config Space IOMMU HW (VT-d / AMD-Vi / SMMU) DMA Remapping + Interrupt Remapping Physical Memory DMA Target Pages
VFIO 3계층 구조: Container(IOMMU 도메인) → Group(IOMMU 그룹) → Device(개별 디바이스 FD)

Container / Group / Device 모델

계층파일 디스크립터(File Descriptor)역할주요 ioctl
Container /dev/vfio/vfio IOMMU 도메인 — DMA 매핑의 단위. 하나의 Container에 여러 Group을 연결하면 같은 IOMMU 주소 공간(Address Space) 공유 VFIO_SET_IOMMU, VFIO_IOMMU_MAP_DMA, VFIO_IOMMU_UNMAP_DMA
Group /dev/vfio/<N> IOMMU 그룹 — 하드웨어가 구분하는 최소 격리 단위. 그룹 내 모든 디바이스가 바인딩되어야 Group이 viable(사용 가능) 상태 VFIO_GROUP_SET_CONTAINER, VFIO_GROUP_GET_DEVICE_FD
Device Group FD에서 획득 개별 PCI 디바이스 — BAR 매핑, 인터럽트 설정, config space 접근 VFIO_DEVICE_GET_INFO, VFIO_DEVICE_GET_REGION_INFO, VFIO_DEVICE_SET_IRQS
Container 공유: 여러 Group을 하나의 Container에 연결하면 동일한 IOVA(I/O Virtual Address) 공간을 공유합니다. VM 패스스루에서는 일반적으로 모든 패스스루 디바이스를 하나의 Container에 연결하여 게스트 물리 메모리(Physical Memory)를 단일 DMA 매핑으로 관리합니다.
참고: VFIO ioctl API(Container→Group→Device FD 흐름), DMA 매핑(IOVA), BAR/MMIO 매핑, MSI-X 인터럽트 처리, 디바이스 패스스루 절차(GPU/NIC/NVMe), SR-IOV + VFIO, mdev(NVIDIA vGPU, Intel GVT-g), 디바이스 리셋, IOMMU 그룹 격리(ACS), 라이브 마이그레이션, 성능 비교, DPDK/SPDK 연동, 커널 설정, 트러블슈팅 등 상세 내용은 VFIO & mdev (디바이스 패스스루) 페이지에서 다룹니다.

Xen 하이퍼바이저

Xen은 2003년 케임브리지 대학교에서 시작된 Type-1 (베어메탈) 하이퍼바이저로, 하드웨어 위에 직접 설치되어 여러 게스트 OS를 동시에 실행합니다. KVM이 Linux 커널을 하이퍼바이저로 변환하는 것과 달리, Xen은 독립적인 마이크로커널 하이퍼바이저로서 Linux보다 먼저 부팅됩니다. Citrix(현 Cloud Software Group)가 상업적으로 발전시켰고, 2013년부터 Linux Foundation 산하 프로젝트로 운영되고 있습니다.

Xen의 산업적 영향: AWS는 2006년 서비스 시작부터 2017년 Nitro 전환까지 약 11년간 Xen을 핵심 하이퍼바이저로 사용했습니다. Alibaba Cloud, Oracle VM Server도 Xen 기반입니다. 현재는 KVM 기반 솔루션이 주류이지만, Xen의 아키텍처적 아이디어(분리 드라이버 모델, Grant Table 등)는 현대 가상화 설계에 깊은 영향을 미쳤습니다.
Xen 하이퍼바이저 아키텍처 Physical Hardware CPU (VT-x/AMD-V) | Memory | NIC | Disk | GPU Xen Hypervisor (Ring -1 / VMX Root Mode) CPU 스케줄링 메모리 관리 (P2M) Event Channels Grant Tables Hypercall 인터페이스 | XSM/FLASK 보안 | IOMMU 제어 Dom0 (관리 도메인) Linux Kernel (전체 하드웨어 접근) 네이티브 드라이버 Backend 드라이버 netback | blkback | pciback XenStore daemon (xenstored) xl / XAPI QEMU (HVM) 특권 도메인: 하드웨어 접근, VM 관리, I/O 중재 Xen Control Interface (XCI) DomU (PV Guest) PV-aware Linux Kernel Hypercall 직접 사용 netfront blkfront Grant Table 매핑 Event Channel HW 가상화 불필요 Hypercall로 특권 명령 대체 DomU (HVM Guest) Unmodified OS Windows / Linux 등 PV driver 에뮬 디바이스 VT-x / AMD-V 하드웨어 QEMU 디바이스 모델 비수정 OS 실행 가능 PV-on-HVM으로 성능 향상 Grant Event

Xen 도메인 유형

도메인 유형설명게스트 OS 수정HW 가상화 필요성능
Dom0 관리 도메인. 하드웨어 직접 접근, 다른 도메인 생성/관리, 백엔드 드라이버 호스팅 Xen 지원 Linux 필수 아니오 네이티브
DomU PV 반가상화 게스트. Hypercall로 특권 명령 대체, PV 드라이버(netfront/blkfront) 사용 필수 (커널 수정) 아니오 높음
DomU HVM 완전 가상화 게스트. 비수정 OS 실행, QEMU 디바이스 모델 사용 불필요 필수 (VT-x/AMD-V) 보통 (PV 드라이버 추가 시 높음)
DomU PVH PV + HVM 결합. HVM 컨테이너에서 PV 인터페이스 사용. QEMU 불필요 PVH 지원 커널 필요 필수 최고 (권장 모드)

Xen PV (Paravirtualization)

Xen PV는 게스트 OS가 가상화 환경임을 인지하고, 특권 명령을 Hypercall로 대체하는 방식입니다. 하드웨어 가상화 확장(VT-x/AMD-V)이 필요 없어 초기 Xen의 핵심 기술이었습니다. 게스트 커널을 수정해야 하지만, I/O 성능이 뛰어납니다.

/*
 * Xen Hypercall: 게스트가 하이퍼바이저에 서비스 요청
 *
 * PV 게스트는 특권 명령(IN/OUT, MOV CR3, WRMSR 등) 대신
 * Hypercall을 사용하여 Xen에 직접 요청합니다.
 *
 * 주요 Hypercall 목록:
 * - HYPERVISOR_memory_op()    : 메모리 관리 (balloon, 매핑)
 * - HYPERVISOR_event_channel_op() : Event Channel 생성/바인딩
 * - HYPERVISOR_grant_table_op()   : Grant Table 조작
 * - HYPERVISOR_sched_op()     : 스케줄러 제어 (yield, block)
 * - HYPERVISOR_console_io()   : 콘솔 입출력
 * - HYPERVISOR_xen_version()  : Xen 버전 정보
 */

/* Hypercall 호출 예시 (arch/x86/xen/enlighten_pv.c 기반) */
static inline long HYPERVISOR_memory_op(unsigned int cmd,
                                         void *arg)
{
    return _hypercall2(long, memory_op, cmd, arg);
    /* x86에서는 VMCALL/VMMCALL 또는 INT 0x82 사용 */
}

/* PV 프론트엔드 드라이버 목록 */
/*
 * netfront (drivers/net/xen-netfront.c)
 *   → 네트워크 프론트엔드. Dom0의 netback과 통신
 *
 * blkfront (drivers/block/xen-blkfront.c)
 *   → 블록 스토리지 프론트엔드. Dom0의 blkback과 통신
 *
 * pvcalls-front (drivers/xen/pvcalls-front.c)
 *   → PV 소켓 호출 프론트엔드
 *
 * xen-fbfront (drivers/video/fbdev/xen-fbfront.c)
 *   → PV 프레임버퍼 (콘솔 디스플레이)
 *
 * xen-kbdfront (drivers/input/misc/xen-kbdfront.c)
 *   → PV 키보드/마우스 입력
 */
Xen PV I/O 경로 (Split Driver Model) DomU (PV Guest) netfront 드라이버 TX/RX Ring Buffer (Grant Ref로 공유) 공유 영역 Shared Ring (Grant Table 매핑) Event Channel (인터럽트) Dom0 (Backend) netback 드라이버 Linux 네트워크 스택 (bridge / veth) Physical NIC Xen Hypervisor — Event Channel 라우팅, Grant Table 검증, 도메인 스케줄링 1. netfront가 패킷을 공유 링에 게시 2. Event Channel로 Dom0에 알림 3. netback이 Grant 매핑으로 데이터 읽어 NIC 전송
PV vs 에뮬레이션: PV 드라이버는 가상 하드웨어를 에뮬레이션하지 않고 공유 메모리와 이벤트 알림으로 직접 통신하므로, 에뮬레이션 오버헤드가 없습니다. virtio의 Split Virtqueue와 개념적으로 유사하며, Xen의 Split Driver Model이 virtio 설계에 영향을 주었습니다.

Xen HVM

Xen HVM(Hardware Virtual Machine)은 Intel VT-x / AMD-V 하드웨어 가상화 확장을 사용하여 수정되지 않은 게스트 OS를 실행합니다. QEMU 디바이스 모델이 레거시 하드웨어(IDE, RTL8139, VGA 등)를 에뮬레이션하므로 Windows 등 비수정 OS를 실행할 수 있습니다.

HVM 구성 요소역할
QEMU-DM디바이스 모델 프로세스(Process). 에뮬레이션 I/O 처리 (Dom0에서 실행)
PV-on-HVM 드라이버HVM 게스트 내에서 PV 드라이버를 설치하여 에뮬레이션 바이패스. xen-platform-pci가 자동 감지
Stub DomainQEMU를 별도 경량 도메인에서 실행하여 Dom0 공격 표면 축소
HVMLOADERHVM 게스트 부팅 펌웨어. BIOS/UEFI 테이블, ACPI, SMBIOS 생성
/*
 * Xen HVM의 I/O 처리 경로:
 *
 * [에뮬레이션 경로 - 느림]
 * Guest I/O (예: outb 0x1F0) → VM-Exit
 *   → Xen이 ioreq를 QEMU-DM에 전달
 *   → QEMU가 디바이스 에뮬레이션 수행
 *   → 결과를 ioreq에 기록
 *   → Xen이 게스트 재진입 (VMRESUME)
 *
 * [PV-on-HVM 경로 - 빠름]
 * Guest (PV 드라이버 설치됨)
 *   → PV 프론트엔드 사용 (netfront/blkfront)
 *   → Grant Table + Event Channel로 Dom0 백엔드와 직접 통신
 *   → QEMU 바이패스!
 *
 * PV-on-HVM은 HVM의 호환성과 PV의 성능을 모두 제공합니다.
 * Windows에서도 Xen PV 드라이버(GPLPV 또는 Citrix PV Tools)를
 * 설치하면 네트워크/디스크 성능이 크게 향상됩니다.
 */

Xen PVH

PVH(PV in HVM container)는 Xen 4.11부터 도입된 차세대 가상화 모드로, HVM의 하드웨어 격리와 PV의 경량 인터페이스를 결합합니다. QEMU 디바이스 모델이 필요 없고 에뮬레이션 레거시 디바이스도 없어 공격 표면이 크게 줄어듭니다.

항목PVHVMPVH (권장)
CPU 가상화Ring deprivilegingVT-x/AMD-VVT-x/AMD-V
I/O 모델PV 드라이버 전용에뮬레이션 + PV 선택PV 드라이버 전용
QEMU 필요불필요필수불필요
부팅 방식Direct kernel bootBIOS/UEFIDirect kernel boot
게스트 수정필수 (광범위)불필요PVH 지원 커널 (최소 수정)
보안 표면중간넓음 (QEMU 에뮬레이션)최소 (QEMU 없음)
권장 용도레거시Windows, 비수정 OSLinux 최신 워크로드
PVH 전환 권장: Linux 4.11+에서 PVH를 지원합니다. 기존 PV 게스트는 PVH로 전환하면 Meltdown/Spectre 같은 CPU 취약점(Vulnerability)에 대한 보안이 강화되고(HVM 격리), 동시에 QEMU가 필요 없어 공격 표면이 줄어듭니다. Xen 프로젝트는 공식적으로 PVH를 기본 모드로 권장합니다.

Grant Tables

Grant Table은 Xen 도메인 간 명시적 메모리 공유 메커니즘입니다. 한 도메인이 자신의 메모리 페이지에 대한 접근 권한(Grant Reference)을 다른 도메인에 부여하면, 상대 도메인이 해당 페이지를 자신의 주소 공간에 매핑할 수 있습니다. 암시적 공유가 없으므로 보안이 보장됩니다.

/* Grant Table API (include/xen/grant_table.h 기반) */

/* ── 1. 외부 도메인에 페이지 접근 권한 부여 ──────────── */
int gnttab_grant_foreign_access(
    domid_t domid,        /* 접근을 허용할 대상 도메인 ID */
    unsigned long frame,  /* 공유할 페이지의 MFN (Machine Frame Number) */
    int readonly          /* 1: 읽기 전용, 0: 읽기/쓰기 */
);
/* 반환: grant_ref_t (양수) — 상대 도메인에 전달할 참조 번호 */

/* ── 2. 접근 권한 철회 ────────────────────────────────── */
int gnttab_end_foreign_access(
    grant_ref_t ref,      /* 철회할 Grant Reference */
    struct page *page      /* 해제할 페이지 (NULL 가능) */
);

/* ── 3. 다른 도메인의 Grant를 로컬에 매핑 ─────────────── */
int gnttab_map_refs(
    struct gnttab_map_grant_ref *map_ops,
    struct gnttab_map_grant_ref *kmap_ops,
    struct page **pages,
    unsigned int count
);

/*
 * Grant Table 동작 흐름 (블록 I/O 예시):
 *
 * DomU (blkfront):
 *   1. 데이터 페이지를 할당
 *   2. gnttab_grant_foreign_access(dom0_id, page_mfn, 0)
 *      → grant_ref 획득 (예: ref=42)
 *   3. 공유 링에 {grant_ref=42, sector, nr_sectors} 요청 기록
 *   4. Event Channel로 Dom0에 알림
 *
 * Dom0 (blkback):
 *   1. Event Channel 수신
 *   2. 공유 링에서 요청 읽기 (grant_ref=42)
 *   3. gnttab_map_refs()로 DomU 페이지를 로컬 매핑
 *   4. 물리 디스크에 데이터 쓰기
 *   5. gnttab_unmap_refs()로 매핑 해제
 *   6. 완료 응답을 공유 링에 기록
 *   7. Event Channel로 DomU에 알림
 *
 * 보안: 각 Grant는 특정 도메인 쌍과 페이지에만 유효.
 *       하이퍼바이저가 모든 Grant 조작을 검증합니다.
 */
Grant Table 보안 모델: 모든 메모리 공유는 Grant Reference를 통해서만 가능하며, 하이퍼바이저가 모든 map/unmap 요청을 검증합니다. 도메인은 명시적으로 허용하지 않은 다른 도메인의 메모리에 절대 접근할 수 없습니다. 이 모델은 KVM의 QEMU 공유 메모리 방식보다 보안 격리가 강하며, Xen 아키텍처의 핵심 보안 기반입니다.

Event Channels

Event Channel은 Xen 도메인 간 경량 비동기 알림 메커니즘입니다. Linux의 인터럽트와 유사하게 동작하며, 도메인 간 통신, VIRQ(Virtual IRQ), IPI(Inter-Processor Interrupt) 등 다양한 용도로 사용됩니다.

Event Channel 유형설명용도
Inter-domain두 도메인 간 양방향 알림 채널PV 드라이버 I/O 완료 알림, XenStore watch
VIRQ가상 인터럽트 (하이퍼바이저 → 도메인)타이머(VIRQ_TIMER), 디버그, 콘솔
IPIvCPU 간 인터럽트SMP 스케줄링, TLB shootdown
Physical IRQ물리 인터럽트를 도메인에 라우팅Dom0 디바이스 드라이버, 패스스루 디바이스
/* Event Channel 바인딩 및 핸들링 (drivers/xen/events/ 기반) */

/* ── inter-domain Event Channel 바인딩 ────────────────── */
int bind_evtchn_to_irqhandler(
    evtchn_port_t evtchn,       /* Event Channel 포트 번호 */
    irq_handler_t handler,      /* 인터럽트 핸들러 함수 */
    unsigned long irqflags,     /* IRQ 플래그 */
    const char *devname,        /* 디바이스 이름 */
    void *dev_id                /* 디바이스 식별자 */
);
/* Event Channel 포트를 Linux IRQ에 매핑하여 표준 인터럽트 핸들러로 처리 */

/* ── VIRQ 바인딩 (하이퍼바이저 가상 인터럽트) ─────────── */
int bind_virq_to_irqhandler(
    unsigned int virq,          /* VIRQ 번호 (예: VIRQ_TIMER) */
    unsigned int cpu,           /* 대상 CPU */
    irq_handler_t handler,
    unsigned long irqflags,
    const char *devname,
    void *dev_id
);

/* ── Event Channel 생성 및 알림 ────────────────────────── */
/* 새 inter-domain 채널 할당 */
struct evtchn_alloc_unbound alloc = {
    .dom        = DOMID_SELF,
    .remote_dom = remote_domid,
};
HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc);
/* alloc.port에 새 포트 번호 반환 */

/* 상대 도메인에 알림 전송 */
struct evtchn_send send = { .port = local_port };
HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);

/*
 * Event Channel 내부 구현:
 *
 * 1. 각 도메인은 공유 정보 페이지(shared_info)에 이벤트 비트맵 보유
 * 2. 알림 전송 시 대상 도메인의 비트맵에 해당 포트 비트 설정
 * 3. Xen이 대상 도메인의 vCPU에 upcall 주입
 * 4. 게스트 커널의 이벤트 핸들러가 비트맵 스캔하여 처리
 *
 * → 하드웨어 인터럽트처럼 동작하지만, PCI/APIC 없이 순수 소프트웨어
 * → KVM의 irqfd와 개념적으로 유사
 */

XenStore

XenStore는 Xen 환경의 중앙 설정 데이터베이스로, 키-값(key-value) 형태의 계층적 네임스페이스를 제공합니다. 도메인 간 디바이스 검색, 설정 교환, 상태 동기화에 사용되며, Dom0에서 xenstored 데몬이 관리합니다.

/* XenStore API (include/xen/xenbus.h 기반) */

/* ── 값 읽기/쓰기 ─────────────────────────────────────── */
char *xenbus_read(
    struct xenbus_transaction t,  /* 트랜잭션 (XBT_NIL=즉시) */
    const char *dir,              /* 디렉터리 경로 */
    const char *node              /* 노드 이름 */
);

int xenbus_printf(
    struct xenbus_transaction t,
    const char *dir,
    const char *node,
    const char *fmt, ...         /* printf 스타일 값 */
);

/* ── Watch: 값 변경 모니터링 ──────────────────────────── */
int xenbus_watch_pathfmt(
    struct xenbus_device *dev,
    struct xenbus_watch *watch,
    xenbus_watch_callback callback,
    const char *pathfmt, ...
);

/*
 * XenStore 네임스페이스 구조 예시:
 *
 * /local/domain/0/                      ← Dom0 노드
 * /local/domain/0/backend/vbd/1/51712/  ← Dom1의 블록 백엔드
 *   physical-device = "8:0"             ← 물리 디바이스 (/dev/sda)
 *   state = "4"                         ← XenbusStateConnected
 *
 * /local/domain/1/                      ← DomU (domid=1) 노드
 * /local/domain/1/device/vbd/51712/     ← 블록 프론트엔드
 *   backend = "/local/domain/0/backend/vbd/1/51712"
 *   state = "4"
 *   ring-ref = "8"                      ← Grant Reference
 *   event-channel = "15"                ← Event Channel 포트
 *
 * state 전이: Initialising(1) → InitWait(2) → Initialised(3)
 *            → Connected(4) → Closing(5) → Closed(6)
 */
# XenStore 관리 명령

# 전체 트리 출력
xenstore-ls

# 특정 경로 읽기
xenstore-read /local/domain/1/device/vbd/51712/ring-ref

# 값 쓰기
xenstore-write /local/domain/1/data/mykey "myvalue"

# 디렉터리 목록
xenstore-list /local/domain/1/device

# 값 변경 감시 (watch)
xenstore-watch /local/domain/1/device/vbd/51712/state

# Dom0에서 DomU 백엔드 상태 확인
xenstore-ls /local/domain/0/backend

Xen Split Driver Model

Xen의 Split Driver Model은 디바이스 드라이버를 프론트엔드(DomU)백엔드(Dom0)로 분리하여 안전한 I/O 가상화를 구현합니다. 두 반쪽은 Grant Table로 공유된 링 버퍼와 Event Channel 알림으로 통신합니다.

Xen Split Driver Model (블록 I/O 예시) DomU (Frontend) Application (read/write) VFS / Block Layer blkfront xen-blkfront.c Request Ring (Grant Ref) 1. bio → blk_rq → ring에 요청 게시 2. 데이터 페이지에 Grant 발급 Shared Ring Buffer Request Ring (req_prod → req_cons) Frontend writes, Backend reads Response Ring (rsp_prod → rsp_cons) Backend writes, Frontend reads Grant Table 페이지 매핑 Event Channel 알림 Dom0 (Backend) blkback xen-blkback.c Block Layer (submit_bio) NVMe / SCSI 드라이버 Physical Disk 3. Grant 매핑으로 데이터 접근 4. 물리 디스크 I/O 수행 Xen Hypervisor Grant Table 검증 | Event Channel 라우팅 | 도메인 격리
/*
 * Xen 공유 링 버퍼 프로토콜 (xen/interface/io/ring.h)
 *
 * DEFINE_RING_TYPES(blkif, blkif_request, blkif_response) 매크로가
 * 프론트/백엔드 링 구조체를 자동 생성합니다.
 *
 * 프론트엔드 (요청 생성):
 */
RING_IDX req_prod = sring->req_prod;
RING_GET_REQUEST(&front_ring, req_prod, &req);
req.operation   = BLKIF_OP_READ;
req.nr_segments = 1;
req.seg[0].gref    = grant_ref;    /* Grant Reference */
req.seg[0].first_sect = 0;
req.seg[0].last_sect  = 7;         /* 8 sectors = 4KB */
front_ring.req_prod_pvt++;
RING_PUSH_REQUESTS(&front_ring);   /* 메모리 배리어 + 인덱스 업데이트 */
notify_remote_via_evtchn(evtchn);  /* Event Channel 알림 */

/*
 * 백엔드 (요청 처리):
 */
while (RING_HAS_UNCONSUMED_REQUESTS(&back_ring)) {
    RING_COPY_REQUEST(&back_ring, back_ring.req_cons, &req);
    back_ring.req_cons++;

    /* Grant 매핑으로 데이터 페이지 접근 */
    gnttab_map_refs(&map_op, NULL, &page, 1);

    /* 물리 디스크 I/O 수행 ... */

    /* 응답 기록 */
    RING_GET_RESPONSE(&back_ring, back_ring.rsp_prod_pvt, &rsp);
    rsp.status = BLKIF_RSP_OKAY;
    back_ring.rsp_prod_pvt++;
    RING_PUSH_RESPONSES(&back_ring);
    notify_remote_via_evtchn(evtchn);
}

/*
 * 제로카피 최적화 (Grant Page Flipping):
 * - 전통적: gnttab_map + memcpy + gnttab_unmap (복사 발생)
 * - 최적화: Grant 페이지를 백엔드의 bio에 직접 삽입 (제로카피)
 * - blkback의 persistent_grants 옵션으로 매핑 캐싱도 가능
 *   → map/unmap 오버헤드 제거 (최대 2-3배 IOPS 향상)
 */

Xen 메모리 관리

Xen은 P2M(Physical-to-Machine) 매핑을 사용하여 각 도메인의 게스트 물리 주소(PFN)를 실제 머신 프레임 번호(MFN)로 변환합니다. KVM의 EPT/NPT와 유사하지만, PV 게스트에서는 소프트웨어적으로 관리합니다.

메모리 관리 기능설명
P2M 매핑 PV: 게스트가 P2M 테이블을 직접 관리 (Hypercall로 업데이트). HVM: EPT/NPT 하드웨어 사용. 게스트는 연속 PFN을 보지만 MFN은 비연속
Ballooning xen-balloon 드라이버가 게스트 내에서 페이지 할당 후 하이퍼바이저에 반환. xl mem-set <domid> <MB>로 동적 조정
Memory Sharing 동일한 페이지를 여러 도메인이 읽기 전용(Read-Only)으로 공유. 중복 제거(dedup)로 메모리 절약. xl mem-sharing-op
SWIOTLB-Xen DMA를 사용하는 PV 도메인에서 bounce buffer 제공. 게스트의 연속 PFN이 MFN으로는 비연속일 수 있어 DMA 호환성 보장
PoD (Populate-on-Demand) 메모리 오버커밋. 실제 접근이 발생할 때만 MFN 할당. 메모리 사용 효율을 높이지만 OOM 위험
/* P2M 매핑 관련 API (arch/x86/xen/p2m.c 기반) */

/* PFN → MFN 변환 */
unsigned long mfn = pfn_to_mfn(pfn);

/* MFN → PFN 역변환 */
unsigned long pfn = mfn_to_pfn(mfn);

/* P2M 엔트리 설정 (PV 게스트에서 직접 관리) */
bool set_phys_to_machine(unsigned long pfn,
                         unsigned long mfn);

/* Xen 메모리 예약/해제 (ballooning에 사용) */
struct xen_memory_reservation reservation = {
    .nr_extents   = nr_pages,
    .extent_order = 0,           /* 4KB 페이지 */
    .domid        = DOMID_SELF,
};
HYPERVISOR_memory_op(XENMEM_decrease_reservation,
                     &reservation);
/* 게스트가 호스트에 페이지 반환 (balloon inflate) */

/*
 * SWIOTLB-Xen 동작:
 *
 * PV 도메인에서 DMA 수행 시:
 * 1. 드라이버가 dma_map_single() 호출
 * 2. xen-swiotlb가 연속 MFN 영역(bounce buffer) 할당
 * 3. 원본 데이터를 bounce buffer에 복사
 * 4. bounce buffer의 bus address를 디바이스에 전달
 * 5. DMA 완료 후 bounce buffer → 원본으로 복사
 *
 * → 추가 복사 비용이 있지만 DMA 호환성 보장
 * → HVM에서는 EPT가 연속 GPA→HPA 매핑을 보장하므로 불필요
 */

Xen 보안

Xen은 마이크로커널 아키텍처를 활용한 강력한 보안 격리를 제공합니다. 하이퍼바이저 TCB(Trusted Computing Base)를 최소화하고, XSM(Xen Security Modules)으로 세밀한 접근 제어(Access Control)를 구현합니다.

보안 메커니즘설명
XSM/FLASK SELinux와 유사한 필수 접근 제어(MAC). Hypercall별, 도메인별 정책 적용. 예: DomU가 Dom0 메모리 접근 불가 정책
분리(Disaggregation) Dom0 권한을 여러 도메인으로 분산. 네트워크 백엔드를 Driver Domain에서 실행하면 Dom0 공격 표면 축소
Driver Domain 특정 하드웨어 드라이버만 실행하는 전용 도메인. NIC 드라이버 취약점이 전체 시스템에 영향을 미치지 않음
Stub Domain QEMU 디바이스 모델을 경량 도메인(MiniOS 기반)에서 실행. Dom0와 격리하여 QEMU 취약점 완화
Grant Table 격리 도메인 간 메모리 공유는 명시적 Grant만 허용. 암시적 공유 없음 → KVM(QEMU 프로세스 내 공유 메모리)보다 강한 격리
Xen ARM: 임베디드/자동차 보안: Xen은 ARM 플랫폼에서도 널리 사용됩니다. ADAS(첨단 운전자 보조 시스템)에서 안전 관련 소프트웨어와 인포테인먼트를 격리하거나, 모바일 보안에서 일반 OS와 보안 OS를 분리하는 데 활용됩니다. ARM TrustZone과 결합하여 Secure World / Normal World 격리를 하이퍼바이저 수준으로 확장합니다.

Xen 관리 도구

도구유형설명
xlCLIXen 기본 관리 도구. 도메인 생성/삭제/마이그레이션 등 전체 라이프사이클 관리
XAPI (xe)API/CLIXenServer/XCP-ng의 관리 API. 풀 관리, 스토리지, 네트워킹 통합
libvirt라이브러리Xen 드라이버 포함. virsh로 KVM/Xen 통합 관리 가능
xentop모니터링도메인별 CPU/메모리/I/O 사용률 실시간(Real-time) 모니터링 (top과 유사)
xen-hptool메모리핫플러그 메모리 관리, NUMA 설정
# xl 주요 명령어

# 도메인 생성 (설정 파일 기반)
xl create /etc/xen/myvm.cfg

# 실행 중인 도메인 목록
xl list
# Name      ID   Mem VCPUs  State  Time(s)
# Domain-0   0  4096     4  r-----   1234.5
# myvm       1  2048     2  -b----    567.8

# 도메인 콘솔 접속
xl console myvm

# 라이브 마이그레이션 (다른 호스트로 이동)
xl migrate myvm remote-host

# 메모리 동적 조정 (ballooning)
xl mem-set myvm 4096

# 도메인 일시 정지 / 재개
xl pause myvm
xl unpause myvm

# 도메인 저장(체크포인트) / 복원
xl save myvm /var/lib/xen/save/myvm.img
xl restore /var/lib/xen/save/myvm.img

# 도메인 정보 상세
xl info
xl vcpu-list myvm
xl network-list myvm
xl block-list myvm

# 도메인 설정 파일 예시 (/etc/xen/myvm.cfg)
# type = "pvh"                   # PVH 모드 (권장)
# name = "myvm"
# memory = 2048
# vcpus = 2
# kernel = "/boot/vmlinuz"
# ramdisk = "/boot/initrd.img"
# root = "/dev/xvda1"
# disk = ['phy:/dev/vg/myvm-disk,xvda,w']
# vif = ['bridge=xenbr0']

KVM vs Xen 비교

항목KVMXen
아키텍처 Type-2 (Linux 커널을 하이퍼바이저로 활용) Type-1 (독립 마이크로커널 하이퍼바이저)
TCB 크기 큼 (Linux 커널 전체 + QEMU) 작음 (Xen 코어 ~300K LOC)
디바이스 모델 QEMU (유저스페이스) QEMU (HVM) 또는 Split Driver (PV/PVH)
I/O 가상화 virtio (준가상화), VFIO (패스스루) Split Driver (PV), virtio, VFIO
메모리 격리 EPT/NPT + QEMU 프로세스 격리 Grant Table 명시적 공유 (더 강한 격리)
성능 우수 (vhost, VFIO, hugepage) 우수 (PV I/O, persistent grants)
관리 에코시스템 libvirt, oVirt, OpenStack, Kubernetes xl, XAPI, libvirt (제한적)
Linux 통합 커널 내장 (mainline) 외부 하이퍼바이저, Linux는 Dom0/DomU로 동작
중첩 가상화 지원 (nested VMX/SVM) 제한적 지원
주요 클라우드 Google Cloud, Azure, IBM Cloud AWS (2017년까지), Alibaba Cloud, Oracle VM
컨테이너 통합 Kata Containers, Firecracker (microVM) Unikernel (MirageOS), 제한적
Xen 프로덕션 사례:
  • AWS — 2006년 EC2 출시부터 2017년 Nitro 전환까지 Xen이 핵심 하이퍼바이저. Nitro는 KVM 기반이지만 Xen의 분리 모델(offload card) 아이디어를 계승
  • Alibaba Cloud (Aliyun) — 커스텀 Xen 기반 가상화 플랫폼 운영, 점진적 KVM 전환 중
  • Oracle VM Server — Xen 기반 엔터프라이즈 가상화, Oracle Database 워크로드 최적화
  • Qubes OS — 데스크톱 보안 OS. Xen 기반 도메인 격리로 업무/개인/네트워크를 완전 분리
  • 자동차 (ADAS) — AUTOSAR Adaptive Platform에서 Xen ARM으로 안전/비안전 파티션 격리

참고 링크

커널 문서

Intel/AMD 사양

LWN 기사

커널 소스

기타 참고 자료

가상화(KVM)와 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.