Virtualization 101 - (4) I/O 가상화

송주환·2023년 5월 13일
1

Virtualization 101

목록 보기
5/6

서버 가상화의 근간을 이루는 기술 세번째, I/O 가상화를 다룰 시간이 되었다.
이번 포스팅에서는 컴퓨터 아키텍처에서 I/O 장치를 다루는 방법과, 가상화 환경에서 I/O 장치를 가상화 하는 방법을 주로 인텔 개발자 문서를 참고하여 알아볼 것이다.

들어가며

컴퓨터 아키텍처에서 I/O는 뗄래야 뗄 수 없는 요소이다. 컴퓨터는 본질적으로 연산을 수행하는 장치이며, 연산을 수행하기 위한 입력 데이터와, 그 연산 결과를 사용자에게 제공하기 위한 출력 장치가 있어야 하기 때문이다.

I/O 가상화를 논하기에 앞서, 먼저 입출력 장치가 무엇인지를 정의해 보자.

연산을 위한 입력을 받고, 처리된 데이터를 출력할 수 있는 하드웨어 디바이스

위 정의에 의거하여, 우리가 PC에서 볼 수 있는 입출력 장치에는 다음과 같은 것들이 있다.

  • 마우스
  • 키보드
  • 스토리지 장치
  • NIC (Network Interface Card)
  • Serial/Parallel Port
  • GPIO
  • etc ...

이 모든 하드웨어 장치들에는 OS 커널이 하드웨어 장치와 통신하기 위한 인터페이스를 제공하는 '드라이버'라는 구현체가 필요하다.
그리고 디바이스와 드라이버가 통신을 주고받는 방식에는 크게 3종류가 존재한다.

  • 인터럽트 (Interrupt)
  • 폴링 (Polling)
  • DMA (Direct Memory Access)

인터럽트는 디바이스가 특정 시그널(핀 또는 패킷)을 CPU에게 보내면, CPU가 즉시 선점되어 등록된 ISR(Interrupt Service Routine)을 실행하는 방식이다.
인터럽트의 장점은 디바이스가 작업을 수행하는 동안 CPU가 다른 일을 처리할 수 있다는 것이다. 따라서 CPU 시간을 효율적으로 활용할 수 있으나, CPU(또는 코어)의 컨텍스트를 전환 -> ISR 진입 -> ISR 반환 의 절차를 거쳐야 하기 때문에 상대적으로 반응 속도가 늦어질 수 있다는 단점을 가지고 있다.

인터럽트는 태스크의 수행 빈도가 낮고, 수행 시간이 긴 장치에 적용하기 적합하다.

폴링은 반대로 CPU가 디바이스의 동작을 계속 모니터링 한다. 디바이스의 처리가 완료되면 CPU는 그것을 즉시 알아차릴 수 있으나 그 동안 다른 일을 할 수 없기 때문에 CPU 시간을 비효율적으로 활용하게 된다.
폴링은 태스크가 발생하는 빈도가 잦고, 개별 태스크의 수행 시간이 짧을 때 유리하다.

마지막으로 DMA는 커널과 장치가 데이터를 효율적으로 주고받기 위한 메커니즘이다.
장치가 메모리에 데이터를 전달하기 위해 데이터 버스를 통해 CPU로 데이터를 보내고, CPU가 그 데이터를 메모리에 쓸 수도 있겠지만, 이렇게 되면 CPU 시간이 낭비될 뿐더러 중간에 여러 레이어를 거치기 때문에 오버헤드도 커진다.
하지만 장치가 직접 메모리에 읽기/쓰기 작업을 수행할 수 있다면, 그러한 오버헤드를 제거할 수 있을 것이다.
이러한 아이디어에 기반하여 DMA가 만들어졌고, 대용량의 데이터를 주고받아야 하는 장치들은 모두 DMA를 사용한다.

위 내용을 도식으로 나타내면 아래와 같다.

