summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorCody Schuffelen <schuffelen@google.com>2019-05-21 12:12:38 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-05-31 17:21:46 -0700
commit6d1ab5094375afb653d9955fe7ccb818eca48665 (patch)
tree863d07e2334dec3f66961afbdcb8a618b08384e1 /src/main.rs
parent580d4186562c9c1e5b399885c6c5647cdde15243 (diff)
downloadcrosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar.gz
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar.bz2
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar.lz
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar.xz
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.tar.zst
crosvm-6d1ab5094375afb653d9955fe7ccb818eca48665.zip
Initial BIOS support.
The --bios argument is added as an alternative to the kernel positional
argument. The BIOS runs in unreal mode (16-bit cs selector set to the
end of 32-bit address space), which matches the default state KVM puts
the segment and data registers into.

Example usage:
Build u-boot with "make qemu-x86_defconfig && make"
Run crosvm with "crosvm_wrapper.sh run --bios=u-boot.rom"

This produces the following message:
"""
U-Boot 2019.01-00017-gdc76aabe6a-dirty (May 21 2019 - 12:17:02 -0700)

CPU:
DRAM:  16 MiB
unable to get online cpu number: -19
Warning: MP init failure
Model: QEMU x86 (I440FX)
Net:   No ethernet found.
error: can't find etc/table-loader
Hit any key to stop autoboot:  0
=>
"""

At this point the u-boot shell works with stdin/stdout, but virtual
disks passed with --rwdisk weren't immediately visible from running
"virtio scan" and "virtio info".

This change puts the bios loading together with the linux kernel loading
code since there is a lot of overlap in functionality.

Bug: b/133358982
Test: ./crosvm_wrapper.sh run --mem=4097 --bios=u-boot.rom
Change-Id: I65b0e1044233af662a642c592d35b106217f3c13
Reviewed-on: https://chromium-review.googlesource.com/1622648
Commit-Ready: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs81
1 files changed, 48 insertions, 33 deletions
diff --git a/src/main.rs b/src/main.rs
index 4c53760..530d119 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -75,16 +75,29 @@ impl TouchDeviceOption {
     }
 }
 
+#[derive(Debug)]
+pub enum Executable {
+    Bios(PathBuf),
+    Kernel(PathBuf),
+    Plugin(PathBuf),
+}
+
+fn executable_is_plugin(executable: &Option<Executable>) -> bool {
+    match executable {
+        Some(Executable::Plugin(_)) => true,
+        _ => false,
+    }
+}
+
 pub struct Config {
     vcpu_count: Option<u32>,
     vcpu_affinity: Vec<usize>,
     memory: Option<usize>,
-    kernel_path: PathBuf,
+    executable_path: Option<Executable>,
     android_fstab: Option<PathBuf>,
     initrd_path: Option<PathBuf>,
     params: Vec<String>,
     socket_path: Option<PathBuf>,
-    plugin: Option<PathBuf>,
     plugin_root: Option<PathBuf>,
     plugin_mounts: Vec<BindMount>,
     plugin_gid_maps: Vec<GidMap>,
@@ -121,12 +134,11 @@ impl Default for Config {
             vcpu_count: None,
             vcpu_affinity: Vec::new(),
             memory: None,
-            kernel_path: PathBuf::default(),
+            executable_path: None,
             android_fstab: None,
             initrd_path: None,
             params: Vec::new(),
             socket_path: None,
-            plugin: None,
             plugin_root: None,
             plugin_mounts: Vec::new(),
             plugin_gid_maps: Vec::new(),
@@ -285,24 +297,20 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> {
 fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::Result<()> {
     match name {
         "" => {
-            if cfg.plugin.is_some() {
-                return Err(argument::Error::TooManyArguments(
-                    "`plugin` can not be used with kernel".to_owned(),
-                ));
-            } else if !cfg.kernel_path.as_os_str().is_empty() {
-                return Err(argument::Error::TooManyArguments(
-                    "expected exactly one kernel path".to_owned(),
-                ));
-            } else {
-                let kernel_path = PathBuf::from(value.unwrap());
-                if !kernel_path.exists() {
-                    return Err(argument::Error::InvalidValue {
-                        value: value.unwrap().to_owned(),
-                        expected: "this kernel path does not exist",
-                    });
-                }
-                cfg.kernel_path = kernel_path;
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
+            }
+            let kernel_path = PathBuf::from(value.unwrap());
+            if !kernel_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this kernel path does not exist",
+                });
             }
+            cfg.executable_path = Some(Executable::Kernel(kernel_path));
         }
         "android-fstab" => {
             if cfg.android_fstab.is_some()
@@ -572,14 +580,11 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
             cfg.seccomp_policy_dir = PathBuf::from(value.unwrap());
         }
         "plugin" => {
-            if !cfg.kernel_path.as_os_str().is_empty() {
-                return Err(argument::Error::TooManyArguments(
-                    "`plugin` can not be used with kernel".to_owned(),
-                ));
-            } else if cfg.plugin.is_some() {
-                return Err(argument::Error::TooManyArguments(
-                    "`plugin` already given".to_owned(),
-                ));
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
             }
             let plugin = PathBuf::from(value.unwrap().to_owned());
             if plugin.is_relative() {
@@ -588,7 +593,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
                     expected: "the plugin path must be an absolute path",
                 });
             }
-            cfg.plugin = Some(plugin);
+            cfg.executable_path = Some(Executable::Plugin(plugin));
         }
         "plugin-root" => {
             cfg.plugin_root = Some(PathBuf::from(value.unwrap().to_owned()));
@@ -762,6 +767,15 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
         "initrd" => {
             cfg.initrd_path = Some(PathBuf::from(value.unwrap().to_owned()));
         }
+        "bios" => {
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
+            }
+            cfg.executable_path = Some(Executable::Bios(PathBuf::from(value.unwrap().to_owned())));
+        }
         "help" => return Err(argument::Error::PrintHelp),
         _ => unreachable!(),
     }
@@ -844,6 +858,7 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
           Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."),
           #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
           Argument::flag("split-irqchip", "(EXPERIMENTAL) enable split-irqchip support"),
+          Argument::value("bios", "PATH", "Path to BIOS/firmware ROM"),
           Argument::short_flag('h', "help", "Print help message.")];
 
     let mut cfg = Config::default();
@@ -851,7 +866,7 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
         set_argument(&mut cfg, name, value)
     })
     .and_then(|_| {
-        if cfg.kernel_path.as_os_str().is_empty() && cfg.plugin.is_none() {
+        if cfg.executable_path.is_none() {
             return Err(argument::Error::ExpectedArgument("`KERNEL`".to_owned()));
         }
         if cfg.host_ip.is_some() || cfg.netmask.is_some() || cfg.mac_address.is_some() {
@@ -871,7 +886,7 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
                 ));
             }
         }
-        if cfg.plugin_root.is_some() && cfg.plugin.is_none() {
+        if cfg.plugin_root.is_some() && !executable_is_plugin(&cfg.executable_path) {
             return Err(argument::Error::ExpectedArgument(
                 "`plugin-root` requires `plugin`".to_owned(),
             ));
@@ -881,7 +896,7 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
 
     match match_res {
         #[cfg(feature = "plugin")]
-        Ok(()) if cfg.plugin.is_some() => match plugin::run_config(cfg) {
+        Ok(()) if executable_is_plugin(&cfg.executable_path) => match plugin::run_config(cfg) {
             Ok(_) => {
                 info!("crosvm and plugin have exited normally");
                 Ok(())