1.. _hld-io-emulation: 2 3I/O Emulation High-Level Design 4############################### 5 6As discussed in :ref:`intro-io-emulation`, there are multiple ways and 7places to handle I/O emulation, including HV, Service VM Kernel HSM, and Service VM 8user-land Device Model (acrn-dm). 9 10I/O emulation in the hypervisor provides these functionalities: 11 12- Maintain lists of port I/O or MMIO handlers in the hypervisor for 13 emulating trapped I/O accesses in a certain range. 14 15- Forward I/O accesses to Service VM when they cannot be handled by the 16 hypervisor by any registered handlers. 17 18:numref:`io-control-flow` illustrates the main control flow steps of I/O emulation 19inside the hypervisor: 20 211. Trap and decode I/O access by VM exits and decode the access from 22 exit qualification or by invoking the instruction decoder. 23 242. If the range of the I/O access overlaps with any registered handler, 25 call that handler if it completely covers the range of the 26 access, or ignore the access if the access crosses the boundary. 27 283. If the range of the I/O access does not overlap the range of any I/O 29 handler, deliver an I/O request to Service VM. 30 31.. figure:: images/ioem-image101.png 32 :align: center 33 :name: io-control-flow 34 35 Control Flow of I/O Emulation in the Hypervisor 36 37I/O emulation does not rely on any calibration data. 38 39Trap Path 40********* 41 42Port I/O accesses are trapped by VM exits with the basic exit reason 43"I/O instruction". The port address to be accessed, size, and direction 44(read or write) are fetched from the VM exit qualification. For writes 45the value to be written to the I/O port is fetched from guest registers 46al, ax or eax, depending on the access size. 47 48MMIO accesses are trapped by VM exits with the basic exit reason "EPT 49violation". The instruction emulator is invoked to decode the 50instruction that triggers the VM exit to get the memory address being 51accessed, size, direction (read or write), and the involved register. 52 53The I/O bitmaps and EPT are used to configure the addresses that will 54trigger VM exits when accessed by a VM. Refer to 55:ref:`io-mmio-emulation` for details. 56 57I/O Emulation in the Hypervisor 58******************************* 59 60When a port I/O or MMIO access is trapped, the hypervisor first checks 61whether the to-be-accessed address falls in the range of any registered 62handler, and calls the handler when such a handler exists. 63 64Handler Management 65================== 66 67Each VM has two lists of I/O handlers, one for port I/O and the other 68for MMIO. Each element of the list contains a memory range and a pointer 69to the handler which emulates the accesses falling in the range. See 70:ref:`io-handler-init` for descriptions of the related data structures. 71 72The I/O handlers are registered on VM creation and never changed until 73the destruction of that VM, when the handlers are unregistered. If 74multiple handlers are registered for the same address, the one 75registered later wins. See :ref:`io-handler-init` for the interfaces 76used to register and unregister I/O handlers. 77 78I/O Dispatching 79=============== 80 81When a port I/O or MMIO access is trapped, the hypervisor first walks 82through the corresponding I/O handler list in the reverse order of 83registration, looking for a proper handler to emulate the access. The 84following cases exist: 85 86- If a handler whose range overlaps the range of the I/O access is 87 found, 88 89 - If the range of the I/O access falls completely in the range the 90 handler can emulate, that handler is called. 91 92 - Otherwise it is implied that the access crosses the boundary of 93 multiple devices which the hypervisor does not emulate. Thus 94 no handler is called and no I/O request will be delivered to 95 Service VM. I/O reads get all 1's and I/O writes are dropped. 96 97- If the range of the I/O access does not overlap with any range of the 98 handlers, the I/O access is delivered to Service VM as an I/O request 99 for further processing. 100 101I/O Requests 102************ 103 104An I/O request is delivered to Service VM vCPU 0 if the hypervisor does not 105find any handler that overlaps the range of a trapped I/O access. This 106section describes the initialization of the I/O request mechanism and 107how an I/O access is emulated via I/O requests in the hypervisor. 108 109Initialization 110============== 111 112For each User VM the hypervisor shares a page with Service VM to exchange I/O 113requests. The 4-KByte page consists of 16 256-Byte slots, indexed by 114vCPU ID. It is required for the DM to allocate and set up the request 115buffer on VM creation, otherwise I/O accesses from User VM cannot be 116emulated by Service VM, and all I/O accesses not handled by the I/O handlers in 117the hypervisor will be dropped (reads get all 1's). 118 119Refer to the following sections for details on I/O requests and the 120initialization of the I/O request buffer. 121 122Types of I/O Requests 123===================== 124 125There are four types of I/O requests: 126 127.. list-table:: 128 :widths: 50 50 129 :header-rows: 1 130 131 * - I/O Request Type 132 - Description 133 134 * - PIO 135 - A port I/O access. 136 137 * - MMIO 138 - An MMIO access to a GPA with no mapping in EPT. 139 140 * - PCI 141 - A PCI configuration space access. 142 143 * - WP 144 - An MMIO access to a GPA with a read-only mapping in EPT. 145 146 147For port I/O accesses, the hypervisor will always deliver an I/O request 148of type PIO to Service VM. For MMIO accesses, the hypervisor will deliver an 149I/O request of either MMIO or WP, depending on the mapping of the 150accessed address (in GPA) in the EPT of the vCPU. The hypervisor will 151never deliver any I/O request of type PCI, but will handle such I/O 152requests in the same ways as port I/O accesses on their completion. 153 154Refer to :ref:`io-structs-interfaces` for a detailed description of the 155data held by each type of I/O request. 156 157I/O Request State Transitions 158============================= 159 160Each slot in the I/O request buffer is managed by a finite state machine 161with four states. The following figure illustrates the state transitions 162and the events that trigger them. 163 164.. figure:: images/ioem-image92.png 165 :align: center 166 167 State Transition of I/O Requests 168 169The four states are: 170 171FREE 172 The I/O request slot is not used and new I/O requests can be 173 delivered. This is the initial state on User VM creation. 174 175PENDING 176 The I/O request slot is occupied with an I/O request pending 177 to be processed by Service VM. 178 179PROCESSING 180 The I/O request has been dispatched to a client but the 181 client has not finished handling it yet. 182 183COMPLETE 184 The client has completed the I/O request but the hypervisor 185 has not consumed the results yet. 186 187The contents of an I/O request slot are owned by the hypervisor when the 188state of an I/O request slot is FREE or COMPLETE. In such cases Service VM can 189only access the state of that slot. Similarly the contents are owned by 190Service VM when the state is PENDING or PROCESSING, when the hypervisor can 191only access the state of that slot. 192 193The states are transferred as follow: 194 1951. To deliver an I/O request, the hypervisor takes the slot 196 corresponding to the vCPU triggering the I/O access, fills the 197 contents, changes the state to PENDING and notifies Service VM via 198 upcall. 199 2002. On upcalls, Service VM dispatches each I/O request in the PENDING state to 201 clients and changes the state to PROCESSING. 202 2033. The client assigned an I/O request changes the state to COMPLETE 204 after it completes the emulation of the I/O request. A hypercall 205 is made to notify the hypervisor on I/O request completion after 206 the state change. 207 2084. The hypervisor finishes the post-work of a I/O request after it is 209 notified on its completion and change the state back to FREE. 210 211States are accessed using atomic operations to avoid getting unexpected 212states on one core when it is written on another. 213 214Note that there is no state to represent a 'failed' I/O request. Service VM 215should return all 1's for reads and ignore writes whenever it cannot 216handle the I/O request, and change the state of the request to COMPLETE. 217 218Post-Work 219========= 220 221After an I/O request is completed, some more work needs to be done for 222I/O reads to update guest registers accordingly. The 223hypervisor re-enters the vCPU thread every time a vCPU is scheduled back 224in, rather than switching to where the vCPU is scheduled out. As a result, 225post-work is introduced for this purpose. 226 227The hypervisor pauses a vCPU before an I/O request is delivered to Service VM. 228Once the I/O request emulation is completed, a client notifies the 229hypervisor by a hypercall. The hypervisor will pick up that request, do 230the post-work, and resume the guest vCPU. The post-work takes care of 231updating the vCPU guest state to reflect the effect of the I/O reads. 232 233.. figure:: images/ioem-image100.png 234 :align: center 235 236 Workflow of MMIO I/O Request Completion 237 238The figure above illustrates the workflow to complete an I/O 239request for MMIO. Once the I/O request is completed, Service VM makes a 240hypercall to notify the hypervisor which resumes the User VM vCPU triggering 241the access after requesting post-work on that vCPU. After the User VM vCPU 242resumes, it does the post-work first to update the guest registers if 243the access reads an address, changes the state of the corresponding I/O 244request slot to FREE, and continues execution of the vCPU. 245 246.. figure:: images/ioem-image106.png 247 :align: center 248 :name: port-io-completion 249 250 Workflow of Port I/O Request Completion 251 252Completion of a port I/O request (shown in :numref:`port-io-completion` 253above) is 254similar to the MMIO case, except the post-work is done before resuming 255the vCPU. This is because the post-work for port I/O reads need to update 256the general register eax of the vCPU, while the post-work for MMIO reads 257need further emulation of the trapped instruction. This is much more 258complex and may impact the performance of the Service VM. 259 260.. _io-structs-interfaces: 261 262Data Structures and Interfaces 263****************************** 264 265External Interfaces 266=================== 267 268The following structures represent an I/O request. *struct acrn_io_request* 269is the main structure and the others are detailed representations of I/O 270requests of different kinds. 271 272.. doxygenstruct:: acrn_mmio_request 273 :project: Project ACRN 274 275.. doxygenstruct:: acrn_pio_request 276 :project: Project ACRN 277 278.. doxygenstruct:: acrn_pci_request 279 :project: Project ACRN 280 281.. doxygenstruct:: acrn_io_request 282 :project: Project ACRN 283 284For hypercalls related to I/O emulation, refer to `I/O Emulation in the Hypervisor`_. 285 286.. _io-handler-init: 287 288Initialization and Deinitialization 289=================================== 290 291The following structure represents a port I/O handler: 292 293.. doxygenstruct:: vm_io_handler_desc 294 :project: Project ACRN 295 296The following structure represents an MMIO handler. 297 298.. doxygenstruct:: mem_io_node 299 :project: Project ACRN 300 301The following APIs are provided to initialize, deinitialize or configure 302I/O bitmaps and register or unregister I/O handlers: 303 304.. doxygenfunction:: allow_guest_pio_access 305 :project: Project ACRN 306 307.. doxygenfunction:: register_pio_emulation_handler 308 :project: Project ACRN 309 310.. doxygenfunction:: register_mmio_emulation_handler 311 :project: Project ACRN 312 313I/O Emulation 314============= 315 316The following APIs are provided for I/O emulation at runtime: 317 318.. doxygenfunction:: acrn_insert_request 319 :project: Project ACRN 320 321.. doxygenfunction:: pio_instr_vmexit_handler 322 :project: Project ACRN 323 324.. doxygenfunction:: ept_violation_vmexit_handler 325 :project: Project ACRN 326