[그림 1. I/O 디바이스의 입출력 처리 방식]


다음으로는 앞서 열거했던 입출력 장치들이 실제로 사용하는 통신 방식을 알아보자.

  • 키보드/마우스: 사용자에게 빠른 응답을 제공해야 하며, 주고받는 데이터가 많지 않기 때문에 인터럽트를 사용한다
  • 스토리지 장치/NIC: 빠른 응답 시간과 대량의 데이터 전송이 모두 필요하기 때문에 인터럽트/폴링을 혼용하면서 실제 데이터 전송은 DMA로 수행한다.
  • Serial/Parallel Port, GPIO: 대량의 데이터를 주고 받지 않기 때문에 일반적으로 인터럽트를 사용한다.

실제로는 폴링만을 사용하는 경우는 거의 없고, 대부분 인터럽트와 폴링을 혼용해서 사용하거나, 인터럽트만을 사용한다.
과거에는 멀티코어 CPU가 일반적이지 않았기에 하나의 장치가 CPU를 계속 점유하고 있는 것이 허용되지 않았을 뿐더러, 폴링이라는 것 자체가 무의미하게 CPU 시간을 낭비하는 것이기에, 극단적으로 응답시간이 짧아야 하는 경우가 아니라면 인터럽트를 사용하는 편이 낫기 때문이다.

하지만 인터럽트가 오히려 비효율적인 경우도 존재한다. 예를 들어 NIC의 경우 기본적으로 패킷이 들어올 때마다 인터럽트가 트리거되어 디바이스 드라이버의 인터럽트 처리 루틴을 호출한다. 현대의 NIC에서는 아주 많은 패킷이 지속적으로 유입되는데, 그 때마다 매번 인터럽트를 트리거하는 것은 비효율적인 일이다.

인터럽트는 컨텍스트 스위칭을 동반하기 때문에 CPU 관점에서 비싼 작업이다. 그렇기에 지금의 NIC 드라이버 구현체는 특정 Threshold를 넘어서는 수의 패킷이 유입되면 특정한 기준 동안 장치를 polling하는 루틴을 사용한다. 다음 순간에 패킷이 들어올 가능성이 아주 높기 때문에, 오히려 계속 CPU를 물고 있는 편이 더 유리한 것이다.

이제 인터럽트와 폴링의 실제 구현에 대해 생각해보자.

폴링은 CPU가 디바이스의 버스를 계속 모니터링하고 있으면 되기에 구현이 상대적으로 간단하다.
하지만 인터럽트의 경우 디바이스가 CPU를 '깨워야' 한다. 어떻게 이게 가능한 것일까?

X86 CPU의 하드웨어 인터럽트 구현

먼저, x86 CPU에는 사전 정의된 예외가 존재한다는 것을 짚고 넘어갈 필요가 있다.

[그림 2. x86 CPU의 예외 목록]

예외 또한 IVT(Interrupt Vector Table)-인텔에서는 IDT(Interrupt Descriptor Table)이라 부른다-에 등록되기에, 인터럽트 핸들러는 IVT 32번(0x20) 이후에 추가될 수 있다.
IVT의 최대 Entity는 256개이며, OS 커널이 필요에 따라 동적으로 등록 및 해제하게 된다. 디바이스는 최대 4개의 핸들러를 등록할 수 있지만, 다른 장치와 인터럽트를 공유하기 때문에 일반적으로 1개의 인터럽트 핸들러를 사용한다.

PIC (Programmable Interrupt Controller)

[그림 3. Intel 8259 Programmable Interrupt Controller]

앞서 말했듯이 인터럽트는 하드웨어 핀의 전압 변동을 통해 트리거된다. 그러나 256개의 인터럽트 호출을 위해 CPU에 256개의 하드웨어 핀을 만드는 것은 비효율적이다. 그래서 디바이스는 CPU가 아닌 PIC(Programmable Interrupt Controller)에 연결되고, PIC가 인터럽트 신호를 CPU에 전달해주는 역할을 맡는다.

