openhcl_boot/
cmdline.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Command line arguments and parsing for openhcl_boot.
5
6use underhill_confidentiality::OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME;
7
8/// Enable the private VTL2 GPA pool for page allocations. This is only enabled
9/// via the command line, because in order to support the VTL2 GPA pool
10/// generically, the boot shim must read serialized data from the previous
11/// OpenHCL instance on a servicing boot in order to guarantee the same memory
12/// layout is presented.
13///
14/// The value specified is the number of 4K pages to reserve for the pool.
15///
16/// TODO: Remove this commandline once support for reading saved state is
17/// supported in openhcl_boot.
18const ENABLE_VTL2_GPA_POOL: &str = "OPENHCL_ENABLE_VTL2_GPA_POOL=";
19
20/// Options controlling sidecar.
21///
22/// * `off`: Disable sidecar support.
23/// * `on`: Enable sidecar support. Sidecar will still only be started if
24///   sidecar is present in the binary and supported on the platform. This
25///   is the default.
26/// * `log`: Enable sidecar logging.
27const SIDECAR: &str = "OPENHCL_SIDECAR=";
28
29#[derive(Debug, PartialEq)]
30pub struct BootCommandLineOptions {
31    pub confidential_debug: bool,
32    pub enable_vtl2_gpa_pool: Option<u64>,
33    pub sidecar: bool,
34    pub sidecar_logging: bool,
35}
36
37impl BootCommandLineOptions {
38    pub const fn new() -> Self {
39        BootCommandLineOptions {
40            confidential_debug: false,
41            enable_vtl2_gpa_pool: None,
42            sidecar: true, // sidecar is enabled by default
43            sidecar_logging: false,
44        }
45    }
46}
47
48impl BootCommandLineOptions {
49    /// Parse arguments from a command line.
50    pub fn parse(&mut self, cmdline: &str) {
51        for arg in cmdline.split_whitespace() {
52            if arg.starts_with(OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME) {
53                let arg = arg.split_once('=').map(|(_, arg)| arg);
54                if arg.is_some_and(|a| a != "0") {
55                    self.confidential_debug = true;
56                }
57            } else if arg.starts_with(ENABLE_VTL2_GPA_POOL) {
58                self.enable_vtl2_gpa_pool = arg.split_once('=').and_then(|(_, arg)| {
59                    let num = arg.parse::<u64>().unwrap_or(0);
60                    // A size of 0 or failure to parse is treated as disabling
61                    // the pool.
62                    if num == 0 { None } else { Some(num) }
63                });
64            } else if arg.starts_with(SIDECAR) {
65                if let Some((_, arg)) = arg.split_once('=') {
66                    for arg in arg.split(',') {
67                        match arg {
68                            "off" => self.sidecar = false,
69                            "on" => self.sidecar = true,
70                            "log" => self.sidecar_logging = true,
71                            _ => {}
72                        }
73                    }
74                }
75            }
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    fn parse_boot_command_line(cmdline: &str) -> BootCommandLineOptions {
85        let mut options = BootCommandLineOptions::new();
86        options.parse(cmdline);
87        options
88    }
89
90    #[test]
91    fn test_vtl2_gpa_pool_parsing() {
92        assert_eq!(
93            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=1"),
94            BootCommandLineOptions {
95                enable_vtl2_gpa_pool: Some(1),
96                ..BootCommandLineOptions::new()
97            }
98        );
99        assert_eq!(
100            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=0"),
101            BootCommandLineOptions {
102                enable_vtl2_gpa_pool: None,
103                ..BootCommandLineOptions::new()
104            }
105        );
106        assert_eq!(
107            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=asdf"),
108            BootCommandLineOptions {
109                enable_vtl2_gpa_pool: None,
110                ..BootCommandLineOptions::new()
111            }
112        );
113        assert_eq!(
114            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=512"),
115            BootCommandLineOptions {
116                enable_vtl2_gpa_pool: Some(512),
117                ..BootCommandLineOptions::new()
118            }
119        );
120    }
121
122    #[test]
123    fn test_sidecar_parsing() {
124        assert_eq!(
125            parse_boot_command_line("OPENHCL_SIDECAR=on"),
126            BootCommandLineOptions {
127                sidecar: true,
128                ..BootCommandLineOptions::new()
129            }
130        );
131        assert_eq!(
132            parse_boot_command_line("OPENHCL_SIDECAR=off"),
133            BootCommandLineOptions {
134                sidecar: false,
135                ..BootCommandLineOptions::new()
136            }
137        );
138        assert_eq!(
139            parse_boot_command_line("OPENHCL_SIDECAR=on,off"),
140            BootCommandLineOptions {
141                sidecar: false,
142                ..BootCommandLineOptions::new()
143            }
144        );
145        assert_eq!(
146            parse_boot_command_line("OPENHCL_SIDECAR=on,log"),
147            BootCommandLineOptions {
148                sidecar: true,
149                sidecar_logging: true,
150                ..BootCommandLineOptions::new()
151            }
152        );
153        assert_eq!(
154            parse_boot_command_line("OPENHCL_SIDECAR=log"),
155            BootCommandLineOptions {
156                sidecar: true,
157                sidecar_logging: true,
158                ..BootCommandLineOptions::new()
159            }
160        );
161    }
162}