vmm/vmm_config/
boot_source.rs1use std::fs::File;
5use std::io;
6
7use serde::{Deserialize, Serialize};
8
9pub const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 nomodule 8250.nr_uarts=0 i8042.noaux \
19 i8042.nomux i8042.dumbkbd swiotlb=noforce";
20
21#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
24#[serde(deny_unknown_fields)]
25pub struct BootSourceConfig {
26 pub kernel_image_path: String,
28 pub initrd_path: Option<String>,
30 pub boot_args: Option<String>,
33}
34
35#[derive(Debug, thiserror::Error, displaydoc::Display)]
37pub enum BootSourceConfigError {
38 InvalidKernelPath(io::Error),
40 InvalidInitrdPath(io::Error),
42 InvalidKernelCommandLine(String),
44}
45
46#[derive(Debug, Default)]
48pub struct BootSource {
49 pub config: BootSourceConfig,
51 pub builder: Option<BootConfig>,
54}
55
56#[derive(Debug)]
58pub struct BootConfig {
59 pub cmdline: linux_loader::cmdline::Cmdline,
61 pub kernel_file: File,
63 pub initrd_file: Option<File>,
65}
66
67impl BootConfig {
68 pub fn new(cfg: &BootSourceConfig) -> Result<Self, BootSourceConfigError> {
70 use self::BootSourceConfigError::{
71 InvalidInitrdPath, InvalidKernelCommandLine, InvalidKernelPath,
72 };
73
74 let kernel_file = File::open(&cfg.kernel_image_path).map_err(InvalidKernelPath)?;
76 let initrd_file: Option<File> = match &cfg.initrd_path {
77 Some(path) => Some(File::open(path).map_err(InvalidInitrdPath)?),
78 None => None,
79 };
80
81 let cmdline_str = match cfg.boot_args.as_ref() {
82 None => DEFAULT_KERNEL_CMDLINE,
83 Some(str) => str.as_str(),
84 };
85 let cmdline =
86 linux_loader::cmdline::Cmdline::try_from(cmdline_str, crate::arch::CMDLINE_MAX_SIZE)
87 .map_err(|err| InvalidKernelCommandLine(err.to_string()))?;
88
89 Ok(BootConfig {
90 cmdline,
91 kernel_file,
92 initrd_file,
93 })
94 }
95}
96
97#[cfg(test)]
98pub(crate) mod tests {
99 use vmm_sys_util::tempfile::TempFile;
100
101 use super::*;
102 use crate::snapshot::Snapshot;
103
104 #[test]
105 fn test_boot_config() {
106 let kernel_file = TempFile::new().unwrap();
107 let kernel_path = kernel_file.as_path().to_str().unwrap().to_string();
108
109 let boot_src_cfg = BootSourceConfig {
110 boot_args: None,
111 initrd_path: None,
112 kernel_image_path: kernel_path,
113 };
114
115 let boot_cfg = BootConfig::new(&boot_src_cfg).unwrap();
116 assert!(boot_cfg.initrd_file.is_none());
117 assert_eq!(
118 boot_cfg.cmdline.as_cstring().unwrap().as_bytes_with_nul(),
119 [DEFAULT_KERNEL_CMDLINE.as_bytes(), b"\0"].concat()
120 );
121 }
122
123 #[test]
124 fn test_serde() {
125 let boot_src_cfg = BootSourceConfig {
126 boot_args: Some(DEFAULT_KERNEL_CMDLINE.to_string()),
127 initrd_path: Some("/tmp/initrd".to_string()),
128 kernel_image_path: "./vmlinux.bin".to_string(),
129 };
130
131 let mut snapshot_data = vec![0u8; 1000];
132 Snapshot::new(&boot_src_cfg)
133 .save(&mut snapshot_data.as_mut_slice())
134 .unwrap();
135 let restored_boot_cfg = Snapshot::load_without_crc_check(snapshot_data.as_slice())
136 .unwrap()
137 .data;
138 assert_eq!(boot_src_cfg, restored_boot_cfg);
139 }
140}