최초 IBM 호환 PC에서는 Intel 8259 PIC를 사용했고, 8259 칩은 기본적으로 8개의 IRQ를 제공했다. 이 값들은 BIOS에 의해 Interrupt 8에서 15 (0x08-0x0F)로 매핑되었다. 그리고 주변 장치의 추가로 인해 8개의 IRQ가 부족해지자 동일한 8259 PIC를 하나 더 추가하여 캐스케이드 형태로 연결하는 구성이 일반화되었다. 이 때 IRQ 2에 해당하는 핀은 마스터 PIC가 슬레이브 PIC에 신호를 전달하는 목적으로 사용되었기에, 두 개의 8259 PIC를 사용하는 구성은 총 15개의 IRQ를 제공할 수 있었다.

그런데 앞서 IVT의 0-31번 엔트리가 CPU 내부 예외로 예약되어 있다고 하지 않았던가? 실제로 IBM PC의 IRQ 번호가 CPU 내부 예외 번호와 충돌했기 때문에, 초기 IBM PC의 PIC는 마스터 오프셋을 0x08로, 슬레이브 오프셋을 0x70으로 설정했다.
리얼 모드 전환 이후 이 오프셋도 문제가 되었고, 현대 OS는 마스터 PIC의 오프셋을 0x20으로, 슬레이브 PIC의 오프셋을 0x28로 설정한다. 즉, 이제 PIC에서 발생하는 인터럽트들은 IVT(=IDT)의 0x20 entry부터 매핑된다.

APIC (Advanced Programmable Interrupt Controller)


[그림 4. MSI를 사용하는 APIC 예시]

이후 멀티프로세서 지원과 효울적인 인터럽트 라우팅을 위해 인텔은 APIC를 개발하였다.
APIC는 Local APIC와 I/O APIC로 구분되는데, Local APIC는 CPU마다 하나씩, I/O APIC는 주변 장치 버스 당 하나씩 존재한다. 초창기 Local APIC는 별도의 칩셋(82489DX)으로 구성되었으나, 곧 프로세서 내부에 내장되었다.

Intel 82093AA I/O APIC 칩의 경우 24개의 프로그래밍 가능한 인터럽트 핀을 제공했으며, 인터럽트 라우팅 테이블을 기반으로 어떤 CPU에 어떤 IRQ 번호로 전달해야 할지 결정할 수 있었다. 그리고 Intel 815부터 I/O APIC는 PCH에 통합되었고, 서버 CPU의 경우 Uncore에 I/O APIC가 존재하기도 한다.
기본적으로 I/O APIC는 확장 가능한 계층 구조이기 때문에, OS는 I/O APIC를 검색하고, 등록하는 올바른 메커니즘을 가지고 있으면 된다. 이를 위해 필요한 것이 MP Configuration Table과 APIC Table로, 하드웨어 토폴로지를 알고 있는 BIOS/UEFI 개발자가 구성한다.

APIC에서 새로 도입된 MSI(Message Signaled Interrupt)는 레거시 INTx의 제한을 넘어 최대 256개의 IVT Table entry를 모두 사용할 수 있으며, 더 이상 Interrupt Vector가 공유되지 않기 때문에 IRQ 충돌 문제와 ISR 구현이 단순해졌다. 또한 개별 장치는 이제 최대 32개의 인터럽트 벡터를 등록할 수 있기 때문에 경우에 따라 더 효율적인 인터럽트 처리를 가능하게 한다.

그런데 CPU는 어떻게 MSI 메시지를 수신하고, 인터럽트를 트리거 할 수 있는 것일까?

이것은 Intel IA-32e Architecture Software Developer Guide 3A Part.1 을 참조하여 확인할 수 있다.

Section 10.11을 보면 Message Address Register(MAR) Format과 Message Data Register(MDR) Format이 있다.

