← Documents Documentation/virt/hyperv/vpci.rst GitHub 원문 ↗

Linux 6.18.37 · 가상화 / Hyper-V

PCI pass-through 장치

Hyper-V DDA·SR-IOV vPCI device의 이중 신원, 설정·제거, interrupt routing, DMA와 CoCo config access를 설명합니다.

Source pathDocumentation/virt/hyperv/vpci.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

vpci.rst:1-316

Hyper-V vPCI는 DDA 또는 SR-IOV physical PCI device를 VM address space에 직접 연결하면서, device 도입과 제거에는 VMBus를 사용하고 정상 I/O에는 일반 PCI driver가 hardware와 직접 통신하게 합니다. 이 이중 신원 덕분에 dynamic offer를 Linux PCI topology로 바꿀 수 있습니다.

설정 때는 instance GUID 기반 PCI domain, config·BAR MMIO, root bus를 만든 뒤 generic PCI scan으로 넘깁니다. 제거는 Eject, PCI remove, Ejection Complete, VMBus rescind 순서이며 60초 timeout이나 설정 중 ejection 때문에 synchronization이 특히 중요합니다.

MSI routing은 VMBus reply를 기다려야 하지만 IRQ lock context에서는 sleep할 수 없어 polling하며 eject도 동시에 감지합니다. x86은 hypercall로 vCPU와 vector를 알리고 arm64는 emulated GICD에 SPI를 기록하며 LPI는 지원하지 않습니다.

