qemu_command_builder/
accel.rs

1use std::path::PathBuf;
2
3use bon::Builder;
4
5use crate::common::*;
6use crate::to_command::{ToArg, ToCommand};
7
8#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default)]
9pub enum OnOffSplit {
10    #[default]
11    On,
12    Off,
13    Split,
14}
15
16impl ToArg for OnOffSplit {
17    fn to_arg(&self) -> &str {
18        match self {
19            OnOffSplit::On => "on",
20            OnOffSplit::Off => "off",
21            OnOffSplit::Split => "split",
22        }
23    }
24}
25
26#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
27pub enum TCGThreadType {
28    Single,
29    Multi,
30}
31
32impl ToArg for TCGThreadType {
33    fn to_arg(&self) -> &str {
34        match self {
35            TCGThreadType::Single => "single",
36            TCGThreadType::Multi => "multi",
37        }
38    }
39}
40
41#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
42pub enum NotifyVMExitType {
43    Run,
44    InternalError,
45    Disable,
46    NotifyWindow(usize),
47}
48
49/// This is used to enable an accelerator. Depending on the target
50/// architecture, kvm, xen, hvf, nvmm, whpx or tcg can be available. By
51/// default, tcg is used. If there is more than one accelerator
52/// specified, the next one is used if the previous one fails to
53/// initialize.
54#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder)]
55pub struct Accel {
56    accel_type: AccelType,
57
58    /// When Xen is in use, this option controls whether Intel
59    /// integrated graphics devices can be passed through to the guest
60    /// (default=off)
61    igd_passthru: Option<OnOffDefaultOff>,
62
63    /// Controls KVM in-kernel irqchip support. The default is full
64    /// acceleration of the interrupt controllers. On x86, split irqchip
65    /// reduces the kernel attack surface, at a performance cost for
66    /// non-MSI interrupts. Disabling the in-kernel irqchip completely
67    /// is not recommended except for debugging purposes.
68    kernel_irqchip: Option<OnOffSplit>,
69
70    /// Defines the size of the KVM shadow MMU.
71    kvm_shadow_mem: Option<usize>, // TODO convert to a byte type
72
73    /// Makes the TCG accelerator put only one guest instruction into
74    /// each translation block. This slows down emulation a lot, but
75    /// can be useful in some situations, such as when trying to analyse
76    /// the logs produced by the ``-d`` option.
77    one_insn_per_tb: Option<OnOff>,
78
79    /// Controls the use of split w^x mapping for the TCG code generation
80    /// buffer. Some operating systems require this to be enabled, and in
81    /// such a case this will default on. On other operating systems, this
82    /// will default off, but one may enable this for testing or debugging.
83    split_wx: Option<OnOff>,
84
85    /// Controls the size (in MiB) of the TCG translation block cache.
86    tb_size: Option<usize>, // TODO convert to a byte type
87
88    /// When the KVM accelerator is used, it controls the size of the per-vCPU
89    /// dirty page ring buffer (number of entries for each vCPU). It should
90    /// be a value that is power of two, and it should be 1024 or bigger (but
91    /// still less than the maximum value that the kernel supports).  4096
92    /// could be a good initial value if you have no idea which is the best.
93    /// Set this value to 0 to disable the feature.  By default, this feature
94    /// is disabled (dirty-ring-size=0).  When enabled, KVM will instead
95    /// record dirty pages in a bitmap.
96    dirty_ring_size: Option<usize>,
97
98    /// KVM implements dirty page logging at the PAGE_SIZE granularity and
99    /// enabling dirty-logging on a huge-page requires breaking it into
100    /// PAGE_SIZE pages in the first place. KVM on ARM does this splitting
101    /// lazily by default. There are performance benefits in doing huge-page
102    /// split eagerly, especially in situations where TLBI costs associated
103    /// with break-before-make sequences are considerable and also if guest
104    /// workloads are read intensive. The size here specifies how many pages
105    /// to break at a time and needs to be a valid block size which is
106    /// 1GB/2MB/4KB, 32MB/16KB and 512MB/64KB for 4KB/16KB/64KB PAGE_SIZE
107    /// respectively. Be wary of specifying a higher size as it will have an
108    /// impact on the memory. By default, this feature is disabled
109    /// (eager-split-size=0).
110    eager_split_size: Option<usize>,
111
112    /// Enables or disables notify VM exit support on x86 host and specify
113    /// the corresponding notify window to trigger the VM exit if enabled.
114    /// ``run`` option enables the feature. It does nothing and continue
115    /// if the exit happens. ``internal-error`` option enables the feature.
116    /// It raises a internal error. ``disable`` option doesn't enable the feature.
117    /// This feature can mitigate the CPU stuck issue due to event windows don't
118    /// open up for a specified of time (i.e. notify-window).
119    /// Default: notify-vmexit=run,notify-window=0.
120    notify_vmexit: Option<Vec<NotifyVMExitType>>,
121
122    /// Enable single or multi-threaded TCG
123    thread: Option<TCGThreadType>,
124
125    /// Sets the path to the KVM device node. Defaults to ``/dev/kvm``. This
126    /// option can be used to pass the KVM device to use via a file descriptor
127    /// by setting the value to ``/dev/fdset/NN``.
128    device: Option<PathBuf>,
129}
130
131impl ToCommand for Accel {
132    fn to_command(&self) -> Vec<String> {
133        let mut cmd = vec![];
134        cmd.push("-accel".to_string());
135
136        let mut args = vec![self.accel_type.to_arg().to_string()];
137
138        if let Some(igd_passthru) = &self.igd_passthru {
139            args.push(format!("igd-passthru={}", igd_passthru.to_arg()));
140        }
141        if let Some(kernel_irqchip) = &self.kernel_irqchip {
142            args.push(format!("kernel_irqchip={}", kernel_irqchip.to_arg()));
143        }
144        if let Some(kvm_shadow_mem) = &self.kvm_shadow_mem {
145            args.push(format!("kvm-shadow-mem={}", kvm_shadow_mem));
146        }
147        if let Some(one_insn_per_tb) = &self.one_insn_per_tb {
148            args.push(format!("one-insn-per-tb={}", one_insn_per_tb.to_arg()));
149        }
150        if let Some(split_wx) = &self.split_wx {
151            args.push(format!("split-wx={}", split_wx.to_arg()));
152        }
153        if let Some(tb_size) = &self.tb_size {
154            args.push(format!("tb-size={}", tb_size));
155        }
156        if let Some(dirty_ring_size) = &self.dirty_ring_size {
157            args.push(format!("dirty-ring-size={}", dirty_ring_size));
158        }
159        if let Some(eager_split_size) = &self.eager_split_size {
160            args.push(format!("eager-split-size={}", eager_split_size));
161        }
162        if let Some(notify_vmexit) = &self.notify_vmexit {
163            let mut nvm_args = vec![];
164            for opt in notify_vmexit {
165                match opt {
166                    NotifyVMExitType::Run => {
167                        nvm_args.push("run".to_string());
168                    }
169                    NotifyVMExitType::InternalError => {
170                        nvm_args.push("internal-error".to_string());
171                    }
172                    NotifyVMExitType::Disable => {
173                        nvm_args.push("disable".to_string());
174                    }
175                    NotifyVMExitType::NotifyWindow(window) => {
176                        nvm_args.push(format!("notify-window={}", window));
177                    }
178                }
179            }
180            args.push(format!("notify-vmexit=={}", nvm_args.join(",")));
181        }
182        if let Some(thread) = &self.thread {
183            args.push(format!("thread={}", thread.to_arg()));
184        }
185        if let Some(device) = &self.device {
186            args.push(format!("device={}", device.display()));
187        }
188        cmd.push(args.join(","));
189        cmd
190    }
191}