[그림 5.1. Message Address Register 구조]

[그림 5.2. Message Data Register 구조]

여기서 우리가 주의 깊게 보아야 할 부분은 Message Address 주소가 0FEE로 시작한다는 것이다. 이 값은 Local APIC Base address로, MSI 지원 장치가 이 주소에 MSI 메시지를 쓰게 되면 지정된 CPU(Destination ID)로 인터럽트가 전달되게 된다.

그렇다면 PCI/PCI-E 장치 드라이버는 인터럽트 핸들러를 어떻게 등록할 수 있을까?

그 대답은 공개된 자료 중 MSI-X Capability Structure에서 찾을 수 있다. (MSI Capability Structure도 있음에 유의)

[그림 6. MSI-X Capability Structure (Intel)]

본래 이 데이터는 PCI-SIG의 MSI-X ECN을 참고해야 하나, 해당 문서는 PCI-SIG의 멤버에게만 공개되어 있기에 인텔의 디자인 문서로 갈음한다.

위 표에서 알 수 있듯이, CPU는 PCI-E BAR Base Address 값에 MSI-X Capability Register에 지정된 Offset 값을 더하여 MSI-X Table의 시작 주소를 구할 수 있다.
커널이 해당 영역에 MSI-X 인터럽트 벡터 테이블을 구성하면 트리거 된 MSI 요청이 ISR을 실행시키게 되는 것이다.

지금까지 MSI에 대해 다룬 내용들을 도식화하면 아래 그림과 같다.

[그림 7. MSI Register/Handling 로직 다이어그램]

PCI-E의 인터럽트 병렬 처리 - MSI-X

PCI 2.2에서 도입된 MSI에 이어, PCI 3.0 규격에서는 MSI-X가 표준화되었다.
MSI와 MSI-X 사이의 차이점은 다음과 같다

  • 서로 다른 CPU(또는 코어)에 인터럽트 등록 허용
  • 디바이스당 최대 2048개의 인터럽트 등록
  • 64비트 주소 지정, 인터럽트 마스킹 필수 지원
  • 불연속적인 인터럽트 테이블 엔트리 지원

PCI 3.0이 등장할 당시에는 MSI-X 지원 장치가 많지 않았으나, 곧 PCI-Express가 등장하면서 현재 대부분의 I/O 장치들은 MSI-X 기능을 지원하게 되었다.

MSI-X에서 가장 주목할만한 점은 바로 서로 다른 CPU에 인터럽트를 등록할 수 있게 되었다는 것이다.
MSI가 최대 32개의 인터럽트를 지원하긴 했지만, 모든 인터럽트는 하나의 CPU에 등록되어야만 했다. MSI-X에서는 이 제약이 사라졌으며, NVMe와 같은 차세대 표준들이 SMP 환경에서 더 높은 성능을 낼 수 있는 아키텍처를 구현할 수 있게 된 배경이 되었다.

서버 가상화 환경에서의 I/O 장치 가상화 방법

이제 서버 가상화 환경에서의 I/O 장치 가상화를 이해하기 위한 배경 지식을 모두 다루었다.
서버 가상화 환경에서 I/O 장치를 가상화하려면 다음과 같은 기능들을 가상화해야 한다.

  • 인터럽트 처리
  • DMA를 위한 MMIO(Memory Mapped I/O)

이 기능들을 구현하기 위해서 다음과 같은 전략들이 시도되었다.

1. 에뮬레이션

[그림 8. 디바이스 에뮬레이션 도식]

디바이스 에뮬레이션은 기존 OS 드라이버와 호환되는 가상 장치를 만들어 VM에 제공해 주는 방식을 말한다.
에뮬레이션의 가장 큰 장점은 바로 호환성이다. 가상 장치만 제대로 구현된다면 Guest OS 수준에서는 수정할 것이 아무것도 없기 때문에 일반적으로 가장 좋은 호환성을 보이며, 그 때문에 가상 장치는 에뮬레이션 대상 물리 장치의 알려진 버그까지도 동일하게 구현한다.

