crosvm: MMIO forwarding.

BUG=b:188011323
TEST=None

Change-Id: I93b722893c29add6e5de173d40ff1523d2b3a687
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2925137
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Junichi Uekawa <uekawa@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/src/crosvm.rs b/src/crosvm.rs
index 9b02a8d..49848ba 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -376,6 +376,8 @@
     #[cfg(feature = "direct")]
     pub direct_pmio: Option<DirectIoOption>,
     #[cfg(feature = "direct")]
+    pub direct_mmio: Option<DirectIoOption>,
+    #[cfg(feature = "direct")]
     pub direct_level_irq: Vec<u32>,
     #[cfg(feature = "direct")]
     pub direct_edge_irq: Vec<u32>,
@@ -468,6 +470,8 @@
             #[cfg(feature = "direct")]
             direct_pmio: None,
             #[cfg(feature = "direct")]
+            direct_mmio: None,
+            #[cfg(feature = "direct")]
             direct_level_irq: Vec::new(),
             #[cfg(feature = "direct")]
             direct_edge_irq: Vec::new(),
diff --git a/src/linux.rs b/src/linux.rs
index 39a2ac7..d087a68 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -2646,6 +2646,18 @@
     };
 
     #[cfg(feature = "direct")]
+    if let Some(mmio) = &cfg.direct_mmio {
+        let direct_io =
+            Arc::new(devices::DirectIo::new(&mmio.path, false).map_err(Error::DirectIo)?);
+        for range in mmio.ranges.iter() {
+            linux
+                .mmio_bus
+                .insert_sync(direct_io.clone(), range.0, range.1)
+                .unwrap();
+        }
+    };
+
+    #[cfg(feature = "direct")]
     let mut irqs = Vec::new();
 
     #[cfg(feature = "direct")]
diff --git a/src/main.rs b/src/main.rs
index 724a3fd..0b0bb53 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1917,6 +1917,15 @@
             cfg.direct_pmio = Some(parse_direct_io_options(value)?);
         }
         #[cfg(feature = "direct")]
+        "direct-mmio" => {
+            if cfg.direct_mmio.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`direct_mmio` already given".to_owned(),
+                ));
+            }
+            cfg.direct_mmio = Some(parse_direct_io_options(value)?);
+        }
+        #[cfg(feature = "direct")]
         "direct-level-irq" => {
             cfg.direct_level_irq
                 .push(
@@ -2230,7 +2239,9 @@
           Argument::value("vhost-user-fs", "SOCKET_PATH:TAG",
                           "Path to a socket path for vhost-user fs, and tag for the shared dir"),
           #[cfg(feature = "direct")]
-          Argument::value("direct-pmio", "PATH@RANGE[,RANGE[,...]]", "Path and ranges for direct port I/O access"),
+          Argument::value("direct-pmio", "PATH@RANGE[,RANGE[,...]]", "Path and ranges for direct port mapped I/O access"),
+          #[cfg(feature = "direct")]
+          Argument::value("direct-mmio", "PATH@RANGE[,RANGE[,...]]", "Path and ranges for direct memory mapped I/O access"),
           #[cfg(feature = "direct")]
           Argument::value("direct-level-irq", "irq", "Enable interrupt passthrough"),
           #[cfg(feature = "direct")]