DMA는 guest에 virtual IOMMU가 없는 direct mode지만 host physical IOMMU가 VM 경계를 보호합니다. CoCo VM의 PCI config access는 encrypted instruction을 host가 decode할 수 없어 implicit trap 대신 explicit hypercall argument를 사용합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 PCI pass-thru devices
4 =========================
5 In a Hyper-V guest VM, PCI pass-thru devices (also called
6 virtual PCI devices, or vPCI devices) are physical PCI devices
7 that are mapped directly into the VM's physical address space.
8 Guest device drivers can interact directly with the hardware
9 without intermediation by the host hypervisor. This approach
10 provides higher bandwidth access to the device with lower
11 latency, compared with devices that are virtualized by the
12 hypervisor. The device should appear to the guest just as it
13 would when running on bare metal, so no changes are required
14 to the Linux device drivers for the device.
15
16 Hyper-V terminology for vPCI devices is "Discrete Device
17 Assignment" (DDA). Public documentation for Hyper-V DDA is
18 available here: `DDA`_
19
20 .. _DDA: https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/plan/plan-for-deploying-devices-using-discrete-device-assignment
21
22 DDA is typically used for storage controllers, such as NVMe,
23 and for GPUs. A similar mechanism for NICs is called SR-IOV
24 and produces the same benefits by allowing a guest device
25 driver to interact directly with the hardware. See Hyper-V
26 public documentation here: `SR-IOV`_
27
28 .. _SR-IOV: https://learn.microsoft.com/en-us/windows-hardware/drivers/network/overview-of-single-root-i-o-virtualization--sr-iov-
29
30 This discussion of vPCI devices includes DDA and SR-IOV
31 devices.
32
33 Device Presentation
34 -------------------
35 Hyper-V provides full PCI functionality for a vPCI device when
36 it is operating, so the Linux device driver for the device can
37 be used unchanged, provided it uses the correct Linux kernel
38 APIs for accessing PCI config space and for other integration
39 with Linux. But the initial detection of the PCI device and
40 its integration with the Linux PCI subsystem must use Hyper-V
41 specific mechanisms. Consequently, vPCI devices on Hyper-V
42 have a dual identity. They are initially presented to Linux
43 guests as VMBus devices via the standard VMBus "offer"
44 mechanism, so they have a VMBus identity and appear under
45 /sys/bus/vmbus/devices. The VMBus vPCI driver in Linux at
46 drivers/pci/controller/pci-hyperv.c handles a newly introduced
47 vPCI device by fabricating a PCI bus topology and creating all
48 the normal PCI device data structures in Linux that would
49 exist if the PCI device were discovered via ACPI on a bare-
50 metal system. Once those data structures are set up, the
51 device also has a normal PCI identity in Linux, and the normal
52 Linux device driver for the vPCI device can function as if it
53 were running in Linux on bare-metal. Because vPCI devices are
54 presented dynamically through the VMBus offer mechanism, they
55 do not appear in the Linux guest's ACPI tables. vPCI devices
56 may be added to a VM or removed from a VM at any time during
57 the life of the VM, and not just during initial boot.
58
59 With this approach, the vPCI device is a VMBus device and a
60 PCI device at the same time. In response to the VMBus offer
61 message, the hv_pci_probe() function runs and establishes a
62 VMBus connection to the vPCI VSP on the Hyper-V host. That
63 connection has a single VMBus channel. The channel is used to
64 exchange messages with the vPCI VSP for the purpose of setting
65 up and configuring the vPCI device in Linux. Once the device
66 is fully configured in Linux as a PCI device, the VMBus
67 channel is used only if Linux changes the vCPU to be interrupted
68 in the guest, or if the vPCI device is removed from
69 the VM while the VM is running. The ongoing operation of the
70 device happens directly between the Linux device driver for
71 the device and the hardware, with VMBus and the VMBus channel
72 playing no role.
73
74 PCI Device Setup
75 ----------------
76 PCI device setup follows a sequence that Hyper-V originally
77 created for Windows guests, and that can be ill-suited for
78 Linux guests due to differences in the overall structure of
79 the Linux PCI subsystem compared with Windows. Nonetheless,
80 with a bit of hackery in the Hyper-V virtual PCI driver for
81 Linux, the virtual PCI device is setup in Linux so that
82 generic Linux PCI subsystem code and the Linux driver for the
83 device "just work".
84
85 Each vPCI device is set up in Linux to be in its own PCI
86 domain with a host bridge. The PCI domainID is derived from
87 bytes 4 and 5 of the instance GUID assigned to the VMBus vPCI
88 device. The Hyper-V host does not guarantee that these bytes
89 are unique, so hv_pci_probe() has an algorithm to resolve
90 collisions. The collision resolution is intended to be stable
91 across reboots of the same VM so that the PCI domainIDs don't
92 change, as the domainID appears in the user space
93 configuration of some devices.
94
95 hv_pci_probe() allocates a guest MMIO range to be used as PCI
96 config space for the device. This MMIO range is communicated
97 to the Hyper-V host over the VMBus channel as part of telling
98 the host that the device is ready to enter d0. See
99 hv_pci_enter_d0(). When the guest subsequently accesses this
100 MMIO range, the Hyper-V host intercepts the accesses and maps
101 them to the physical device PCI config space.
102
103 hv_pci_probe() also gets BAR information for the device from
104 the Hyper-V host, and uses this information to allocate MMIO
105 space for the BARs. That MMIO space is then setup to be
106 associated with the host bridge so that it works when generic
107 PCI subsystem code in Linux processes the BARs.
108
109 Finally, hv_pci_probe() creates the root PCI bus. At this
110 point the Hyper-V virtual PCI driver hackery is done, and the
111 normal Linux PCI machinery for scanning the root bus works to
112 detect the device, to perform driver matching, and to
113 initialize the driver and device.
114
115 PCI Device Removal
116 ------------------
117 A Hyper-V host may initiate removal of a vPCI device from a
118 guest VM at any time during the life of the VM. The removal
119 is instigated by an admin action taken on the Hyper-V host and
120 is not under the control of the guest OS.
121
122 A guest VM is notified of the removal by an unsolicited
123 "Eject" message sent from the host to the guest over the VMBus
124 channel associated with the vPCI device. Upon receipt of such
125 a message, the Hyper-V virtual PCI driver in Linux
126 asynchronously invokes Linux kernel PCI subsystem calls to
127 shutdown and remove the device. When those calls are
128 complete, an "Ejection Complete" message is sent back to
129 Hyper-V over the VMBus channel indicating that the device has
130 been removed. At this point, Hyper-V sends a VMBus rescind
131 message to the Linux guest, which the VMBus driver in Linux
132 processes by removing the VMBus identity for the device. Once
133 that processing is complete, all vestiges of the device having
134 been present are gone from the Linux kernel. The rescind
135 message also indicates to the guest that Hyper-V has stopped
136 providing support for the vPCI device in the guest. If the
137 guest were to attempt to access that device's MMIO space, it
138 would be an invalid reference. Hypercalls affecting the device
139 return errors, and any further messages sent in the VMBus
140 channel are ignored.
141
142 After sending the Eject message, Hyper-V allows the guest VM
143 60 seconds to cleanly shutdown the device and respond with
144 Ejection Complete before sending the VMBus rescind
145 message. If for any reason the Eject steps don't complete
146 within the allowed 60 seconds, the Hyper-V host forcibly
147 performs the rescind steps, which will likely result in
148 cascading errors in the guest because the device is now no
149 longer present from the guest standpoint and accessing the
150 device MMIO space will fail.
151
152 Because ejection is asynchronous and can happen at any point
153 during the guest VM lifecycle, proper synchronization in the
154 Hyper-V virtual PCI driver is very tricky. Ejection has been
155 observed even before a newly offered vPCI device has been
156 fully setup. The Hyper-V virtual PCI driver has been updated
157 several times over the years to fix race conditions when
158 ejections happen at inopportune times. Care must be taken when
159 modifying this code to prevent re-introducing such problems.
160 See comments in the code.
161
162 Interrupt Assignment
163 --------------------
164 The Hyper-V virtual PCI driver supports vPCI devices using
165 MSI, multi-MSI, or MSI-X. Assigning the guest vCPU that will
166 receive the interrupt for a particular MSI or MSI-X message is
167 complex because of the way the Linux setup of IRQs maps onto
168 the Hyper-V interfaces. For the single-MSI and MSI-X cases,
169 Linux calls hv_compse_msi_msg() twice, with the first call
170 containing a dummy vCPU and the second call containing the
171 real vCPU. Furthermore, hv_irq_unmask() is finally called
172 (on x86) or the GICD registers are set (on arm64) to specify
173 the real vCPU again. Each of these three calls interact
174 with Hyper-V, which must decide which physical CPU should
175 receive the interrupt before it is forwarded to the guest VM.
176 Unfortunately, the Hyper-V decision-making process is a bit
177 limited, and can result in concentrating the physical
178 interrupts on a single CPU, causing a performance bottleneck.
179 See details about how this is resolved in the extensive
180 comment above the function hv_compose_msi_req_get_cpu().
181
182 The Hyper-V virtual PCI driver implements the
183 irq_chip.irq_compose_msi_msg function as hv_compose_msi_msg().
184 Unfortunately, on Hyper-V the implementation requires sending
185 a VMBus message to the Hyper-V host and awaiting an interrupt
186 indicating receipt of a reply message. Since
187 irq_chip.irq_compose_msi_msg can be called with IRQ locks
188 held, it doesn't work to do the normal sleep until awakened by
189 the interrupt. Instead hv_compose_msi_msg() must send the
190 VMBus message, and then poll for the completion message. As
191 further complexity, the vPCI device could be ejected/rescinded
192 while the polling is in progress, so this scenario must be
193 detected as well. See comments in the code regarding this
194 very tricky area.
195
196 Most of the code in the Hyper-V virtual PCI driver (pci-
197 hyperv.c) applies to Hyper-V and Linux guests running on x86
198 and on arm64 architectures. But there are differences in how
199 interrupt assignments are managed. On x86, the Hyper-V
200 virtual PCI driver in the guest must make a hypercall to tell
201 Hyper-V which guest vCPU should be interrupted by each
202 MSI/MSI-X interrupt, and the x86 interrupt vector number that
203 the x86_vector IRQ domain has picked for the interrupt. This
204 hypercall is made by hv_arch_irq_unmask(). On arm64, the
205 Hyper-V virtual PCI driver manages the allocation of an SPI
206 for each MSI/MSI-X interrupt. The Hyper-V virtual PCI driver
207 stores the allocated SPI in the architectural GICD registers,
208 which Hyper-V emulates, so no hypercall is necessary as with
209 x86. Hyper-V does not support using LPIs for vPCI devices in
210 arm64 guest VMs because it does not emulate a GICv3 ITS.
211
212 The Hyper-V virtual PCI driver in Linux supports vPCI devices
213 whose drivers create managed or unmanaged Linux IRQs. If the
214 smp_affinity for an unmanaged IRQ is updated via the /proc/irq
215 interface, the Hyper-V virtual PCI driver is called to tell
216 the Hyper-V host to change the interrupt targeting and
217 everything works properly. However, on x86 if the x86_vector
218 IRQ domain needs to reassign an interrupt vector due to
219 running out of vectors on a CPU, there's no path to inform the
220 Hyper-V host of the change, and things break. Fortunately,
221 guest VMs operate in a constrained device environment where
222 using all the vectors on a CPU doesn't happen. Since such a
223 problem is only a theoretical concern rather than a practical
224 concern, it has been left unaddressed.
225
226 DMA
227 ---
228 By default, Hyper-V pins all guest VM memory in the host
229 when the VM is created, and programs the physical IOMMU to
230 allow the VM to have DMA access to all its memory. Hence
231 it is safe to assign PCI devices to the VM, and allow the
232 guest operating system to program the DMA transfers. The
233 physical IOMMU prevents a malicious guest from initiating
234 DMA to memory belonging to the host or to other VMs on the
235 host. From the Linux guest standpoint, such DMA transfers
236 are in "direct" mode since Hyper-V does not provide a virtual
237 IOMMU in the guest.
238
239 Hyper-V assumes that physical PCI devices always perform
240 cache-coherent DMA. When running on x86, this behavior is
241 required by the architecture. When running on arm64, the
242 architecture allows for both cache-coherent and
243 non-cache-coherent devices, with the behavior of each device
244 specified in the ACPI DSDT. But when a PCI device is assigned
245 to a guest VM, that device does not appear in the DSDT, so the
246 Hyper-V VMBus driver propagates cache-coherency information
247 from the VMBus node in the ACPI DSDT to all VMBus devices,
248 including vPCI devices (since they have a dual identity as a VMBus
249 device and as a PCI device). See vmbus_dma_configure().
250 Current Hyper-V versions always indicate that the VMBus is
251 cache coherent, so vPCI devices on arm64 always get marked as
252 cache coherent and the CPU does not perform any sync
253 operations as part of dma_map/unmap_*() calls.
254
255 vPCI protocol versions
256 ----------------------
257 As previously described, during vPCI device setup and teardown
258 messages are passed over a VMBus channel between the Hyper-V
259 host and the Hyper-v vPCI driver in the Linux guest. Some
260 messages have been revised in newer versions of Hyper-V, so
261 the guest and host must agree on the vPCI protocol version to
262 be used. The version is negotiated when communication over
263 the VMBus channel is first established. See
264 hv_pci_protocol_negotiation(). Newer versions of the protocol
265 extend support to VMs with more than 64 vCPUs, and provide
266 additional information about the vPCI device, such as the
267 guest virtual NUMA node to which it is most closely affined in
268 the underlying hardware.
269
270 Guest NUMA node affinity
271 ------------------------
272 When the vPCI protocol version provides it, the guest NUMA
273 node affinity of the vPCI device is stored as part of the Linux
274 device information for subsequent use by the Linux driver. See
275 hv_pci_assign_numa_node(). If the negotiated protocol version
276 does not support the host providing NUMA affinity information,
277 the Linux guest defaults the device NUMA node to 0. But even
278 when the negotiated protocol version includes NUMA affinity
279 information, the ability of the host to provide such
280 information depends on certain host configuration options. If
281 the guest receives NUMA node value "0", it could mean NUMA
282 node 0, or it could mean "no information is available".
283 Unfortunately it is not possible to distinguish the two cases
284 from the guest side.
285
286 PCI config space access in a CoCo VM
287 ------------------------------------
288 Linux PCI device drivers access PCI config space using a
289 standard set of functions provided by the Linux PCI subsystem.
290 In Hyper-V guests these standard functions map to functions
291 hv_pcifront_read_config() and hv_pcifront_write_config()
292 in the Hyper-V virtual PCI driver. In normal VMs,
293 these hv_pcifront_*() functions directly access the PCI config
294 space, and the accesses trap to Hyper-V to be handled.
295 But in CoCo VMs, memory encryption prevents Hyper-V
296 from reading the guest instruction stream to emulate the
297 access, so the hv_pcifront_*() functions must invoke
298 hypercalls with explicit arguments describing the access to be
299 made.
300
301 Config Block back-channel
302 -------------------------
303 The Hyper-V host and Hyper-V virtual PCI driver in Linux
304 together implement a non-standard back-channel communication
305 path between the host and guest. The back-channel path uses
306 messages sent over the VMBus channel associated with the vPCI
307 device. The functions hyperv_read_cfg_blk() and
308 hyperv_write_cfg_blk() are the primary interfaces provided to
309 other parts of the Linux kernel. As of this writing, these
310 interfaces are used only by the Mellanox mlx5 driver to pass
311 diagnostic data to a Hyper-V host running in the Azure public
312 cloud. The functions hyperv_read_cfg_blk() and
313 hyperv_write_cfg_blk() are implemented in a separate module
314 (pci-hyperv-intf.c, under CONFIG_PCI_HYPERV_INTERFACE) that
315 effectively stubs them out when running in non-Hyper-V
316 environments.
317

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