하지만 인터럽트 또는 I/O가 발생할 때마다 VM Exit가 발생하여 예외 핸들러를 통과해야 하기 때문에, 상당한 성능 저하가 나타난다.
그리고 에뮬레이션 대상 장치를 하이퍼바이저에서 직접 구현해야 하기 때문에, 실질적으로 가상화 환경에서 지원할 수 있는 디바이스의 종류는 제한적이다.

2. 반가상화

[그림 9. 디바이스 반가상화 도식]

다바이스 에뮬레이션의 성능 문제를 완화하기 위해 반가상화 방식의 디바이스가 등장하였다.
기본적으로 에뮬레이션된 가상 장치를 VM에 제공하는 것 까지는 동일하나, 장치 드라이버는 자신이 가상화 환경에 있다는 것을 인지하고, 가능하다면 Hypercall을 통해 하이퍼바이저 API에 접근한다. 가상 장치는 더 이상 I/O가 발생할 때마다 VM Exit 를 일으킬 필요가 없으며, 성능도 그만큼 향상된다.

일반적으로 대량의 I/O가 발생하는 디스크 컨트롤러와 NIC 드라이버를 반가상화 방식으로 구현하게 된다.

3. Pass-through

앞서 이야기 한 두 방식의 구현을 살펴보고 있으면 한 가지 의문이 생길 것이다.

I/O 가상화를 위해 필요하다던 MMIO 구현은 어디 있지?

그렇다. 에뮬레이션과 반가상화 방식으로 구현된 가상 디바이스들은 Host의 물리 디바이스와 MMIO로 직접 통신하지 않는다. 왜냐하면 게스트 OS가 인식하고 있는 장치는 호스트에 연결된 물리 장치가 아니며, 디바이스 드라이버 또한 그 물리 장치를 위해 만들어진 것이 아니기 때문이다.

그러나 이전 포스트에서 다룬 IOMMU를 통해 특정 메모리 영역을 VM에 직접 노출시켜줄 수 있다면, 아예 VM의 디바이스 드라이버가 직접 물리 장치를 제어할 수 있을 것이다.
이 개념을 이용하여 구현된 것이 바로 PCI-E Passthrough이다.


[그림 10. IOMMU를 통한 VM to Device DMA]


그런데, 과연 IOMMU만으로 충분할까?
물리 장치에 대한 MMIO를 제공하는 것만이 아니라, 물리 장치에서 발생하는 인터럽트 또한 VM이 수신할 수 있어야 하지 않을까?

그렇기 때문에 x86 CPU 제조사들은 디바이스를 VM에 직접 노출하기 위한 추가 기능들을 개발해야 했고, 인텔은 그러한 기능들을 하나의 패키지로 묶어서 VT-d라고 부른다.

Intel VT-d

이 단락은 Intel Virtualization Technology for Directed I/O 문서를 참고하여 작성되었다. 이 글을 작성하는 시점에서의 문서 리비전은 4.0이다.

DMA Remapping

[그림 11. DMA Address Translation 도식]

위 그림은 VT-d에서 DMA Address Translation을 처리하는 방식에 대한 아이디어를 보여준다. 동일한 DMA 주소 영역을 가진 장치 두 개는 서로 다른 도메인에 할당되며, 서로 다른 호스트 페이지 주소에 매핑된다.
이 때, 도메인이란 Address Isolation을 제공하는 범위를 말한다. 장치가 도메인 단위로 할당되면, 하나의 도메인에 속한 여러 VM들이 동일한 장치를 공유하는 Virtual Function 기능을 구현할 수 있다.
서로 다른 도메인에 속한 장치는 서로 통신할 수 없으며, 이것은 단순히 허용되지 않은 메모리 범위로의 접근을 차단하는 방식으로 구현된다.

