Contents
- Introduction: Techniques to Design Virtualization
- Trap and Emulate
- Techniques to Virtualize x86
- Memory Virtualization
- I/O Virtualization
- KVM/QEMU Hardware-assisted Virtualization
- Hardware-assisted Virtualization
- KVM/QEMU Virtualization
- Practice: kvm-hello-world
1. Introduction: Techniquest to Design Virtualization
1.1 Trap and Emulate
프로세서들은 일반적으로 privilege level을 정의하여 user process와 OS를 다른 level에서 실행시킨다. x86 아키텍처에서는 ring 0, 1, 2, 3으로 privilege level을 4개로 정의하였으며 user process는 ring 3, OS는 ring 0 level에서 실행할 수 있도록 하여 가장 높은 privilege level인 ring 0만 priviliged intruction을 실행할 수 있다.
하지만 가상화 환경에서는 위 이미지에서 볼 수 있다시피 VM은 ring 3, VMM/Host OS는 Ring 0에서 실행한다. Guest OS는 ring 0에서 실행되고 있다고 착각을 하고 ring 3에서 guest app으로부터 보호를 받는다. 이때, Guest OS가 privilege instruction을 어떻게 실행할 수 있을까?
Guest OS에서 privileged instruction을 실행시킬 수 있도록 하는 방법이 Trap-and-Emulate이다. Trap-and-Emulate는 VMM보다 낮은 권한에서 실행되는 VM이 privileged instruction을 실행을 할 때 VMM로 trap하는 방식이다. (e.g., IDT 설정, CR3 레지스터 설정, 하드웨어 접근)
1) Guest App이 privileged instruction 실행 시도 --> Trap 발생
2) VMM으로 제어권이 전환되고 VMM에서 명령어 에뮬레이션
3) 에뮬레이션이 완료되면 VMM은 guest OS에게 제어권과 처리결과 return
운영체제는 Ring 0에서 실행되도록 설계가 되었으며, 기존의 x86 아키텍처는 가상화를 염두하지 않고 설계가 되었다. 이로 인해 예상대로 트랩이 발생하지 않는 문제가 발생할 수 있다. (2000년대 초반부터는 Intel's VMX or AMD's AMD-V에서 hardware virtualization 지원 기능이 도입되었다.)
하드웨어 상태를 변경하는 일부 x86 명령어 (Sensitive Instruction)는 privileged와 non-privileged mode 모두에서 실행될 수 있지만, Ring 0과 그 외 level에서는 동작 방식이 다르게 설계되어 있다. 그렇기 때문에 트랩이 발생해야 하는 상황에서도 트랩이 발생하지 않을 수 있는 문제가 있다.
예를 들면, x86의 popf 명령어는 스택에서 pop한 값으로 eflags 레지스터를 설정할 수 있다. ring 0에서는 정상적으로 설정되지만, ring 1에서는 일부 플래그 값들만 설정되어 Trap을 발생시키지 않는다는 문제점이 있다. (eflags 레지스터는 CPU의 동작 제어 및 연산 결과 반영을 위해 다양한 플래그 값을 설정하는 중요한 레지스터이므로, 이러한 문제는 가상화 환경에서 예상치 못한 동작을 유발할 수 있다.
Popek Goldberg throrem은 Popek과 Goldberg는 1974년에 가상화가 성공적으로 구현되기 위해 컴퓨터 아키텍처가 충족해야 할 조건들을 정의한다. 효율적인 VMM을 구현하기 위해서는 sensitive instruction이 privileged instruction의 하위 집합이 되어야 한다. 즉, VM 내에서 명령어가 실행될 때 모든 특권 명령어가 트랩 가능하여 VMM에 의해 처리될 수 있어야 한다.
- Sensitve instruction: 하드웨어 상태를 변경하는 명령어
- Privilieged instruction: Ring0에서만 실행될 수 있는 명령
1.2 Techniques to Virtualize x86
- Para-Virtualization
- Guest OS의 코드를 수정
- Guest OS는 privilieged instruction 실행 시, VMM으로 Hypercall 수행
- OS 소스코드를 수정하지 않으면 동작이 불가하기 때문에, OS 소스코드를 수정해야 한다.
- E.g., Xen Hypervisor
- Full-Virtualization
- Dynamic Binary Translation → Guest OS의 코드를 수정하지 않아도 됨
- 하지만, Para-Virtualization에 비해 높은 오버헤드
- E.g., VMware Workstation
- Hardware-assisted Virtualization
- 프로세서에는 특별한 VMX 실행 모드가 존재
- CPU의 가상화 모드 지원 필요: Intel VT-x, AMD AMD-V
- x86은 4개의 non-VMX root mode + 4개의 VMX mode
- VMM은 Ring 0에서 VMX mode로 진입하여 Guest OS 실행하며 Trap 발생 시 VMM으로 제어권이 이동
- E.g., KVM/QEMU
- 프로세서에는 특별한 VMX 실행 모드가 존재
x86은 Intel이 개발한 microprocessor 계열을 부르는 말이자, 이들과 호환되는 프로세서들에서 사용한 ISA (Instruction Set Architecture)이다.
1.3 Memory Virtualization
Guest OS는 GVA → GPA로 매핑하여 모든 가상주소에 접근이 가능하다고 가정한다. 반면, VMM/Host OS는 GPA → HPA로 매핑하여 host 메모리에 분산 저장한다.
이러한 가상화 환경에서 MMU는 페이지 테이블을 2가지 주요 방식으로 참조한다.
- Shadow paging
- GVA → HPA 매핑 결합
- 소프트웨어 기반의 메모리 관리 기법으로, VMM은 Guest 페이지 테이블의 변경사항을 매번 추적하고 shadow page table을 주기적으로 업데이트해야한다는 단점이 있다.
- VMM은 Guest OS가 사용하는 페이지 테이블을 복사하여 호스트가 이해할 수 있는 형식으로 변환하고 guest page table의 변경사항을 기반으로 업데이트한다.
- Extended Page Table (EPT)
- MMU는 분리된 GVA → GPA, GPA → HPA 매핑을 참조한다.
- EPT는 하드웨어 지원을 활용한 메모리 관리 MMU는 가상화 환경을 인지하고, 2개의 분리된 페이지 테이블을 참조한다. 하드웨어 방식이기 때문에 Shadow paging보다는 효율적이지만 주소 변환을 2개 페이지 테이블 모두에서 수행해야 한다는 단점이 있다.
1.4 I/O Virtualization
I/O 가상화 기법으로는 Emulation과 Direct I/O가 있다. 이러한 기법은 VM이 Host 시스템의 I/O 자원에 접근하고 효율적으로 사용할 수 있도록 지원한다.
- Emulation (Para/Full-virtualization)
- Guest OS가 I/O 연산 수행 시 trap 발생시키면 VMM은 해당 I/O 연산을 emulation
- Direct I/O or Device Passthrough
- 각 VM에 직접 하드웨어 장치 슬라이드를 할당하여, VMM을 거치지 않고 Guest OS가 직접 해당 장치를 제어하고 I/O 연산을 수행
2. KVM/QEMU Hardware-assisted Virtualization
2.1 Hardware-assisted Virtualization
기존 x86 아키텍처는 가상화를 고려하여 설계되지 않았지만, 2000년 초반에 Intel과 AMD는 가상화를 지원하는 프로세서를 출시하면서 Hardware-assisted virtualization이 도입되었다. VM을 실행시키기 위해 Hypervisor들이 CPU의 vitualization 기능을 활용하여 VMX mode라는 특별한 privilieged level을 사용한다.
2.2 KVM/QEMU VIrtualization
Linux에 KVM/QEMU를 설치하면 libvirt도 함께 설치를 해야 한다. libvirt는 Red Hat에 만든 open source로, hypervisor를 관리하기 위한 도구/API 집합이다.
쉽게 말해, 여러 hypervisor들의 공통된 중요 핵심 기능들을 모아서 한 번에 다루도록 API를 제공하는 것이다.
- Linux에 동작하는 system daemon으로 hyperviosr와 통신
- 하이퍼바이저 관리, VM 생성 등에 사용할 수 있는 API 제공
- 명령형 도구 (virsh)와 GUI 기반 도구 (virt-manager) 제공
QEMU는 KVM과 협력하여 가상화를 지원하며, 호스트에서 사용자 프로세스로 작동하면서 Guest VM의 CPU, memory, device를 관리한다.
- QEMU는 User process이고 KVM은 장치파일(/dev/kvm)로, QEMU의 open/ioctl syscall을 통해 KVM과 통신한다.
- Guest VM의 physical memory 할당을 위해 mmap를 사용하고 vCPU마다 Thread를 생성한다. --> Host OS는 QEMU를 일반적인 멀티스레드 프로세스로 간주
- Fild descriptor 종류
- KVM
- VM (KVM_CREATE_VM)
- Virtual CPU (KVM_CREATE_VCPU)
- Virtual Device (KVM_CREATE_DEVICE)
- VMX mode
- VMX mode로 진입 및 종료를 위한 CPU 명령어
- VMLAUNCH, VMRESUME - VMX mode 진입하기 위해 KVM이 호출
- VMEXIT - VMX mode를 종료하기 위해 Guest OS가 호출
- VMX 진입/종료 명령에서 CPU는 Host OS와 Guest OS 간의 conetxt switch
- 모든 전환은 Hardware에 의해 수행
- 페이지 테이블, CPU 레지스터 값 등이 전환
- 모드 전환 시 CPU context의 저장 위치
- Host OS 또는 Guest OS의 데이터 구조체에만 저장되는 것은 불가
- VMCS (VM Control Structure) 또는 VMCB (VM Control Blck) 라고 불리는 영역에 저장
- VMX mode로 진입 및 종료를 위한 CPU 명령어
- VMCS
- 두 VMX mode 모두에서 접근 가능한 공통 메모리 영역 (VM 당 하나의 VMCS)
- 저장 정보들
- Host CPU context: VM이 실행될 떄 저장, VM이 종료될 떄 복원
- Guest CPU context: VM이 종료될 때 저장, VM이 시작될 때 복원
- VM-execution/exit/entry: KVM은 Guest 메모리와 CPU context를 설정할 수 있으며, 어떤 명령어와 이벤트가 VM을 종료해야 하는지를 지정 가능
- Exit information: 종료 사유 및 기타 종료 관련 정보
- VMCS 정보는 kvm_run 구조체를 통해서 QEMU와 공유
- VMCS는 커널 모드에서 KVM만 액세스 가능 (QEMU user space에서는 액세스 불가)
- VMX mode 실행
- 하드웨어 지원 (VMX mode)을 이용하여 Trap-and-Emulate 효과 달성
- Guest OS는 Ring 0에서 실행되지만, Trap-and-Emulate 달성
- Guest OS는 제한적으로 실행
- Guset OS는 특정 명령 실행 시 KVM으로 종료
- VM 종료: vmcall 명령어 / EPT page fault / interrupt / sensitive instructions...
- Guest는 하드웨어에 대한 접근 불가, 하드웨어 접근은 KVM에 의해 에뮬레이션 필요
- KVM은 VMCS를 통해 VM 종료를 설정 가능
- 하드웨어 지원 (VMX mode)을 이용하여 Trap-and-Emulate 효과 달성
- Host view
- Host는 QEMU를 일반 멀티스레드 프로세스로 인지한다.
- 프로세스는 ioctl 호출을 통해 KVM 장치와 통신
- 여러 QEMU VCPU 스레드는 여러 코어에서 병렬로 스케줄링이 가능하다.
- KVM이 VM을 시작하면 Host OS context가 VMCS에 저장
- Host OS 실행이 중단 (모든 호스트 프로세스가 중지)
- CPU가 Guest OS 컨텍스트를 로드하고 Guest OS가 실행을 시작
- Guest OS가 종료되면 Host OS 컨텍스트가 VMCS에서 복원
- Host OS가 실행을 멈췄던 KVM에서 실행 재개
- KVM은 QEMU로 돌아가거나, Host는 다른 프로세스로 실행을 전환
- Host OS는 Guest OS 실행을 인식하지 못함
- Host는 QEMU를 일반 멀티스레드 프로세스로 인지한다.
2.3 Practice: kvm-hello-world
https://github.com/dpw/kvm-hello-world
GitHub - dpw/kvm-hello-world: A minimal kvm example
A minimal kvm example. Contribute to dpw/kvm-hello-world development by creating an account on GitHub.
github.com
하단 코드는 QEMU가 동작하는 코드이다.
- QEMU의 VCPU 스레드는 KVM 커널 모듈에 KVM_RUN 명령어를 제공
- KVM은 VMCS의 VM 정보를 설정하고, VMX 모드에서 Guest OS를 실행
- Guset OS는 VM 종료가 발생하기 전까지 CPU에서 일반적인 방식으로 실행
- 실행 흐름의 제어는 VM 종료 시에 KVM/Host OS로 이동
- VM 종료는 KVM 혹은 QEMU에 의해 처리
- Host는 Guset OS를 인지하지 못하고 QEMU를 일반적인 프로세스처럼 스케줄링
open(/dev/kvm) // KVM 디바이스 오픈
ioctl(qemu_fd, KVM_CREATE_VM) // VM 생성
ioctl(vm_fd, KVM_CREATE_VCPU) // VCPU 생성
for(;;) { // 각 VCPU마다 Loop 수행
ioctl(vcpu_fd, KVM_RUN) // KVM이 VMX 모드로 전환 후, Guest VM 실행
// VM이 VMX 모드를 종료하면 호스트의 QEMU로 복귀
// VM의 EXIT를 처리하고 Guest VM으로 다시 복귀
switch(exit_reason) {
case KVM_EXIT_IO:
case KVM_EXIT_HLT:
}
}
'Study > Cloud Computing' 카테고리의 다른 글
[Cloud Security] Container Security (0) | 2024.12.07 |
---|---|
[Cloud Security] Introduction to Cloud Security (0) | 2024.12.02 |
Monitor and Manage Google Cloud Resources (6) | 2024.09.22 |
[Cloud] 쿠버네티스 실습 (0) | 2024.05.13 |
[Cloud] 컨테이너 오케스트레이션과 쿠버네티스 (2) - 실습 (0) | 2024.05.02 |