PCI pass-through, DDA와 SR-IOV

1-31

Hyper-V guest VM에서 PCI pass-through device는 virtual PCI device 또는 vPCI device라고도 하며, VM의 physical address space에 직접 mapping된 physical PCI device입니다.

Guest device driver는 host hypervisor의 중개 없이 hardware와 직접 상호 작용할 수 있습니다. Hypervisor가 virtualize하는 device보다 latency가 낮고 bandwidth가 높은 접근을 제공합니다.

Device는 bare-metal에서 실행할 때와 똑같이 guest에 보여야 하므로 해당 device의 Linux driver를 변경할 필요가 없습니다.

Hyper-V 용어로 vPCI device는 Discrete Device Assignment(DDA)입니다. 원문은 Microsoft의 Hyper-V DDA 공개 문서 링크를 제공합니다.

DDA는 보통 NVMe 같은 storage controller와 GPU에 사용합니다. NIC에는 유사한 SR-IOV mechanism을 사용하며 guest driver가 hardware와 직접 통신하게 해 같은 이점을 제공합니다. 이 문서에서 vPCI device라는 말은 DDA와 SR-IOV device를 모두 포함합니다.

Hyper-V PCI 직접 할당 방식
Mechanism대표 장치효과
DDANVMe 등 storage controller, GPUPhysical device를 VM address space에 직접 mapping
SR-IOVNIC virtual functionGuest driver가 network hardware와 직접 상호 작용

대상 장치와 공통 효과를 정리합니다.

.. SPDX-License-Identifier: GPL-2.0

PCI pass-thru devices
=========================
In a Hyper-V guest VM, PCI pass-thru devices (also called
virtual PCI devices, or vPCI devices) are physical PCI devices
that are mapped directly into the VM's physical address space.
Guest device drivers can interact directly with the hardware
without intermediation by the host hypervisor.  This approach
provides higher bandwidth access to the device with lower
latency, compared with devices that are virtualized by the
hypervisor.  The device should appear to the guest just as it
would when running on bare metal, so no changes are required
to the Linux device drivers for the device.

Hyper-V terminology for vPCI devices is "Discrete Device
Assignment" (DDA).  Public documentation for Hyper-V DDA is
available here: `DDA`_

.. _DDA: https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/plan/plan-for-deploying-devices-using-discrete-device-assignment

DDA is typically used for storage controllers, such as NVMe,
and for GPUs.  A similar mechanism for NICs is called SR-IOV
and produces the same benefits by allowing a guest device
driver to interact directly with the hardware.  See Hyper-V
public documentation here: `SR-IOV`_

.. _SR-IOV: https://learn.microsoft.com/en-us/windows-hardware/drivers/network/overview-of-single-root-i-o-virtualization--sr-iov-