DMA Request의 주소 변환은 DMA Remapping hardware가 전적으로 담당하며, 이 동작은 디바이스와 OS에게 투명하게 이루어진다.
그렇다면, 장치는 실제로 어떻게 올바른 목표 호스트 페이지를 찾을 수 있을까?

[그림 12. Device to Domain Mapping 도식]

PCI-E Transaction Layer Header에는 해당 요청을 발행한 장치의 PCI-E 버스 번호, 장치 번호, Function 번호가 포함되어 있다.
DMA Remapping hardware는 이 정보를 참고하여 도메인별 페이지 테이블을 유지한다. 페이지 테이블 탐색 방식은 PML4 탐색과 동일하며, Remapping hardware는 2MB/1GB Hugepage를 지원한다.

MMU에서의 Table walkthrough와 마찬가지로, DMA Remapping 또한 별도의 TLB(Table Lookaside Buffer)를 갖는다. 기본적으로 TLB는 DMA Remapping Hardware에 존재하지만, 크기가 제한적이기 때문에 해당 플랫폼에서 Active 된 DMA Remapping target 수와 DMA Address locality의 영향을 심하게 받는다.
덧붙여, Intel CPU의 DMA Remapping hardware TLB 크기는 문서화되어 있지 않은 것으로 보인다.

이러한 잠재적인 확장성 문제를 해소하기 위한 방법으로 Device TLB가 제안되었다.

[그림 13. Device TLB 개념 도식]

이 기능은 PCI-E Base Specification 4.0 이후의 ATS(Address Translation Service)에서 지원된다.

Interrupt Remapping

장치에서 발행한 인터럽트를 올바른 VM에 전달하기 위한 Interrupt Remapping 또한 하드웨어적으로 지원된다.
이 때, 장치는 Remappable Format Interrupt Request를 발행해야 한다.

[그림 14. Remappable Format Interrupt Request의 Address Field 설명]

Compatible Format과의 차이점은 바로 Handle로, 후술할 Interrupt Remapping Table을 참조하기 위해 사용된다.
Interrupt Remapping Hardware는 메모리에 위치한 IRT(Interrupt Remapping Table)을 통해 이 기능을 수행한다. IRT는 1단계 테이블 구조를 가지고 있으며, 테이블의 위치와 크기는 IRTAR(Interrupt Remap Table Address Register)을 통해 지정된다.

[그림 15. IRTAR 구조 (Intel)]

위 표에서 알 수 있듯이 IRTE(Interrupt Remapping Table Entry)의 최대 크기는 65535 이다.

그렇다면 IRTE는 어떤 구조를 가지고 있을까?

[그림 16. Interrupt Remapping Table Entry 구조]

위 128비트의 구조체 중 우리가 관심을 가질 부분은 SID (Source Identifier)와 Destination ID이다.

[그림 17. IRTE의 Source ID와 Destination ID 설명]

xAPIC의 경우, 8비트짜리 APIC Destination ID가 보인다. 이것은 CPU의 ID를 나타내는 것으로, xAPIC의 CPU Core 확장성이 최대 256개였기 때문에 인텔은 이 제한을 해소한 x2APIC를 만들었다.
위 표에서 확인할 수 있듯이, x2APIC에서는 32비트의 APIC Destination ID를 가진다.

즉, 장치에서 발행한 Interrupt Request는 IRT -> IRTE -> APIC Destination ID를 따라 목적지인 물리 CPU에 전달되는 것이다.

Interrupt Posting

Interrupt remapping을 통해 장치에서 발행한 Interrupt Request를 VM에 전달할 수 있게 되었으니 이제 우리가 원하던 기능은 모두 구현된 것이 아닐까?

