crosvm-direct: p-t support for port and memory I/O.

Option to passthrough port and memory mapped IO and
enable direct host device access for the guest.

BUG=b:179801783
TEST=boot and validate access with iotools.

Change-Id: I93fcc93fecccab49fd9c08b5406bcc3533128147
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2733578
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Tomasz Jeznach <tjeznach@chromium.org>
diff --git a/src/linux.rs b/src/linux.rs
index bae9434..9ac3e64 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -135,6 +135,7 @@
     CreateWaitContext(base::Error),
     DeviceJail(minijail::Error),
     DevicePivotRoot(minijail::Error),
+    DirectIo(io::Error),
     Disk(PathBuf, io::Error),
     DiskImageLock(base::Error),
     DropCapabilities(base::Error),
@@ -248,6 +249,7 @@
             CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
             DeviceJail(e) => write!(f, "failed to jail device: {}", e),
             DevicePivotRoot(e) => write!(f, "failed to pivot root device: {}", e),
+            DirectIo(e) => write!(f, "failed to open direct io device: {}", e),
             Disk(p, e) => write!(f, "failed to load disk image {}: {}", p.display(), e),
             DiskImageLock(e) => write!(f, "failed to lock disk image: {}", e),
             DropCapabilities(e) => write!(f, "failed to drop process capabilities: {}", e),
@@ -2496,7 +2498,7 @@
         fs_device_sockets.push(fs_device_socket);
     }
 
-    let linux: RunnableLinuxVm<_, Vcpu, _> = Arch::build_vm(
+    let mut linux: RunnableLinuxVm<_, Vcpu, _> = Arch::build_vm(
         components,
         &cfg.serial_parameters,
         simple_jail(&cfg, "serial")?,
@@ -2524,6 +2526,18 @@
     )
     .map_err(Error::BuildVm)?;
 
+    #[cfg(feature = "direct")]
+    if let Some(pmio) = &cfg.direct_pmio {
+        let direct_io =
+            Arc::new(devices::DirectIo::new(&pmio.path, false).map_err(Error::DirectIo)?);
+        for range in pmio.ranges.iter() {
+            linux
+                .io_bus
+                .insert_sync(direct_io.clone(), range.0, range.1)
+                .unwrap();
+        }
+    };
+
     run_control(
         linux,
         control_server_socket,