This discussion of vPCI devices includes DDA and SR-IOV
devices.

Device presentation과 이중 신원

32-73

Hyper-V는 동작 중인 vPCI device에 완전한 PCI 기능을 제공합니다. Driver가 PCI config space 접근과 Linux 통합에 올바른 kernel API를 사용한다면 기존 Linux device driver를 수정 없이 사용할 수 있습니다.

하지만 최초 PCI device 탐지와 Linux PCI subsystem 통합에는 Hyper-V 전용 mechanism이 필요합니다. 따라서 Hyper-V의 vPCI device는 VMBus device와 PCI device라는 이중 신원을 가집니다.

처음에는 표준 VMBus `offer` mechanism으로 Linux guest에 제시되므로 VMBus identity가 생기고 `/sys/bus/vmbus/devices` 아래에 나타납니다.

`drivers/pci/controller/pci-hyperv.c`의 Linux VMBus vPCI driver는 새 vPCI device를 받으면 PCI bus topology를 인위적으로 만들고, bare-metal에서 ACPI로 device를 발견했을 때 존재했을 정상 PCI device data structure를 모두 생성합니다.

이 data structure 설정이 끝나면 device는 정상적인 Linux PCI identity도 얻습니다. 이후 일반 Linux driver는 bare-metal에서처럼 동작합니다.

vPCI device는 VMBus offer를 통해 동적으로 제시되므로 Linux guest의 ACPI table에는 나타나지 않습니다. Initial boot 때뿐 아니라 VM이 살아 있는 동안 언제든 추가하거나 제거할 수 있습니다.

vPCI의 이중 신원
Identity표현·경로역할
VMBus`/sys/bus/vmbus/devices`Offer, 설정, CPU target 변경, 제거
PCILinux PCI subsystemGeneric PCI scan, driver matching, 정상 device I/O

장치 도입 단계와 정상 실행 단계의 표현을 구분합니다.

VMBus offer에 응답해 `hv_pci_probe()`가 실행되고 Hyper-V host의 vPCI VSP와 VMBus connection을 만듭니다. 이 connection은 VMBus channel 하나를 가지며 Linux 안에서 vPCI device를 설정하고 구성하는 message 교환에 사용합니다.

PCI device 구성이 끝난 뒤 VMBus channel은 Linux가 guest에서 interrupt 받을 vCPU를 변경하거나 실행 중인 VM에서 vPCI device가 제거될 때만 사용됩니다. 일상적인 device 동작은 Linux device driver와 hardware 사이에서 직접 이루어지며 VMBus와 channel은 관여하지 않습니다.

vPCI device presentation
Hyper-V가 vPCI device를 VMBus offer로 제시`hv_pci_probe()`가 vPCI VSP channel 구성Driver가 PCI bus topology와 device structure 생성Device가 Linux PCI identity 획득Generic Linux PCI driver가 bare-metal 방식으로 동작

VMBus offer에서 일반 PCI device로 전환되는 흐름입니다.


Device Presentation
-------------------
Hyper-V provides full PCI functionality for a vPCI device when
it is operating, so the Linux device driver for the device can
be used unchanged, provided it uses the correct Linux kernel
APIs for accessing PCI config space and for other integration
with Linux.  But the initial detection of the PCI device and
its integration with the Linux PCI subsystem must use Hyper-V
specific mechanisms.  Consequently, vPCI devices on Hyper-V
have a dual identity.  They are initially presented to Linux
guests as VMBus devices via the standard VMBus "offer"
mechanism, so they have a VMBus identity and appear under
/sys/bus/vmbus/devices.  The VMBus vPCI driver in Linux at
drivers/pci/controller/pci-hyperv.c handles a newly introduced
vPCI device by fabricating a PCI bus topology and creating all
the normal PCI device data structures in Linux that would
exist if the PCI device were discovered via ACPI on a bare-
metal system.  Once those data structures are set up, the
device also has a normal PCI identity in Linux, and the normal
Linux device driver for the vPCI device can function as if it
were running in Linux on bare-metal.  Because vPCI devices are
presented dynamically through the VMBus offer mechanism, they
do not appear in the Linux guest's ACPI tables.  vPCI devices
may be added to a VM or removed from a VM at any time during
the life of the VM, and not just during initial boot.

With this approach, the vPCI device is a VMBus device and a
PCI device at the same time.  In response to the VMBus offer
message, the hv_pci_probe() function runs and establishes a
VMBus connection to the vPCI VSP on the Hyper-V host.  That
connection has a single VMBus channel.  The channel is used to
exchange messages with the vPCI VSP for the purpose of setting
up and configuring the vPCI device in Linux.  Once the device
is fully configured in Linux as a PCI device, the VMBus
channel is used only if Linux changes the vCPU to be interrupted
in the guest, or if the vPCI device is removed from
the VM while the VM is running.  The ongoing operation of the
device happens directly between the Linux device driver for
the device and the hardware, with VMBus and the VMBus channel
playing no role.

PCI device 설정

74-114

PCI device setup은 Hyper-V가 원래 Windows guest용으로 만든 sequence를 따릅니다. Linux PCI subsystem의 전체 구조가 Windows와 달라 Linux guest에는 잘 맞지 않을 수 있지만 Hyper-V virtual PCI driver의 몇 가지 우회 구현으로 generic Linux PCI code와 device driver가 그대로 동작하게 합니다.

Linux에서는 vPCI device마다 host bridge가 있는 별도 PCI domain을 만듭니다. PCI domainID는 VMBus vPCI device의 instance GUID 중 4번과 5번 byte에서 유도합니다.

Hyper-V host는 두 byte의 고유성을 보장하지 않으므로 `hv_pci_probe()`에는 충돌 해결 algorithm이 있습니다. 일부 device의 user-space configuration에 domainID가 기록되므로 같은 VM을 reboot해도 domainID가 바뀌지 않도록 안정적인 해를 고르는 것이 목적입니다.

`hv_pci_probe()`는 device의 PCI config space로 사용할 guest MMIO range를 할당합니다. Device가 d0 state에 들어갈 준비가 됐다고 host에 알리는 과정에서 이 range를 VMBus channel로 전달합니다. 관련 함수는 `hv_pci_enter_d0()`입니다.

Guest가 나중에 이 MMIO range에 접근하면 Hyper-V host가 access를 intercept해 physical device의 PCI config space로 mapping합니다.

`hv_pci_probe()`는 host에서 device BAR 정보도 받아 BAR용 MMIO space를 할당합니다. Generic Linux PCI subsystem이 BAR를 처리할 때 올바르게 동작하도록 이 MMIO space를 host bridge와 연결합니다.