기능은 모두 구현된 것이 맞지만, 아직 중요한 문제가 하나 남아있다. 바로 성능이다.
Interrupt Remapping에서 볼 수 있듯이, IRTE에 기록된 Destination ID는 pCPU ID이다. 다시 말해 인터럽트는 '특정 물리 CPU'로 전달된다는 것이다.
하지만, 가상머신의 경우 vCPU가 실행되는 pCPU는 고정되어 있지 않다. 그렇기 때문에 vCPU 스케줄링 과정에서 다음과 같은 문제가 생긴다.

  1. VMX는 pCPU에 도착한 인터럽트 요청이 어떤 VM을 목표로 도착한 것인지 확인하고, vCPU를 깨워야 한다
  2. VM의 vCPU가 다른 pCPU로 마이그레이션 되면 IRTE의 Destination ID도 함께 업데이트 되어야 한다
  3. 만약 다른 pCPU에 위치한 VM을 목적지로 한 인터럽트 요청이 도착하면 IPI를 통해 해당 pCPU를 깨워야 한다

vCPU가 Oppertunistic하게 여러 pCPU 사이를 이동한다는 점을 감안하면 성가신 일이며, Remapped interrupt가 발생할 때 VM Exit가 실행되어야 한다는 것 또한 상당한 오버헤드를 가져온다.

이 문제를 해결하기 위해 인텔은 VT-d에 Interrupt Posting을 도입하였다.

[그림 18. Posted Interrupt 개념 (Intel)

Intel의 Feng Wu가 아주 멋진 다이어그램을 만들어 주었다. 위 그림에서 보이듯이 Interrupt Posting 모드의 장치 인터럽트가 IRTE를 찌르면 IRTE는 vCPU의 Posted Descriptor를 가리키게 된다.

[그림 19. Posted Interrupt Descriptor 구조]

Posted Descriptor는 64바이트로 정렬된 구조체로, Posted Interrupt를 기록하기 위해 사용된다.

VMCS는 NDST(Notification Destination = APIC Dest ID)-NV(Notification Vector = pCPU IVT ID) 쌍을 통해 Notification Event를 발생시키고, 최종적으로 Posted Interrpt Descriptor에 지정된 Vector(=pCPU IVTE, 8비트)의 Interrput Vector를 트리거 하여 pCPU에서 실행시키게 된다.

이제 vCPU가 마이그레이션 될 때에도 IRTE를 변경할 필요가 없으며, 개별 VM의 원자적 마이그레이션이 가능해진다. 즉, vCPU가 마이그레이션 될 때, VMM은 타겟 pCPU의 IVT에 ANV를 추가하고, PD의 NDST와 NV만 변경하면 된다.

그리고 Interrupt Event 수신이 VM 컨텍스트에서 발생하기 때문에 더 이상 인터럽트가 VM Exit를 발생시키지 않음으로써 VM 성능이 향상된다.

정리

이것으로 서버 가상화를 구현하는 빌딩 블록인 CPU 가상화, 메모리 가상화, I/O 가상화를 모두 다루었다.
I/O 가상화의 개념과 구현이 가장 복잡하기 때문에 글이 길어지게 되었지만, 이 글을 통해 실제로 I/O 가상화 기능이 어떻게 동작하는지 이해할 수 있게 되었으면 한다.

다음으로는 이번 포스팅에서 다루지 못한 VGA 가상화와 VT-d를 활용한 Virtual Function에 대한 이야기를 다룰 것이다.
I/O 가상화 기술에 대한 포스팅이 마무리되면 네트워크 가상화로 넘어가게 될 것 같다.

레퍼런스

OSDev Wiki - Exceptions
OSDev Wiki - 8259 PIC
Driver porting: Network drivers
Intel IA-32e Architecture Software Developer Guide 3A Part.1
PCI-SIG - MSI-X ECN
Intel® Arria® 10 Avalon® Streaming with SR-IOV IP for PCIe* User Guide - MSI-X Capability Structure
Intel Virtualization Technology for Directed I/O
VT-d Interrupt Remapping 分析
VT-d Posted Interrupts

profile
Virtualization / Network / Storage / Server Hardware and.. Linux

0개의 댓글