이전글에서 가상화 기본 개념을 정리했다. 이어서 현대의 System VM 은 어떻게 구현되는지에 대해 공부한 내용을 정리해본다.
1. 에뮬레이션 (Emulation) 과 Qemu (Quick EMUlator)
Qemu 는 가상 환경을 만들기 위해 필요한 모든 하드웨어 시스템을 에뮬레이트한다. 여기서 에뮬레이트란, 가상의 하드웨어를 실제 물리 머신 위에서 소프트웨어적으로 구현하는 것이다. 이를 위해 가상환경에서 동작하는 어플리케이션 프로그램이나 운영체제가 하드웨어 자원(이라고 믿고 있지만 실제로는 Qemu 인) 에 보내는 요청을 적절히 처리할 수 있어야 한다. Qemu 는 에뮬레이트 되는 하드웨어의 모든 명령어를 실제 물리머신이 처리할 수 있도록 binary translation 을 하는 방식으로 이를 구현한다. 그러나 Translation 을 아무리 적절하고 효율적으로 한다고 해도, 서로 다른 물리머신의 명령어 세트이기 때문에 오버헤드가 발생하기 되고, 실제 물리머신보다 더 느린 환경이 만들어지게 된다.
2. 하드웨어 지원 가상화 (hardware assisted virtualization)
1) 하드웨어 지원 가상화란
가상화되는 하드웨어 시스템과 실제 물리머신이 동일한 ISA 를 가지는 경우를 생각해보자. 이 경우 가상 환경에서 요청되는 명령어들이 실제 하드웨어에서도 그대로 실행이 가능해지므로 Qemu 가 별도의 Binary Translation 작업을 하지 않아도 된다. 따라서 Binary Translation 의 오버헤드가 줄어들 것이다.
그러나 이는 CPU 가 유저모드일 때에 국한된 설명으로, 가상머신에서 메모리 페이지 테이블 설정, I/O 요청, 인터럽트 처리 등 CPU 의 커널 모드에서 이뤄지는 작업을 처리하기 위해서는 여전히 호스트 OS 의 협력이 필요해진다. 왜냐하면 가상머신은 호스트 OS 입장에서 하나의 프로세스에 지나지 않기 때문에 커널 모드를 이용할 수 없기 때문이다.
이러한 커널 모드에서 이루어지는 특권 명령들은 에뮬레이터의 소프트웨어적인 해석을 통해 구현되게 되며, 이로써 가상머신과 실제 물리머신이 ISA 가 동일하다 하더라도 오버헤드가 남아있게 되는것이다. 이러한 에뮬레이션의 오버헤드를 줄이기 위해서는 소프트웨어 수준이 아닌 CPU 수준의 가상화가 필요해진다. 즉, 에뮬레이터에서 필요로 하는 특권 명령을 소프트웨어적으로 해석해서 수행하지 않고, 곧바로 하드웨어 자원에서 시키는 것이다. Intel, AMD 같은 CPU 제조사들은 이러한 가상화 기술을 CPU 차원에서 도입하게 되었다. (VT-x, SVM)
+) 가상머신에서 구동되는 프로세스가 메모리를 할당 받고 이를 관리하기 위해 가상머신에서 메모리 페이지 테이블을 설정하는 경우를 생각해보자 Qemu 는 이를 에뮬레이션 하기 위해 전적으로 호스트 OS 에 의지하게 될 것이다. 왜냐하면 메모레 페이지 테이블의 설정은 커널 모드에서만 수행할 수 있는 특권 명령이고, 실제 물리머신의 입장에서 가상머신은 프로세스에 불과하기 때문에 이러한 특권명령을 처리할 수 없기 때문이다. 그러나 하드웨어 가상화 기술을 사용하면 이러한 특권 명령을 호스트 OS 의 도움 없이 바로 수행할 수 있게 된다.
2) VMX-root 와 VMX-nonroot
위에서 이야기 했듯 가상화를 지원하는 CPU 는 가상머신이 특권 명령을 직접 처리할 수 있게 해준다. 그러나 그렇다고 가상머신이 모든 특권 명령을 처리할 수 있도록 최고 수준의 특권이 주어지는 것은 아니다. 메모리 관리나 I/O 작업 중 일부의 경우는 가상머신의 명령이 제한되며, 이를 수행하기 위해서는 하이퍼바이저의 관리가 필요하다.
이는 CPU 가 유저모드와 커널모드로 동작하는 방식과 흡사한데, 가상화 기능을 지원하는 CPU 는 이러한 동작 방식을 그대로 적용하여 두가지 (VMX-root 모드와 VMX-nonroot 모드) 모드를 오가며서 동작한다. 즉, 가상머신이 직접 CPU 자원을 다루는 경우 VMX-nonroot 모드로 동작하고 하이퍼바이저가 이를 대신 수행해주는 경우에는 VMX-root 모드로 전환된다.
프로세스가 자신의 권한 밖의 요청을 하기위해서는 시스템 콜을 이용해 OS 에게 요청을 하고 이를 통해 CPU 가 유저 모드와 커널 모드를 오간다. 프로세스는 OS 의 존재를 알고 이에 의존하는 것이다. 그러나 가상머신의 경우 하이퍼바이저에게 의존하지 않으며, 더 정확하게는 존재 자체를 모른다. 가상머신은 자신의 특권 수준을 인식하지 않고 필요한 명령을 CPU 에게 하게되는데 이때 CPU 가 권한 밖의 요청이 들어왔다는 것을 판단하게 되고 하이퍼바이저에게 이를 전달하기 위해 vm-exit 를 발생(시스템 콜과 흡사하다) 하여 VMX 모드를 전환한다. 이를 통해 더욱 독립적인 가상환경을 구현할 수 있게 된다.
3) KVM
앞서 이야기한대로 하드웨어에서 지원하는 가상화를 사용하기 위해서는 하이퍼바이저의 도움을 받아야 한다. 이를 통해 가상 머신은 CPU 자원을 직접 이용하여, 에뮬레이션의 오버헤드를 줄이고 더 '가속화' 된 가상화 환경을 구성할 수 있다. 때문에 하드웨어 지원 가상화를 이용하는 것을 '하드웨어 가속(Hardware acceleration') 이라고 한다.
또한, 이러한 하드웨어 가속을 이용하기 위해 하이퍼바이저의 도움을 받아야 한다고 하였는데 더 구체적으로는 하이퍼바이저에게 하드웨어 가속모드를 쓸 수 있게 해주는 '엑셀러레이터(Accelerator)' 의 도움을 받아야 한다. 이 중 대표적인 것이 리눅스 커널에 포함되어 있는 KVM 모듈이다. 여러 리눅스 기반의 하이퍼바이저는 KVM 을 이용하여 하드웨어 가속모드를 지원한다. Xen 하이퍼바이저의 경우 KVM 을 사용하지 않고 내부적으로 엑셀러레이터를 구현하고 있다.
Qemu + KVM 아키텍쳐
위 정리된 내용을 기반으로 Qemu 와 KVM 을 이용한 가상화 환경의 아키텍쳐를 그릴 수 있다. 아래는 Qemu Wiki 페이지에서 찾은 그림이다.
위에서 설명하지 않은 개념들을 보충하였다. 사실 아직 아키텍쳐가 완전히 이해되는 것은 아니라서, 설명은 나중에 보충하려고 한다.
Ring 0 와 Ring 3
CPU의 권한 수준을 나타내는 것으로 Ring 0 는 커널모드 수준 특권 명령을 수행하는 권한, Ring 3 는 유저모 드 수준의 명령을 싱행하는 권한을 말한다. 참고로 Ring 1, 2 는 실제로 거의 쓰이지 않지만 하드웨어 가상화 기술이 도입되기 이전에는 가상머신에게 Ring 1 (중간 정도의 권한) 권한을 부여하여 특권 명령을 실행하도록 하였다. 하드웨어 가상화 기술이 만들어지면서 VMX 모드가 생겨서 가상 머신도 Ring 0 권한을 부여하게 되었다.
VMCS
Virtual Machine Control Structure 의 줄임말로 가상머신과 호스트 간의 상태를 저장하는 데이터 구조를 말한다. VMX 모드를 전환할 때, 이전의 데이터 값을 저장/복원한다. 마치 프로세스 전환시 PCB 가 하는 역할을 해준다고 볼 수 있다.
gCR3
게스트 가상머신의 CR3 레지스터라는 의미로, 게스트 가상머신에서 메모리에 접근할 때 쓰는 페이지 테이블 정보를 가지는 레지스터이다.
EPT, EPT Violation
EPT(Extended Page Table) 는 가상머신의 가상 메모리 주소를 실제 메모리 주소로 맵핑해주는 페이지 테이블로, VT-x 에서 사용된다. 게스트의 가상주소를 게스트의 물리주소로, 게스트의 물리 주소를 호스트의 물리 주소(HPA, Host Page Address)로 변환하는 이중 페이지 테이블 구조로 되어있다.
가상머신에서 가상 메모리를 통해 실제 메모리 공간에 접근을 시도할 때, 허용되지 않은 메모리 공간을 접근하려고 하면 CPU 는 VM Exit 를 통해 VMX 모드를 전환, KVM 에게 요청하여 EPT 변경을 요청하게 된다.
가상 머신의 성능을 더 끌어올리기 위해서 반 가상화(Para-virtualization) 나 PCI passthrough 라는 기술을 사용하기도 하는데, 다음 게시글에서 이런 개념을 더 써보려고 한다.