마지막으로 `hv_pci_probe()`가 root PCI bus를 생성합니다. 이 시점부터 Hyper-V virtual PCI driver의 우회 작업은 끝나고 정상 Linux PCI machinery가 root bus를 scan해 device를 발견하고 driver matching과 driver·device 초기화를 수행합니다.

PCI device setup sequence
Instance GUID byte 4·5에서 PCI domainID 유도하고 collision 해결Device 전용 host bridge와 PCI domain 생성PCI config용 guest MMIO range 할당`hv_pci_enter_d0()`로 host에 MMIO range 전달Host BAR 정보로 BAR MMIO와 host bridge 구성Root PCI bus 생성Generic Linux PCI scan·matching·initialization

Hyper-V 전용 준비가 generic PCI scan으로 이어집니다.

vPCI MMIO 영역
영역설정 주체동작
PCI config MMIO`hv_pci_probe()`, `hv_pci_enter_d0()`Host가 access를 physical config space로 intercept·mapping
BAR MMIOHost BAR 정보 + guest allocationHost bridge resource로 generic PCI subsystem에 제공

Config access와 BAR access를 위한 설정을 구분합니다.

PCI Device Setup
----------------
PCI device setup follows a sequence that Hyper-V originally
created for Windows guests, and that can be ill-suited for
Linux guests due to differences in the overall structure of
the Linux PCI subsystem compared with Windows.  Nonetheless,
with a bit of hackery in the Hyper-V virtual PCI driver for
Linux, the virtual PCI device is setup in Linux so that
generic Linux PCI subsystem code and the Linux driver for the
device "just work".

Each vPCI device is set up in Linux to be in its own PCI
domain with a host bridge.  The PCI domainID is derived from
bytes 4 and 5 of the instance GUID assigned to the VMBus vPCI
device.  The Hyper-V host does not guarantee that these bytes
are unique, so hv_pci_probe() has an algorithm to resolve
collisions.  The collision resolution is intended to be stable
across reboots of the same VM so that the PCI domainIDs don't
change, as the domainID appears in the user space
configuration of some devices.

hv_pci_probe() allocates a guest MMIO range to be used as PCI
config space for the device.  This MMIO range is communicated
to the Hyper-V host over the VMBus channel as part of telling
the host that the device is ready to enter d0.  See
hv_pci_enter_d0().  When the guest subsequently accesses this
MMIO range, the Hyper-V host intercepts the accesses and maps
them to the physical device PCI config space.

hv_pci_probe() also gets BAR information for the device from
the Hyper-V host, and uses this information to allocate MMIO
space for the BARs.  That MMIO space is then setup to be
associated with the host bridge so that it works when generic
PCI subsystem code in Linux processes the BARs.

Finally, hv_pci_probe() creates the root PCI bus.  At this
point the Hyper-V virtual PCI driver hackery is done, and the
normal Linux PCI machinery for scanning the root bus works to
detect the device, to perform driver matching, and to
initialize the driver and device.

PCI device 제거

115-160

Hyper-V host는 VM이 살아 있는 동안 언제든 vPCI device 제거를 시작할 수 있습니다. Host 관리자의 동작으로 시작되며 guest OS가 제어하지 않습니다.

Host는 해당 vPCI device의 VMBus channel로 unsolicited `Eject` message를 보내 제거 사실을 guest에 알립니다. Linux Hyper-V virtual PCI driver는 이를 받으면 Linux kernel PCI subsystem 호출을 비동기로 실행해 device를 shutdown하고 제거합니다.

PCI 제거 호출이 끝나면 guest는 같은 VMBus channel로 `Ejection Complete` message를 보내 device가 제거됐다고 알립니다. Hyper-V는 이어서 VMBus rescind message를 보냅니다.

Linux VMBus driver가 rescind를 처리하면 device의 VMBus identity도 제거되고 kernel에서 device가 있었던 흔적이 모두 사라집니다. Rescind는 Hyper-V가 guest의 해당 vPCI device 지원을 중단했다는 뜻이기도 합니다.

그 뒤 해당 device MMIO space에 접근하면 invalid reference가 됩니다. Device에 영향을 주는 hypercall은 error를 반환하고 VMBus channel로 보내는 추가 message도 무시됩니다.

정상 vPCI ejection
Host 관리자가 device 제거 요청Hyper-V가 VMBus channel로 `Eject` 전송Linux가 PCI subsystem을 통해 비동기 shutdown·removeGuest가 `Ejection Complete` 응답Hyper-V가 VMBus rescind 전송Linux가 VMBus identity와 남은 상태 제거

PCI identity를 먼저 제거하고 VMBus identity를 나중에 정리합니다.

Hyper-V는 Eject를 보낸 뒤 guest가 clean shutdown을 마치고 Ejection Complete로 응답할 때까지 60초를 기다립니다. 60초 안에 끝나지 않으면 host가 강제로 rescind 단계로 넘어갑니다.

강제 rescind 뒤 guest 관점에서는 device가 이미 사라졌으므로 MMIO access가 실패하고 연쇄 error가 발생할 가능성이 큽니다.

Ejection은 비동기이며 VM 수명 주기의 어느 순간에도 일어날 수 있어 Hyper-V virtual PCI driver의 올바른 synchronization이 매우 어렵습니다. 새로 offer된 vPCI device가 완전히 설정되기 전에 ejection이 관찰된 적도 있습니다.

불리한 시점의 ejection race를 고치기 위해 driver는 여러 해에 걸쳐 여러 번 갱신됐습니다. Code를 수정할 때 race condition을 다시 만들지 않도록 code comment를 주의 깊게 확인해야 합니다.

Ejection 시간 제한
상황Host 동작Guest 영향
60초 안에 완료Ejection Complete 수신 후 rescindPCI와 VMBus identity를 순서대로 제거
60초 timeoutEject 완료 전 강제 rescindMMIO 실패와 cascading error 가능

정상 완료와 timeout 후 강제 rescind를 비교합니다.

PCI Device Removal
------------------
A Hyper-V host may initiate removal of a vPCI device from a
guest VM at any time during the life of the VM.  The removal
is instigated by an admin action taken on the Hyper-V host and
is not under the control of the guest OS.

A guest VM is notified of the removal by an unsolicited
"Eject" message sent from the host to the guest over the VMBus
channel associated with the vPCI device.  Upon receipt of such
a message, the Hyper-V virtual PCI driver in Linux
asynchronously invokes Linux kernel PCI subsystem calls to
shutdown and remove the device.  When those calls are
complete, an "Ejection Complete" message is sent back to
Hyper-V over the VMBus channel indicating that the device has
been removed.  At this point, Hyper-V sends a VMBus rescind
message to the Linux guest, which the VMBus driver in Linux
processes by removing the VMBus identity for the device.  Once
that processing is complete, all vestiges of the device having
been present are gone from the Linux kernel.  The rescind
message also indicates to the guest that Hyper-V has stopped
providing support for the vPCI device in the guest.  If the
guest were to attempt to access that device's MMIO space, it
would be an invalid reference. Hypercalls affecting the device
return errors, and any further messages sent in the VMBus
channel are ignored.

