1use underhill_confidentiality::OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME;
7
8const IGVM_VTL2_GPA_POOL_CONFIG: &str = "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=";
18
19const ENABLE_VTL2_GPA_POOL: &str = "OPENHCL_ENABLE_VTL2_GPA_POOL=";
23
24const SIDECAR: &str = "OPENHCL_SIDECAR=";
32
33const DISABLE_NVME_KEEP_ALIVE: &str = "OPENHCL_DISABLE_NVME_KEEP_ALIVE=";
35
36const VTL2_GPA_POOL_NUMA: &str = "OPENHCL_VTL2_GPA_POOL_NUMA=";
42
43#[derive(Debug, PartialEq, Clone, Copy)]
45pub enum Vtl2GpaPoolLookupTable {
46 Release,
47 Debug,
48}
49
50#[derive(Debug, PartialEq, Clone, Copy)]
51pub enum Vtl2GpaPoolConfig {
52 Heuristics(Vtl2GpaPoolLookupTable),
64
65 Off,
67
68 Pages(u64),
70}
71
72impl<S: AsRef<str>> From<S> for Vtl2GpaPoolConfig {
73 fn from(arg: S) -> Self {
74 match arg.as_ref() {
75 "debug" => Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Debug),
76 "release" => Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release),
77 "off" => Vtl2GpaPoolConfig::Off,
78 _ => {
79 let num = arg.as_ref().parse::<u64>().unwrap_or(0);
80 if num == 0 {
83 Vtl2GpaPoolConfig::Off
84 } else {
85 Vtl2GpaPoolConfig::Pages(num)
86 }
87 }
88 }
89 }
90}
91
92#[derive(Debug, PartialEq)]
93pub enum SidecarOptions {
94 Enabled {
98 enable_logging: bool,
99 cpu_threshold: Option<u32>,
100 },
101 DisabledServicing,
104 DisabledCommandLine,
106}
107
108impl SidecarOptions {
109 pub const DEFAULT_CPU_THRESHOLD: Option<u32> = Some(100);
110 pub const fn default() -> Self {
111 SidecarOptions::Enabled {
112 enable_logging: false,
113 cpu_threshold: Self::DEFAULT_CPU_THRESHOLD,
114 }
115 }
116}
117
118#[derive(Debug, PartialEq)]
119pub struct BootCommandLineOptions {
120 pub confidential_debug: bool,
121 pub enable_vtl2_gpa_pool: Vtl2GpaPoolConfig,
122 pub sidecar: SidecarOptions,
123 pub disable_nvme_keep_alive: bool,
124 pub vtl2_gpa_pool_numa_split: bool,
127}
128
129impl BootCommandLineOptions {
130 pub const fn new() -> Self {
131 BootCommandLineOptions {
132 confidential_debug: false,
133 enable_vtl2_gpa_pool: Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release), sidecar: SidecarOptions::default(),
135 disable_nvme_keep_alive: false,
136 vtl2_gpa_pool_numa_split: false,
137 }
138 }
139}
140
141impl BootCommandLineOptions {
142 pub fn parse(&mut self, cmdline: &str) {
144 let mut override_vtl2_gpa_pool: Option<Vtl2GpaPoolConfig> = None;
145 for arg in cmdline.split_whitespace() {
146 if arg.starts_with(OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME) {
147 let arg = arg.split_once('=').map(|(_, arg)| arg);
148 if arg.is_some_and(|a| a != "0") {
149 self.confidential_debug = true;
150 }
151 } else if arg.starts_with(IGVM_VTL2_GPA_POOL_CONFIG) {
152 if let Some((_, arg)) = arg.split_once('=') {
153 self.enable_vtl2_gpa_pool = Vtl2GpaPoolConfig::from(arg);
154 } else {
155 log::warn!("Missing value for IGVM_VTL2_GPA_POOL_CONFIG argument");
156 }
157 } else if arg.starts_with(ENABLE_VTL2_GPA_POOL) {
158 if let Some((_, arg)) = arg.split_once('=') {
159 override_vtl2_gpa_pool = Some(Vtl2GpaPoolConfig::from(arg));
160 } else {
161 log::warn!("Missing value for ENABLE_VTL2_GPA_POOL argument");
162 }
163 } else if arg.starts_with(SIDECAR) {
164 if let Some((_, arg)) = arg.split_once('=') {
165 for arg in arg.split(',') {
166 match arg {
167 "off" => self.sidecar = SidecarOptions::DisabledCommandLine,
168 "on" => {
169 self.sidecar = SidecarOptions::Enabled {
170 enable_logging: false,
171 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
172 }
173 }
174 "log" => {
175 self.sidecar = SidecarOptions::Enabled {
176 enable_logging: true,
177 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
178 }
179 }
180 _ => {}
181 }
182 }
183 }
184 } else if arg.starts_with(DISABLE_NVME_KEEP_ALIVE) {
185 let arg = arg.split_once('=').map(|(_, arg)| arg);
186 if arg.is_some_and(|a| a != "0") {
187 self.disable_nvme_keep_alive = true;
188 }
189 } else if arg.starts_with(VTL2_GPA_POOL_NUMA) {
190 if let Some((_, arg)) = arg.split_once('=') {
191 match arg {
192 "split" => self.vtl2_gpa_pool_numa_split = true,
193 _ => log::warn!("Unknown value for OPENHCL_VTL2_GPA_POOL_NUMA: {arg}"),
194 }
195 }
196 }
197 }
198
199 if let Some(override_config) = override_vtl2_gpa_pool {
200 self.enable_vtl2_gpa_pool = override_config;
201 log::info!(
202 "Overriding VTL2 GPA pool config to {:?} from command line",
203 override_config
204 );
205 }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 fn parse_boot_command_line(cmdline: &str) -> BootCommandLineOptions {
214 let mut options = BootCommandLineOptions::new();
215 options.parse(cmdline);
216 options
217 }
218
219 #[test]
220 fn test_vtl2_gpa_pool_parsing() {
221 for (cmdline, expected) in [
222 (
223 "",
225 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release),
226 ),
227 (
228 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=1",
229 Vtl2GpaPoolConfig::Pages(1),
230 ),
231 (
232 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=0",
233 Vtl2GpaPoolConfig::Off,
234 ),
235 (
236 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=asdf",
237 Vtl2GpaPoolConfig::Off,
238 ),
239 (
240 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=512",
241 Vtl2GpaPoolConfig::Pages(512),
242 ),
243 (
244 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=off",
245 Vtl2GpaPoolConfig::Off,
246 ),
247 (
248 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=debug",
249 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Debug),
250 ),
251 (
252 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=release",
253 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release),
254 ),
255 (
256 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=release OPENHCL_ENABLE_VTL2_GPA_POOL=debug",
258 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Debug),
259 ),
260 ] {
261 assert_eq!(
262 parse_boot_command_line(cmdline).enable_vtl2_gpa_pool,
263 expected,
264 "Failed parsing VTL2 GPA pool config from command line: {}",
265 cmdline
266 );
267 }
268 }
269
270 #[test]
271 fn test_sidecar_parsing() {
272 assert_eq!(
273 parse_boot_command_line("OPENHCL_SIDECAR=on"),
274 BootCommandLineOptions {
275 sidecar: SidecarOptions::Enabled {
276 enable_logging: false,
277 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
278 },
279 ..BootCommandLineOptions::new()
280 }
281 );
282 assert_eq!(
283 parse_boot_command_line("OPENHCL_SIDECAR=off"),
284 BootCommandLineOptions {
285 sidecar: SidecarOptions::DisabledCommandLine,
286 ..BootCommandLineOptions::new()
287 }
288 );
289 assert_eq!(
290 parse_boot_command_line("OPENHCL_SIDECAR=on,off"),
291 BootCommandLineOptions {
292 sidecar: SidecarOptions::DisabledCommandLine,
293 ..BootCommandLineOptions::new()
294 }
295 );
296 assert_eq!(
297 parse_boot_command_line("OPENHCL_SIDECAR=on,log"),
298 BootCommandLineOptions {
299 sidecar: SidecarOptions::Enabled {
300 enable_logging: true,
301 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
302 },
303 ..BootCommandLineOptions::new()
304 }
305 );
306 assert_eq!(
307 parse_boot_command_line("OPENHCL_SIDECAR=log"),
308 BootCommandLineOptions {
309 sidecar: SidecarOptions::Enabled {
310 enable_logging: true,
311 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
312 },
313 ..BootCommandLineOptions::new()
314 }
315 );
316 }
317}