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: true,
136 vtl2_gpa_pool_numa_split: false,
137 }
138 }
139}
140
141impl BootCommandLineOptions {
142 pub fn parse(&mut self, cmdline: &str) {
144 self.disable_nvme_keep_alive = true;
146
147 let mut override_vtl2_gpa_pool: Option<Vtl2GpaPoolConfig> = None;
148 for arg in cmdline.split_whitespace() {
149 if arg.starts_with(OPENHCL_CONFIDENTIAL_DEBUG_ENV_VAR_NAME) {
150 let arg = arg.split_once('=').map(|(_, arg)| arg);
151 if arg.is_some_and(|a| a != "0") {
152 self.confidential_debug = true;
153 }
154 } else if arg.starts_with(IGVM_VTL2_GPA_POOL_CONFIG) {
155 if let Some((_, arg)) = arg.split_once('=') {
156 self.enable_vtl2_gpa_pool = Vtl2GpaPoolConfig::from(arg);
157 } else {
158 log::warn!("Missing value for IGVM_VTL2_GPA_POOL_CONFIG argument");
159 }
160 } else if arg.starts_with(ENABLE_VTL2_GPA_POOL) {
161 if let Some((_, arg)) = arg.split_once('=') {
162 override_vtl2_gpa_pool = Some(Vtl2GpaPoolConfig::from(arg));
163 } else {
164 log::warn!("Missing value for ENABLE_VTL2_GPA_POOL argument");
165 }
166 } else if arg.starts_with(SIDECAR) {
167 if let Some((_, arg)) = arg.split_once('=') {
168 for arg in arg.split(',') {
169 match arg {
170 "off" => self.sidecar = SidecarOptions::DisabledCommandLine,
171 "on" => {
172 self.sidecar = SidecarOptions::Enabled {
173 enable_logging: false,
174 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
175 }
176 }
177 "log" => {
178 self.sidecar = SidecarOptions::Enabled {
179 enable_logging: true,
180 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
181 }
182 }
183 _ => {}
184 }
185 }
186 }
187 } else if arg.starts_with(DISABLE_NVME_KEEP_ALIVE) {
188 let arg = arg.split_once('=').map(|(_, arg)| arg);
189 if arg.is_some_and(|a| a == "0") {
190 self.disable_nvme_keep_alive = false;
191 }
192 } else if arg.starts_with(VTL2_GPA_POOL_NUMA) {
193 if let Some((_, arg)) = arg.split_once('=') {
194 match arg {
195 "split" => self.vtl2_gpa_pool_numa_split = true,
196 _ => log::warn!("Unknown value for OPENHCL_VTL2_GPA_POOL_NUMA: {arg}"),
197 }
198 }
199 }
200 }
201
202 if let Some(override_config) = override_vtl2_gpa_pool {
203 self.enable_vtl2_gpa_pool = override_config;
204 log::info!(
205 "Overriding VTL2 GPA pool config to {:?} from command line",
206 override_config
207 );
208 }
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 fn parse_boot_command_line(cmdline: &str) -> BootCommandLineOptions {
217 let mut options = BootCommandLineOptions::new();
218 options.parse(cmdline);
219 options
220 }
221
222 #[test]
223 fn test_vtl2_gpa_pool_parsing() {
224 for (cmdline, expected) in [
225 (
226 "",
228 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release),
229 ),
230 (
231 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=1",
232 Vtl2GpaPoolConfig::Pages(1),
233 ),
234 (
235 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=0",
236 Vtl2GpaPoolConfig::Off,
237 ),
238 (
239 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=asdf",
240 Vtl2GpaPoolConfig::Off,
241 ),
242 (
243 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=512",
244 Vtl2GpaPoolConfig::Pages(512),
245 ),
246 (
247 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=off",
248 Vtl2GpaPoolConfig::Off,
249 ),
250 (
251 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=debug",
252 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Debug),
253 ),
254 (
255 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=release",
256 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Release),
257 ),
258 (
259 "OPENHCL_IGVM_VTL2_GPA_POOL_CONFIG=release OPENHCL_ENABLE_VTL2_GPA_POOL=debug",
261 Vtl2GpaPoolConfig::Heuristics(Vtl2GpaPoolLookupTable::Debug),
262 ),
263 ] {
264 assert_eq!(
265 parse_boot_command_line(cmdline).enable_vtl2_gpa_pool,
266 expected,
267 "Failed parsing VTL2 GPA pool config from command line: {}",
268 cmdline
269 );
270 }
271 }
272
273 #[test]
274 fn test_sidecar_parsing() {
275 assert_eq!(
276 parse_boot_command_line("OPENHCL_SIDECAR=on"),
277 BootCommandLineOptions {
278 sidecar: SidecarOptions::Enabled {
279 enable_logging: false,
280 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
281 },
282 ..BootCommandLineOptions::new()
283 }
284 );
285 assert_eq!(
286 parse_boot_command_line("OPENHCL_SIDECAR=off"),
287 BootCommandLineOptions {
288 sidecar: SidecarOptions::DisabledCommandLine,
289 ..BootCommandLineOptions::new()
290 }
291 );
292 assert_eq!(
293 parse_boot_command_line("OPENHCL_SIDECAR=on,off"),
294 BootCommandLineOptions {
295 sidecar: SidecarOptions::DisabledCommandLine,
296 ..BootCommandLineOptions::new()
297 }
298 );
299 assert_eq!(
300 parse_boot_command_line("OPENHCL_SIDECAR=on,log"),
301 BootCommandLineOptions {
302 sidecar: SidecarOptions::Enabled {
303 enable_logging: true,
304 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
305 },
306 ..BootCommandLineOptions::new()
307 }
308 );
309 assert_eq!(
310 parse_boot_command_line("OPENHCL_SIDECAR=log"),
311 BootCommandLineOptions {
312 sidecar: SidecarOptions::Enabled {
313 enable_logging: true,
314 cpu_threshold: SidecarOptions::DEFAULT_CPU_THRESHOLD,
315 },
316 ..BootCommandLineOptions::new()
317 }
318 );
319 }
320}