After sending the Eject message, Hyper-V allows the guest VM
60 seconds to cleanly shutdown the device and respond with
Ejection Complete before sending the VMBus rescind
message.  If for any reason the Eject steps don't complete
within the allowed 60 seconds, the Hyper-V host forcibly
performs the rescind steps, which will likely result in
cascading errors in the guest because the device is now no
longer present from the guest standpoint and accessing the
device MMIO space will fail.

Because ejection is asynchronous and can happen at any point
during the guest VM lifecycle, proper synchronization in the
Hyper-V virtual PCI driver is very tricky.  Ejection has been
observed even before a newly offered vPCI device has been
fully setup.  The Hyper-V virtual PCI driver has been updated
several times over the years to fix race conditions when
ejections happen at inopportune times. Care must be taken when
modifying this code to prevent re-introducing such problems.
See comments in the code.

Interrupt 할당

161-225

Hyper-V virtual PCI driver는 MSI, multi-MSI, MSI-X를 사용하는 vPCI device를 지원합니다. 특정 MSI 또는 MSI-X message를 받을 guest vCPU를 할당하는 과정은 Linux IRQ 설정과 Hyper-V interface가 mapping되는 방식 때문에 복잡합니다.

Single-MSI와 MSI-X에서는 Linux가 `hv_compose_msi_msg()`를 두 번 호출합니다. 첫 호출에는 dummy vCPU가, 두 번째 호출에는 실제 vCPU가 들어갑니다. 이어서 x86에서는 `hv_irq_unmask()`를 호출하고 arm64에서는 GICD register를 설정해 실제 vCPU를 다시 지정합니다.

세 호출은 모두 Hyper-V와 상호 작용합니다. Hyper-V는 interrupt를 guest VM에 전달하기 전에 어느 physical CPU가 받을지 결정해야 하지만 이 의사 결정은 제약이 있어 physical interrupt가 CPU 하나에 몰리고 성능 병목이 생길 수 있습니다. 해결 방법은 `hv_compose_msi_req_get_cpu()` 위의 긴 comment를 참조합니다.

MSI target 설정 단계
단계전달 정보Architecture
첫 composeDummy vCPU공통
두 번째 composeReal vCPU공통
Unmask·GICDReal vCPU 재지정x86: `hv_irq_unmask()`, arm64: GICD

같은 실제 vCPU 정보가 Hyper-V에 여러 단계로 전달됩니다.

Linux Hyper-V virtual PCI driver는 `irq_chip.irq_compose_msi_msg`를 `hv_compose_msi_msg()`로 구현합니다. Hyper-V에서는 이 구현이 host에 VMBus message를 보내고 reply 수신 interrupt를 기다려야 합니다.

하지만 IRQ lock을 잡은 상태에서 `irq_chip.irq_compose_msi_msg`가 호출될 수 있어 일반적인 sleep-and-wakeup 방식은 사용할 수 없습니다. 따라서 `hv_compose_msi_msg()`는 VMBus message를 보낸 뒤 completion message를 polling해야 합니다.

Polling 중 vPCI device가 eject 또는 rescind될 수도 있으므로 이 상황도 감지해야 합니다. 원문은 이 까다로운 영역의 code comment를 확인하라고 강조합니다.

`pci-hyperv.c`의 대부분은 x86과 arm64 Hyper-V Linux guest에서 공통이지만 interrupt assignment는 architecture별로 다릅니다.

x86에서는 guest Hyper-V virtual PCI driver가 hypercall로 각 MSI/MSI-X interrupt가 향할 guest vCPU와 `x86_vector` IRQ domain이 선택한 x86 interrupt vector 번호를 Hyper-V에 알려야 합니다. 이 hypercall은 `hv_arch_irq_unmask()`가 수행합니다.

Arm64에서는 driver가 MSI/MSI-X interrupt마다 SPI를 할당하고 Hyper-V가 emulate하는 architecture GICD register에 기록합니다. x86 같은 hypercall은 필요하지 않습니다. Hyper-V는 GICv3 ITS를 emulate하지 않으므로 arm64 guest의 vPCI device에 LPI를 사용할 수 없습니다.

Architecture별 MSI/MSI-X routing
ArchitectureInterrupt resourceHyper-V 전달 방식제한
x86x86 vector`hv_arch_irq_unmask()` hypercallVector 재할당 통지 경로 부족
arm64SPIEmulated GICD registerGICv3 ITS 미지원, LPI 사용 불가

Guest vCPU와 interrupt 번호를 Hyper-V에 전달하는 방법입니다.

Linux driver는 managed 또는 unmanaged Linux IRQ를 만드는 vPCI device를 모두 지원합니다. Unmanaged IRQ의 `smp_affinity`를 `/proc/irq`에서 바꾸면 Hyper-V virtual PCI driver가 host에 target 변경을 알려 정상 동작합니다.

다만 x86에서 CPU의 vector가 부족해 `x86_vector` IRQ domain이 interrupt vector를 재할당해야 할 때는 변경을 Hyper-V host에 알릴 경로가 없어 동작이 깨집니다. Guest VM의 제한된 device 환경에서는 CPU vector를 모두 쓰는 일이 사실상 없어 이 문제는 실무보다 이론적 우려로 남겨 두었습니다.

IRQ compose의 비수면 대기
`hv_compose_msi_msg()`가 VMBus request 전송IRQ lock 때문에 sleep 불가Completion message를 polling동시에 eject/rescind 여부 감시유효한 reply이면 MSI routing 완료

IRQ lock context에서도 host reply를 받아야 하는 제약입니다.


Interrupt Assignment
--------------------
The Hyper-V virtual PCI driver supports vPCI devices using
MSI, multi-MSI, or MSI-X.  Assigning the guest vCPU that will
receive the interrupt for a particular MSI or MSI-X message is
complex because of the way the Linux setup of IRQs maps onto
the Hyper-V interfaces.  For the single-MSI and MSI-X cases,
Linux calls hv_compse_msi_msg() twice, with the first call
containing a dummy vCPU and the second call containing the
real vCPU.  Furthermore, hv_irq_unmask() is finally called
(on x86) or the GICD registers are set (on arm64) to specify
the real vCPU again.  Each of these three calls interact
with Hyper-V, which must decide which physical CPU should
receive the interrupt before it is forwarded to the guest VM.
Unfortunately, the Hyper-V decision-making process is a bit
limited, and can result in concentrating the physical
interrupts on a single CPU, causing a performance bottleneck.
See details about how this is resolved in the extensive
comment above the function hv_compose_msi_req_get_cpu().

