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