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 crate::boot_logger::LoggerType;
7use underhill_confidentiality::OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME;
8
9/// Enable boot logging in the bootloader.
10///
11/// Format of `OPENHCL_BOOT_LOG=<logger>`, with valid loggers being:
12///     - `com3`: use the com3 serial port, available on no isolation or Tdx.
13const BOOT_LOG: &str = "OPENHCL_BOOT_LOG=";
14const SERIAL_LOGGER: &str = "com3";
15
16/// Enable the private VTL2 GPA pool for page allocations. This is only enabled
17/// via the command line, because in order to support the VTL2 GPA pool
18/// generically, the boot shim must read serialized data from the previous
19/// OpenHCL instance on a servicing boot in order to guarantee the same memory
20/// layout is presented.
21///
22/// The value specified is the number of 4K pages to reserve for the pool.
23///
24/// TODO: Remove this commandline once support for reading saved state is
25/// supported in openhcl_boot.
26const ENABLE_VTL2_GPA_POOL: &str = "OPENHCL_ENABLE_VTL2_GPA_POOL=";
27
28/// Options controlling sidecar.
29///
30/// * `off`: Disable sidecar support.
31/// * `on`: Enable sidecar support. Sidecar will still only be started if
32///   sidecar is present in the binary and supported on the platform. This
33///   is the default.
34/// * `log`: Enable sidecar logging.
35const SIDECAR: &str = "OPENHCL_SIDECAR=";
36
37#[derive(Debug, PartialEq)]
38pub struct BootCommandLineOptions {
39    pub logger: Option<LoggerType>,
40    pub confidential_debug: bool,
41    pub enable_vtl2_gpa_pool: Option<u64>,
42    pub sidecar: bool,
43    pub sidecar_logging: bool,
44}
45
46impl BootCommandLineOptions {
47    pub const fn new() -> Self {
48        BootCommandLineOptions {
49            logger: None,
50            confidential_debug: false,
51            enable_vtl2_gpa_pool: None,
52            sidecar: true, // sidecar is enabled by default
53            sidecar_logging: false,
54        }
55    }
56}
57
58impl BootCommandLineOptions {
59    /// Parse arguments from a command line.
60    pub fn parse(&mut self, cmdline: &str) {
61        for arg in cmdline.split_whitespace() {
62            if arg.starts_with(BOOT_LOG) {
63                if let Some(SERIAL_LOGGER) = arg.split_once('=').map(|(_, arg)| arg) {
64                    self.logger = Some(LoggerType::Serial)
65                }
66            } else if arg.starts_with(OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME) {
67                let arg = arg.split_once('=').map(|(_, arg)| arg);
68                if arg.is_some_and(|a| a != "0") {
69                    self.confidential_debug = true;
70                    // Explicit logger specification overrides this default.
71                    if self.logger.is_none() {
72                        self.logger = Some(LoggerType::Serial);
73                    }
74                }
75            } else if arg.starts_with(ENABLE_VTL2_GPA_POOL) {
76                self.enable_vtl2_gpa_pool = arg.split_once('=').and_then(|(_, arg)| {
77                    let num = arg.parse::<u64>().unwrap_or(0);
78                    // A size of 0 or failure to parse is treated as disabling
79                    // the pool.
80                    if num == 0 { None } else { Some(num) }
81                });
82            } else if arg.starts_with(SIDECAR) {
83                if let Some((_, arg)) = arg.split_once('=') {
84                    for arg in arg.split(',') {
85                        match arg {
86                            "off" => self.sidecar = false,
87                            "on" => self.sidecar = true,
88                            "log" => self.sidecar_logging = true,
89                            _ => {}
90                        }
91                    }
92                }
93            }
94        }
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    fn parse_boot_command_line(cmdline: &str) -> BootCommandLineOptions {
103        let mut options = BootCommandLineOptions::new();
104        options.parse(cmdline);
105        options
106    }
107
108    #[test]
109    fn test_console_parsing() {
110        assert_eq!(
111            parse_boot_command_line("OPENHCL_BOOT_LOG=com3"),
112            BootCommandLineOptions {
113                logger: Some(LoggerType::Serial),
114                ..BootCommandLineOptions::new()
115            }
116        );
117
118        assert_eq!(
119            parse_boot_command_line("OPENHCL_BOOT_LOG=1"),
120            BootCommandLineOptions {
121                logger: None,
122                ..BootCommandLineOptions::new()
123            }
124        );
125
126        assert_eq!(
127            parse_boot_command_line("OPENHCL_BOOT_LOG=random"),
128            BootCommandLineOptions {
129                logger: None,
130                ..BootCommandLineOptions::new()
131            }
132        );
133
134        assert_eq!(
135            parse_boot_command_line("OPENHCL_BOOT_LOG==com3"),
136            BootCommandLineOptions {
137                logger: None,
138                ..BootCommandLineOptions::new()
139            }
140        );
141
142        assert_eq!(
143            parse_boot_command_line("OPENHCL_BOOT_LOGserial"),
144            BootCommandLineOptions {
145                logger: None,
146                ..BootCommandLineOptions::new()
147            }
148        );
149
150        let cmdline = format!("{OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME}=1");
151        assert_eq!(
152            parse_boot_command_line(&cmdline),
153            BootCommandLineOptions {
154                logger: Some(LoggerType::Serial),
155                confidential_debug: true,
156                ..BootCommandLineOptions::new()
157            }
158        );
159    }
160
161    #[test]
162    fn test_vtl2_gpa_pool_parsing() {
163        assert_eq!(
164            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=1"),
165            BootCommandLineOptions {
166                enable_vtl2_gpa_pool: Some(1),
167                ..BootCommandLineOptions::new()
168            }
169        );
170        assert_eq!(
171            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=0"),
172            BootCommandLineOptions {
173                enable_vtl2_gpa_pool: None,
174                ..BootCommandLineOptions::new()
175            }
176        );
177        assert_eq!(
178            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=asdf"),
179            BootCommandLineOptions {
180                enable_vtl2_gpa_pool: None,
181                ..BootCommandLineOptions::new()
182            }
183        );
184        assert_eq!(
185            parse_boot_command_line("OPENHCL_ENABLE_VTL2_GPA_POOL=512"),
186            BootCommandLineOptions {
187                enable_vtl2_gpa_pool: Some(512),
188                ..BootCommandLineOptions::new()
189            }
190        );
191    }
192
193    #[test]
194    fn test_sidecar_parsing() {
195        assert_eq!(
196            parse_boot_command_line("OPENHCL_SIDECAR=on"),
197            BootCommandLineOptions {
198                sidecar: true,
199                ..BootCommandLineOptions::new()
200            }
201        );
202        assert_eq!(
203            parse_boot_command_line("OPENHCL_SIDECAR=off"),
204            BootCommandLineOptions {
205                sidecar: false,
206                ..BootCommandLineOptions::new()
207            }
208        );
209        assert_eq!(
210            parse_boot_command_line("OPENHCL_SIDECAR=on,off"),
211            BootCommandLineOptions {
212                sidecar: false,
213                ..BootCommandLineOptions::new()
214            }
215        );
216        assert_eq!(
217            parse_boot_command_line("OPENHCL_SIDECAR=on,log"),
218            BootCommandLineOptions {
219                sidecar: true,
220                sidecar_logging: true,
221                ..BootCommandLineOptions::new()
222            }
223        );
224        assert_eq!(
225            parse_boot_command_line("OPENHCL_SIDECAR=log"),
226            BootCommandLineOptions {
227                sidecar: true,
228                sidecar_logging: true,
229                ..BootCommandLineOptions::new()
230            }
231        );
232    }
233}