The Hyper-V virtual PCI driver implements the
irq_chip.irq_compose_msi_msg function as hv_compose_msi_msg().
Unfortunately, on Hyper-V the implementation requires sending
a VMBus message to the Hyper-V host and awaiting an interrupt
indicating receipt of a reply message.  Since
irq_chip.irq_compose_msi_msg can be called with IRQ locks
held, it doesn't work to do the normal sleep until awakened by
the interrupt. Instead hv_compose_msi_msg() must send the
VMBus message, and then poll for the completion message. As
further complexity, the vPCI device could be ejected/rescinded
while the polling is in progress, so this scenario must be
detected as well.  See comments in the code regarding this
very tricky area.

Most of the code in the Hyper-V virtual PCI driver (pci-
hyperv.c) applies to Hyper-V and Linux guests running on x86
and on arm64 architectures.  But there are differences in how
interrupt assignments are managed.  On x86, the Hyper-V
virtual PCI driver in the guest must make a hypercall to tell
Hyper-V which guest vCPU should be interrupted by each
MSI/MSI-X interrupt, and the x86 interrupt vector number that
the x86_vector IRQ domain has picked for the interrupt.  This
hypercall is made by hv_arch_irq_unmask().  On arm64, the
Hyper-V virtual PCI driver manages the allocation of an SPI
for each MSI/MSI-X interrupt.  The Hyper-V virtual PCI driver
stores the allocated SPI in the architectural GICD registers,
which Hyper-V emulates, so no hypercall is necessary as with
x86.  Hyper-V does not support using LPIs for vPCI devices in
arm64 guest VMs because it does not emulate a GICv3 ITS.

The Hyper-V virtual PCI driver in Linux supports vPCI devices
whose drivers create managed or unmanaged Linux IRQs.  If the
smp_affinity for an unmanaged IRQ is updated via the /proc/irq
interface, the Hyper-V virtual PCI driver is called to tell
the Hyper-V host to change the interrupt targeting and
everything works properly.  However, on x86 if the x86_vector
IRQ domain needs to reassign an interrupt vector due to
running out of vectors on a CPU, there's no path to inform the
Hyper-V host of the change, and things break.  Fortunately,
guest VMs operate in a constrained device environment where
using all the vectors on a CPU doesn't happen. Since such a
problem is only a theoretical concern rather than a practical
concern, it has been left unaddressed.

DMA와 cache coherency

226-254

기본적으로 Hyper-V는 VM을 만들 때 guest memory 전체를 host에 pin하고 physical IOMMU를 설정해 VM이 자기 memory 전체에 DMA access할 수 있게 합니다.

따라서 PCI device를 VM에 할당하고 guest OS가 DMA transfer를 program해도 안전합니다. Physical IOMMU는 악의적인 guest가 host 또는 같은 host의 다른 VM memory로 DMA를 시작하지 못하게 막습니다.

Linux guest 관점에서 Hyper-V가 guest 안에 virtual IOMMU를 제공하지 않으므로 이 DMA transfer는 `direct` mode입니다.

Hyper-V vPCI DMA 격리
계층역할
Guest LinuxDevice가 guest memory에 direct DMA
Hyper-V hostVM 생성 때 guest memory pin
Physical IOMMUHost·다른 VM memory로 향하는 DMA 차단

Guest에는 direct DMA로 보이지만 host physical IOMMU가 경계를 강제합니다.

Hyper-V는 physical PCI device가 항상 cache-coherent DMA를 수행한다고 가정합니다. x86에서는 architecture가 이를 요구합니다.

Arm64는 cache-coherent device와 non-cache-coherent device를 모두 허용하며 보통 각 device의 동작을 ACPI DSDT에 기록합니다. 하지만 VM에 할당된 PCI device는 DSDT에 나타나지 않습니다.

그래서 Hyper-V VMBus driver는 ACPI DSDT의 VMBus node가 가진 cache-coherency 정보를 vPCI device를 포함한 모든 VMBus device에 전파합니다. vPCI device가 VMBus와 PCI 이중 신원을 가지기 때문에 이 전파가 적용됩니다. 관련 함수는 `vmbus_dma_configure()`입니다.

현재 Hyper-V version은 항상 VMBus가 cache coherent라고 표시합니다. 따라서 arm64의 vPCI device도 cache coherent로 표시되고 CPU는 `dma_map/unmap_*()` 호출 과정에서 sync operation을 수행하지 않습니다.

Cache coherency 처리
환경판정·동작
x86Architecture상 cache-coherent DMA 필수
arm64 bare metalDevice별 DSDT 정보 사용 가능
arm64 Hyper-V vPCIVMBus node 정보를 전파하며 현재는 항상 coherent

Architecture와 firmware 정보 경로를 비교합니다.

DMA
---
By default, Hyper-V pins all guest VM memory in the host
when the VM is created, and programs the physical IOMMU to
allow the VM to have DMA access to all its memory.  Hence
it is safe to assign PCI devices to the VM, and allow the
guest operating system to program the DMA transfers.  The
physical IOMMU prevents a malicious guest from initiating
DMA to memory belonging to the host or to other VMs on the
host. From the Linux guest standpoint, such DMA transfers
are in "direct" mode since Hyper-V does not provide a virtual
IOMMU in the guest.

Hyper-V assumes that physical PCI devices always perform
cache-coherent DMA.  When running on x86, this behavior is
required by the architecture.  When running on arm64, the
architecture allows for both cache-coherent and
non-cache-coherent devices, with the behavior of each device
specified in the ACPI DSDT.  But when a PCI device is assigned
to a guest VM, that device does not appear in the DSDT, so the
Hyper-V VMBus driver propagates cache-coherency information
from the VMBus node in the ACPI DSDT to all VMBus devices,
including vPCI devices (since they have a dual identity as a VMBus
device and as a PCI device).  See vmbus_dma_configure().
Current Hyper-V versions always indicate that the VMBus is
cache coherent, so vPCI devices on arm64 always get marked as
cache coherent and the CPU does not perform any sync
operations as part of dma_map/unmap_*() calls.

vPCI protocol version

255-269

앞서 설명한 것처럼 vPCI device 설정과 teardown 동안 Hyper-V host와 Linux guest의 vPCI driver가 VMBus channel로 message를 교환합니다.

새 Hyper-V version에서 일부 message 형식이 바뀌었으므로 guest와 host는 사용할 vPCI protocol version에 합의해야 합니다. VMBus channel 통신을 처음 만들 때 `hv_pci_protocol_negotiation()`으로 version을 협상합니다.

새 protocol version은 vCPU가 64개를 넘는 VM까지 지원 범위를 넓히며, underlying hardware에서 vPCI device와 가장 가까운 guest virtual NUMA node 같은 추가 device 정보도 제공합니다.

