crosvm: pstore works for ARCVM on x86_64

Adds support for pstore on ARCVM on x86_64.
The backend file of the buffer will be passed via argument of the crosvm.

BUG=b:144962428
TEST=kernel crash on eve-arcvm, check /sys/fs/pstore/console-ramoops-0
     Launch crostini manually on eve-arcvm

Change-Id: I29492ac7a9067aa2ae23eb03fbb942ab7dd3aa8d
Signed-off-by: Kansho Nishida <kansho@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1973391
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Kansho Nishida <kansho@chromium.org>
diff --git a/src/main.rs b/src/main.rs
index 45efc0f..e053082 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,6 +16,7 @@
 use std::thread::sleep;
 use std::time::Duration;
 
+use arch::Pstore;
 use crosvm::{
     argument::{self, print_help, set_arguments, Argument},
     linux, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption,
@@ -577,6 +578,47 @@
                 block_size: sys_util::pagesize() as u32,
             });
         }
+        "pstore" => {
+            if cfg.pstore.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`pstore` already given".to_owned(),
+                ));
+            }
+
+            let value = value.unwrap();
+            let components: Vec<&str> = value.split(',').collect();
+            if components.len() != 2 {
+                return Err(argument::Error::InvalidValue {
+                    value: value.to_owned(),
+                    expected: "pstore must have exactly 2 components: path=<path>,size=<size>",
+                });
+            }
+            cfg.pstore = Some(Pstore {
+                path: {
+                    if components[0].len() <= 5 || !components[0].starts_with("path=") {
+                        return Err(argument::Error::InvalidValue {
+                            value: components[0].to_owned(),
+                            expected: "pstore path must follow with `path=`",
+                        });
+                    };
+                    PathBuf::from(&components[0][5..])
+                },
+                size: {
+                    if components[1].len() <= 5 || !components[1].starts_with("size=") {
+                        return Err(argument::Error::InvalidValue {
+                            value: components[1].to_owned(),
+                            expected: "pstore size must follow with `size=`",
+                        });
+                    };
+                    components[1][5..]
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.to_owned(),
+                            expected: "pstore size must be an integer",
+                        })?
+                },
+            });
+        }
         "host_ip" => {
             if cfg.host_ip.is_some() {
                 return Err(argument::Error::TooManyArguments(
@@ -1059,6 +1101,7 @@
           Argument::value("rwqcow", "PATH", "Path to a writable qcow2 disk image. (Deprecated; use --rwdisk instead.)"),
           Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
           Argument::value("pmem-device", "PATH", "Path to a disk image."),
+          Argument::value("pstore", "path=PATH,size=SIZE", "Path to pstore buffer backend file follewed by size."),
           Argument::value("host_ip",
                           "IP",
                           "IP address to assign to host tap interface."),