새 vPCI protocol의 확장
기능내용
Large VM64개 초과 vCPU 지원
TopologyDevice에 가장 가까운 guest virtual NUMA node 전달

협상 version이 제공하는 대표 기능입니다.

vPCI protocol versions
----------------------
As previously described, during vPCI device setup and teardown
messages are passed over a VMBus channel between the Hyper-V
host and the Hyper-v vPCI driver in the Linux guest.  Some
messages have been revised in newer versions of Hyper-V, so
the guest and host must agree on the vPCI protocol version to
be used.  The version is negotiated when communication over
the VMBus channel is first established.  See
hv_pci_protocol_negotiation(). Newer versions of the protocol
extend support to VMs with more than 64 vCPUs, and provide
additional information about the vPCI device, such as the
guest virtual NUMA node to which it is most closely affined in
the underlying hardware.

Guest NUMA node affinity

270-285

협상한 vPCI protocol이 guest NUMA affinity 정보를 제공하면 `hv_pci_assign_numa_node()`가 이를 Linux device 정보에 저장하고 Linux driver가 나중에 사용합니다.

협상 protocol이 host의 NUMA affinity 제공을 지원하지 않으면 Linux guest는 device NUMA node를 0으로 정합니다.

Protocol이 NUMA 정보를 지원하더라도 host가 실제 정보를 제공할 수 있는지는 특정 host configuration option에 달려 있습니다. Guest가 NUMA node 값 `0`을 받았을 때 실제 node 0인지 정보가 없다는 뜻인지 guest 쪽에서는 구분할 수 없습니다.

NUMA node 값 0의 의미
조건Guest의 node 0 해석
Protocol이 affinity 미지원Fallback node 0
Host가 affinity 정보 제공실제 NUMA node 0일 수 있음
Host configuration상 정보 없음Unknown을 0으로 표현할 수 있음

Protocol과 host configuration 때문에 같은 값이 두 의미를 가질 수 있습니다.

Guest NUMA node affinity
------------------------
When the vPCI protocol version provides it, the guest NUMA
node affinity of the vPCI device is stored as part of the Linux
device information for subsequent use by the Linux driver. See
hv_pci_assign_numa_node().  If the negotiated protocol version
does not support the host providing NUMA affinity information,
the Linux guest defaults the device NUMA node to 0.  But even
when the negotiated protocol version includes NUMA affinity
information, the ability of the host to provide such
information depends on certain host configuration options.  If
the guest receives NUMA node value "0", it could mean NUMA
node 0, or it could mean "no information is available".
Unfortunately it is not possible to distinguish the two cases
from the guest side.

CoCo VM의 PCI config space 접근

286-300

Linux PCI device driver는 Linux PCI subsystem이 제공하는 표준 함수로 PCI config space에 접근합니다. Hyper-V guest에서는 이 함수들이 Hyper-V virtual PCI driver의 `hv_pcifront_read_config()`와 `hv_pcifront_write_config()`에 mapping됩니다.

일반 VM에서는 `hv_pcifront_*()` 함수가 PCI config space에 직접 접근하고 access가 trap되어 Hyper-V가 처리합니다.

CoCo VM에서는 memory encryption 때문에 Hyper-V가 guest instruction stream을 읽어 access를 emulate할 수 없습니다. 따라서 `hv_pcifront_*()` 함수가 수행할 access를 명시적인 argument로 설명해 hypercall을 호출해야 합니다.

PCI config access
VM접근 방식이유
Normal VMDirect config access → Hyper-V trap·emulationHost가 instruction stream을 볼 수 있음
CoCo VMExplicit-argument hypercallEncryption으로 host가 instruction decode 불가

일반 VM의 implicit trap과 CoCo VM의 explicit hypercall을 비교합니다.

PCI config space access in a CoCo VM
------------------------------------
Linux PCI device drivers access PCI config space using a
standard set of functions provided by the Linux PCI subsystem.
In Hyper-V guests these standard functions map to functions
hv_pcifront_read_config() and hv_pcifront_write_config()
in the Hyper-V virtual PCI driver.  In normal VMs,
these hv_pcifront_*() functions directly access the PCI config
space, and the accesses trap to Hyper-V to be handled.
But in CoCo VMs, memory encryption prevents Hyper-V
from reading the guest instruction stream to emulate the
access, so the hv_pcifront_*() functions must invoke
hypercalls with explicit arguments describing the access to be
made.

Config Block back-channel

301-316

Hyper-V host와 Linux Hyper-V virtual PCI driver는 host와 guest 사이에 비표준 back-channel communication path를 함께 구현합니다. 이 경로는 vPCI device에 연결된 VMBus channel로 message를 보냅니다.

다른 Linux kernel 영역에 제공하는 주 interface는 `hyperv_read_cfg_blk()`와 `hyperv_write_cfg_blk()`입니다.

문서 작성 시점에는 Azure public cloud의 Hyper-V host에 diagnostic data를 전달하기 위해 Mellanox `mlx5` driver만 이 interface를 사용합니다.

두 함수는 `CONFIG_PCI_HYPERV_INTERFACE` 아래 별도 module인 `pci-hyperv-intf.c`에 구현됩니다. Non-Hyper-V 환경에서는 사실상 아무 동작도 하지 않는 stub이 됩니다.

Config Block back-channel
Mellanox `mlx5` driver가 diagnostic data 준비`hyperv_read_cfg_blk()` 또는 `hyperv_write_cfg_blk()` 호출vPCI device의 VMBus channel로 message 교환Azure Hyper-V host가 diagnostic data 처리

현재 mlx5 진단 data가 이동하는 비표준 경로입니다.

Config Block 구현
항목내용
Source`pci-hyperv-intf.c`
Config`CONFIG_PCI_HYPERV_INTERFACE`
Hyper-VVMBus back-channel 제공
Non-Hyper-VInterface를 stub 처리

Build option과 runtime 환경에 따른 동작입니다.

Config Block back-channel
-------------------------
The Hyper-V host and Hyper-V virtual PCI driver in Linux
together implement a non-standard back-channel communication
path between the host and guest.  The back-channel path uses
messages sent over the VMBus channel associated with the vPCI
device.  The functions hyperv_read_cfg_blk() and
hyperv_write_cfg_blk() are the primary interfaces provided to
other parts of the Linux kernel.  As of this writing, these
interfaces are used only by the Mellanox mlx5 driver to pass
diagnostic data to a Hyper-V host running in the Azure public
cloud.  The functions hyperv_read_cfg_blk() and
hyperv_write_cfg_blk() are implemented in a separate module
(pci-hyperv-intf.c, under CONFIG_PCI_HYPERV_INTERFACE) that
effectively stubs them out when running in non-Hyper-V
environments.