diff --git a/0001-Micro-fix-the-ioctl-allow-for-aarch64.patch b/0001-Micro-fix-the-ioctl-allow-for-aarch64.patch new file mode 100644 index 0000000000000000000000000000000000000000..a863589c01d2b4af9cccea2b332bae6337468234 --- /dev/null +++ b/0001-Micro-fix-the-ioctl-allow-for-aarch64.patch @@ -0,0 +1,44 @@ +diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs +index d7e1b1d..42e9171 100644 +--- a/machine/src/aarch64/micro.rs ++++ b/machine/src/aarch64/micro.rs +@@ -235,6 +235,7 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_ONE_REG() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DEVICE_ATTR() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_REG_LIST() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_ONE_REG() as u32) + } + + pub(crate) fn arch_syscall_whitelist() -> Vec { +diff --git a/machine/src/micro_common/syscall.rs b/machine/src/micro_common/syscall.rs +index fe03164..6ae9a56 100644 +--- a/machine/src/micro_common/syscall.rs ++++ b/machine/src/micro_common/syscall.rs +@@ -86,6 +86,7 @@ pub fn syscall_whitelist() -> Vec { + BpfRule::new(libc::SYS_accept4), + BpfRule::new(libc::SYS_lseek), + futex_rule(), ++ BpfRule::new(libc::SYS_clone), + BpfRule::new(libc::SYS_exit), + BpfRule::new(libc::SYS_exit_group), + BpfRule::new(libc::SYS_rt_sigreturn), +@@ -158,6 +159,7 @@ fn ioctl_allow_list() -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_API_VERSION() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32); + arch_ioctl_allow_list(bpf_rule) + } +diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs +index d8fb92e..7b4e08e 100644 +--- a/machine/src/x86_64/micro.rs ++++ b/machine/src/x86_64/micro.rs +@@ -238,7 +238,6 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_LAPIC() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MSRS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MSRS() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_CPUID2() as u32) + } + diff --git a/0002-snapshot-bugfix-VM-run-failed-from-memory-snapshot.patch b/0002-snapshot-bugfix-VM-run-failed-from-memory-snapshot.patch new file mode 100644 index 0000000000000000000000000000000000000000..e1445ecda2f2cca672ef669f1642b16744b2edc6 --- /dev/null +++ b/0002-snapshot-bugfix-VM-run-failed-from-memory-snapshot.patch @@ -0,0 +1,302 @@ +From 3a5ef152b5e803998e6ec5a1e7172c01fcce8bcf Mon Sep 17 00:00:00 2001 +From: l00484210 +Date: Wed, 11 Dec 2024 20:23:47 +0800 +Subject: [PATCH] snapshot: bugfix VM run failed from memory snapshot + +The kernel does not need to be loaded for snapshot restoration. + +Signed-off-by: Mingwang Li +--- + cpu/src/lib.rs | 22 ++++++++------- + cpu/src/x86_64/mod.rs | 2 +- + devices/src/acpi/cpu_controller.rs | 4 +-- + machine/src/aarch64/micro.rs | 40 +++++++++++++++------------ + machine/src/aarch64/standard.rs | 44 ++++++++++++++++++------------ + machine/src/lib.rs | 2 +- + machine/src/x86_64/micro.rs | 9 ++++-- + machine/src/x86_64/standard.rs | 13 +++++++-- + 8 files changed, 83 insertions(+), 53 deletions(-) + +diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs +index 7a11629..7698132 100644 +--- a/cpu/src/lib.rs ++++ b/cpu/src/lib.rs +@@ -118,7 +118,7 @@ pub trait CPUInterface { + /// Realize `CPU` structure, set registers value for `CPU`. + fn realize( + &self, +- boot: &CPUBootConfig, ++ boot: &Option, + topology: &CPUTopology, + #[cfg(target_arch = "aarch64")] features: &CPUFeatures, + ) -> Result<()>; +@@ -310,7 +310,7 @@ impl CPU { + impl CPUInterface for CPU { + fn realize( + &self, +- boot: &CPUBootConfig, ++ boot: &Option, + topology: &CPUTopology, + #[cfg(target_arch = "aarch64")] config: &CPUFeatures, + ) -> Result<()> { +@@ -323,14 +323,16 @@ impl CPUInterface for CPU { + )))); + } + +- self.hypervisor_cpu +- .set_boot_config( +- self.arch_cpu.clone(), +- boot, +- #[cfg(target_arch = "aarch64")] +- config, +- ) +- .with_context(|| "Failed to realize arch cpu")?; ++ if let Some(boot) = boot { ++ self.hypervisor_cpu ++ .set_boot_config( ++ self.arch_cpu.clone(), ++ boot, ++ #[cfg(target_arch = "aarch64")] ++ config, ++ ) ++ .with_context(|| "Failed to realize arch cpu")?; ++ } + + self.arch_cpu + .lock() +diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs +index 0a8ad16..acb6fb2 100644 +--- a/cpu/src/x86_64/mod.rs ++++ b/cpu/src/x86_64/mod.rs +@@ -75,7 +75,7 @@ pub enum X86RegsIndex { + + /// X86 CPU booting configure information + #[allow(clippy::upper_case_acronyms)] +-#[derive(Default, Clone, Debug)] ++#[derive(Default, Clone, Debug, Copy)] + pub struct X86CPUBootConfig { + pub prot64_mode: bool, + /// Register %rip value +diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs +index 1259e8d..73f2601 100644 +--- a/devices/src/acpi/cpu_controller.rs ++++ b/devices/src/acpi/cpu_controller.rs +@@ -157,8 +157,8 @@ impl CpuController { + None + } + +- pub fn get_boot_config(&self) -> &CPUBootConfig { +- &self.cpu_config.as_ref().unwrap().boot_config ++ pub fn get_boot_config(&self) -> CPUBootConfig { ++ self.cpu_config.as_ref().unwrap().boot_config + } + + pub fn get_hotplug_cpu_info(&self) -> (String, u8) { +diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs +index 42e9171..3e7cf38 100644 +--- a/machine/src/aarch64/micro.rs ++++ b/machine/src/aarch64/micro.rs +@@ -20,7 +20,7 @@ use address_space::{AddressSpace, GuestAddress, Region}; + use cpu::CPUTopology; + use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; + use hypervisor::kvm::aarch64::*; +-use machine_manager::config::{SerialConfig, VmConfig}; ++use machine_manager::config::{MigrateMode, SerialConfig, VmConfig}; + use migration::{MigrationManager, MigrationStatus}; + use util::{ + device_tree::{self, CompileFDT, FdtBuilder}, +@@ -160,8 +160,12 @@ impl MachineOps for LightMachine { + vm_config.machine_config.nr_cpus, + )?; + +- let boot_config = +- locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; ++ let migrate_info = locked_vm.get_migrate_info(); ++ let boot_config = if migrate_info.0 == MigrateMode::Unknown { ++ Some(locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?) ++ } else { ++ None ++ }; + let cpu_config = locked_vm.load_cpu_features(vm_config)?; + + let hypervisor = locked_vm.base.hypervisor.clone(); +@@ -186,20 +190,22 @@ impl MachineOps for LightMachine { + locked_vm.add_devices(vm_config)?; + trace::replaceable_info(&locked_vm.replaceable_info); + +- let mut fdt_helper = FdtBuilder::new(); +- locked_vm +- .generate_fdt_node(&mut fdt_helper) +- .with_context(|| MachineError::GenFdtErr)?; +- let fdt_vec = fdt_helper.finish()?; +- locked_vm +- .base +- .sys_mem +- .write( +- &mut fdt_vec.as_slice(), +- GuestAddress(boot_config.fdt_addr), +- fdt_vec.len() as u64, +- ) +- .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; ++ if let Some(boot_cfg) = boot_config { ++ let mut fdt_helper = FdtBuilder::new(); ++ locked_vm ++ .generate_fdt_node(&mut fdt_helper) ++ .with_context(|| MachineError::GenFdtErr)?; ++ let fdt_vec = fdt_helper.finish()?; ++ locked_vm ++ .base ++ .sys_mem ++ .write( ++ &mut fdt_vec.as_slice(), ++ GuestAddress(boot_cfg.fdt_addr), ++ fdt_vec.len() as u64, ++ ) ++ .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; ++ } + + MigrationManager::register_vm_instance(vm.clone()); + MigrationManager::register_migration_instance(locked_vm.base.migration_hypervisor.clone()); +diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs +index 8544a2b..416298a 100644 +--- a/machine/src/aarch64/standard.rs ++++ b/machine/src/aarch64/standard.rs +@@ -606,8 +606,16 @@ impl MachineOps for StdMachine { + .with_context(|| MachineError::InitPCIeHostErr)?; + let fwcfg = locked_vm.add_fwcfg_device(nr_cpus)?; + +- let boot_config = locked_vm +- .load_boot_source(fwcfg.as_ref(), MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; ++ let migrate = locked_vm.get_migrate_info(); ++ let boot_config = ++ if migrate.0 == MigrateMode::Unknown { ++ Some(locked_vm.load_boot_source( ++ fwcfg.as_ref(), ++ MEM_LAYOUT[LayoutEntryType::Mem as usize].0, ++ )?) ++ } else { ++ None ++ }; + let cpu_config = locked_vm.load_cpu_features(vm_config)?; + + let hypervisor = locked_vm.base.hypervisor.clone(); +@@ -632,21 +640,23 @@ impl MachineOps for StdMachine { + .add_devices(vm_config) + .with_context(|| "Failed to add devices")?; + +- let mut fdt_helper = FdtBuilder::new(); +- locked_vm +- .generate_fdt_node(&mut fdt_helper) +- .with_context(|| MachineError::GenFdtErr)?; +- let fdt_vec = fdt_helper.finish()?; +- locked_vm.dtb_vec = fdt_vec.clone(); +- locked_vm +- .base +- .sys_mem +- .write( +- &mut fdt_vec.as_slice(), +- GuestAddress(boot_config.fdt_addr), +- fdt_vec.len() as u64, +- ) +- .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; ++ if let Some(boot_cfg) = boot_config { ++ let mut fdt_helper = FdtBuilder::new(); ++ locked_vm ++ .generate_fdt_node(&mut fdt_helper) ++ .with_context(|| MachineError::GenFdtErr)?; ++ let fdt_vec = fdt_helper.finish()?; ++ locked_vm.dtb_vec = fdt_vec.clone(); ++ locked_vm ++ .base ++ .sys_mem ++ .write( ++ &mut fdt_vec.as_slice(), ++ GuestAddress(boot_cfg.fdt_addr), ++ fdt_vec.len() as u64, ++ ) ++ .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; ++ } + + // If it is direct kernel boot mode, the ACPI can not be enabled. + if let Some(fw_cfg) = fwcfg { +diff --git a/machine/src/lib.rs b/machine/src/lib.rs +index 6c13c03..c1c0c22 100644 +--- a/machine/src/lib.rs ++++ b/machine/src/lib.rs +@@ -465,7 +465,7 @@ pub trait MachineOps { + nr_cpus: u8, + #[cfg(target_arch = "x86_64")] max_cpus: u8, + topology: &CPUTopology, +- boot_cfg: &CPUBootConfig, ++ boot_cfg: &Option, + #[cfg(target_arch = "aarch64")] vcpu_cfg: &CPUFeatures, + ) -> Result>> + where +diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs +index 7b4e08e..77ea440 100644 +--- a/machine/src/x86_64/micro.rs ++++ b/machine/src/x86_64/micro.rs +@@ -22,7 +22,7 @@ use cpu::{CPUBootConfig, CPUTopology}; + use devices::legacy::FwCfgOps; + use hypervisor::kvm::x86_64::*; + use hypervisor::kvm::*; +-use machine_manager::config::{SerialConfig, VmConfig}; ++use machine_manager::config::{MigrateMode, SerialConfig, VmConfig}; + use migration::{MigrationManager, MigrationStatus}; + use util::seccomp::{BpfRule, SeccompCmpOpt}; + use virtio::VirtioMmioDevice; +@@ -174,7 +174,12 @@ impl MachineOps for LightMachine { + locked_vm.add_devices(vm_config)?; + trace::replaceable_info(&locked_vm.replaceable_info); + +- let boot_config = locked_vm.load_boot_source(None)?; ++ let migrate_info = locked_vm.get_migrate_info(); ++ let boot_config = if migrate_info.0 == MigrateMode::Unknown { ++ Some(locked_vm.load_boot_source(None)?) ++ } else { ++ None ++ }; + let hypervisor = locked_vm.base.hypervisor.clone(); + locked_vm.base.cpus.extend(::init_vcpu( + vm.clone(), +diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs +index 790e542..3aac836 100644 +--- a/machine/src/x86_64/standard.rs ++++ b/machine/src/x86_64/standard.rs +@@ -371,7 +371,7 @@ impl StdMachineOps for StdMachine { + hypervisor, + self.base.cpu_topo.max_cpus, + )?; +- vcpu.realize(boot_cfg, topology).with_context(|| { ++ vcpu.realize(&Some(boot_cfg), topology).with_context(|| { + format!( + "Failed to realize arch cpu register/features for CPU {}", + vcpu_id +@@ -559,7 +559,12 @@ impl MachineOps for StdMachine { + locked_vm.add_devices(vm_config)?; + + let fwcfg = locked_vm.add_fwcfg_device(nr_cpus, max_cpus)?; +- let boot_config = locked_vm.load_boot_source(fwcfg.as_ref())?; ++ let migrate = locked_vm.get_migrate_info(); ++ let boot_config = if migrate.0 == MigrateMode::Unknown { ++ Some(locked_vm.load_boot_source(fwcfg.as_ref())?) ++ } else { ++ None ++ }; + let topology = CPUTopology::new().set_topology(( + vm_config.machine_config.nr_threads, + vm_config.machine_config.nr_cores, +@@ -575,7 +580,9 @@ impl MachineOps for StdMachine { + &boot_config, + )?); + +- locked_vm.init_cpu_controller(boot_config, topology, vm.clone())?; ++ if migrate.0 == MigrateMode::Unknown { ++ locked_vm.init_cpu_controller(boot_config.unwrap(), topology, vm.clone())?; ++ } + + if let Some(fw_cfg) = fwcfg { + locked_vm +-- +2.33.0 + diff --git a/0003-hypervisor-kvm-Fix-setting-core-reg-error-when-resto.patch b/0003-hypervisor-kvm-Fix-setting-core-reg-error-when-resto.patch new file mode 100644 index 0000000000000000000000000000000000000000..053333f9c71bb871d219825953ef95670a800ae4 --- /dev/null +++ b/0003-hypervisor-kvm-Fix-setting-core-reg-error-when-resto.patch @@ -0,0 +1,135 @@ +From 5551d6b5abaf9d5241904425e3991c256b30d22f Mon Sep 17 00:00:00 2001 +From: frankyj915 +Date: Sun, 15 Dec 2024 09:31:20 +0800 +Subject: [PATCH 1/2] hypervisor/kvm: Fix setting core reg error when restoring + VM + +vcpu_init() should be called before setting vcpu regs. + +Fix 5edbafc(migration: bugfix for mgiration) + +Signed-off-by: frankyj915 +--- + cpu/src/lib.rs | 20 +++++++++----------- + hypervisor/src/kvm/aarch64/mod.rs | 6 ++++-- + hypervisor/src/kvm/mod.rs | 4 ++-- + hypervisor/src/kvm/x86_64/mod.rs | 8 +++++--- + 4 files changed, 20 insertions(+), 18 deletions(-) + +diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs +index 7698132..873cb49 100644 +--- a/cpu/src/lib.rs ++++ b/cpu/src/lib.rs +@@ -160,7 +160,7 @@ pub trait CPUHypervisorOps: Send + Sync { + fn set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &CPUBootConfig, ++ boot_config: &Option, + #[cfg(target_arch = "aarch64")] vcpu_config: &CPUFeatures, + ) -> Result<()>; + +@@ -323,16 +323,14 @@ impl CPUInterface for CPU { + )))); + } + +- if let Some(boot) = boot { +- self.hypervisor_cpu +- .set_boot_config( +- self.arch_cpu.clone(), +- boot, +- #[cfg(target_arch = "aarch64")] +- config, +- ) +- .with_context(|| "Failed to realize arch cpu")?; +- } ++ self.hypervisor_cpu ++ .set_boot_config( ++ self.arch_cpu.clone(), ++ boot, ++ #[cfg(target_arch = "aarch64")] ++ config, ++ ) ++ .with_context(|| "Failed to realize arch cpu")?; + + self.arch_cpu + .lock() +diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs +index 0721236..5d2a938 100644 +--- a/hypervisor/src/kvm/aarch64/mod.rs ++++ b/hypervisor/src/kvm/aarch64/mod.rs +@@ -135,7 +135,7 @@ impl KvmCpu { + pub fn arch_set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &CPUBootConfig, ++ boot_config: &Option, + vcpu_config: &CPUFeatures, + ) -> Result<()> { + let mut kvi = self.kvi.lock().unwrap(); +@@ -169,7 +169,9 @@ impl KvmCpu { + } + drop(kvi); + +- arch_cpu.lock().unwrap().set_core_reg(boot_config); ++ if let Some(cfg) = boot_config { ++ arch_cpu.lock().unwrap().set_core_reg(cfg); ++ } + + self.arch_vcpu_init()?; + +diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs +index 671eb54..e20f102 100644 +--- a/hypervisor/src/kvm/mod.rs ++++ b/hypervisor/src/kvm/mod.rs +@@ -544,7 +544,7 @@ impl CPUHypervisorOps for KvmCpu { + fn set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &CPUBootConfig, ++ boot_config: &Option, + #[cfg(target_arch = "aarch64")] vcpu_config: &CPUFeatures, + ) -> Result<()> { + #[cfg(target_arch = "aarch64")] +@@ -1067,7 +1067,7 @@ mod test { + let cpu = CPU::new(hypervisor_cpu.clone(), 0, x86_cpu, vm.clone()); + // test `set_boot_config` function + assert!(hypervisor_cpu +- .set_boot_config(cpu.arch().clone(), &cpu_config) ++ .set_boot_config(cpu.arch().clone(), &Some(cpu_config)) + .is_ok()); + + // test setup special registers +diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs +index 7d7e7b5..e7d08ef 100644 +--- a/hypervisor/src/kvm/x86_64/mod.rs ++++ b/hypervisor/src/kvm/x86_64/mod.rs +@@ -84,7 +84,7 @@ impl KvmCpu { + pub fn arch_set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &CPUBootConfig, ++ boot_config: &Option, + ) -> Result<()> { + let mut locked_arch_cpu = arch_cpu.lock().unwrap(); + let apic_id = locked_arch_cpu.apic_id; +@@ -93,12 +93,14 @@ impl KvmCpu { + .get_lapic() + .with_context(|| format!("Failed to get lapic for CPU {}/KVM", apic_id))?; + locked_arch_cpu.setup_lapic(lapic)?; +- locked_arch_cpu.setup_regs(boot_config); + let sregs = self + .fd + .get_sregs() + .with_context(|| format!("Failed to get sregs for CPU {}/KVM", apic_id))?; +- locked_arch_cpu.setup_sregs(sregs, boot_config)?; ++ if let Some(cfg) = boot_config { ++ locked_arch_cpu.setup_regs(cfg); ++ locked_arch_cpu.setup_sregs(sregs, cfg)?; ++ } + locked_arch_cpu.setup_fpu(); + locked_arch_cpu.setup_msrs(); + +-- +2.34.1 + diff --git a/0004-micro_comman-syscall-Update-ioctl-allow-list.patch b/0004-micro_comman-syscall-Update-ioctl-allow-list.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa229589c8814fb2bbed56992e3ab6d3d05f87ad --- /dev/null +++ b/0004-micro_comman-syscall-Update-ioctl-allow-list.patch @@ -0,0 +1,50 @@ +From e9c9d3de82eb926ab6d494358c7a1891b171e190 Mon Sep 17 00:00:00 2001 +From: frankyj915 +Date: Sun, 15 Dec 2024 09:35:03 +0800 +Subject: [PATCH] micro_comman/syscall: Update ioctl allow list + +Signed-off-by: frankyj915 +--- + hypervisor/src/kvm/mod.rs | 6 ++++++ + machine/src/micro_common/syscall.rs | 8 +++++++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs +index e20f102..b88aeed 100644 +--- a/hypervisor/src/kvm/mod.rs ++++ b/hypervisor/src/kvm/mod.rs +@@ -99,6 +99,12 @@ ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip); + ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level); + ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state); + ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events); ++#[cfg(target_arch = "x86_64")] ++ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2); ++#[cfg(target_arch = "x86_64")] ++ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data); ++#[cfg(target_arch = "x86_64")] ++ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip); + + #[allow(clippy::upper_case_acronyms)] + #[derive(Default)] +diff --git a/machine/src/micro_common/syscall.rs b/machine/src/micro_common/syscall.rs +index 6ae9a56..ca8327f 100644 +--- a/machine/src/micro_common/syscall.rs ++++ b/machine/src/micro_common/syscall.rs +@@ -160,7 +160,13 @@ fn ioctl_allow_list() -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32); ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_USER_MEMORY_REGION); ++ #[cfg(target_arch = "x86_64")] ++ let bpf_rule = bpf_rule ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_PIT2() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_CLOCK() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_IRQCHIP() as u32); + arch_ioctl_allow_list(bpf_rule) + } + +-- +2.34.1 + diff --git a/0005-update-Rust-VMM-dependencies-and-re-vendor.patch b/0005-update-Rust-VMM-dependencies-and-re-vendor.patch new file mode 100644 index 0000000000000000000000000000000000000000..a73ffff07b86af502d5c821cd002c5e7ecb03471 --- /dev/null +++ b/0005-update-Rust-VMM-dependencies-and-re-vendor.patch @@ -0,0 +1,57600 @@ +From 79abdde6121759b5364236db8125b29a60afcc49 Mon Sep 17 00:00:00 2001 +From: Ruoqing He +Date: Sun, 22 Dec 2024 16:40:11 +0800 +Subject: [PATCH] Update Rust-VMM dependencies and re-vendor + +Signed-off-by: Ruoqing He +--- + .cargo/config | 1 - + Cargo.lock | 51 +- + address_space/Cargo.toml | 2 +- + block_backend/Cargo.toml | 2 +- + boot_loader/Cargo.toml | 2 +- + chardev_backend/Cargo.toml | 2 +- + cpu/Cargo.toml | 4 +- + devices/Cargo.toml | 2 +- + hypervisor/Cargo.toml | 6 +- + machine/Cargo.toml | 2 +- + machine_manager/Cargo.toml | 2 +- + migration/Cargo.toml | 2 +- + tests/mod_test/Cargo.toml | 2 +- + trace/Cargo.toml | 2 +- + ui/Cargo.toml | 2 +- + util/Cargo.toml | 4 +- + vendor/bitflags-1.3.2/.cargo-checksum.json | 1 + + vendor/bitflags-1.3.2/CHANGELOG.md | 206 + + vendor/bitflags-1.3.2/CODE_OF_CONDUCT.md | 73 + + vendor/bitflags-1.3.2/Cargo.toml | 58 + + vendor/bitflags-1.3.2/LICENSE-APACHE | 201 + + vendor/bitflags-1.3.2/LICENSE-MIT | 25 + + vendor/bitflags-1.3.2/README.md | 32 + + .../bitflags-1.3.2/src/example_generated.rs | 14 + + vendor/bitflags-1.3.2/src/lib.rs | 1729 +++ + .../tests/basic.rs | 0 + .../tests/compile-fail/impls/copy.rs | 0 + .../tests/compile-fail/impls/copy.stderr.beta | 0 + .../tests/compile-fail/impls/eq.rs | 0 + .../tests/compile-fail/impls/eq.stderr.beta | 0 + .../non_integer_base/all_defined.rs | 0 + .../non_integer_base/all_defined.stderr.beta | 0 + .../non_integer_base/all_missing.rs | 0 + .../non_integer_base/all_missing.stderr.beta | 0 + .../compile-fail/visibility/private_field.rs | 0 + .../visibility/private_field.stderr.beta | 0 + .../compile-fail/visibility/private_flags.rs | 0 + .../visibility/private_flags.stderr.beta | 0 + .../compile-fail/visibility/pub_const.rs | 0 + .../visibility/pub_const.stderr.beta | 0 + .../tests/compile-pass/impls/convert.rs | 0 + .../tests/compile-pass/impls/default.rs | 0 + .../compile-pass/impls/inherent_methods.rs | 0 + .../tests/compile-pass/redefinition/core.rs | 0 + .../compile-pass/redefinition/stringify.rs | 0 + .../tests/compile-pass/repr/c.rs | 0 + .../tests/compile-pass/repr/transparent.rs | 0 + .../compile-pass/visibility/bits_field.rs | 0 + .../tests/compile-pass/visibility/pub_in.rs | 0 + .../tests/compile.rs | 0 + vendor/bitflags/.cargo-checksum.json | 2 +- + vendor/bitflags/CHANGELOG.md | 349 +- + vendor/bitflags/CONTRIBUTING.md | 9 + + vendor/bitflags/Cargo.lock | 383 + + vendor/bitflags/Cargo.toml | 76 +- + vendor/bitflags/README.md | 53 +- + vendor/bitflags/SECURITY.md | 13 + + vendor/bitflags/benches/parse.rs | 96 + + vendor/bitflags/examples/custom_bits_type.rs | 97 + + vendor/bitflags/examples/custom_derive.rs | 23 + + vendor/bitflags/examples/fmt.rs | 49 + + vendor/bitflags/examples/macro_free.rs | 61 + + vendor/bitflags/examples/serde.rs | 36 + + vendor/bitflags/spec.md | 552 + + vendor/bitflags/src/example_generated.rs | 57 +- + vendor/bitflags/src/external.rs | 262 + + vendor/bitflags/src/external/arbitrary.rs | 33 + + vendor/bitflags/src/external/bytemuck.rs | 19 + + vendor/bitflags/src/external/serde.rs | 93 + + vendor/bitflags/src/internal.rs | 125 + + vendor/bitflags/src/iter.rs | 145 + + vendor/bitflags/src/lib.rs | 2308 ++-- + vendor/bitflags/src/parser.rs | 332 + + vendor/bitflags/src/public.rs | 578 + + vendor/bitflags/src/tests.rs | 131 + + vendor/bitflags/src/tests/all.rs | 23 + + vendor/bitflags/src/tests/bits.rs | 36 + + vendor/bitflags/src/tests/complement.rs | 53 + + vendor/bitflags/src/tests/contains.rs | 108 + + vendor/bitflags/src/tests/difference.rs | 92 + + vendor/bitflags/src/tests/empty.rs | 23 + + vendor/bitflags/src/tests/eq.rs | 10 + + vendor/bitflags/src/tests/extend.rs | 42 + + vendor/bitflags/src/tests/flags.rs | 46 + + vendor/bitflags/src/tests/fmt.rs | 97 + + vendor/bitflags/src/tests/from_bits.rs | 45 + + vendor/bitflags/src/tests/from_bits_retain.rs | 38 + + .../bitflags/src/tests/from_bits_truncate.rs | 42 + + vendor/bitflags/src/tests/from_name.rs | 42 + + vendor/bitflags/src/tests/insert.rs | 91 + + vendor/bitflags/src/tests/intersection.rs | 79 + + vendor/bitflags/src/tests/intersects.rs | 91 + + vendor/bitflags/src/tests/is_all.rs | 32 + + vendor/bitflags/src/tests/is_empty.rs | 31 + + vendor/bitflags/src/tests/iter.rs | 209 + + vendor/bitflags/src/tests/parser.rs | 332 + + vendor/bitflags/src/tests/remove.rs | 100 + + .../src/tests/symmetric_difference.rs | 110 + + vendor/bitflags/src/tests/union.rs | 71 + + vendor/bitflags/src/traits.rs | 431 + + vendor/kvm-bindings/.cargo-checksum.json | 2 +- + vendor/kvm-bindings/CHANGELOG.md | 64 + + vendor/kvm-bindings/CONTRIBUTING.md | 76 +- + vendor/kvm-bindings/Cargo.toml | 41 +- + vendor/kvm-bindings/README.md | 20 +- + .../kvm-bindings/coverage_config_aarch64.json | 2 +- + .../kvm-bindings/coverage_config_x86_64.json | 6 +- + vendor/kvm-bindings/src/arm64/bindings.rs | 8704 +++++------- + vendor/kvm-bindings/src/arm64/mod.rs | 5 +- + vendor/kvm-bindings/src/arm64/serialize.rs | 79 + + vendor/kvm-bindings/src/lib.rs | 30 +- + vendor/kvm-bindings/src/riscv64/bindings.rs | 8307 ++++++++++++ + .../kvm-bindings/src/riscv64/fam_wrappers.rs | 49 + + .../kvm-bindings/src/{x86 => riscv64}/mod.rs | 9 +- + vendor/kvm-bindings/src/riscv64/serialize.rs | 96 + + vendor/kvm-bindings/src/serialize.rs | 66 + + .../src/{x86 => x86_64}/bindings.rs | 11173 ++++++++-------- + .../src/{x86 => x86_64}/fam_wrappers.rs | 90 +- + vendor/kvm-bindings/src/x86_64/mod.rs | 14 + + vendor/kvm-bindings/src/x86_64/serialize.rs | 156 + + vendor/kvm-ioctls/.cargo-checksum.json | 2 +- + vendor/kvm-ioctls/CHANGELOG.md | 157 +- + vendor/kvm-ioctls/CODEOWNERS | 2 +- + vendor/kvm-ioctls/Cargo.toml | 19 +- + vendor/kvm-ioctls/README.md | 11 +- + vendor/kvm-ioctls/build.rs | 2 + + vendor/kvm-ioctls/coverage_config_x86_64.json | 2 +- + vendor/kvm-ioctls/src/cap.rs | 39 +- + vendor/kvm-ioctls/src/ioctls/device.rs | 195 +- + vendor/kvm-ioctls/src/ioctls/mod.rs | 133 +- + vendor/kvm-ioctls/src/ioctls/system.rs | 68 +- + vendor/kvm-ioctls/src/ioctls/vcpu.rs | 1448 +- + vendor/kvm-ioctls/src/ioctls/vm.rs | 898 +- + vendor/kvm-ioctls/src/kvm_ioctls.rs | 175 +- + vendor/kvm-ioctls/src/lib.rs | 45 +- + vendor/vmm-sys-util/.cargo-checksum.json | 2 +- + vendor/vmm-sys-util/CHANGELOG.md | 23 + + vendor/vmm-sys-util/CODEOWNERS | 2 +- + vendor/vmm-sys-util/Cargo.toml | 21 +- + .../vmm-sys-util/coverage_config_x86_64.json | 2 +- + vendor/vmm-sys-util/src/fam.rs | 240 +- + vendor/vmm-sys-util/src/lib.rs | 3 +- + vendor/vmm-sys-util/src/linux/aio.rs | 2 +- + vendor/vmm-sys-util/src/linux/epoll.rs | 35 +- + vendor/vmm-sys-util/src/linux/fallocate.rs | 1 + + vendor/vmm-sys-util/src/linux/poll.rs | 44 +- + vendor/vmm-sys-util/src/linux/seek_hole.rs | 26 +- + .../vmm-sys-util/src/linux/sock_ctrl_msg.rs | 16 +- + vendor/vmm-sys-util/src/linux/timerfd.rs | 1 + + vendor/vmm-sys-util/src/linux/write_zeroes.rs | 24 +- + vendor/vmm-sys-util/src/rand.rs | 26 +- + vendor/vmm-sys-util/src/syscall.rs | 18 +- + vendor/vmm-sys-util/src/tempfile.rs | 28 +- + vendor/vmm-sys-util/src/unix/tempdir.rs | 1 + + vfio/Cargo.toml | 6 +- + virtio/Cargo.toml | 2 +- + 156 files changed, 29944 insertions(+), 13347 deletions(-) + create mode 100644 vendor/bitflags-1.3.2/.cargo-checksum.json + create mode 100644 vendor/bitflags-1.3.2/CHANGELOG.md + create mode 100644 vendor/bitflags-1.3.2/CODE_OF_CONDUCT.md + create mode 100644 vendor/bitflags-1.3.2/Cargo.toml + create mode 100644 vendor/bitflags-1.3.2/LICENSE-APACHE + create mode 100644 vendor/bitflags-1.3.2/LICENSE-MIT + create mode 100644 vendor/bitflags-1.3.2/README.md + create mode 100644 vendor/bitflags-1.3.2/src/example_generated.rs + create mode 100644 vendor/bitflags-1.3.2/src/lib.rs + rename vendor/{bitflags => bitflags-1.3.2}/tests/basic.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/impls/copy.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/impls/copy.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/impls/eq.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/impls/eq.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/non_integer_base/all_defined.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/non_integer_base/all_defined.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/non_integer_base/all_missing.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/non_integer_base/all_missing.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/private_field.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/private_field.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/private_flags.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/private_flags.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/pub_const.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-fail/visibility/pub_const.stderr.beta (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/impls/convert.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/impls/default.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/impls/inherent_methods.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/redefinition/core.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/redefinition/stringify.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/repr/c.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/repr/transparent.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/visibility/bits_field.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile-pass/visibility/pub_in.rs (100%) + rename vendor/{bitflags => bitflags-1.3.2}/tests/compile.rs (100%) + create mode 100644 vendor/bitflags/CONTRIBUTING.md + create mode 100644 vendor/bitflags/Cargo.lock + create mode 100644 vendor/bitflags/SECURITY.md + create mode 100644 vendor/bitflags/benches/parse.rs + create mode 100644 vendor/bitflags/examples/custom_bits_type.rs + create mode 100644 vendor/bitflags/examples/custom_derive.rs + create mode 100644 vendor/bitflags/examples/fmt.rs + create mode 100644 vendor/bitflags/examples/macro_free.rs + create mode 100644 vendor/bitflags/examples/serde.rs + create mode 100644 vendor/bitflags/spec.md + create mode 100644 vendor/bitflags/src/external.rs + create mode 100644 vendor/bitflags/src/external/arbitrary.rs + create mode 100644 vendor/bitflags/src/external/bytemuck.rs + create mode 100644 vendor/bitflags/src/external/serde.rs + create mode 100644 vendor/bitflags/src/internal.rs + create mode 100644 vendor/bitflags/src/iter.rs + create mode 100644 vendor/bitflags/src/parser.rs + create mode 100644 vendor/bitflags/src/public.rs + create mode 100644 vendor/bitflags/src/tests.rs + create mode 100644 vendor/bitflags/src/tests/all.rs + create mode 100644 vendor/bitflags/src/tests/bits.rs + create mode 100644 vendor/bitflags/src/tests/complement.rs + create mode 100644 vendor/bitflags/src/tests/contains.rs + create mode 100644 vendor/bitflags/src/tests/difference.rs + create mode 100644 vendor/bitflags/src/tests/empty.rs + create mode 100644 vendor/bitflags/src/tests/eq.rs + create mode 100644 vendor/bitflags/src/tests/extend.rs + create mode 100644 vendor/bitflags/src/tests/flags.rs + create mode 100644 vendor/bitflags/src/tests/fmt.rs + create mode 100644 vendor/bitflags/src/tests/from_bits.rs + create mode 100644 vendor/bitflags/src/tests/from_bits_retain.rs + create mode 100644 vendor/bitflags/src/tests/from_bits_truncate.rs + create mode 100644 vendor/bitflags/src/tests/from_name.rs + create mode 100644 vendor/bitflags/src/tests/insert.rs + create mode 100644 vendor/bitflags/src/tests/intersection.rs + create mode 100644 vendor/bitflags/src/tests/intersects.rs + create mode 100644 vendor/bitflags/src/tests/is_all.rs + create mode 100644 vendor/bitflags/src/tests/is_empty.rs + create mode 100644 vendor/bitflags/src/tests/iter.rs + create mode 100644 vendor/bitflags/src/tests/parser.rs + create mode 100644 vendor/bitflags/src/tests/remove.rs + create mode 100644 vendor/bitflags/src/tests/symmetric_difference.rs + create mode 100644 vendor/bitflags/src/tests/union.rs + create mode 100644 vendor/bitflags/src/traits.rs + create mode 100644 vendor/kvm-bindings/src/arm64/serialize.rs + create mode 100644 vendor/kvm-bindings/src/riscv64/bindings.rs + create mode 100644 vendor/kvm-bindings/src/riscv64/fam_wrappers.rs + rename vendor/kvm-bindings/src/{x86 => riscv64}/mod.rs (73%) + create mode 100644 vendor/kvm-bindings/src/riscv64/serialize.rs + create mode 100644 vendor/kvm-bindings/src/serialize.rs + rename vendor/kvm-bindings/src/{x86 => x86_64}/bindings.rs (66%) + rename vendor/kvm-bindings/src/{x86 => x86_64}/fam_wrappers.rs (60%) + create mode 100644 vendor/kvm-bindings/src/x86_64/mod.rs + create mode 100644 vendor/kvm-bindings/src/x86_64/serialize.rs + +diff --git a/.cargo/config b/.cargo/config +index 31ec474..1f84b46 100644 +--- a/.cargo/config ++++ b/.cargo/config +@@ -11,7 +11,6 @@ + # See the Mulan PSL v2 for more details. + + [build] +- + [target.'cfg(target_arch = "aarch64", not(target_env = "ohos"))'] + rustflags = [ + "-C", "link-arg=-lgcc", +diff --git a/Cargo.lock b/Cargo.lock +index fba3e56..99a1e19 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" + dependencies = [ + "alsa-sys", +- "bitflags", ++ "bitflags 1.3.2", + "libc", + "nix 0.24.3", + ] +@@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "6ba16453d10c712284061a05f6510f75abeb92b56ba88dfeb48c74775020cc22" + dependencies = [ + "atk-sys", +- "bitflags", ++ "bitflags 1.3.2", + "glib", + "libc", + ] +@@ -117,7 +117,7 @@ version = "0.65.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", +@@ -140,6 +140,12 @@ version = "1.3.2" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + ++[[package]] ++name = "bitflags" ++version = "2.6.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" ++ + [[package]] + name = "bitintr" + version = "0.3.0" +@@ -199,7 +205,7 @@ version = "0.17.10" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "cairo-sys-rs", + "glib", + "libc", +@@ -279,7 +285,7 @@ version = "4.1.4" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "once_cell", +@@ -493,7 +499,7 @@ version = "0.17.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "be1df5ea52cccd7e3a0897338b5564968274b52f5fd12601e0afa44f454c74d3" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", +@@ -509,7 +515,7 @@ version = "0.17.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "gdk-pixbuf-sys", + "gio", + "glib", +@@ -584,7 +590,7 @@ version = "0.17.9" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "d14522e56c6bcb6f7a3aebc25cbcfb06776af4c0c25232b601b4383252d7cb92" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-io", +@@ -617,7 +623,7 @@ version = "0.17.9" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "a7f1de7cbde31ea4f0a919453a2dcece5d54d5b70e08f8ad254dc4840f5f09b6" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-executor", +@@ -683,7 +689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "b6c4222ab92b08d4d0bab90ddb6185b4e575ceeea8b8cdf00b938d7b6661d966" + dependencies = [ + "atk", +- "bitflags", ++ "bitflags 1.3.2", + "cairo-rs", + "field-offset", + "futures-channel", +@@ -786,7 +792,7 @@ version = "0.6.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "8b7b36074613a723279637061b40db993208908a94f10ccb14436ce735bc0f57" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "libc", + ] + +@@ -807,19 +813,20 @@ dependencies = [ + + [[package]] + name = "kvm-bindings" +-version = "0.6.0" ++version = "0.10.0" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "efe70e65a5b092161d17f5005b66e5eefe7a94a70c332e755036fc4af78c4e79" ++checksum = "fa4933174d0cc4b77b958578cd45784071cc5ae212c2d78fbd755aaaa6dfa71a" + dependencies = [ + "vmm-sys-util", + ] + + [[package]] + name = "kvm-ioctls" +-version = "0.15.0" ++version = "0.19.1" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "9bdde2b46ee7b6587ef79f751019c4726c4f2d3e4628df5d69f3f9c5cb6c6bd4" ++checksum = "e013ae7fcd2c6a8f384104d16afe7ea02969301ea2bb2a56e44b011ebc907cab" + dependencies = [ ++ "bitflags 2.6.0", + "kvm-bindings", + "libc", + "vmm-sys-util", +@@ -859,7 +866,7 @@ version = "2.27.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "libc", + "libpulse-sys", + "num-derive", +@@ -1073,7 +1080,7 @@ version = "0.24.3" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "cfg-if", + "libc", + ] +@@ -1084,7 +1091,7 @@ version = "0.26.2" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +@@ -1190,7 +1197,7 @@ version = "0.17.4" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "52c280b82a881e4208afb3359a8e7fde27a1b272280981f1f34610bed5770d37" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "gio", + "glib", + "libc", +@@ -1902,11 +1909,11 @@ dependencies = [ + + [[package]] + name = "vmm-sys-util" +-version = "0.11.1" ++version = "0.12.1" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" ++checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" + dependencies = [ +- "bitflags", ++ "bitflags 1.3.2", + "libc", + ] + +diff --git a/address_space/Cargo.toml b/address_space/Cargo.toml +index 7ff4088..b9e7b1d 100644 +--- a/address_space/Cargo.toml ++++ b/address_space/Cargo.toml +@@ -10,7 +10,7 @@ description = "provide memory management for VM" + libc = "0.2" + log = "0.4" + nix = { version = "0.26.2", default-features = false, features = ["fs", "feature"] } +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + arc-swap = "1.6.0" + thiserror = "1.0" + anyhow = "1.0" +diff --git a/block_backend/Cargo.toml b/block_backend/Cargo.toml +index 6f7c45b..d052bd0 100644 +--- a/block_backend/Cargo.toml ++++ b/block_backend/Cargo.toml +@@ -7,7 +7,7 @@ license = "Mulan PSL v2" + + [dependencies] + thiserror = "1.0" +-vmm-sys-util = "0.11.0" ++vmm-sys-util = "0.12.1" + anyhow = "1.0" + log = "0.4" + byteorder = "1.4.3" +diff --git a/boot_loader/Cargo.toml b/boot_loader/Cargo.toml +index d04c4ce..cbd2287 100644 +--- a/boot_loader/Cargo.toml ++++ b/boot_loader/Cargo.toml +@@ -8,7 +8,7 @@ license = "Mulan PSL v2" + [dependencies] + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } + log = "0.4" + address_space = { path = "../address_space" } + devices = { path = "../devices" } +diff --git a/chardev_backend/Cargo.toml b/chardev_backend/Cargo.toml +index 83b47b3..8a1b153 100644 +--- a/chardev_backend/Cargo.toml ++++ b/chardev_backend/Cargo.toml +@@ -6,7 +6,7 @@ edition = "2021" + license = "Mulan PSL v2" + + [dependencies] +-vmm-sys-util = "0.11.0" ++vmm-sys-util = "0.12.1" + anyhow = "1.0" + log = "0.4" + libc = "0.2" +diff --git a/cpu/Cargo.toml b/cpu/Cargo.toml +index a665ede..1be3d7b 100644 +--- a/cpu/Cargo.toml ++++ b/cpu/Cargo.toml +@@ -9,11 +9,11 @@ description = "CPU emulation" + [dependencies] + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } + nix = { version = "0.26.2", default-features = false, features = ["fs", "feature"] } + log = "0.4" + libc = "0.2" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + machine_manager = { path = "../machine_manager" } + migration = { path = "../migration" } + migration_derive = { path = "../migration/migration_derive" } +diff --git a/devices/Cargo.toml b/devices/Cargo.toml +index 316752a..2e6574e 100644 +--- a/devices/Cargo.toml ++++ b/devices/Cargo.toml +@@ -12,7 +12,7 @@ anyhow = "1.0" + libc = "0.2" + log = "0.4" + serde = { version = "1.0", features = ["derive"] } +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + byteorder = "1.4.3" + drm-fourcc = ">=2.2.0" + once_cell = "1.18.0" +diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml +index df70a5b..97f4190 100644 +--- a/hypervisor/Cargo.toml ++++ b/hypervisor/Cargo.toml +@@ -8,11 +8,11 @@ license = "Mulan PSL v2" + [dependencies] + anyhow = "1.0" + thiserror = "1.0" +-kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } +-kvm-ioctls = "0.15.0" ++kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-ioctls = "0.19.1" + libc = "0.2" + log = "0.4" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + address_space = { path = "../address_space" } + cpu = { path = "../cpu" } + devices = { path = "../devices" } +diff --git a/machine/Cargo.toml b/machine/Cargo.toml +index 2f677f8..e5d9253 100644 +--- a/machine/Cargo.toml ++++ b/machine/Cargo.toml +@@ -10,7 +10,7 @@ description = "Emulation machines" + log = "0.4" + libc = "0.2" + serde_json = "1.0" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + thiserror = "1.0" + anyhow = "1.0" + acpi = { path = "../acpi" } +diff --git a/machine_manager/Cargo.toml b/machine_manager/Cargo.toml +index 29e151b..ec787bc 100644 +--- a/machine_manager/Cargo.toml ++++ b/machine_manager/Cargo.toml +@@ -12,7 +12,7 @@ regex = "1" + log = "0.4" + libc = "0.2" + serde_json = "1.0" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + hex = "0.4.3" + serde = { version = "1.0", features = ["derive"] } + strum = "0.24.1" +diff --git a/migration/Cargo.toml b/migration/Cargo.toml +index e1469d9..25769c8 100644 +--- a/migration/Cargo.toml ++++ b/migration/Cargo.toml +@@ -5,7 +5,7 @@ authors = ["Huawei StratoVirt Team"] + edition = "2021" + + [dependencies] +-kvm-ioctls = "0.15.0" ++kvm-ioctls = "0.19.1" + serde = { version = "1.0", features = ["derive"] } + serde_json = "1.0" + once_cell = "1.18.0" +diff --git a/tests/mod_test/Cargo.toml b/tests/mod_test/Cargo.toml +index 9ccebc0..9b144af 100644 +--- a/tests/mod_test/Cargo.toml ++++ b/tests/mod_test/Cargo.toml +@@ -8,7 +8,7 @@ license = "Mulan PSL v2" + [dependencies] + rand = "0.8.5" + hex = "0.4.3" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + anyhow = "1.0" + serde_json = "1.0" + libc = "0.2" +diff --git a/trace/Cargo.toml b/trace/Cargo.toml +index 267a356..ad6cf1b 100644 +--- a/trace/Cargo.toml ++++ b/trace/Cargo.toml +@@ -12,7 +12,7 @@ lazy_static = "1.4.0" + regex = "1" + anyhow = "1.0" + trace_generator = { path = "trace_generator" } +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + + [features] + trace_to_logger = [] +diff --git a/ui/Cargo.toml b/ui/Cargo.toml +index 56f2b6f..b7faa42 100644 +--- a/ui/Cargo.toml ++++ b/ui/Cargo.toml +@@ -12,7 +12,7 @@ anyhow = "1.0" + libc = "0.2" + log = "0.4" + serde_json = "1.0" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + once_cell = "1.18.0" + sscanf = "0.4.1" + bitintr = "0.3.0" +diff --git a/util/Cargo.toml b/util/Cargo.toml +index 95aefcd..5bf691e 100644 +--- a/util/Cargo.toml ++++ b/util/Cargo.toml +@@ -11,12 +11,12 @@ license = "Mulan PSL v2" + arc-swap = "1.6.0" + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } + nix = { version = "0.26.2", default-features = false, features = ["poll", "term", "time", "signal", "fs", "feature"] } + libc = "0.2" + libloading = "0.7.4" + log = { version = "0.4", features = ["std"]} +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + byteorder = "1.4.3" + once_cell = "1.18.0" + io-uring = "0.6.0" +diff --git a/vendor/bitflags-1.3.2/.cargo-checksum.json b/vendor/bitflags-1.3.2/.cargo-checksum.json +new file mode 100644 +index 0000000..7e8d470 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/.cargo-checksum.json +@@ -0,0 +1 @@ ++{"files":{"CHANGELOG.md":"d362fc1fccaaf4d421bcf0fe8b80ddb4f625dade0c1ee52d08bd0b95509a49d1","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","Cargo.toml":"87aced7532a7974eb37ab5fe6037f0abafc36d6b2d74891ecd2bf2f14f50d11e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"baa8604f8afb34fd93b9c79729daafb884dedcaf34023e4af8ad037d916061fd","src/example_generated.rs":"e43eb59e90f317f38d436670a6067d2fd9eb35fb319fe716184e4a04e24ed1b2","src/lib.rs":"e6477688535ee326d27238aeedc9cb4320ac35b9d17a4deda09e0587b0ccdbd4","tests/basic.rs":"146f1cbf6279bc609242cd3349f29cb21b41294f5e4921875f5ec95bd83529a2","tests/compile-fail/impls/copy.rs":"b791371237ddc75a7c04d2130e03b462c9c00a80dca08bd45aa97433d9c0d13a","tests/compile-fail/impls/copy.stderr.beta":"77d83484ce221d4b6ff2f7de843929a452d779fcfff428122710dd8218c298e3","tests/compile-fail/impls/eq.rs":"0cee8b9e07d537890e0189710293b53972d0fab63c09366f33c391065afafa99","tests/compile-fail/impls/eq.stderr.beta":"381fc6143d45ce76d7cecc47aa59cb69fe5e79c0b60a4a85d5c6163b400b3cc7","tests/compile-fail/non_integer_base/all_defined.rs":"95e14cad9e94560262f2862c3c01865ac30369b69da1001b0e7285cb55e6cb75","tests/compile-fail/non_integer_base/all_defined.stderr.beta":"1760739a276690903bb03844025587d37939f5dfcbfab309db3c86f32bdbf748","tests/compile-fail/non_integer_base/all_missing.rs":"b3d9da619d23213731ba2581aa7999c796c3c79aaf4f0ee6b11ceec08a11537f","tests/compile-fail/non_integer_base/all_missing.stderr.beta":"37e102290d3867e175b21976be798939f294efb17580d5b51e7b17b590d55132","tests/compile-fail/visibility/private_field.rs":"38e4d3fe6471829360d12c8d09b097f6a21aa93fb51eac3b215d96bdae23316b","tests/compile-fail/visibility/private_field.stderr.beta":"5aa24a3ebb39326f31927721c5017b8beb66c3e501fb865a3fa814c9763bfa0f","tests/compile-fail/visibility/private_flags.rs":"2ce4235802aa4e9c96c4e77d9e31d8401ef58dcda4741325184f0764ab1fe393","tests/compile-fail/visibility/private_flags.stderr.beta":"f3eb9f7baf2689258f3519ff7ee5c6ec3c237264ebcfe63f40c40f2023e5022f","tests/compile-fail/visibility/pub_const.rs":"8f813a97ac518c5ea8ac65b184101912452384afaf7b8d6c5e62f8370eca3c0a","tests/compile-fail/visibility/pub_const.stderr.beta":"823976ae1794d7f5372e2ec9aabba497e7bb88004722904c38da342ed98e8962","tests/compile-pass/impls/convert.rs":"88fe80bfb9cd5779f0e1d92c9ec02a8b6bb67e334c07f2309e9c0ba5ef776eb0","tests/compile-pass/impls/default.rs":"c508f9a461691f44b45142fa5ad599f02326e1de4c0cbca6c0593f4652eba109","tests/compile-pass/impls/inherent_methods.rs":"ecc26388e9a394bfa7a5bb69a5d621ab3d4d1e53f28f657bb8e78fe79f437913","tests/compile-pass/redefinition/core.rs":"ff5b6e72f87acc6ebb12405d3c0f6e3fa62e669933656a454bb63b30ea44179c","tests/compile-pass/redefinition/stringify.rs":"1edbce42b900c14425d7ffa14e83e165ebe452d7dccd8c0a8a821bdec64f5c93","tests/compile-pass/repr/c.rs":"6fda17f7c2edfcd155314579e83d0fc8a16209e400f1f9a5ca77bd9a799041f2","tests/compile-pass/repr/transparent.rs":"6cdc87a2137d8a4e0c8ce9b6cba83c82255f8ea125951bf614418685600489ce","tests/compile-pass/visibility/bits_field.rs":"1f3e5ba5a047440066a9f6bf7b7af33f5b06f6b1da3dd9af6886168199a7ea0a","tests/compile-pass/visibility/pub_in.rs":"e95312ff60966d42ec4bc00225507895a9b8ec24056ce6a9edd9145be35d730f","tests/compile.rs":"f27c67a7dd183ca30efea1b6e0880e3469a6dd63b92b1fd711c082df182c9eec"},"package":"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"} +\ No newline at end of file +diff --git a/vendor/bitflags-1.3.2/CHANGELOG.md b/vendor/bitflags-1.3.2/CHANGELOG.md +new file mode 100644 +index 0000000..12fea16 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/CHANGELOG.md +@@ -0,0 +1,206 @@ ++# 1.3.2 ++ ++- Allow `non_snake_case` in generated flags types ([#256]) ++ ++[#252]: https://github.com/bitflags/bitflags/pull/256 ++ ++# 1.3.1 ++ ++- Revert unconditional `#[repr(transparent)]` ([#252]) ++ ++[#252]: https://github.com/bitflags/bitflags/pull/252 ++ ++# 1.3.0 (yanked) ++ ++- Add `#[repr(transparent)]` ([#187]) ++ ++- End `empty` doc comment with full stop ([#202]) ++ ++- Fix typo in crate root docs ([#206]) ++ ++- Document from_bits_unchecked unsafety ([#207]) ++ ++- Let `is_all` ignore extra bits ([#211]) ++ ++- Allows empty flag definition ([#225]) ++ ++- Making crate accessible from std ([#227]) ++ ++- Make `from_bits` a const fn ([#229]) ++ ++- Allow multiple bitflags structs in one macro invocation ([#235]) ++ ++- Add named functions to perform set operations ([#244]) ++ ++- Fix typos in method docs ([#245]) ++ ++- Modernization of the `bitflags` macro to take advantage of newer features and 2018 idioms ([#246]) ++ ++- Fix regression (in an unreleased feature) and simplify tests ([#247]) ++ ++- Use `Self` and fix bug when overriding `stringify!` ([#249]) ++ ++[#187]: https://github.com/bitflags/bitflags/pull/187 ++[#202]: https://github.com/bitflags/bitflags/pull/202 ++[#206]: https://github.com/bitflags/bitflags/pull/206 ++[#207]: https://github.com/bitflags/bitflags/pull/207 ++[#211]: https://github.com/bitflags/bitflags/pull/211 ++[#225]: https://github.com/bitflags/bitflags/pull/225 ++[#227]: https://github.com/bitflags/bitflags/pull/227 ++[#229]: https://github.com/bitflags/bitflags/pull/229 ++[#235]: https://github.com/bitflags/bitflags/pull/235 ++[#244]: https://github.com/bitflags/bitflags/pull/244 ++[#245]: https://github.com/bitflags/bitflags/pull/245 ++[#246]: https://github.com/bitflags/bitflags/pull/246 ++[#247]: https://github.com/bitflags/bitflags/pull/247 ++[#249]: https://github.com/bitflags/bitflags/pull/249 ++ ++# 1.2.1 ++ ++- Remove extraneous `#[inline]` attributes ([#194]) ++ ++[#194]: https://github.com/bitflags/bitflags/pull/194 ++ ++# 1.2.0 ++ ++- Fix typo: {Lower, Upper}Exp - {Lower, Upper}Hex ([#183]) ++ ++- Add support for "unknown" bits ([#188]) ++ ++[#183]: https://github.com/rust-lang-nursery/bitflags/pull/183 ++[#188]: https://github.com/rust-lang-nursery/bitflags/pull/188 ++ ++# 1.1.0 ++ ++This is a re-release of `1.0.5`, which was yanked due to a bug in the RLS. ++ ++# 1.0.5 ++ ++- Use compiletest_rs flags supported by stable toolchain ([#171]) ++ ++- Put the user provided attributes first ([#173]) ++ ++- Make bitflags methods `const` on newer compilers ([#175]) ++ ++[#171]: https://github.com/rust-lang-nursery/bitflags/pull/171 ++[#173]: https://github.com/rust-lang-nursery/bitflags/pull/173 ++[#175]: https://github.com/rust-lang-nursery/bitflags/pull/175 ++ ++# 1.0.4 ++ ++- Support Rust 2018 style macro imports ([#165]) ++ ++ ```rust ++ use bitflags::bitflags; ++ ``` ++ ++[#165]: https://github.com/rust-lang-nursery/bitflags/pull/165 ++ ++# 1.0.3 ++ ++- Improve zero value flag handling and documentation ([#157]) ++ ++[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157 ++ ++# 1.0.2 ++ ++- 30% improvement in compile time of bitflags crate ([#156]) ++ ++- Documentation improvements ([#153]) ++ ++- Implementation cleanup ([#149]) ++ ++[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156 ++[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153 ++[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149 ++ ++# 1.0.1 ++- Add support for `pub(restricted)` specifier on the bitflags struct ([#135]) ++- Optimize performance of `all()` when called from a separate crate ([#136]) ++ ++[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135 ++[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136 ++ ++# 1.0.0 ++- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24]) ++ ++- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants ++ ++- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112]) ++ ++- Other improvements to unit tests and documentation ([#106] and [#115]) ++ ++[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24 ++[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106 ++[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112 ++[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115 ++ ++## How to update your code to use associated constants ++Assuming the following structure definition: ++```rust ++bitflags! { ++ struct Something: u8 { ++ const FOO = 0b01, ++ const BAR = 0b10 ++ } ++} ++``` ++In 0.9 and older you could do: ++```rust ++let x = FOO.bits | BAR.bits; ++``` ++Now you must use: ++```rust ++let x = Something::FOO.bits | Something::BAR.bits; ++``` ++ ++# 0.9.1 ++- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105]) ++ ++[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105 ++ ++# 0.9.0 ++- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84]) ++ ++- **[breaking change]** Terminate const items with semicolons instead of commas ([#87]) ++ ++- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86]) ++ ++- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85]) ++ ++- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74]) ++ ++[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74 ++[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84 ++[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85 ++[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86 ++[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87 ++ ++# 0.8.2 ++- Update feature flag used when building bitflags as a dependency of the Rust toolchain ++ ++# 0.8.1 ++- Allow bitflags to be used as a dependency of the Rust toolchain ++ ++# 0.8.0 ++- Add support for the experimental `i128` and `u128` integer types ([#57]) ++- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55]) ++ This may break code that defines its own set method ++ ++[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55 ++[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57 ++ ++# 0.7.1 ++*(yanked)* ++ ++# 0.7.0 ++- Implement the Extend trait ([#49]) ++- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51]) ++ ++[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49 ++[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51 ++ ++# 0.6.0 ++- The `no_std` feature was removed as it is now the default ++- The `assignment_operators` feature was remove as it is now enabled by default ++- Some clippy suggestions have been applied +diff --git a/vendor/bitflags-1.3.2/CODE_OF_CONDUCT.md b/vendor/bitflags-1.3.2/CODE_OF_CONDUCT.md +new file mode 100644 +index 0000000..f7add90 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/CODE_OF_CONDUCT.md +@@ -0,0 +1,73 @@ ++# Contributor Covenant Code of Conduct ++ ++## Our Pledge ++ ++In the interest of fostering an open and welcoming environment, we as ++contributors and maintainers pledge to making participation in our project and ++our community a harassment-free experience for everyone, regardless of age, body ++size, disability, ethnicity, gender identity and expression, level of experience, ++education, socio-economic status, nationality, personal appearance, race, ++religion, or sexual identity and orientation. ++ ++## Our Standards ++ ++Examples of behavior that contributes to creating a positive environment ++include: ++ ++* Using welcoming and inclusive language ++* Being respectful of differing viewpoints and experiences ++* Gracefully accepting constructive criticism ++* Focusing on what is best for the community ++* Showing empathy towards other community members ++ ++Examples of unacceptable behavior by participants include: ++ ++* The use of sexualized language or imagery and unwelcome sexual attention or ++ advances ++* Trolling, insulting/derogatory comments, and personal or political attacks ++* Public or private harassment ++* Publishing others' private information, such as a physical or electronic ++ address, without explicit permission ++* Other conduct which could reasonably be considered inappropriate in a ++ professional setting ++ ++## Our Responsibilities ++ ++Project maintainers are responsible for clarifying the standards of acceptable ++behavior and are expected to take appropriate and fair corrective action in ++response to any instances of unacceptable behavior. ++ ++Project maintainers have the right and responsibility to remove, edit, or ++reject comments, commits, code, wiki edits, issues, and other contributions ++that are not aligned to this Code of Conduct, or to ban temporarily or ++permanently any contributor for other behaviors that they deem inappropriate, ++threatening, offensive, or harmful. ++ ++## Scope ++ ++This Code of Conduct applies both within project spaces and in public spaces ++when an individual is representing the project or its community. Examples of ++representing a project or community include using an official project e-mail ++address, posting via an official social media account, or acting as an appointed ++representative at an online or offline event. Representation of a project may be ++further defined and clarified by project maintainers. ++ ++## Enforcement ++ ++Instances of abusive, harassing, or otherwise unacceptable behavior may be ++reported by contacting the project team at coc@senaite.org. All ++complaints will be reviewed and investigated and will result in a response that ++is deemed necessary and appropriate to the circumstances. The project team is ++obligated to maintain confidentiality with regard to the reporter of an incident. ++Further details of specific enforcement policies may be posted separately. ++ ++Project maintainers who do not follow or enforce the Code of Conduct in good ++faith may face temporary or permanent repercussions as determined by other ++members of the project's leadership. ++ ++## Attribution ++ ++This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, ++available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html ++ ++[homepage]: https://www.contributor-covenant.org +\ No newline at end of file +diff --git a/vendor/bitflags-1.3.2/Cargo.toml b/vendor/bitflags-1.3.2/Cargo.toml +new file mode 100644 +index 0000000..9d54c72 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/Cargo.toml +@@ -0,0 +1,58 @@ ++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO ++# ++# When uploading crates to the registry Cargo will automatically ++# "normalize" Cargo.toml files for maximal compatibility ++# with all versions of Cargo and also rewrite `path` dependencies ++# to registry (e.g., crates.io) dependencies ++# ++# If you believe there's an error in this file please file an ++# issue against the rust-lang/cargo repository. If you're ++# editing this file be aware that the upstream Cargo.toml ++# will likely look very different (and much more reasonable) ++ ++[package] ++edition = "2018" ++name = "bitflags" ++version = "1.3.2" ++authors = ["The Rust Project Developers"] ++exclude = ["bors.toml"] ++description = "A macro to generate structures which behave like bitflags.\n" ++homepage = "https://github.com/bitflags/bitflags" ++documentation = "https://docs.rs/bitflags" ++readme = "README.md" ++keywords = ["bit", "bitmask", "bitflags", "flags"] ++categories = ["no-std"] ++license = "MIT/Apache-2.0" ++repository = "https://github.com/bitflags/bitflags" ++[package.metadata.docs.rs] ++features = ["example_generated"] ++[dependencies.compiler_builtins] ++version = "0.1.2" ++optional = true ++ ++[dependencies.core] ++version = "1.0.0" ++optional = true ++package = "rustc-std-workspace-core" ++[dev-dependencies.rustversion] ++version = "1.0" ++ ++[dev-dependencies.serde] ++version = "1.0" ++ ++[dev-dependencies.serde_derive] ++version = "1.0" ++ ++[dev-dependencies.serde_json] ++version = "1.0" ++ ++[dev-dependencies.trybuild] ++version = "1.0" ++ ++[dev-dependencies.walkdir] ++version = "2.3" ++ ++[features] ++default = [] ++example_generated = [] ++rustc-dep-of-std = ["core", "compiler_builtins"] +diff --git a/vendor/bitflags-1.3.2/LICENSE-APACHE b/vendor/bitflags-1.3.2/LICENSE-APACHE +new file mode 100644 +index 0000000..16fe87b +--- /dev/null ++++ b/vendor/bitflags-1.3.2/LICENSE-APACHE +@@ -0,0 +1,201 @@ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++END OF TERMS AND CONDITIONS ++ ++APPENDIX: How to apply the Apache License to your work. ++ ++ To apply the Apache License to your work, attach the following ++ boilerplate notice, with the fields enclosed by brackets "[]" ++ replaced with your own identifying information. (Don't include ++ the brackets!) The text should be enclosed in the appropriate ++ comment syntax for the file format. We also recommend that a ++ file or class name and description of purpose be included on the ++ same "printed page" as the copyright notice for easier ++ identification within third-party archives. ++ ++Copyright [yyyy] [name of copyright owner] ++ ++Licensed under the Apache License, Version 2.0 (the "License"); ++you may not use this file except in compliance with the License. ++You may obtain a copy of the License at ++ ++ http://www.apache.org/licenses/LICENSE-2.0 ++ ++Unless required by applicable law or agreed to in writing, software ++distributed under the License is distributed on an "AS IS" BASIS, ++WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++See the License for the specific language governing permissions and ++limitations under the License. +diff --git a/vendor/bitflags-1.3.2/LICENSE-MIT b/vendor/bitflags-1.3.2/LICENSE-MIT +new file mode 100644 +index 0000000..39d4bdb +--- /dev/null ++++ b/vendor/bitflags-1.3.2/LICENSE-MIT +@@ -0,0 +1,25 @@ ++Copyright (c) 2014 The Rust Project Developers ++ ++Permission is hereby granted, free of charge, to any ++person obtaining a copy of this software and associated ++documentation files (the "Software"), to deal in the ++Software without restriction, including without ++limitation the rights to use, copy, modify, merge, ++publish, distribute, sublicense, and/or sell copies of ++the Software, and to permit persons to whom the Software ++is furnished to do so, subject to the following ++conditions: ++ ++The above copyright notice and this permission notice ++shall be included in all copies or substantial portions ++of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ++ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED ++TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT ++SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR ++IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. +diff --git a/vendor/bitflags-1.3.2/README.md b/vendor/bitflags-1.3.2/README.md +new file mode 100644 +index 0000000..0da0f85 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/README.md +@@ -0,0 +1,32 @@ ++bitflags ++======== ++ ++[![Rust](https://github.com/bitflags/bitflags/workflows/Rust/badge.svg)](https://github.com/bitflags/bitflags/actions) ++[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) ++[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags) ++[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags) ++![License](https://img.shields.io/crates/l/bitflags.svg) ++ ++A Rust macro to generate structures which behave like a set of bitflags ++ ++- [Documentation](https://docs.rs/bitflags) ++- [Release notes](https://github.com/bitflags/bitflags/releases) ++ ++## Usage ++ ++Add this to your `Cargo.toml`: ++ ++```toml ++[dependencies] ++bitflags = "1.3" ++``` ++ ++and this to your source code: ++ ++```rust ++use bitflags::bitflags; ++``` ++ ++## Rust Version Support ++ ++The minimum supported Rust version is 1.46 due to use of associated constants and const functions. +diff --git a/vendor/bitflags-1.3.2/src/example_generated.rs b/vendor/bitflags-1.3.2/src/example_generated.rs +new file mode 100644 +index 0000000..cf188d9 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/src/example_generated.rs +@@ -0,0 +1,14 @@ ++//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS ++//! CRATE**. ++ ++bitflags! { ++ /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). ++ /// Note that this struct is just for documentation purposes only, it must not be used outside ++ /// this crate. ++ pub struct Flags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; ++ const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++ } ++} +diff --git a/vendor/bitflags-1.3.2/src/lib.rs b/vendor/bitflags-1.3.2/src/lib.rs +new file mode 100644 +index 0000000..935e432 +--- /dev/null ++++ b/vendor/bitflags-1.3.2/src/lib.rs +@@ -0,0 +1,1729 @@ ++// Copyright 2014 The Rust Project Developers. See the COPYRIGHT ++// file at the top-level directory of this distribution and at ++// http://rust-lang.org/COPYRIGHT. ++// ++// Licensed under the Apache License, Version 2.0 or the MIT license ++// , at your ++// option. This file may not be copied, modified, or distributed ++// except according to those terms. ++ ++//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. ++//! It can be used for creating typesafe wrappers around C APIs. ++//! ++//! The `bitflags!` macro generates `struct`s that manage a set of flags. The ++//! flags should only be defined for integer types, otherwise unexpected type ++//! errors may occur at compile time. ++//! ++//! # Example ++//! ++//! ``` ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! struct Flags: u32 { ++//! const A = 0b00000001; ++//! const B = 0b00000010; ++//! const C = 0b00000100; ++//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++//! } ++//! } ++//! ++//! fn main() { ++//! let e1 = Flags::A | Flags::C; ++//! let e2 = Flags::B | Flags::C; ++//! assert_eq!((e1 | e2), Flags::ABC); // union ++//! assert_eq!((e1 & e2), Flags::C); // intersection ++//! assert_eq!((e1 - e2), Flags::A); // set difference ++//! assert_eq!(!e2, Flags::A); // set complement ++//! } ++//! ``` ++//! ++//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code ++//! generated by the above `bitflags!` expansion. ++//! ++//! The generated `struct`s can also be extended with type and trait ++//! implementations: ++//! ++//! ``` ++//! use std::fmt; ++//! ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! struct Flags: u32 { ++//! const A = 0b00000001; ++//! const B = 0b00000010; ++//! } ++//! } ++//! ++//! impl Flags { ++//! pub fn clear(&mut self) { ++//! self.bits = 0; // The `bits` field can be accessed from within the ++//! // same module where the `bitflags!` macro was invoked. ++//! } ++//! } ++//! ++//! impl fmt::Display for Flags { ++//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++//! write!(f, "hi!") ++//! } ++//! } ++//! ++//! fn main() { ++//! let mut flags = Flags::A | Flags::B; ++//! flags.clear(); ++//! assert!(flags.is_empty()); ++//! assert_eq!(format!("{}", flags), "hi!"); ++//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); ++//! assert_eq!(format!("{:?}", Flags::B), "B"); ++//! } ++//! ``` ++//! ++//! # Visibility ++//! ++//! The generated structs and their associated flag constants are not exported ++//! out of the current module by default. A definition can be exported out of ++//! the current module by adding `pub` before `struct`: ++//! ++//! ``` ++//! mod example { ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! pub struct Flags1: u32 { ++//! const A = 0b00000001; ++//! } ++//! ++//! # pub ++//! struct Flags2: u32 { ++//! const B = 0b00000010; ++//! } ++//! } ++//! } ++//! ++//! fn main() { ++//! let flag1 = example::Flags1::A; ++//! let flag2 = example::Flags2::B; // error: const `B` is private ++//! } ++//! ``` ++//! ++//! # Attributes ++//! ++//! Attributes can be attached to the generated `struct`s by placing them ++//! before the `struct` keyword. ++//! ++//! ## Representations ++//! ++//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type ++//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype. ++//! ++//! ``` ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! #[repr(transparent)] ++//! struct Flags: u32 { ++//! const A = 0b00000001; ++//! const B = 0b00000010; ++//! const C = 0b00000100; ++//! } ++//! } ++//! ``` ++//! ++//! # Trait implementations ++//! ++//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` ++//! traits are automatically derived for the `struct`s using the `derive` attribute. ++//! Additional traits can be derived by providing an explicit `derive` ++//! attribute on `struct`. ++//! ++//! The `Extend` and `FromIterator` traits are implemented for the `struct`s, ++//! too: `Extend` adds the union of the instances of the `struct` iterated over, ++//! while `FromIterator` calculates the union. ++//! ++//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also ++//! implemented by displaying the bits value of the internal struct. ++//! ++//! ## Operators ++//! ++//! The following operator traits are implemented for the generated `struct`s: ++//! ++//! - `BitOr` and `BitOrAssign`: union ++//! - `BitAnd` and `BitAndAssign`: intersection ++//! - `BitXor` and `BitXorAssign`: toggle ++//! - `Sub` and `SubAssign`: set difference ++//! - `Not`: set complement ++//! ++//! # Methods ++//! ++//! The following methods are defined for the generated `struct`s: ++//! ++//! - `empty`: an empty set of flags ++//! - `all`: the set of all defined flags ++//! - `bits`: the raw value of the flags currently stored ++//! - `from_bits`: convert from underlying bit representation, unless that ++//! representation contains bits that do not correspond to a ++//! defined flag ++//! - `from_bits_truncate`: convert from underlying bit representation, dropping ++//! any bits that do not correspond to defined flags ++//! - `from_bits_unchecked`: convert from underlying bit representation, keeping ++//! all bits (even those not corresponding to defined ++//! flags) ++//! - `is_empty`: `true` if no flags are currently stored ++//! - `is_all`: `true` if currently set flags exactly equal all defined flags ++//! - `intersects`: `true` if there are flags common to both `self` and `other` ++//! - `contains`: `true` if all of the flags in `other` are contained within `self` ++//! - `insert`: inserts the specified flags in-place ++//! - `remove`: removes the specified flags in-place ++//! - `toggle`: the specified flags will be inserted if not present, and removed ++//! if they are. ++//! - `set`: inserts or removes the specified flags depending on the passed value ++//! - `intersection`: returns a new set of flags, containing only the flags present ++//! in both `self` and `other` (the argument to the function). ++//! - `union`: returns a new set of flags, containing any flags present in ++//! either `self` or `other` (the argument to the function). ++//! - `difference`: returns a new set of flags, containing all flags present in ++//! `self` without any of the flags present in `other` (the ++//! argument to the function). ++//! - `symmetric_difference`: returns a new set of flags, containing all flags ++//! present in either `self` or `other` (the argument ++//! to the function), but not both. ++//! - `complement`: returns a new set of flags, containing all flags which are ++//! not set in `self`, but which are allowed for this type. ++//! ++//! ## Default ++//! ++//! The `Default` trait is not automatically implemented for the generated structs. ++//! ++//! If your default value is equal to `0` (which is the same value as calling `empty()` ++//! on the generated struct), you can simply derive `Default`: ++//! ++//! ``` ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! // Results in default value with bits: 0 ++//! #[derive(Default)] ++//! struct Flags: u32 { ++//! const A = 0b00000001; ++//! const B = 0b00000010; ++//! const C = 0b00000100; ++//! } ++//! } ++//! ++//! fn main() { ++//! let derived_default: Flags = Default::default(); ++//! assert_eq!(derived_default.bits(), 0); ++//! } ++//! ``` ++//! ++//! If your default value is not equal to `0` you need to implement `Default` yourself: ++//! ++//! ``` ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! struct Flags: u32 { ++//! const A = 0b00000001; ++//! const B = 0b00000010; ++//! const C = 0b00000100; ++//! } ++//! } ++//! ++//! // explicit `Default` implementation ++//! impl Default for Flags { ++//! fn default() -> Flags { ++//! Flags::A | Flags::C ++//! } ++//! } ++//! ++//! fn main() { ++//! let implemented_default: Flags = Default::default(); ++//! assert_eq!(implemented_default, (Flags::A | Flags::C)); ++//! } ++//! ``` ++//! ++//! # Zero Flags ++//! ++//! Flags with a value equal to zero will have some strange behavior that one should be aware of. ++//! ++//! ``` ++//! use bitflags::bitflags; ++//! ++//! bitflags! { ++//! struct Flags: u32 { ++//! const NONE = 0b00000000; ++//! const SOME = 0b00000001; ++//! } ++//! } ++//! ++//! fn main() { ++//! let empty = Flags::empty(); ++//! let none = Flags::NONE; ++//! let some = Flags::SOME; ++//! ++//! // Zero flags are treated as always present ++//! assert!(empty.contains(Flags::NONE)); ++//! assert!(none.contains(Flags::NONE)); ++//! assert!(some.contains(Flags::NONE)); ++//! ++//! // Zero flags will be ignored when testing for emptiness ++//! assert!(none.is_empty()); ++//! } ++//! ``` ++//! ++//! Users should generally avoid defining a flag with a value of zero. ++ ++#![cfg_attr(not(test), no_std)] ++#![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] ++ ++#[doc(hidden)] ++pub extern crate core as _core; ++ ++/// The macro used to generate the flag structures. ++/// ++/// See the [crate level docs](../bitflags/index.html) for complete documentation. ++/// ++/// # Example ++/// ++/// ``` ++/// use bitflags::bitflags; ++/// ++/// bitflags! { ++/// struct Flags: u32 { ++/// const A = 0b00000001; ++/// const B = 0b00000010; ++/// const C = 0b00000100; ++/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++/// } ++/// } ++/// ++/// fn main() { ++/// let e1 = Flags::A | Flags::C; ++/// let e2 = Flags::B | Flags::C; ++/// assert_eq!((e1 | e2), Flags::ABC); // union ++/// assert_eq!((e1 & e2), Flags::C); // intersection ++/// assert_eq!((e1 - e2), Flags::A); // set difference ++/// assert_eq!(!e2, Flags::A); // set complement ++/// } ++/// ``` ++/// ++/// The generated `struct`s can also be extended with type and trait ++/// implementations: ++/// ++/// ``` ++/// use std::fmt; ++/// ++/// use bitflags::bitflags; ++/// ++/// bitflags! { ++/// struct Flags: u32 { ++/// const A = 0b00000001; ++/// const B = 0b00000010; ++/// } ++/// } ++/// ++/// impl Flags { ++/// pub fn clear(&mut self) { ++/// self.bits = 0; // The `bits` field can be accessed from within the ++/// // same module where the `bitflags!` macro was invoked. ++/// } ++/// } ++/// ++/// impl fmt::Display for Flags { ++/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++/// write!(f, "hi!") ++/// } ++/// } ++/// ++/// fn main() { ++/// let mut flags = Flags::A | Flags::B; ++/// flags.clear(); ++/// assert!(flags.is_empty()); ++/// assert_eq!(format!("{}", flags), "hi!"); ++/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); ++/// assert_eq!(format!("{:?}", Flags::B), "B"); ++/// } ++/// ``` ++#[macro_export(local_inner_macros)] ++macro_rules! bitflags { ++ ( ++ $(#[$outer:meta])* ++ $vis:vis struct $BitFlags:ident: $T:ty { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:ident = $value:expr; ++ )* ++ } ++ ++ $($t:tt)* ++ ) => { ++ $(#[$outer])* ++ #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] ++ $vis struct $BitFlags { ++ bits: $T, ++ } ++ ++ __impl_bitflags! { ++ $BitFlags: $T { ++ $( ++ $(#[$inner $($args)*])* ++ $Flag = $value; ++ )* ++ } ++ } ++ ++ bitflags! { ++ $($t)* ++ } ++ }; ++ () => {}; ++} ++ ++// A helper macro to implement the `all` function. ++#[macro_export(local_inner_macros)] ++#[doc(hidden)] ++macro_rules! __impl_all_bitflags { ++ ( ++ $BitFlags:ident: $T:ty { ++ $( ++ $(#[$attr:ident $($args:tt)*])* ++ $Flag:ident = $value:expr; ++ )+ ++ } ++ ) => { ++ // See `Debug::fmt` for why this approach is taken. ++ #[allow(non_snake_case)] ++ trait __BitFlags { ++ $( ++ const $Flag: $T = 0; ++ )+ ++ } ++ #[allow(non_snake_case)] ++ impl __BitFlags for $BitFlags { ++ $( ++ __impl_bitflags! { ++ #[allow(deprecated)] ++ $(? #[$attr $($args)*])* ++ const $Flag: $T = Self::$Flag.bits; ++ } ++ )+ ++ } ++ Self { bits: $(::$Flag)|+ } ++ }; ++ ( ++ $BitFlags:ident: $T:ty { } ++ ) => { ++ Self { bits: 0 } ++ }; ++} ++ ++#[macro_export(local_inner_macros)] ++#[doc(hidden)] ++macro_rules! __impl_bitflags { ++ ( ++ $BitFlags:ident: $T:ty { ++ $( ++ $(#[$attr:ident $($args:tt)*])* ++ $Flag:ident = $value:expr; ++ )* ++ } ++ ) => { ++ impl $crate::_core::fmt::Debug for $BitFlags { ++ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { ++ // This convoluted approach is to handle #[cfg]-based flag ++ // omission correctly. For example it needs to support: ++ // ++ // #[cfg(unix)] const A: Flag = /* ... */; ++ // #[cfg(windows)] const B: Flag = /* ... */; ++ ++ // Unconditionally define a check for every flag, even disabled ++ // ones. ++ #[allow(non_snake_case)] ++ trait __BitFlags { ++ $( ++ #[inline] ++ fn $Flag(&self) -> bool { false } ++ )* ++ } ++ ++ // Conditionally override the check for just those flags that ++ // are not #[cfg]ed away. ++ #[allow(non_snake_case)] ++ impl __BitFlags for $BitFlags { ++ $( ++ __impl_bitflags! { ++ #[allow(deprecated)] ++ #[inline] ++ $(? #[$attr $($args)*])* ++ fn $Flag(&self) -> bool { ++ if Self::$Flag.bits == 0 && self.bits != 0 { ++ false ++ } else { ++ self.bits & Self::$Flag.bits == Self::$Flag.bits ++ } ++ } ++ } ++ )* ++ } ++ ++ let mut first = true; ++ $( ++ if ::$Flag(self) { ++ if !first { ++ f.write_str(" | ")?; ++ } ++ first = false; ++ f.write_str($crate::_core::stringify!($Flag))?; ++ } ++ )* ++ let extra_bits = self.bits & !Self::all().bits(); ++ if extra_bits != 0 { ++ if !first { ++ f.write_str(" | ")?; ++ } ++ first = false; ++ f.write_str("0x")?; ++ $crate::_core::fmt::LowerHex::fmt(&extra_bits, f)?; ++ } ++ if first { ++ f.write_str("(empty)")?; ++ } ++ Ok(()) ++ } ++ } ++ impl $crate::_core::fmt::Binary for $BitFlags { ++ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { ++ $crate::_core::fmt::Binary::fmt(&self.bits, f) ++ } ++ } ++ impl $crate::_core::fmt::Octal for $BitFlags { ++ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { ++ $crate::_core::fmt::Octal::fmt(&self.bits, f) ++ } ++ } ++ impl $crate::_core::fmt::LowerHex for $BitFlags { ++ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { ++ $crate::_core::fmt::LowerHex::fmt(&self.bits, f) ++ } ++ } ++ impl $crate::_core::fmt::UpperHex for $BitFlags { ++ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { ++ $crate::_core::fmt::UpperHex::fmt(&self.bits, f) ++ } ++ } ++ ++ #[allow(dead_code)] ++ impl $BitFlags { ++ $( ++ $(#[$attr $($args)*])* ++ pub const $Flag: Self = Self { bits: $value }; ++ )* ++ ++ /// Returns an empty set of flags. ++ #[inline] ++ pub const fn empty() -> Self { ++ Self { bits: 0 } ++ } ++ ++ /// Returns the set containing all flags. ++ #[inline] ++ pub const fn all() -> Self { ++ __impl_all_bitflags! { ++ $BitFlags: $T { ++ $( ++ $(#[$attr $($args)*])* ++ $Flag = $value; ++ )* ++ } ++ } ++ } ++ ++ /// Returns the raw value of the flags currently stored. ++ #[inline] ++ pub const fn bits(&self) -> $T { ++ self.bits ++ } ++ ++ /// Convert from underlying bit representation, unless that ++ /// representation contains bits that do not correspond to a flag. ++ #[inline] ++ pub const fn from_bits(bits: $T) -> $crate::_core::option::Option { ++ if (bits & !Self::all().bits()) == 0 { ++ $crate::_core::option::Option::Some(Self { bits }) ++ } else { ++ $crate::_core::option::Option::None ++ } ++ } ++ ++ /// Convert from underlying bit representation, dropping any bits ++ /// that do not correspond to flags. ++ #[inline] ++ pub const fn from_bits_truncate(bits: $T) -> Self { ++ Self { bits: bits & Self::all().bits } ++ } ++ ++ /// Convert from underlying bit representation, preserving all ++ /// bits (even those not corresponding to a defined flag). ++ /// ++ /// # Safety ++ /// ++ /// The caller of the `bitflags!` macro can chose to allow or ++ /// disallow extra bits for their bitflags type. ++ /// ++ /// The caller of `from_bits_unchecked()` has to ensure that ++ /// all bits correspond to a defined flag or that extra bits ++ /// are valid for this bitflags type. ++ #[inline] ++ pub const unsafe fn from_bits_unchecked(bits: $T) -> Self { ++ Self { bits } ++ } ++ ++ /// Returns `true` if no flags are currently stored. ++ #[inline] ++ pub const fn is_empty(&self) -> bool { ++ self.bits() == Self::empty().bits() ++ } ++ ++ /// Returns `true` if all flags are currently set. ++ #[inline] ++ pub const fn is_all(&self) -> bool { ++ Self::all().bits | self.bits == self.bits ++ } ++ ++ /// Returns `true` if there are flags common to both `self` and `other`. ++ #[inline] ++ pub const fn intersects(&self, other: Self) -> bool { ++ !(Self { bits: self.bits & other.bits}).is_empty() ++ } ++ ++ /// Returns `true` if all of the flags in `other` are contained within `self`. ++ #[inline] ++ pub const fn contains(&self, other: Self) -> bool { ++ (self.bits & other.bits) == other.bits ++ } ++ ++ /// Inserts the specified flags in-place. ++ #[inline] ++ pub fn insert(&mut self, other: Self) { ++ self.bits |= other.bits; ++ } ++ ++ /// Removes the specified flags in-place. ++ #[inline] ++ pub fn remove(&mut self, other: Self) { ++ self.bits &= !other.bits; ++ } ++ ++ /// Toggles the specified flags in-place. ++ #[inline] ++ pub fn toggle(&mut self, other: Self) { ++ self.bits ^= other.bits; ++ } ++ ++ /// Inserts or removes the specified flags depending on the passed value. ++ #[inline] ++ pub fn set(&mut self, other: Self, value: bool) { ++ if value { ++ self.insert(other); ++ } else { ++ self.remove(other); ++ } ++ } ++ ++ /// Returns the intersection between the flags in `self` and ++ /// `other`. ++ /// ++ /// Specifically, the returned set contains only the flags which are ++ /// present in *both* `self` *and* `other`. ++ /// ++ /// This is equivalent to using the `&` operator (e.g. ++ /// [`ops::BitAnd`]), as in `flags & other`. ++ /// ++ /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html ++ #[inline] ++ #[must_use] ++ pub const fn intersection(self, other: Self) -> Self { ++ Self { bits: self.bits & other.bits } ++ } ++ ++ /// Returns the union of between the flags in `self` and `other`. ++ /// ++ /// Specifically, the returned set contains all flags which are ++ /// present in *either* `self` *or* `other`, including any which are ++ /// present in both (see [`Self::symmetric_difference`] if that ++ /// is undesirable). ++ /// ++ /// This is equivalent to using the `|` operator (e.g. ++ /// [`ops::BitOr`]), as in `flags | other`. ++ /// ++ /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html ++ #[inline] ++ #[must_use] ++ pub const fn union(self, other: Self) -> Self { ++ Self { bits: self.bits | other.bits } ++ } ++ ++ /// Returns the difference between the flags in `self` and `other`. ++ /// ++ /// Specifically, the returned set contains all flags present in ++ /// `self`, except for the ones present in `other`. ++ /// ++ /// It is also conceptually equivalent to the "bit-clear" operation: ++ /// `flags & !other` (and this syntax is also supported). ++ /// ++ /// This is equivalent to using the `-` operator (e.g. ++ /// [`ops::Sub`]), as in `flags - other`. ++ /// ++ /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html ++ #[inline] ++ #[must_use] ++ pub const fn difference(self, other: Self) -> Self { ++ Self { bits: self.bits & !other.bits } ++ } ++ ++ /// Returns the [symmetric difference][sym-diff] between the flags ++ /// in `self` and `other`. ++ /// ++ /// Specifically, the returned set contains the flags present which ++ /// are present in `self` or `other`, but that are not present in ++ /// both. Equivalently, it contains the flags present in *exactly ++ /// one* of the sets `self` and `other`. ++ /// ++ /// This is equivalent to using the `^` operator (e.g. ++ /// [`ops::BitXor`]), as in `flags ^ other`. ++ /// ++ /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference ++ /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html ++ #[inline] ++ #[must_use] ++ pub const fn symmetric_difference(self, other: Self) -> Self { ++ Self { bits: self.bits ^ other.bits } ++ } ++ ++ /// Returns the complement of this set of flags. ++ /// ++ /// Specifically, the returned set contains all the flags which are ++ /// not set in `self`, but which are allowed for this type. ++ /// ++ /// Alternatively, it can be thought of as the set difference ++ /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) ++ /// ++ /// This is equivalent to using the `!` operator (e.g. ++ /// [`ops::Not`]), as in `!flags`. ++ /// ++ /// [`Self::all()`]: Self::all ++ /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html ++ #[inline] ++ #[must_use] ++ pub const fn complement(self) -> Self { ++ Self::from_bits_truncate(!self.bits) ++ } ++ ++ } ++ ++ impl $crate::_core::ops::BitOr for $BitFlags { ++ type Output = Self; ++ ++ /// Returns the union of the two sets of flags. ++ #[inline] ++ fn bitor(self, other: $BitFlags) -> Self { ++ Self { bits: self.bits | other.bits } ++ } ++ } ++ ++ impl $crate::_core::ops::BitOrAssign for $BitFlags { ++ /// Adds the set of flags. ++ #[inline] ++ fn bitor_assign(&mut self, other: Self) { ++ self.bits |= other.bits; ++ } ++ } ++ ++ impl $crate::_core::ops::BitXor for $BitFlags { ++ type Output = Self; ++ ++ /// Returns the left flags, but with all the right flags toggled. ++ #[inline] ++ fn bitxor(self, other: Self) -> Self { ++ Self { bits: self.bits ^ other.bits } ++ } ++ } ++ ++ impl $crate::_core::ops::BitXorAssign for $BitFlags { ++ /// Toggles the set of flags. ++ #[inline] ++ fn bitxor_assign(&mut self, other: Self) { ++ self.bits ^= other.bits; ++ } ++ } ++ ++ impl $crate::_core::ops::BitAnd for $BitFlags { ++ type Output = Self; ++ ++ /// Returns the intersection between the two sets of flags. ++ #[inline] ++ fn bitand(self, other: Self) -> Self { ++ Self { bits: self.bits & other.bits } ++ } ++ } ++ ++ impl $crate::_core::ops::BitAndAssign for $BitFlags { ++ /// Disables all flags disabled in the set. ++ #[inline] ++ fn bitand_assign(&mut self, other: Self) { ++ self.bits &= other.bits; ++ } ++ } ++ ++ impl $crate::_core::ops::Sub for $BitFlags { ++ type Output = Self; ++ ++ /// Returns the set difference of the two sets of flags. ++ #[inline] ++ fn sub(self, other: Self) -> Self { ++ Self { bits: self.bits & !other.bits } ++ } ++ } ++ ++ impl $crate::_core::ops::SubAssign for $BitFlags { ++ /// Disables all flags enabled in the set. ++ #[inline] ++ fn sub_assign(&mut self, other: Self) { ++ self.bits &= !other.bits; ++ } ++ } ++ ++ impl $crate::_core::ops::Not for $BitFlags { ++ type Output = Self; ++ ++ /// Returns the complement of this set of flags. ++ #[inline] ++ fn not(self) -> Self { ++ Self { bits: !self.bits } & Self::all() ++ } ++ } ++ ++ impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { ++ fn extend>(&mut self, iterator: T) { ++ for item in iterator { ++ self.insert(item) ++ } ++ } ++ } ++ ++ impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { ++ fn from_iter>(iterator: T) -> Self { ++ let mut result = Self::empty(); ++ result.extend(iterator); ++ result ++ } ++ } ++ }; ++ ++ // Every attribute that the user writes on a const is applied to the ++ // corresponding const that we generate, but within the implementation of ++ // Debug and all() we want to ignore everything but #[cfg] attributes. In ++ // particular, including a #[deprecated] attribute on those items would fail ++ // to compile. ++ // https://github.com/bitflags/bitflags/issues/109 ++ // ++ // Input: ++ // ++ // ? #[cfg(feature = "advanced")] ++ // ? #[deprecated(note = "Use something else.")] ++ // ? #[doc = r"High quality documentation."] ++ // fn f() -> i32 { /* ... */ } ++ // ++ // Output: ++ // ++ // #[cfg(feature = "advanced")] ++ // fn f() -> i32 { /* ... */ } ++ ( ++ $(#[$filtered:meta])* ++ ? #[cfg $($cfgargs:tt)*] ++ $(? #[$rest:ident $($restargs:tt)*])* ++ fn $($item:tt)* ++ ) => { ++ __impl_bitflags! { ++ $(#[$filtered])* ++ #[cfg $($cfgargs)*] ++ $(? #[$rest $($restargs)*])* ++ fn $($item)* ++ } ++ }; ++ ( ++ $(#[$filtered:meta])* ++ // $next != `cfg` ++ ? #[$next:ident $($nextargs:tt)*] ++ $(? #[$rest:ident $($restargs:tt)*])* ++ fn $($item:tt)* ++ ) => { ++ __impl_bitflags! { ++ $(#[$filtered])* ++ // $next filtered out ++ $(? #[$rest $($restargs)*])* ++ fn $($item)* ++ } ++ }; ++ ( ++ $(#[$filtered:meta])* ++ fn $($item:tt)* ++ ) => { ++ $(#[$filtered])* ++ fn $($item)* ++ }; ++ ++ // Every attribute that the user writes on a const is applied to the ++ // corresponding const that we generate, but within the implementation of ++ // Debug and all() we want to ignore everything but #[cfg] attributes. In ++ // particular, including a #[deprecated] attribute on those items would fail ++ // to compile. ++ // https://github.com/bitflags/bitflags/issues/109 ++ // ++ // const version ++ // ++ // Input: ++ // ++ // ? #[cfg(feature = "advanced")] ++ // ? #[deprecated(note = "Use something else.")] ++ // ? #[doc = r"High quality documentation."] ++ // const f: i32 { /* ... */ } ++ // ++ // Output: ++ // ++ // #[cfg(feature = "advanced")] ++ // const f: i32 { /* ... */ } ++ ( ++ $(#[$filtered:meta])* ++ ? #[cfg $($cfgargs:tt)*] ++ $(? #[$rest:ident $($restargs:tt)*])* ++ const $($item:tt)* ++ ) => { ++ __impl_bitflags! { ++ $(#[$filtered])* ++ #[cfg $($cfgargs)*] ++ $(? #[$rest $($restargs)*])* ++ const $($item)* ++ } ++ }; ++ ( ++ $(#[$filtered:meta])* ++ // $next != `cfg` ++ ? #[$next:ident $($nextargs:tt)*] ++ $(? #[$rest:ident $($restargs:tt)*])* ++ const $($item:tt)* ++ ) => { ++ __impl_bitflags! { ++ $(#[$filtered])* ++ // $next filtered out ++ $(? #[$rest $($restargs)*])* ++ const $($item)* ++ } ++ }; ++ ( ++ $(#[$filtered:meta])* ++ const $($item:tt)* ++ ) => { ++ $(#[$filtered])* ++ const $($item)* ++ }; ++} ++ ++#[cfg(feature = "example_generated")] ++pub mod example_generated; ++ ++#[cfg(test)] ++mod tests { ++ use std::collections::hash_map::DefaultHasher; ++ use std::hash::{Hash, Hasher}; ++ ++ bitflags! { ++ #[doc = "> The first principle is that you must not fool yourself — and"] ++ #[doc = "> you are the easiest person to fool."] ++ #[doc = "> "] ++ #[doc = "> - Richard Feynman"] ++ #[derive(Default)] ++ struct Flags: u32 { ++ const A = 0b00000001; ++ #[doc = " macros are way better at generating code than trans is"] ++ const B = 0b00000010; ++ const C = 0b00000100; ++ #[doc = "* cmr bed"] ++ #[doc = "* strcat table"] ++ #[doc = " wait what?"] ++ const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++ } ++ ++ struct _CfgFlags: u32 { ++ #[cfg(unix)] ++ const _CFG_A = 0b01; ++ #[cfg(windows)] ++ const _CFG_B = 0b01; ++ #[cfg(unix)] ++ const _CFG_C = Self::_CFG_A.bits | 0b10; ++ } ++ ++ struct AnotherSetOfFlags: i8 { ++ const ANOTHER_FLAG = -1_i8; ++ } ++ ++ struct LongFlags: u32 { ++ const LONG_A = 0b1111111111111111; ++ } ++ } ++ ++ bitflags! { ++ struct EmptyFlags: u32 { ++ } ++ } ++ ++ #[test] ++ fn test_bits() { ++ assert_eq!(Flags::empty().bits(), 0b00000000); ++ assert_eq!(Flags::A.bits(), 0b00000001); ++ assert_eq!(Flags::ABC.bits(), 0b00000111); ++ ++ assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); ++ assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); ++ ++ assert_eq!(EmptyFlags::empty().bits(), 0b00000000); ++ } ++ ++ #[test] ++ fn test_from_bits() { ++ assert_eq!(Flags::from_bits(0), Some(Flags::empty())); ++ assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); ++ assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); ++ assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); ++ assert_eq!(Flags::from_bits(0b1000), None); ++ ++ assert_eq!( ++ AnotherSetOfFlags::from_bits(!0_i8), ++ Some(AnotherSetOfFlags::ANOTHER_FLAG) ++ ); ++ ++ assert_eq!(EmptyFlags::from_bits(0), Some(EmptyFlags::empty())); ++ assert_eq!(EmptyFlags::from_bits(0b1), None); ++ } ++ ++ #[test] ++ fn test_from_bits_truncate() { ++ assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); ++ assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); ++ assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); ++ assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); ++ assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); ++ assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); ++ ++ assert_eq!( ++ AnotherSetOfFlags::from_bits_truncate(0_i8), ++ AnotherSetOfFlags::empty() ++ ); ++ ++ assert_eq!(EmptyFlags::from_bits_truncate(0), EmptyFlags::empty()); ++ assert_eq!(EmptyFlags::from_bits_truncate(0b1), EmptyFlags::empty()); ++ } ++ ++ #[test] ++ fn test_from_bits_unchecked() { ++ let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; ++ assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty()); ++ assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A); ++ assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B); ++ ++ assert_eq!( ++ unsafe { Flags::from_bits_unchecked(0b11) }, ++ (Flags::A | Flags::B) ++ ); ++ assert_eq!( ++ unsafe { Flags::from_bits_unchecked(0b1000) }, ++ (extra | Flags::empty()) ++ ); ++ assert_eq!( ++ unsafe { Flags::from_bits_unchecked(0b1001) }, ++ (extra | Flags::A) ++ ); ++ ++ let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) }; ++ assert_eq!( ++ unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, ++ (extra | EmptyFlags::empty()) ++ ); ++ } ++ ++ #[test] ++ fn test_is_empty() { ++ assert!(Flags::empty().is_empty()); ++ assert!(!Flags::A.is_empty()); ++ assert!(!Flags::ABC.is_empty()); ++ ++ assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); ++ ++ assert!(EmptyFlags::empty().is_empty()); ++ assert!(EmptyFlags::all().is_empty()); ++ } ++ ++ #[test] ++ fn test_is_all() { ++ assert!(Flags::all().is_all()); ++ assert!(!Flags::A.is_all()); ++ assert!(Flags::ABC.is_all()); ++ ++ let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; ++ assert!(!extra.is_all()); ++ assert!(!(Flags::A | extra).is_all()); ++ assert!((Flags::ABC | extra).is_all()); ++ ++ assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); ++ ++ assert!(EmptyFlags::all().is_all()); ++ assert!(EmptyFlags::empty().is_all()); ++ } ++ ++ #[test] ++ fn test_two_empties_do_not_intersect() { ++ let e1 = Flags::empty(); ++ let e2 = Flags::empty(); ++ assert!(!e1.intersects(e2)); ++ ++ assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); ++ } ++ ++ #[test] ++ fn test_empty_does_not_intersect_with_full() { ++ let e1 = Flags::empty(); ++ let e2 = Flags::ABC; ++ assert!(!e1.intersects(e2)); ++ } ++ ++ #[test] ++ fn test_disjoint_intersects() { ++ let e1 = Flags::A; ++ let e2 = Flags::B; ++ assert!(!e1.intersects(e2)); ++ } ++ ++ #[test] ++ fn test_overlapping_intersects() { ++ let e1 = Flags::A; ++ let e2 = Flags::A | Flags::B; ++ assert!(e1.intersects(e2)); ++ } ++ ++ #[test] ++ fn test_contains() { ++ let e1 = Flags::A; ++ let e2 = Flags::A | Flags::B; ++ assert!(!e1.contains(e2)); ++ assert!(e2.contains(e1)); ++ assert!(Flags::ABC.contains(e2)); ++ ++ assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); ++ ++ assert!(EmptyFlags::empty().contains(EmptyFlags::empty())); ++ } ++ ++ #[test] ++ fn test_insert() { ++ let mut e1 = Flags::A; ++ let e2 = Flags::A | Flags::B; ++ e1.insert(e2); ++ assert_eq!(e1, e2); ++ ++ let mut e3 = AnotherSetOfFlags::empty(); ++ e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); ++ assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); ++ } ++ ++ #[test] ++ fn test_remove() { ++ let mut e1 = Flags::A | Flags::B; ++ let e2 = Flags::A | Flags::C; ++ e1.remove(e2); ++ assert_eq!(e1, Flags::B); ++ ++ let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; ++ e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); ++ assert_eq!(e3, AnotherSetOfFlags::empty()); ++ } ++ ++ #[test] ++ fn test_operators() { ++ let e1 = Flags::A | Flags::C; ++ let e2 = Flags::B | Flags::C; ++ assert_eq!((e1 | e2), Flags::ABC); // union ++ assert_eq!((e1 & e2), Flags::C); // intersection ++ assert_eq!((e1 - e2), Flags::A); // set difference ++ assert_eq!(!e2, Flags::A); // set complement ++ assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle ++ let mut e3 = e1; ++ e3.toggle(e2); ++ assert_eq!(e3, Flags::A | Flags::B); ++ ++ let mut m4 = AnotherSetOfFlags::empty(); ++ m4.toggle(AnotherSetOfFlags::empty()); ++ assert_eq!(m4, AnotherSetOfFlags::empty()); ++ } ++ ++ #[test] ++ fn test_operators_unchecked() { ++ let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; ++ let e1 = Flags::A | Flags::C | extra; ++ let e2 = Flags::B | Flags::C; ++ assert_eq!((e1 | e2), (Flags::ABC | extra)); // union ++ assert_eq!((e1 & e2), Flags::C); // intersection ++ assert_eq!((e1 - e2), (Flags::A | extra)); // set difference ++ assert_eq!(!e2, Flags::A); // set complement ++ assert_eq!(!e1, Flags::B); // set complement ++ assert_eq!(e1 ^ e2, Flags::A | Flags::B | extra); // toggle ++ let mut e3 = e1; ++ e3.toggle(e2); ++ assert_eq!(e3, Flags::A | Flags::B | extra); ++ } ++ ++ #[test] ++ fn test_set_ops_basic() { ++ let ab = Flags::A.union(Flags::B); ++ let ac = Flags::A.union(Flags::C); ++ let bc = Flags::B.union(Flags::C); ++ assert_eq!(ab.bits, 0b011); ++ assert_eq!(bc.bits, 0b110); ++ assert_eq!(ac.bits, 0b101); ++ ++ assert_eq!(ab, Flags::B.union(Flags::A)); ++ assert_eq!(ac, Flags::C.union(Flags::A)); ++ assert_eq!(bc, Flags::C.union(Flags::B)); ++ ++ assert_eq!(ac, Flags::A | Flags::C); ++ assert_eq!(bc, Flags::B | Flags::C); ++ assert_eq!(ab.union(bc), Flags::ABC); ++ ++ assert_eq!(ac, Flags::A | Flags::C); ++ assert_eq!(bc, Flags::B | Flags::C); ++ ++ assert_eq!(ac.union(bc), ac | bc); ++ assert_eq!(ac.union(bc), Flags::ABC); ++ assert_eq!(bc.union(ac), Flags::ABC); ++ ++ assert_eq!(ac.intersection(bc), ac & bc); ++ assert_eq!(ac.intersection(bc), Flags::C); ++ assert_eq!(bc.intersection(ac), Flags::C); ++ ++ assert_eq!(ac.difference(bc), ac - bc); ++ assert_eq!(bc.difference(ac), bc - ac); ++ assert_eq!(ac.difference(bc), Flags::A); ++ assert_eq!(bc.difference(ac), Flags::B); ++ ++ assert_eq!(bc.complement(), !bc); ++ assert_eq!(bc.complement(), Flags::A); ++ assert_eq!(ac.symmetric_difference(bc), Flags::A.union(Flags::B)); ++ assert_eq!(bc.symmetric_difference(ac), Flags::A.union(Flags::B)); ++ } ++ ++ #[test] ++ fn test_set_ops_const() { ++ // These just test that these compile and don't cause use-site panics ++ // (would be possible if we had some sort of UB) ++ const INTERSECT: Flags = Flags::all().intersection(Flags::C); ++ const UNION: Flags = Flags::A.union(Flags::C); ++ const DIFFERENCE: Flags = Flags::all().difference(Flags::A); ++ const COMPLEMENT: Flags = Flags::C.complement(); ++ const SYM_DIFFERENCE: Flags = UNION.symmetric_difference(DIFFERENCE); ++ assert_eq!(INTERSECT, Flags::C); ++ assert_eq!(UNION, Flags::A | Flags::C); ++ assert_eq!(DIFFERENCE, Flags::all() - Flags::A); ++ assert_eq!(COMPLEMENT, !Flags::C); ++ assert_eq!(SYM_DIFFERENCE, (Flags::A | Flags::C) ^ (Flags::all() - Flags::A)); ++ } ++ ++ #[test] ++ fn test_set_ops_unchecked() { ++ let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; ++ let e1 = Flags::A.union(Flags::C).union(extra); ++ let e2 = Flags::B.union(Flags::C); ++ assert_eq!(e1.bits, 0b1101); ++ assert_eq!(e1.union(e2), (Flags::ABC | extra)); ++ assert_eq!(e1.intersection(e2), Flags::C); ++ assert_eq!(e1.difference(e2), Flags::A | extra); ++ assert_eq!(e2.difference(e1), Flags::B); ++ assert_eq!(e2.complement(), Flags::A); ++ assert_eq!(e1.complement(), Flags::B); ++ assert_eq!(e1.symmetric_difference(e2), Flags::A | Flags::B | extra); // toggle ++ } ++ ++ #[test] ++ fn test_set_ops_exhaustive() { ++ // Define a flag that contains gaps to help exercise edge-cases, ++ // especially around "unknown" flags (e.g. ones outside of `all()` ++ // `from_bits_unchecked`). ++ // - when lhs and rhs both have different sets of unknown flags. ++ // - unknown flags at both ends, and in the middle ++ // - cases with "gaps". ++ bitflags! { ++ struct Test: u16 { ++ // Intentionally no `A` ++ const B = 0b000000010; ++ // Intentionally no `C` ++ const D = 0b000001000; ++ const E = 0b000010000; ++ const F = 0b000100000; ++ const G = 0b001000000; ++ // Intentionally no `H` ++ const I = 0b100000000; ++ } ++ } ++ let iter_test_flags = ++ || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) }); ++ ++ for a in iter_test_flags() { ++ assert_eq!( ++ a.complement(), ++ Test::from_bits_truncate(!a.bits), ++ "wrong result: !({:?})", ++ a, ++ ); ++ assert_eq!(a.complement(), !a, "named != op: !({:?})", a); ++ for b in iter_test_flags() { ++ // Check that the named operations produce the expected bitwise ++ // values. ++ assert_eq!( ++ a.union(b).bits, ++ a.bits | b.bits, ++ "wrong result: `{:?}` | `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!( ++ a.intersection(b).bits, ++ a.bits & b.bits, ++ "wrong result: `{:?}` & `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!( ++ a.symmetric_difference(b).bits, ++ a.bits ^ b.bits, ++ "wrong result: `{:?}` ^ `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!( ++ a.difference(b).bits, ++ a.bits & !b.bits, ++ "wrong result: `{:?}` - `{:?}`", ++ a, ++ b, ++ ); ++ // Note: Difference is checked as both `a - b` and `b - a` ++ assert_eq!( ++ b.difference(a).bits, ++ b.bits & !a.bits, ++ "wrong result: `{:?}` - `{:?}`", ++ b, ++ a, ++ ); ++ // Check that the named set operations are equivalent to the ++ // bitwise equivalents ++ assert_eq!(a.union(b), a | b, "named != op: `{:?}` | `{:?}`", a, b,); ++ assert_eq!( ++ a.intersection(b), ++ a & b, ++ "named != op: `{:?}` & `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!( ++ a.symmetric_difference(b), ++ a ^ b, ++ "named != op: `{:?}` ^ `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!(a.difference(b), a - b, "named != op: `{:?}` - `{:?}`", a, b,); ++ // Note: Difference is checked as both `a - b` and `b - a` ++ assert_eq!(b.difference(a), b - a, "named != op: `{:?}` - `{:?}`", b, a,); ++ // Verify that the operations which should be symmetric are ++ // actually symmetric. ++ assert_eq!(a.union(b), b.union(a), "asymmetry: `{:?}` | `{:?}`", a, b,); ++ assert_eq!( ++ a.intersection(b), ++ b.intersection(a), ++ "asymmetry: `{:?}` & `{:?}`", ++ a, ++ b, ++ ); ++ assert_eq!( ++ a.symmetric_difference(b), ++ b.symmetric_difference(a), ++ "asymmetry: `{:?}` ^ `{:?}`", ++ a, ++ b, ++ ); ++ } ++ } ++ } ++ ++ #[test] ++ fn test_set() { ++ let mut e1 = Flags::A | Flags::C; ++ e1.set(Flags::B, true); ++ e1.set(Flags::C, false); ++ ++ assert_eq!(e1, Flags::A | Flags::B); ++ } ++ ++ #[test] ++ fn test_assignment_operators() { ++ let mut m1 = Flags::empty(); ++ let e1 = Flags::A | Flags::C; ++ // union ++ m1 |= Flags::A; ++ assert_eq!(m1, Flags::A); ++ // intersection ++ m1 &= e1; ++ assert_eq!(m1, Flags::A); ++ // set difference ++ m1 -= m1; ++ assert_eq!(m1, Flags::empty()); ++ // toggle ++ m1 ^= e1; ++ assert_eq!(m1, e1); ++ } ++ ++ #[test] ++ fn test_const_fn() { ++ const _M1: Flags = Flags::empty(); ++ ++ const M2: Flags = Flags::A; ++ assert_eq!(M2, Flags::A); ++ ++ const M3: Flags = Flags::C; ++ assert_eq!(M3, Flags::C); ++ } ++ ++ #[test] ++ fn test_extend() { ++ let mut flags; ++ ++ flags = Flags::empty(); ++ flags.extend([].iter().cloned()); ++ assert_eq!(flags, Flags::empty()); ++ ++ flags = Flags::empty(); ++ flags.extend([Flags::A, Flags::B].iter().cloned()); ++ assert_eq!(flags, Flags::A | Flags::B); ++ ++ flags = Flags::A; ++ flags.extend([Flags::A, Flags::B].iter().cloned()); ++ assert_eq!(flags, Flags::A | Flags::B); ++ ++ flags = Flags::B; ++ flags.extend([Flags::A, Flags::ABC].iter().cloned()); ++ assert_eq!(flags, Flags::ABC); ++ } ++ ++ #[test] ++ fn test_from_iterator() { ++ assert_eq!([].iter().cloned().collect::(), Flags::empty()); ++ assert_eq!( ++ [Flags::A, Flags::B].iter().cloned().collect::(), ++ Flags::A | Flags::B ++ ); ++ assert_eq!( ++ [Flags::A, Flags::ABC].iter().cloned().collect::(), ++ Flags::ABC ++ ); ++ } ++ ++ #[test] ++ fn test_lt() { ++ let mut a = Flags::empty(); ++ let mut b = Flags::empty(); ++ ++ assert!(!(a < b) && !(b < a)); ++ b = Flags::B; ++ assert!(a < b); ++ a = Flags::C; ++ assert!(!(a < b) && b < a); ++ b = Flags::C | Flags::B; ++ assert!(a < b); ++ } ++ ++ #[test] ++ fn test_ord() { ++ let mut a = Flags::empty(); ++ let mut b = Flags::empty(); ++ ++ assert!(a <= b && a >= b); ++ a = Flags::A; ++ assert!(a > b && a >= b); ++ assert!(b < a && b <= a); ++ b = Flags::B; ++ assert!(b > a && b >= a); ++ assert!(a < b && a <= b); ++ } ++ ++ fn hash(t: &T) -> u64 { ++ let mut s = DefaultHasher::new(); ++ t.hash(&mut s); ++ s.finish() ++ } ++ ++ #[test] ++ fn test_hash() { ++ let mut x = Flags::empty(); ++ let mut y = Flags::empty(); ++ assert_eq!(hash(&x), hash(&y)); ++ x = Flags::all(); ++ y = Flags::ABC; ++ assert_eq!(hash(&x), hash(&y)); ++ } ++ ++ #[test] ++ fn test_default() { ++ assert_eq!(Flags::empty(), Flags::default()); ++ } ++ ++ #[test] ++ fn test_debug() { ++ assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); ++ assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); ++ assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); ++ let extra = unsafe { Flags::from_bits_unchecked(0xb8) }; ++ assert_eq!(format!("{:?}", extra), "0xb8"); ++ assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8"); ++ ++ assert_eq!( ++ format!("{:?}", Flags::ABC | extra), ++ "A | B | C | ABC | 0xb8" ++ ); ++ ++ assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)"); ++ } ++ ++ #[test] ++ fn test_binary() { ++ assert_eq!(format!("{:b}", Flags::ABC), "111"); ++ assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); ++ let extra = unsafe { Flags::from_bits_unchecked(0b1010000) }; ++ assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111"); ++ assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111"); ++ } ++ ++ #[test] ++ fn test_octal() { ++ assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); ++ assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); ++ let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) }; ++ assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777"); ++ assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777"); ++ } ++ ++ #[test] ++ fn test_lowerhex() { ++ assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); ++ assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); ++ let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; ++ assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff"); ++ assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff"); ++ } ++ ++ #[test] ++ fn test_upperhex() { ++ assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); ++ assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); ++ let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; ++ assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF"); ++ assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF"); ++ } ++ ++ mod submodule { ++ bitflags! { ++ pub struct PublicFlags: i8 { ++ const X = 0; ++ } ++ ++ struct PrivateFlags: i8 { ++ const Y = 0; ++ } ++ } ++ ++ #[test] ++ fn test_private() { ++ let _ = PrivateFlags::Y; ++ } ++ } ++ ++ #[test] ++ fn test_public() { ++ let _ = submodule::PublicFlags::X; ++ } ++ ++ mod t1 { ++ mod foo { ++ pub type Bar = i32; ++ } ++ ++ bitflags! { ++ /// baz ++ struct Flags: foo::Bar { ++ const A = 0b00000001; ++ #[cfg(foo)] ++ const B = 0b00000010; ++ #[cfg(foo)] ++ const C = 0b00000010; ++ } ++ } ++ } ++ ++ #[test] ++ fn test_in_function() { ++ bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ #[cfg(any())] // false ++ const B = 2; ++ } ++ } ++ assert_eq!(Flags::all(), Flags::A); ++ assert_eq!(format!("{:?}", Flags::A), "A"); ++ } ++ ++ #[test] ++ fn test_deprecated() { ++ bitflags! { ++ pub struct TestFlags: u32 { ++ #[deprecated(note = "Use something else.")] ++ const ONE = 1; ++ } ++ } ++ } ++ ++ #[test] ++ fn test_pub_crate() { ++ mod module { ++ bitflags! { ++ pub (crate) struct Test: u8 { ++ const FOO = 1; ++ } ++ } ++ } ++ ++ assert_eq!(module::Test::FOO.bits(), 1); ++ } ++ ++ #[test] ++ fn test_pub_in_module() { ++ mod module { ++ mod submodule { ++ bitflags! { ++ // `pub (in super)` means only the module `module` will ++ // be able to access this. ++ pub (in super) struct Test: u8 { ++ const FOO = 1; ++ } ++ } ++ } ++ ++ mod test { ++ // Note: due to `pub (in super)`, ++ // this cannot be accessed directly by the testing code. ++ pub(super) fn value() -> u8 { ++ super::submodule::Test::FOO.bits() ++ } ++ } ++ ++ pub fn value() -> u8 { ++ test::value() ++ } ++ } ++ ++ assert_eq!(module::value(), 1) ++ } ++ ++ #[test] ++ fn test_zero_value_flags() { ++ bitflags! { ++ struct Flags: u32 { ++ const NONE = 0b0; ++ const SOME = 0b1; ++ } ++ } ++ ++ assert!(Flags::empty().contains(Flags::NONE)); ++ assert!(Flags::SOME.contains(Flags::NONE)); ++ assert!(Flags::NONE.is_empty()); ++ ++ assert_eq!(format!("{:?}", Flags::empty()), "NONE"); ++ assert_eq!(format!("{:?}", Flags::SOME), "SOME"); ++ } ++ ++ #[test] ++ fn test_empty_bitflags() { ++ bitflags! {} ++ } ++ ++ #[test] ++ fn test_u128_bitflags() { ++ bitflags! { ++ struct Flags128: u128 { ++ const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; ++ const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; ++ const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; ++ const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++ } ++ } ++ ++ assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C); ++ assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); ++ assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); ++ assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); ++ assert_eq!( ++ Flags128::ABC.bits, ++ 0x8000_0000_0000_1000_0000_0000_0000_0001 ++ ); ++ assert_eq!(format!("{:?}", Flags128::A), "A"); ++ assert_eq!(format!("{:?}", Flags128::B), "B"); ++ assert_eq!(format!("{:?}", Flags128::C), "C"); ++ assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC"); ++ } ++ ++ #[test] ++ fn test_serde_bitflags_serialize() { ++ let flags = SerdeFlags::A | SerdeFlags::B; ++ ++ let serialized = serde_json::to_string(&flags).unwrap(); ++ ++ assert_eq!(serialized, r#"{"bits":3}"#); ++ } ++ ++ #[test] ++ fn test_serde_bitflags_deserialize() { ++ let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); ++ ++ let expected = SerdeFlags::C | SerdeFlags::D; ++ ++ assert_eq!(deserialized.bits, expected.bits); ++ } ++ ++ #[test] ++ fn test_serde_bitflags_roundtrip() { ++ let flags = SerdeFlags::A | SerdeFlags::B; ++ ++ let deserialized: SerdeFlags = serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); ++ ++ assert_eq!(deserialized.bits, flags.bits); ++ } ++ ++ bitflags! { ++ #[derive(serde::Serialize, serde::Deserialize)] ++ struct SerdeFlags: u32 { ++ const A = 1; ++ const B = 2; ++ const C = 4; ++ const D = 8; ++ } ++ } ++} +diff --git a/vendor/bitflags/tests/basic.rs b/vendor/bitflags-1.3.2/tests/basic.rs +similarity index 100% +rename from vendor/bitflags/tests/basic.rs +rename to vendor/bitflags-1.3.2/tests/basic.rs +diff --git a/vendor/bitflags/tests/compile-fail/impls/copy.rs b/vendor/bitflags-1.3.2/tests/compile-fail/impls/copy.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/impls/copy.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/impls/copy.rs +diff --git a/vendor/bitflags/tests/compile-fail/impls/copy.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/impls/copy.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/impls/copy.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/impls/copy.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/impls/eq.rs b/vendor/bitflags-1.3.2/tests/compile-fail/impls/eq.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/impls/eq.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/impls/eq.rs +diff --git a/vendor/bitflags/tests/compile-fail/impls/eq.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/impls/eq.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/impls/eq.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/impls/eq.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/non_integer_base/all_defined.rs b/vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_defined.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/non_integer_base/all_defined.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_defined.rs +diff --git a/vendor/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/non_integer_base/all_missing.rs b/vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_missing.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/non_integer_base/all_missing.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_missing.rs +diff --git a/vendor/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/visibility/private_field.rs b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_field.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/private_field.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_field.rs +diff --git a/vendor/bitflags/tests/compile-fail/visibility/private_field.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_field.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/private_field.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_field.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/visibility/private_flags.rs b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_flags.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/private_flags.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_flags.rs +diff --git a/vendor/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta +diff --git a/vendor/bitflags/tests/compile-fail/visibility/pub_const.rs b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/pub_const.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/pub_const.rs +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/pub_const.rs +diff --git a/vendor/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta b/vendor/bitflags-1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta +similarity index 100% +rename from vendor/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta +rename to vendor/bitflags-1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta +diff --git a/vendor/bitflags/tests/compile-pass/impls/convert.rs b/vendor/bitflags-1.3.2/tests/compile-pass/impls/convert.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/impls/convert.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/impls/convert.rs +diff --git a/vendor/bitflags/tests/compile-pass/impls/default.rs b/vendor/bitflags-1.3.2/tests/compile-pass/impls/default.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/impls/default.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/impls/default.rs +diff --git a/vendor/bitflags/tests/compile-pass/impls/inherent_methods.rs b/vendor/bitflags-1.3.2/tests/compile-pass/impls/inherent_methods.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/impls/inherent_methods.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/impls/inherent_methods.rs +diff --git a/vendor/bitflags/tests/compile-pass/redefinition/core.rs b/vendor/bitflags-1.3.2/tests/compile-pass/redefinition/core.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/redefinition/core.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/redefinition/core.rs +diff --git a/vendor/bitflags/tests/compile-pass/redefinition/stringify.rs b/vendor/bitflags-1.3.2/tests/compile-pass/redefinition/stringify.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/redefinition/stringify.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/redefinition/stringify.rs +diff --git a/vendor/bitflags/tests/compile-pass/repr/c.rs b/vendor/bitflags-1.3.2/tests/compile-pass/repr/c.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/repr/c.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/repr/c.rs +diff --git a/vendor/bitflags/tests/compile-pass/repr/transparent.rs b/vendor/bitflags-1.3.2/tests/compile-pass/repr/transparent.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/repr/transparent.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/repr/transparent.rs +diff --git a/vendor/bitflags/tests/compile-pass/visibility/bits_field.rs b/vendor/bitflags-1.3.2/tests/compile-pass/visibility/bits_field.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/visibility/bits_field.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/visibility/bits_field.rs +diff --git a/vendor/bitflags/tests/compile-pass/visibility/pub_in.rs b/vendor/bitflags-1.3.2/tests/compile-pass/visibility/pub_in.rs +similarity index 100% +rename from vendor/bitflags/tests/compile-pass/visibility/pub_in.rs +rename to vendor/bitflags-1.3.2/tests/compile-pass/visibility/pub_in.rs +diff --git a/vendor/bitflags/tests/compile.rs b/vendor/bitflags-1.3.2/tests/compile.rs +similarity index 100% +rename from vendor/bitflags/tests/compile.rs +rename to vendor/bitflags-1.3.2/tests/compile.rs +diff --git a/vendor/bitflags/.cargo-checksum.json b/vendor/bitflags/.cargo-checksum.json +index 7e8d470..9ed6cb2 100644 +--- a/vendor/bitflags/.cargo-checksum.json ++++ b/vendor/bitflags/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{"CHANGELOG.md":"d362fc1fccaaf4d421bcf0fe8b80ddb4f625dade0c1ee52d08bd0b95509a49d1","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","Cargo.toml":"87aced7532a7974eb37ab5fe6037f0abafc36d6b2d74891ecd2bf2f14f50d11e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"baa8604f8afb34fd93b9c79729daafb884dedcaf34023e4af8ad037d916061fd","src/example_generated.rs":"e43eb59e90f317f38d436670a6067d2fd9eb35fb319fe716184e4a04e24ed1b2","src/lib.rs":"e6477688535ee326d27238aeedc9cb4320ac35b9d17a4deda09e0587b0ccdbd4","tests/basic.rs":"146f1cbf6279bc609242cd3349f29cb21b41294f5e4921875f5ec95bd83529a2","tests/compile-fail/impls/copy.rs":"b791371237ddc75a7c04d2130e03b462c9c00a80dca08bd45aa97433d9c0d13a","tests/compile-fail/impls/copy.stderr.beta":"77d83484ce221d4b6ff2f7de843929a452d779fcfff428122710dd8218c298e3","tests/compile-fail/impls/eq.rs":"0cee8b9e07d537890e0189710293b53972d0fab63c09366f33c391065afafa99","tests/compile-fail/impls/eq.stderr.beta":"381fc6143d45ce76d7cecc47aa59cb69fe5e79c0b60a4a85d5c6163b400b3cc7","tests/compile-fail/non_integer_base/all_defined.rs":"95e14cad9e94560262f2862c3c01865ac30369b69da1001b0e7285cb55e6cb75","tests/compile-fail/non_integer_base/all_defined.stderr.beta":"1760739a276690903bb03844025587d37939f5dfcbfab309db3c86f32bdbf748","tests/compile-fail/non_integer_base/all_missing.rs":"b3d9da619d23213731ba2581aa7999c796c3c79aaf4f0ee6b11ceec08a11537f","tests/compile-fail/non_integer_base/all_missing.stderr.beta":"37e102290d3867e175b21976be798939f294efb17580d5b51e7b17b590d55132","tests/compile-fail/visibility/private_field.rs":"38e4d3fe6471829360d12c8d09b097f6a21aa93fb51eac3b215d96bdae23316b","tests/compile-fail/visibility/private_field.stderr.beta":"5aa24a3ebb39326f31927721c5017b8beb66c3e501fb865a3fa814c9763bfa0f","tests/compile-fail/visibility/private_flags.rs":"2ce4235802aa4e9c96c4e77d9e31d8401ef58dcda4741325184f0764ab1fe393","tests/compile-fail/visibility/private_flags.stderr.beta":"f3eb9f7baf2689258f3519ff7ee5c6ec3c237264ebcfe63f40c40f2023e5022f","tests/compile-fail/visibility/pub_const.rs":"8f813a97ac518c5ea8ac65b184101912452384afaf7b8d6c5e62f8370eca3c0a","tests/compile-fail/visibility/pub_const.stderr.beta":"823976ae1794d7f5372e2ec9aabba497e7bb88004722904c38da342ed98e8962","tests/compile-pass/impls/convert.rs":"88fe80bfb9cd5779f0e1d92c9ec02a8b6bb67e334c07f2309e9c0ba5ef776eb0","tests/compile-pass/impls/default.rs":"c508f9a461691f44b45142fa5ad599f02326e1de4c0cbca6c0593f4652eba109","tests/compile-pass/impls/inherent_methods.rs":"ecc26388e9a394bfa7a5bb69a5d621ab3d4d1e53f28f657bb8e78fe79f437913","tests/compile-pass/redefinition/core.rs":"ff5b6e72f87acc6ebb12405d3c0f6e3fa62e669933656a454bb63b30ea44179c","tests/compile-pass/redefinition/stringify.rs":"1edbce42b900c14425d7ffa14e83e165ebe452d7dccd8c0a8a821bdec64f5c93","tests/compile-pass/repr/c.rs":"6fda17f7c2edfcd155314579e83d0fc8a16209e400f1f9a5ca77bd9a799041f2","tests/compile-pass/repr/transparent.rs":"6cdc87a2137d8a4e0c8ce9b6cba83c82255f8ea125951bf614418685600489ce","tests/compile-pass/visibility/bits_field.rs":"1f3e5ba5a047440066a9f6bf7b7af33f5b06f6b1da3dd9af6886168199a7ea0a","tests/compile-pass/visibility/pub_in.rs":"e95312ff60966d42ec4bc00225507895a9b8ec24056ce6a9edd9145be35d730f","tests/compile.rs":"f27c67a7dd183ca30efea1b6e0880e3469a6dd63b92b1fd711c082df182c9eec"},"package":"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"} +\ No newline at end of file ++{"files":{"CHANGELOG.md":"c98723b209ac4c66625e034b113a55a43a5c1c9e49c0e3b86123d0cd62bae573","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","CONTRIBUTING.md":"6c9f96eacb20af877ae2d16f024904f3038b93448a8488e9dbcac0df7f6439a5","Cargo.lock":"d3e3bce47b94298f2de893a7d91035f2b73a887905a7ffd4ddb668efdd0aee20","Cargo.toml":"92e110c36340bda13f3b329a2aa24aede8bdcb7fa035806926f7ce438dde87f2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"e9b1329fee85868f1aa674d0505cd95b86a259e2a1762347e5af4a5abedd61d4","SECURITY.md":"68704c8128fa2e776ed7cbda741fbf61ad52f998a96350ee7ee4dbf64c6573bc","benches/parse.rs":"f1390d62322c6880d65bd931e183d49b313f287879a6bfaa36b1cb1921090b51","examples/custom_bits_type.rs":"e53b32051adc5d97860e0b48c8f3a301a041d73b4939c0d7caa5f0cfcc0b9739","examples/custom_derive.rs":"a404e8f606efdd1b43e0c365e4142ccc3dc3ba230127ddeea89cd8784bb55a1e","examples/fmt.rs":"87ba37a1fb8528570c74ea26d8e8948e1179c3d867b928bea1080880258e0a99","examples/macro_free.rs":"69e7f284b53b5214d51228a686e87f127b52a3b74711e45537ebfa5583a180e5","examples/serde.rs":"08b21b35d5c10fdca132fe0f36c8067bb44f559e96617a9257ab6316a20cbc75","spec.md":"fcdd939df30c59b0643be09027df664b71cbea9b9989185441482c5576160fed","src/example_generated.rs":"d018caf059f6ffc4c2403b771a6d76679fa5af03c329a91bd9252957df695e7f","src/external.rs":"734d3f470e6a669297d2df421ce3976fe613d8aa9c071d5ce6fe3ca890e5b815","src/external/arbitrary.rs":"fa8c9187028b9bc54856977b0914676f62101010e7a9450abd577fd78c89552f","src/external/bytemuck.rs":"3afcef382122867040fddd5e4153d633d1ed5596fe5d7dfac66a8e61c2513df5","src/external/serde.rs":"4a09db12534a20fe554a08dc5f1c8124b379292d41fa75628abcd2ca21587573","src/internal.rs":"645b13af0c7302258df61239073a4b8203d09f27b6c17f8a6f1f8c3e427f5334","src/iter.rs":"dbaa6437c1c044f689185ce3fafe43df8796bed19bbdd2c20334a52de5eeee73","src/lib.rs":"1feb0eea02f88491c99c7962b0ce6e66bdedea0ab0cac375d4c9c2d879248dc7","src/parser.rs":"4e788b29f5d0542c409a8b43c703bcb4a6c2a57c181cadd17f565f0abb39681e","src/public.rs":"78ba06e1a5830b36960adf9bd79aaf47d783b9b8a0f1fa33b0d7a340c15fd1d1","src/tests.rs":"b120c27ff0c67a819527de9d8171f1f4c5d37ba4009c54abeb869c70e6035f14","src/tests/all.rs":"e99a865cd4271a524c2fe95503e96d851b35990570aed6fb2e9dac7a14da31b6","src/tests/bits.rs":"3840c34b2ea5d1802404b9ce5bcc1d3fa6ccd8dfba2e29e6d07c605f817d90df","src/tests/complement.rs":"d0e6d4c3daf49e0a7438c9f1c1ac91fad1b37f258c03593f6cd6a695ee626f5e","src/tests/contains.rs":"58bb3cb8c86550e775d11134da1d4aca85c83f943ea454e3a5f222772c674a24","src/tests/difference.rs":"d0d2b96bb52658b8ac019210da74ca75a53e76622f668855142ea6e97c28cb0e","src/tests/empty.rs":"817d6e93ced7cb7576ff0e334aa1a44703f3f96871ff2c6bdcb8f207e6551f67","src/tests/eq.rs":"b816767680a029e9c163e37af074dd4e604c4a3e4936f829f0ca3774fd5f0e37","src/tests/extend.rs":"5fabb9fd0254c64da019149c24063fceff72da3eb4ad73b57c1cc4c04b008364","src/tests/flags.rs":"2f48d3a25db1cf66fe98c9959abc70875deb9f7b38b2c278dc70c46e0d4ec277","src/tests/fmt.rs":"a2d4148491f3202f030f63633eee941b741e3be29a68cf376f008dbe5cb11e5c","src/tests/from_bits.rs":"d94c65b88bf89961d0cfc1b3152a7f1acc285bae160a1628438effda11b8e2c1","src/tests/from_bits_retain.rs":"980591dfaf91e940f42d9a1ce890f237514dd59d458fc264abcf9ceabbc40677","src/tests/from_bits_truncate.rs":"d3406b5e107ebb6449b98a59eee6cc5d84f947d4aaee1ee7e80dc7202de179f0","src/tests/from_name.rs":"f4a055d1f3c86decef70ef8f3020cef5c4e229718c20b3d59d5a3abc3a8b1298","src/tests/insert.rs":"3fab5da800a6fc0654dfb5f859f95da65a507eb9fda8695083c2712266dff0b9","src/tests/intersection.rs":"baf1454c9e4eba552264870a556ee0032d9f2bb8cac361833d571235e0b52221","src/tests/intersects.rs":"c55e36179fd8bc636f04ea9bbce346dcaafe57915d13f1df28c5b83117dbd08e","src/tests/is_all.rs":"b2f11faa7c954bd85c8fb39999e0c37d983cf7895152bc13c7ddde106aa33b6d","src/tests/is_empty.rs":"11f21323cdca7ff92dd89e09de667dba69e8dce88e2d3e27ea68ace91d15d070","src/tests/iter.rs":"4ba121932b527e787b82745405c7c65c1084c242e2dda3290d475ec160d265e4","src/tests/parser.rs":"fa2fb8dedcf16601af609a5e21d9c5840c7f96a1e3a587f7f2ea3dc8387f7628","src/tests/remove.rs":"6e75f8508d2dc1a2cba89ef691f4387a665a4fd13853bb1dd0fd80c783b89947","src/tests/symmetric_difference.rs":"0a89f084f9de1dd5b1932fe72c3b10a3c93cbaa16832b3a31b6a85e3bbd3ba6e","src/tests/union.rs":"88f398ee4600bb1e59bf6d02d1f6ff33f5f853eab5a6c700bd8a683c6ee4651a","src/traits.rs":"b79d008daec546136fae4497966fc85a33663d86ea2d9213fd23b412d4d77b66"},"package":"b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"} +\ No newline at end of file +diff --git a/vendor/bitflags/CHANGELOG.md b/vendor/bitflags/CHANGELOG.md +index 12fea16..f17d469 100644 +--- a/vendor/bitflags/CHANGELOG.md ++++ b/vendor/bitflags/CHANGELOG.md +@@ -1,8 +1,353 @@ ++# 2.6.0 ++ ++## What's Changed ++* Sync CHANGELOG.md with github release notes by @dextero in https://github.com/bitflags/bitflags/pull/402 ++* Update error messages and zerocopy by @KodrAus in https://github.com/bitflags/bitflags/pull/403 ++* Bump minimum declared versions of dependencies by @dextero in https://github.com/bitflags/bitflags/pull/404 ++* chore(deps): bump serde_derive and bytemuck versions by @joshka in https://github.com/bitflags/bitflags/pull/405 ++* add OSFF Scorecard workflow by @KodrAus in https://github.com/bitflags/bitflags/pull/396 ++* Update stderr messages by @KodrAus in https://github.com/bitflags/bitflags/pull/408 ++* Fix typo by @waywardmonkeys in https://github.com/bitflags/bitflags/pull/410 ++* Allow specifying outer attributes in impl mode by @KodrAus in https://github.com/bitflags/bitflags/pull/411 ++ ++## New Contributors ++* @dextero made their first contribution in https://github.com/bitflags/bitflags/pull/402 ++* @joshka made their first contribution in https://github.com/bitflags/bitflags/pull/405 ++* @waywardmonkeys made their first contribution in https://github.com/bitflags/bitflags/pull/410 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.5.0...2.6.0 ++ ++# 2.5.0 ++ ++## What's Changed ++* Derive `Debug` for `Flag` by @tgross35 in https://github.com/bitflags/bitflags/pull/398 ++* Support truncating or strict-named variants of parsing and formatting by @KodrAus in https://github.com/bitflags/bitflags/pull/400 ++ ++## New Contributors ++* @tgross35 made their first contribution in https://github.com/bitflags/bitflags/pull/398 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.2...2.5.0 ++ ++# 2.4.2 ++ ++## What's Changed ++* Cargo.toml: Anchor excludes to root of the package by @jamessan in https://github.com/bitflags/bitflags/pull/387 ++* Update error messages by @KodrAus in https://github.com/bitflags/bitflags/pull/390 ++* Add support for impl mode structs to be repr(packed) by @GnomedDev in https://github.com/bitflags/bitflags/pull/388 ++* Remove old `unused_tuple_struct_fields` lint by @dtolnay in https://github.com/bitflags/bitflags/pull/393 ++* Delete use of `local_inner_macros` by @dtolnay in https://github.com/bitflags/bitflags/pull/392 ++ ++## New Contributors ++* @jamessan made their first contribution in https://github.com/bitflags/bitflags/pull/387 ++* @GnomedDev made their first contribution in https://github.com/bitflags/bitflags/pull/388 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.1...2.4.2 ++ ++# 2.4.1 ++ ++## What's Changed ++* Allow some new pedantic clippy lints by @KodrAus in https://github.com/bitflags/bitflags/pull/380 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.0...2.4.1 ++ ++# 2.4.0 ++ ++## What's Changed ++* Remove html_root_url by @eldruin in https://github.com/bitflags/bitflags/pull/368 ++* Support unnamed flags by @KodrAus in https://github.com/bitflags/bitflags/pull/371 ++* Update smoke test to verify all Clippy and rustc lints by @MitMaro in https://github.com/bitflags/bitflags/pull/374 ++* Specify the behavior of bitflags by @KodrAus in https://github.com/bitflags/bitflags/pull/369 ++ ++## New Contributors ++* @eldruin made their first contribution in https://github.com/bitflags/bitflags/pull/368 ++* @MitMaro made their first contribution in https://github.com/bitflags/bitflags/pull/374 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.3...2.4.0 ++ ++# 2.3.3 ++ ++## Changes to `-=` ++ ++The `-=` operator was incorrectly changed to truncate bits that didn't correspond to valid flags in `2.3.0`. This has ++been fixed up so it once again behaves the same as `-` and `difference`. ++ ++## Changes to `!` ++ ++The `!` operator previously called `Self::from_bits_truncate`, which would truncate any bits that only partially ++overlapped with a valid flag. It will now use `bits & Self::all().bits()`, so any bits that overlap any bits ++specified by any flag will be respected. This is unlikely to have any practical implications, but enables defining ++a flag like `const ALL = !0` as a way to signal that any bit pattern is a known set of flags. ++ ++## Changes to formatting ++ ++Zero-valued flags will never be printed. You'll either get `0x0` for empty flags using debug formatting, or the ++set of flags with zero-valued flags omitted for others. ++ ++Composite flags will no longer be redundantly printed if there are extra bits to print at the end that don't correspond ++to a valid flag. ++ ++## What's Changed ++* Fix up incorrect sub assign behavior and other cleanups by @KodrAus in https://github.com/bitflags/bitflags/pull/366 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.2...2.3.3 ++ ++# 2.3.2 ++ ++## What's Changed ++* [doc] [src/lib.rs] delete redundant path prefix by @OccupyMars2025 in https://github.com/bitflags/bitflags/pull/361 ++ ++## New Contributors ++* @OccupyMars2025 made their first contribution in https://github.com/bitflags/bitflags/pull/361 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.1...2.3.2 ++ ++# 2.3.1 ++ ++## What's Changed ++* Fix Self in flags value expressions by @KodrAus in https://github.com/bitflags/bitflags/pull/355 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.0...2.3.1 ++ ++# 2.3.0 ++ ++## Major changes ++ ++### `BitFlags` trait deprecated in favor of `Flags` trait ++ ++This release introduces the `Flags` trait and deprecates the `BitFlags` trait. These two traits are semver compatible so if you have public API code depending on `BitFlags` you can move to `Flags` without breaking end-users. This is possible because the `BitFlags` trait was never publicly implementable, so it now carries `Flags` as a supertrait. All implementations of `Flags` additionally implement `BitFlags`. ++ ++The `Flags` trait is a publicly implementable version of the old `BitFlags` trait. The original `BitFlags` trait carried some macro baggage that made it difficult to implement, so a new `Flags` trait has been introduced as the _One True Trait_ for interacting with flags types generically. See the the `macro_free` and `custom_derive` examples for more details. ++ ++### `Bits` trait publicly exposed ++ ++The `Bits` trait for the underlying storage of flags values is also now publicly implementable. This lets you define your own exotic backing storage for flags. See the `custom_bits_type` example for more details. ++ ++## What's Changed ++* Use explicit hashes for actions steps by @KodrAus in https://github.com/bitflags/bitflags/pull/350 ++* Support ejecting flags types from the bitflags macro by @KodrAus in https://github.com/bitflags/bitflags/pull/351 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.2.1...2.3.0 ++ ++# 2.2.1 ++ ++## What's Changed ++* Refactor attribute filtering to apply per-flag by @KodrAus in https://github.com/bitflags/bitflags/pull/345 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.2.0...2.2.1 ++ ++# 2.2.0 ++ ++## What's Changed ++* Create SECURITY.md by @KodrAus in https://github.com/bitflags/bitflags/pull/338 ++* add docs to describe the behavior of multi-bit flags by @nicholasbishop in https://github.com/bitflags/bitflags/pull/340 ++* Add support for bytemuck by @KodrAus in https://github.com/bitflags/bitflags/pull/336 ++* Add a top-level macro for filtering attributes by @KodrAus in https://github.com/bitflags/bitflags/pull/341 ++ ++## New Contributors ++* @nicholasbishop made their first contribution in https://github.com/bitflags/bitflags/pull/340 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.1.0...2.2.0 ++ ++# 2.1.0 ++ ++## What's Changed ++* Add docs for the internal Field0 and examples of formatting/parsing by @KodrAus in https://github.com/bitflags/bitflags/pull/328 ++* Add support for arbitrary by @KodrAus in https://github.com/bitflags/bitflags/pull/324 ++* Fix up missing docs for consts within consts by @KodrAus in https://github.com/bitflags/bitflags/pull/330 ++* Ignore clippy lint in generated code by @Jake-Shadle in https://github.com/bitflags/bitflags/pull/331 ++ ++## New Contributors ++* @Jake-Shadle made their first contribution in https://github.com/bitflags/bitflags/pull/331 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.2...2.1.0 ++ ++# 2.0.2 ++ ++## What's Changed ++* Fix up missing isize and usize Bits impls by @KodrAus in https://github.com/bitflags/bitflags/pull/321 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.1...2.0.2 ++ ++# 2.0.1 ++ ++## What's Changed ++* Fix up some docs issues by @KodrAus in https://github.com/bitflags/bitflags/pull/309 ++* Make empty_flag() const. by @tormeh in https://github.com/bitflags/bitflags/pull/313 ++* Fix formatting of multi-bit flags with partial overlap by @KodrAus in https://github.com/bitflags/bitflags/pull/316 ++ ++## New Contributors ++* @tormeh made their first contribution in https://github.com/bitflags/bitflags/pull/313 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0...2.0.1 ++ ++# 2.0.0 ++ ++## Major changes ++ ++This release includes some major changes over `1.x`. If you use `bitflags!` types in your public API then upgrading this library may cause breakage in your downstream users. ++ ++### ⚠️ Serialization ++ ++You'll need to add the `serde` Cargo feature in order to `#[derive(Serialize, Deserialize)]` on your generated flags types: ++ ++```rust ++bitflags! { ++ #[derive(Serialize, Deserialize)] ++ #[serde(transparent)] ++ pub struct Flags: T { ++ .. ++ } ++} ++``` ++ ++where `T` is the underlying bits type you're using, such as `u32`. ++ ++The default serialization format with `serde` **has changed** if you `#[derive(Serialize, Deserialize)]` on your generated flags types. It will now use a formatted string for human-readable formats and the underlying bits type for compact formats. ++ ++To keep the old format, see the https://github.com/KodrAus/bitflags-serde-legacy library. ++ ++### ⚠️ Traits ++ ++Generated flags types now derive fewer traits. If you need to maintain backwards compatibility, you can derive the following yourself: ++ ++```rust ++#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] ++``` ++ ++### ⚠️ Methods ++ ++The unsafe `from_bits_unchecked` method is now a safe `from_bits_retain` method. ++ ++You can add the following method to your generated types to keep them compatible: ++ ++```rust ++#[deprecated = "use the safe `from_bits_retain` method instead"] ++pub unsafe fn from_bits_unchecked(bits: T) -> Self { ++ Self::from_bits_retain(bits) ++} ++``` ++ ++where `T` is the underlying bits type you're using, such as `u32`. ++ ++### ⚠️ `.bits` field ++ ++You can now use the `.bits()` method instead of the old `.bits`. ++ ++The representation of generated flags types has changed from a struct with the single field `bits` to a newtype. ++ ++## What's Changed ++* Fix a typo and call out MSRV bump by @KodrAus in https://github.com/bitflags/bitflags/pull/259 ++* BitFlags trait by @arturoc in https://github.com/bitflags/bitflags/pull/220 ++* Add a hidden trait to discourage manual impls of BitFlags by @KodrAus in https://github.com/bitflags/bitflags/pull/261 ++* Sanitize `Ok` by @konsumlamm in https://github.com/bitflags/bitflags/pull/266 ++* Fix bug in `Debug` implementation by @konsumlamm in https://github.com/bitflags/bitflags/pull/268 ++* Fix a typo in the generated documentation by @wackbyte in https://github.com/bitflags/bitflags/pull/271 ++* Use SPDX license format by @atouchet in https://github.com/bitflags/bitflags/pull/272 ++* serde tests fail in CI by @arturoc in https://github.com/bitflags/bitflags/pull/277 ++* Fix beta test output by @KodrAus in https://github.com/bitflags/bitflags/pull/279 ++* Add example to the README.md file by @tiaanl in https://github.com/bitflags/bitflags/pull/270 ++* Iterator over all the enabled options by @arturoc in https://github.com/bitflags/bitflags/pull/278 ++* from_bits_(truncate) fail with composite flags by @arturoc in https://github.com/bitflags/bitflags/pull/276 ++* Add more platform coverage to CI by @KodrAus in https://github.com/bitflags/bitflags/pull/280 ++* rework the way cfgs are handled by @KodrAus in https://github.com/bitflags/bitflags/pull/281 ++* Split generated code into two types by @KodrAus in https://github.com/bitflags/bitflags/pull/282 ++* expose bitflags iters using nameable types by @KodrAus in https://github.com/bitflags/bitflags/pull/286 ++* Support creating flags from their names by @KodrAus in https://github.com/bitflags/bitflags/pull/287 ++* Update README.md by @KodrAus in https://github.com/bitflags/bitflags/pull/288 ++* Prepare for 2.0.0-rc.1 release by @KodrAus in https://github.com/bitflags/bitflags/pull/289 ++* Add missing "if" to contains doc-comment in traits.rs by @rusty-snake in https://github.com/bitflags/bitflags/pull/291 ++* Forbid unsafe_code by @fintelia in https://github.com/bitflags/bitflags/pull/294 ++* serde: enable no-std support by @nim65s in https://github.com/bitflags/bitflags/pull/296 ++* Add a parser for flags formatted as bar-separated-values by @KodrAus in https://github.com/bitflags/bitflags/pull/297 ++* Prepare for 2.0.0-rc.2 release by @KodrAus in https://github.com/bitflags/bitflags/pull/299 ++* Use strip_prefix instead of starts_with + slice by @QuinnPainter in https://github.com/bitflags/bitflags/pull/301 ++* Fix up some clippy lints by @KodrAus in https://github.com/bitflags/bitflags/pull/302 ++* Prepare for 2.0.0-rc.3 release by @KodrAus in https://github.com/bitflags/bitflags/pull/303 ++* feat: Add minimum permissions to rust.yml workflow by @gabibguti in https://github.com/bitflags/bitflags/pull/305 ++ ++## New Contributors ++* @wackbyte made their first contribution in https://github.com/bitflags/bitflags/pull/271 ++* @atouchet made their first contribution in https://github.com/bitflags/bitflags/pull/272 ++* @tiaanl made their first contribution in https://github.com/bitflags/bitflags/pull/270 ++* @rusty-snake made their first contribution in https://github.com/bitflags/bitflags/pull/291 ++* @fintelia made their first contribution in https://github.com/bitflags/bitflags/pull/294 ++* @nim65s made their first contribution in https://github.com/bitflags/bitflags/pull/296 ++* @QuinnPainter made their first contribution in https://github.com/bitflags/bitflags/pull/301 ++* @gabibguti made their first contribution in https://github.com/bitflags/bitflags/pull/305 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/1.3.2...2.0.0 ++ ++# 2.0.0-rc.3 ++ ++## What's Changed ++* Use strip_prefix instead of starts_with + slice by @QuinnPainter in https://github.com/bitflags/bitflags/pull/301 ++* Fix up some clippy lints by @KodrAus in https://github.com/bitflags/bitflags/pull/302 ++ ++## New Contributors ++* @QuinnPainter made their first contribution in https://github.com/bitflags/bitflags/pull/301 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0-rc.2...2.0.0-rc.3 ++ ++# 2.0.0-rc.2 ++ ++## Changes to `serde` serialization ++ ++**⚠️ NOTE ⚠️** This release changes the default serialization you'll get if you `#[derive(Serialize, Deserialize)]` ++on your generated flags types. It will now use a formatted string for human-readable formats and the underlying bits ++type for compact formats. ++ ++To keep the old behavior, see the [`bitflags-serde-legacy`](https://github.com/KodrAus/bitflags-serde-legacy) library. ++ ++## What's Changed ++ ++* Add missing "if" to contains doc-comment in traits.rs by @rusty-snake in https://github.com/bitflags/bitflags/pull/291 ++* Forbid unsafe_code by @fintelia in https://github.com/bitflags/bitflags/pull/294 ++* serde: enable no-std support by @nim65s in https://github.com/bitflags/bitflags/pull/296 ++* Add a parser for flags formatted as bar-separated-values by @KodrAus in https://github.com/bitflags/bitflags/pull/297 ++ ++## New Contributors ++* @rusty-snake made their first contribution in https://github.com/bitflags/bitflags/pull/291 ++* @fintelia made their first contribution in https://github.com/bitflags/bitflags/pull/294 ++* @nim65s made their first contribution in https://github.com/bitflags/bitflags/pull/296 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0-rc.1...2.0.0-rc.2 ++ ++# 2.0.0-rc.1 ++ ++This is a big release including a few years worth of work on a new `BitFlags` trait, iteration, and better macro organization for future extensibility. ++ ++## What's Changed ++* Fix a typo and call out MSRV bump by @KodrAus in https://github.com/bitflags/bitflags/pull/259 ++* BitFlags trait by @arturoc in https://github.com/bitflags/bitflags/pull/220 ++* Add a hidden trait to discourage manual impls of BitFlags by @KodrAus in https://github.com/bitflags/bitflags/pull/261 ++* Sanitize `Ok` by @konsumlamm in https://github.com/bitflags/bitflags/pull/266 ++* Fix bug in `Debug` implementation by @konsumlamm in https://github.com/bitflags/bitflags/pull/268 ++* Fix a typo in the generated documentation by @wackbyte in https://github.com/bitflags/bitflags/pull/271 ++* Use SPDX license format by @atouchet in https://github.com/bitflags/bitflags/pull/272 ++* serde tests fail in CI by @arturoc in https://github.com/bitflags/bitflags/pull/277 ++* Fix beta test output by @KodrAus in https://github.com/bitflags/bitflags/pull/279 ++* Add example to the README.md file by @tiaanl in https://github.com/bitflags/bitflags/pull/270 ++* Iterator over all the enabled options by @arturoc in https://github.com/bitflags/bitflags/pull/278 ++* from_bits_(truncate) fail with composite flags by @arturoc in https://github.com/bitflags/bitflags/pull/276 ++* Add more platform coverage to CI by @KodrAus in https://github.com/bitflags/bitflags/pull/280 ++* rework the way cfgs are handled by @KodrAus in https://github.com/bitflags/bitflags/pull/281 ++* Split generated code into two types by @KodrAus in https://github.com/bitflags/bitflags/pull/282 ++* expose bitflags iters using nameable types by @KodrAus in https://github.com/bitflags/bitflags/pull/286 ++* Support creating flags from their names by @KodrAus in https://github.com/bitflags/bitflags/pull/287 ++* Update README.md by @KodrAus in https://github.com/bitflags/bitflags/pull/288 ++ ++## New Contributors ++* @wackbyte made their first contribution in https://github.com/bitflags/bitflags/pull/271 ++* @atouchet made their first contribution in https://github.com/bitflags/bitflags/pull/272 ++* @tiaanl made their first contribution in https://github.com/bitflags/bitflags/pull/270 ++ ++**Full Changelog**: https://github.com/bitflags/bitflags/compare/1.3.2...2.0.0-rc.1 ++ + # 1.3.2 + + - Allow `non_snake_case` in generated flags types ([#256]) + +-[#252]: https://github.com/bitflags/bitflags/pull/256 ++[#256]: https://github.com/bitflags/bitflags/pull/256 + + # 1.3.1 + +@@ -12,6 +357,8 @@ + + # 1.3.0 (yanked) + ++**This release bumps the Minimum Supported Rust Version to `1.46.0`** ++ + - Add `#[repr(transparent)]` ([#187]) + + - End `empty` doc comment with full stop ([#202]) +diff --git a/vendor/bitflags/CONTRIBUTING.md b/vendor/bitflags/CONTRIBUTING.md +new file mode 100644 +index 0000000..5883363 +--- /dev/null ++++ b/vendor/bitflags/CONTRIBUTING.md +@@ -0,0 +1,9 @@ ++# Updating compile-fail test outputs ++ ++`bitflags` uses the `trybuild` crate to integration test its macros. Since Rust error messages change frequently enough that `nightly` builds produce spurious failures, we only check the compiler output in `beta` builds. If you run: ++ ++``` ++TRYBUILD=overwrite cargo +beta test --all ++``` ++ ++it will run the tests and update the `trybuild` output files. +diff --git a/vendor/bitflags/Cargo.lock b/vendor/bitflags/Cargo.lock +new file mode 100644 +index 0000000..5f98ce0 +--- /dev/null ++++ b/vendor/bitflags/Cargo.lock +@@ -0,0 +1,383 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "arbitrary" ++version = "1.3.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" ++dependencies = [ ++ "derive_arbitrary", ++] ++ ++[[package]] ++name = "bitflags" ++version = "2.6.0" ++dependencies = [ ++ "arbitrary", ++ "bytemuck", ++ "compiler_builtins", ++ "rustc-std-workspace-core", ++ "rustversion", ++ "serde", ++ "serde_derive", ++ "serde_json", ++ "serde_test", ++ "trybuild", ++ "zerocopy", ++] ++ ++[[package]] ++name = "bytemuck" ++version = "1.16.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" ++dependencies = [ ++ "bytemuck_derive", ++] ++ ++[[package]] ++name = "bytemuck_derive" ++version = "1.7.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "byteorder" ++version = "1.5.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" ++ ++[[package]] ++name = "compiler_builtins" ++version = "0.1.112" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b15acab2bb4fe4dad1f1e31f3d9e714f50ef561a0f87dd8a9da004f14d455e1a" ++ ++[[package]] ++name = "derive_arbitrary" ++version = "1.3.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "equivalent" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" ++ ++[[package]] ++name = "glob" ++version = "0.3.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" ++ ++[[package]] ++name = "hashbrown" ++version = "0.14.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" ++ ++[[package]] ++name = "indexmap" ++version = "2.2.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" ++dependencies = [ ++ "equivalent", ++ "hashbrown", ++] ++ ++[[package]] ++name = "itoa" ++version = "1.0.11" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" ++ ++[[package]] ++name = "memchr" ++version = "2.7.4" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" ++ ++[[package]] ++name = "proc-macro2" ++version = "1.0.86" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" ++dependencies = [ ++ "unicode-ident", ++] ++ ++[[package]] ++name = "quote" ++version = "1.0.36" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" ++dependencies = [ ++ "proc-macro2", ++] ++ ++[[package]] ++name = "rustc-std-workspace-core" ++version = "1.0.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" ++ ++[[package]] ++name = "rustversion" ++version = "1.0.17" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" ++ ++[[package]] ++name = "ryu" ++version = "1.0.18" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" ++ ++[[package]] ++name = "serde" ++version = "1.0.203" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" ++dependencies = [ ++ "serde_derive", ++] ++ ++[[package]] ++name = "serde_derive" ++version = "1.0.203" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "serde_json" ++version = "1.0.117" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" ++dependencies = [ ++ "itoa", ++ "ryu", ++ "serde", ++] ++ ++[[package]] ++name = "serde_spanned" ++version = "0.6.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "serde_test" ++version = "1.0.176" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "syn" ++version = "2.0.68" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "unicode-ident", ++] ++ ++[[package]] ++name = "termcolor" ++version = "1.4.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" ++dependencies = [ ++ "winapi-util", ++] ++ ++[[package]] ++name = "toml" ++version = "0.8.14" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" ++dependencies = [ ++ "serde", ++ "serde_spanned", ++ "toml_datetime", ++ "toml_edit", ++] ++ ++[[package]] ++name = "toml_datetime" ++version = "0.6.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "toml_edit" ++version = "0.22.14" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" ++dependencies = [ ++ "indexmap", ++ "serde", ++ "serde_spanned", ++ "toml_datetime", ++ "winnow", ++] ++ ++[[package]] ++name = "trybuild" ++version = "1.0.96" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3" ++dependencies = [ ++ "glob", ++ "serde", ++ "serde_derive", ++ "serde_json", ++ "termcolor", ++ "toml", ++] ++ ++[[package]] ++name = "unicode-ident" ++version = "1.0.12" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" ++ ++[[package]] ++name = "winapi-util" ++version = "0.1.8" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" ++dependencies = [ ++ "windows-sys", ++] ++ ++[[package]] ++name = "windows-sys" ++version = "0.52.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" ++dependencies = [ ++ "windows-targets", ++] ++ ++[[package]] ++name = "windows-targets" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" ++dependencies = [ ++ "windows_aarch64_gnullvm", ++ "windows_aarch64_msvc", ++ "windows_i686_gnu", ++ "windows_i686_gnullvm", ++ "windows_i686_msvc", ++ "windows_x86_64_gnu", ++ "windows_x86_64_gnullvm", ++ "windows_x86_64_msvc", ++] ++ ++[[package]] ++name = "windows_aarch64_gnullvm" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" ++ ++[[package]] ++name = "windows_aarch64_msvc" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" ++ ++[[package]] ++name = "windows_i686_gnu" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" ++ ++[[package]] ++name = "windows_i686_gnullvm" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" ++ ++[[package]] ++name = "windows_i686_msvc" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" ++ ++[[package]] ++name = "windows_x86_64_gnu" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" ++ ++[[package]] ++name = "windows_x86_64_gnullvm" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" ++ ++[[package]] ++name = "windows_x86_64_msvc" ++version = "0.52.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" ++ ++[[package]] ++name = "winnow" ++version = "0.6.13" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" ++dependencies = [ ++ "memchr", ++] ++ ++[[package]] ++name = "zerocopy" ++version = "0.7.34" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" ++dependencies = [ ++ "byteorder", ++ "zerocopy-derive", ++] ++ ++[[package]] ++name = "zerocopy-derive" ++version = "0.7.34" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] +diff --git a/vendor/bitflags/Cargo.toml b/vendor/bitflags/Cargo.toml +index 9d54c72..54c4b82 100644 +--- a/vendor/bitflags/Cargo.toml ++++ b/vendor/bitflags/Cargo.toml +@@ -3,29 +3,49 @@ + # When uploading crates to the registry Cargo will automatically + # "normalize" Cargo.toml files for maximal compatibility + # with all versions of Cargo and also rewrite `path` dependencies +-# to registry (e.g., crates.io) dependencies ++# to registry (e.g., crates.io) dependencies. + # +-# If you believe there's an error in this file please file an +-# issue against the rust-lang/cargo repository. If you're +-# editing this file be aware that the upstream Cargo.toml +-# will likely look very different (and much more reasonable) ++# If you are reading this file be aware that the original Cargo.toml ++# will likely look very different (and much more reasonable). ++# See Cargo.toml.orig for the original contents. + + [package] +-edition = "2018" ++edition = "2021" ++rust-version = "1.56.0" + name = "bitflags" +-version = "1.3.2" ++version = "2.6.0" + authors = ["The Rust Project Developers"] +-exclude = ["bors.toml"] +-description = "A macro to generate structures which behave like bitflags.\n" ++exclude = [ ++ "/tests", ++ "/.github", ++] ++description = """ ++A macro to generate structures which behave like bitflags. ++""" + homepage = "https://github.com/bitflags/bitflags" + documentation = "https://docs.rs/bitflags" + readme = "README.md" +-keywords = ["bit", "bitmask", "bitflags", "flags"] ++keywords = [ ++ "bit", ++ "bitmask", ++ "bitflags", ++ "flags", ++] + categories = ["no-std"] +-license = "MIT/Apache-2.0" ++license = "MIT OR Apache-2.0" + repository = "https://github.com/bitflags/bitflags" ++ + [package.metadata.docs.rs] + features = ["example_generated"] ++ ++[dependencies.arbitrary] ++version = "1.0" ++optional = true ++ ++[dependencies.bytemuck] ++version = "1.12" ++optional = true ++ + [dependencies.compiler_builtins] + version = "0.1.2" + optional = true +@@ -34,25 +54,43 @@ optional = true + version = "1.0.0" + optional = true + package = "rustc-std-workspace-core" +-[dev-dependencies.rustversion] ++ ++[dependencies.serde] ++version = "1.0.103" ++optional = true ++default-features = false ++ ++[dev-dependencies.arbitrary] + version = "1.0" ++features = ["derive"] ++ ++[dev-dependencies.bytemuck] ++version = "1.12.2" ++features = ["derive"] + +-[dev-dependencies.serde] ++[dev-dependencies.rustversion] + version = "1.0" + + [dev-dependencies.serde_derive] +-version = "1.0" ++version = "1.0.103" + + [dev-dependencies.serde_json] + version = "1.0" + ++[dev-dependencies.serde_test] ++version = "1.0.19" ++ + [dev-dependencies.trybuild] +-version = "1.0" ++version = "1.0.18" + +-[dev-dependencies.walkdir] +-version = "2.3" ++[dev-dependencies.zerocopy] ++version = "0.7" ++features = ["derive"] + + [features] +-default = [] + example_generated = [] +-rustc-dep-of-std = ["core", "compiler_builtins"] ++rustc-dep-of-std = [ ++ "core", ++ "compiler_builtins", ++] ++std = [] +diff --git a/vendor/bitflags/README.md b/vendor/bitflags/README.md +index 0da0f85..f2ad555 100644 +--- a/vendor/bitflags/README.md ++++ b/vendor/bitflags/README.md +@@ -2,14 +2,24 @@ bitflags + ======== + + [![Rust](https://github.com/bitflags/bitflags/workflows/Rust/badge.svg)](https://github.com/bitflags/bitflags/actions) +-[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) + [![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags) + [![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags) + ![License](https://img.shields.io/crates/l/bitflags.svg) + +-A Rust macro to generate structures which behave like a set of bitflags ++`bitflags` generates flags enums with well-defined semantics and ergonomic end-user APIs. ++ ++You can use `bitflags` to: ++ ++- provide more user-friendly bindings to C APIs where flags may or may not be fully known in advance. ++- generate efficient options types with string parsing and formatting support. ++ ++You can't use `bitflags` to: ++ ++- guarantee only bits corresponding to defined flags will ever be set. `bitflags` allows access to the underlying bits type so arbitrary bits may be set. ++- define bitfields. `bitflags` only generates types where set bits denote the presence of some combination of flags. + + - [Documentation](https://docs.rs/bitflags) ++- [Specification](https://github.com/bitflags/bitflags/blob/main/spec.md) + - [Release notes](https://github.com/bitflags/bitflags/releases) + + ## Usage +@@ -18,7 +28,7 @@ Add this to your `Cargo.toml`: + + ```toml + [dependencies] +-bitflags = "1.3" ++bitflags = "2.6.0" + ``` + + and this to your source code: +@@ -27,6 +37,41 @@ and this to your source code: + use bitflags::bitflags; + ``` + ++## Example ++ ++Generate a flags structure: ++ ++```rust ++use bitflags::bitflags; ++ ++// The `bitflags!` macro generates `struct`s that manage a set of flags. ++bitflags! { ++ /// Represents a set of flags. ++ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] ++ struct Flags: u32 { ++ /// The value `A`, at bit position `0`. ++ const A = 0b00000001; ++ /// The value `B`, at bit position `1`. ++ const B = 0b00000010; ++ /// The value `C`, at bit position `2`. ++ const C = 0b00000100; ++ ++ /// The combination of `A`, `B`, and `C`. ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ } ++} ++ ++fn main() { ++ let e1 = Flags::A | Flags::C; ++ let e2 = Flags::B | Flags::C; ++ assert_eq!((e1 | e2), Flags::ABC); // union ++ assert_eq!((e1 & e2), Flags::C); // intersection ++ assert_eq!((e1 - e2), Flags::A); // set difference ++ assert_eq!(!e2, Flags::A); // set complement ++} ++``` ++ + ## Rust Version Support + +-The minimum supported Rust version is 1.46 due to use of associated constants and const functions. ++The minimum supported Rust version is documented in the `Cargo.toml` file. ++This may be bumped in minor releases as necessary. +diff --git a/vendor/bitflags/SECURITY.md b/vendor/bitflags/SECURITY.md +new file mode 100644 +index 0000000..790ac5b +--- /dev/null ++++ b/vendor/bitflags/SECURITY.md +@@ -0,0 +1,13 @@ ++# Security Policy ++ ++## Supported Versions ++ ++Security updates are applied only to the latest release. ++ ++## Reporting a Vulnerability ++ ++If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. ++ ++Please disclose it at [security advisory](https://github.com/bitflags/bitflags/security/advisories/new). ++ ++This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. +diff --git a/vendor/bitflags/benches/parse.rs b/vendor/bitflags/benches/parse.rs +new file mode 100644 +index 0000000..caa9203 +--- /dev/null ++++ b/vendor/bitflags/benches/parse.rs +@@ -0,0 +1,96 @@ ++#![feature(test)] ++ ++extern crate test; ++ ++use std::{ ++ fmt::{self, Display}, ++ str::FromStr, ++}; ++ ++bitflags::bitflags! { ++ struct Flags10: u32 { ++ const A = 0b0000_0000_0000_0001; ++ const B = 0b0000_0000_0000_0010; ++ const C = 0b0000_0000_0000_0100; ++ const D = 0b0000_0000_0000_1000; ++ const E = 0b0000_0000_0001_0000; ++ const F = 0b0000_0000_0010_0000; ++ const G = 0b0000_0000_0100_0000; ++ const H = 0b0000_0000_1000_0000; ++ const I = 0b0000_0001_0000_0000; ++ const J = 0b0000_0010_0000_0000; ++ } ++} ++ ++impl FromStr for Flags10 { ++ type Err = bitflags::parser::ParseError; ++ ++ fn from_str(flags: &str) -> Result { ++ Ok(Flags10(flags.parse()?)) ++ } ++} ++ ++impl Display for Flags10 { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ Display::fmt(&self.0, f) ++ } ++} ++ ++#[bench] ++fn format_flags_1_present(b: &mut test::Bencher) { ++ b.iter(|| Flags10::J.to_string()) ++} ++ ++#[bench] ++fn format_flags_5_present(b: &mut test::Bencher) { ++ b.iter(|| (Flags10::F | Flags10::G | Flags10::H | Flags10::I | Flags10::J).to_string()) ++} ++ ++#[bench] ++fn format_flags_10_present(b: &mut test::Bencher) { ++ b.iter(|| { ++ (Flags10::A ++ | Flags10::B ++ | Flags10::C ++ | Flags10::D ++ | Flags10::E ++ | Flags10::F ++ | Flags10::G ++ | Flags10::H ++ | Flags10::I ++ | Flags10::J) ++ .to_string() ++ }) ++} ++ ++#[bench] ++fn parse_flags_1_10(b: &mut test::Bencher) { ++ b.iter(|| { ++ let flags: Flags10 = "J".parse().unwrap(); ++ flags ++ }) ++} ++ ++#[bench] ++fn parse_flags_5_10(b: &mut test::Bencher) { ++ b.iter(|| { ++ let flags: Flags10 = "F | G | H | I | J".parse().unwrap(); ++ flags ++ }) ++} ++ ++#[bench] ++fn parse_flags_10_10(b: &mut test::Bencher) { ++ b.iter(|| { ++ let flags: Flags10 = "A | B | C | D | E | F | G | H | I | J".parse().unwrap(); ++ flags ++ }) ++} ++ ++#[bench] ++fn parse_flags_1_10_hex(b: &mut test::Bencher) { ++ b.iter(|| { ++ let flags: Flags10 = "0xFF".parse().unwrap(); ++ flags ++ }) ++} +diff --git a/vendor/bitflags/examples/custom_bits_type.rs b/vendor/bitflags/examples/custom_bits_type.rs +new file mode 100644 +index 0000000..8924bfd +--- /dev/null ++++ b/vendor/bitflags/examples/custom_bits_type.rs +@@ -0,0 +1,97 @@ ++use std::ops::{BitAnd, BitOr, BitXor, Not}; ++ ++use bitflags::{Bits, Flag, Flags}; ++ ++// Define a custom container that can be used in flags types ++// Note custom bits types can't be used in `bitflags!` ++// without making the trait impls `const`. This is currently ++// unstable ++#[derive(Clone, Copy, Debug)] ++pub struct CustomBits([bool; 3]); ++ ++impl Bits for CustomBits { ++ const EMPTY: Self = CustomBits([false; 3]); ++ ++ const ALL: Self = CustomBits([true; 3]); ++} ++ ++impl PartialEq for CustomBits { ++ fn eq(&self, other: &Self) -> bool { ++ self.0 == other.0 ++ } ++} ++ ++impl BitAnd for CustomBits { ++ type Output = Self; ++ ++ fn bitand(self, other: Self) -> Self { ++ CustomBits([ ++ self.0[0] & other.0[0], ++ self.0[1] & other.0[1], ++ self.0[2] & other.0[2], ++ ]) ++ } ++} ++ ++impl BitOr for CustomBits { ++ type Output = Self; ++ ++ fn bitor(self, other: Self) -> Self { ++ CustomBits([ ++ self.0[0] | other.0[0], ++ self.0[1] | other.0[1], ++ self.0[2] | other.0[2], ++ ]) ++ } ++} ++ ++impl BitXor for CustomBits { ++ type Output = Self; ++ ++ fn bitxor(self, other: Self) -> Self { ++ CustomBits([ ++ self.0[0] & other.0[0], ++ self.0[1] & other.0[1], ++ self.0[2] & other.0[2], ++ ]) ++ } ++} ++ ++impl Not for CustomBits { ++ type Output = Self; ++ ++ fn not(self) -> Self { ++ CustomBits([!self.0[0], !self.0[1], !self.0[2]]) ++ } ++} ++ ++#[derive(Clone, Copy, Debug)] ++pub struct CustomFlags(CustomBits); ++ ++impl CustomFlags { ++ pub const A: Self = CustomFlags(CustomBits([true, false, false])); ++ pub const B: Self = CustomFlags(CustomBits([false, true, false])); ++ pub const C: Self = CustomFlags(CustomBits([false, false, true])); ++} ++ ++impl Flags for CustomFlags { ++ const FLAGS: &'static [Flag] = &[ ++ Flag::new("A", Self::A), ++ Flag::new("B", Self::B), ++ Flag::new("C", Self::C), ++ ]; ++ ++ type Bits = CustomBits; ++ ++ fn bits(&self) -> Self::Bits { ++ self.0 ++ } ++ ++ fn from_bits_retain(bits: Self::Bits) -> Self { ++ CustomFlags(bits) ++ } ++} ++ ++fn main() { ++ println!("{:?}", CustomFlags::A.union(CustomFlags::C)); ++} +diff --git a/vendor/bitflags/examples/custom_derive.rs b/vendor/bitflags/examples/custom_derive.rs +new file mode 100644 +index 0000000..4239ee4 +--- /dev/null ++++ b/vendor/bitflags/examples/custom_derive.rs +@@ -0,0 +1,23 @@ ++//! An example of implementing the `BitFlags` trait manually for a flags type. ++ ++use std::str; ++ ++use bitflags::bitflags; ++ ++// Define a flags type outside of the `bitflags` macro as a newtype ++// It can accept custom derives for libraries `bitflags` doesn't support natively ++#[derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes)] ++#[repr(transparent)] ++pub struct ManualFlags(u32); ++ ++// Next: use `impl Flags` instead of `struct Flags` ++bitflags! { ++ impl ManualFlags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ } ++} ++ ++fn main() {} +diff --git a/vendor/bitflags/examples/fmt.rs b/vendor/bitflags/examples/fmt.rs +new file mode 100644 +index 0000000..724b207 +--- /dev/null ++++ b/vendor/bitflags/examples/fmt.rs +@@ -0,0 +1,49 @@ ++//! An example of implementing Rust's standard formatting and parsing traits for flags types. ++ ++use core::{fmt, str}; ++ ++bitflags::bitflags! { ++ // You can `#[derive]` the `Debug` trait, but implementing it manually ++ // can produce output like `A | B` instead of `Flags(A | B)`. ++ // #[derive(Debug)] ++ #[derive(PartialEq, Eq)] ++ pub struct Flags: u32 { ++ const A = 1; ++ const B = 2; ++ const C = 4; ++ const D = 8; ++ } ++} ++ ++impl fmt::Debug for Flags { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ bitflags::parser::to_writer(self, f) ++ } ++} ++ ++impl fmt::Display for Flags { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ bitflags::parser::to_writer(self, f) ++ } ++} ++ ++impl str::FromStr for Flags { ++ type Err = bitflags::parser::ParseError; ++ ++ fn from_str(flags: &str) -> Result { ++ bitflags::parser::from_str(flags) ++ } ++} ++ ++fn main() -> Result<(), bitflags::parser::ParseError> { ++ let flags = Flags::A | Flags::B; ++ ++ println!("{}", flags); ++ ++ let formatted = flags.to_string(); ++ let parsed: Flags = formatted.parse()?; ++ ++ assert_eq!(flags, parsed); ++ ++ Ok(()) ++} +diff --git a/vendor/bitflags/examples/macro_free.rs b/vendor/bitflags/examples/macro_free.rs +new file mode 100644 +index 0000000..7563379 +--- /dev/null ++++ b/vendor/bitflags/examples/macro_free.rs +@@ -0,0 +1,61 @@ ++//! An example of implementing the `BitFlags` trait manually for a flags type. ++//! ++//! This example doesn't use any macros. ++ ++use std::{fmt, str}; ++ ++use bitflags::{Flag, Flags}; ++ ++// First: Define your flags type. It just needs to be `Sized + 'static`. ++pub struct ManualFlags(u32); ++ ++// Not required: Define some constants for valid flags ++impl ManualFlags { ++ pub const A: ManualFlags = ManualFlags(0b00000001); ++ pub const B: ManualFlags = ManualFlags(0b00000010); ++ pub const C: ManualFlags = ManualFlags(0b00000100); ++ pub const ABC: ManualFlags = ManualFlags(0b00000111); ++} ++ ++// Next: Implement the `BitFlags` trait, specifying your set of valid flags ++// and iterators ++impl Flags for ManualFlags { ++ const FLAGS: &'static [Flag] = &[ ++ Flag::new("A", Self::A), ++ Flag::new("B", Self::B), ++ Flag::new("C", Self::C), ++ ]; ++ ++ type Bits = u32; ++ ++ fn bits(&self) -> u32 { ++ self.0 ++ } ++ ++ fn from_bits_retain(bits: u32) -> Self { ++ Self(bits) ++ } ++} ++ ++// Not required: Add parsing support ++impl str::FromStr for ManualFlags { ++ type Err = bitflags::parser::ParseError; ++ ++ fn from_str(input: &str) -> Result { ++ bitflags::parser::from_str(input) ++ } ++} ++ ++// Not required: Add formatting support ++impl fmt::Display for ManualFlags { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ bitflags::parser::to_writer(self, f) ++ } ++} ++ ++fn main() { ++ println!( ++ "{}", ++ ManualFlags::A.union(ManualFlags::B).union(ManualFlags::C) ++ ); ++} +diff --git a/vendor/bitflags/examples/serde.rs b/vendor/bitflags/examples/serde.rs +new file mode 100644 +index 0000000..22eae2d +--- /dev/null ++++ b/vendor/bitflags/examples/serde.rs +@@ -0,0 +1,36 @@ ++//! An example of implementing `serde::Serialize` and `serde::Deserialize`. ++//! The `#[serde(transparent)]` attribute is recommended to serialize directly ++//! to the underlying bits type without wrapping it in a `serde` newtype. ++ ++#[cfg(feature = "serde")] ++fn main() { ++ use serde_derive::*; ++ ++ bitflags::bitflags! { ++ #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] ++ #[serde(transparent)] ++ pub struct Flags: u32 { ++ const A = 1; ++ const B = 2; ++ const C = 4; ++ const D = 8; ++ } ++ } ++ ++ let flags = Flags::A | Flags::B; ++ ++ let serialized = serde_json::to_string(&flags).unwrap(); ++ ++ println!("{:?} -> {}", flags, serialized); ++ ++ assert_eq!(serialized, r#""A | B""#); ++ ++ let deserialized: Flags = serde_json::from_str(&serialized).unwrap(); ++ ++ println!("{} -> {:?}", serialized, flags); ++ ++ assert_eq!(deserialized, flags); ++} ++ ++#[cfg(not(feature = "serde"))] ++fn main() {} +diff --git a/vendor/bitflags/spec.md b/vendor/bitflags/spec.md +new file mode 100644 +index 0000000..43dae1d +--- /dev/null ++++ b/vendor/bitflags/spec.md +@@ -0,0 +1,552 @@ ++# Bitflags ++ ++`bitflags` generates flags enums with well-defined semantics and ergonomic end-user APIs. ++ ++You can use `bitflags` to: ++ ++- provide more user-friendly bindings to C APIs where flags may or may not be fully known in advance. ++- generate efficient options types with string parsing and formatting support. ++ ++You can't use `bitflags` to: ++ ++- guarantee only bits corresponding to defined flags will ever be set. `bitflags` allows access to the underlying bits type so arbitrary bits may be set. ++- define bitfields. `bitflags` only generates types where set bits denote the presence of some combination of flags. ++ ++## Definitions ++ ++This section formally defines the terminology and semantics of `bitflags`. It's organized so more fundamental concepts are introduced before those that build on them. It may be helpful to start from the bottom of the section and refer back up to concepts defined earlier. ++ ++Examples use `bitflags` syntax with `u8` as the bits type. ++ ++### Bits type ++ ++A type that defines a fixed number of bits at specific locations. ++ ++---- ++ ++Bits types are typically fixed-width unsigned integers. For example, `u8` is a bits type that defines 8 bits; bit-0 through bit-7. ++ ++### Bits value ++ ++An instance of a bits type where each bit may be set (`1`) or unset (`0`). ++ ++---- ++ ++Some examples of bits values for the bits type `u8` are: ++ ++```rust ++0b0000_0000 ++0b1111_1111 ++0b1010_0101 ++``` ++ ++#### Equality ++ ++Two bits values are equal if their bits are in the same configuration; set bits in one are set in the other, and unset bits in one are unset in the other. ++ ++#### Operations ++ ++Bits values define the bitwise operators and (`&`), or (`|`), exclusive-or (`^`), and negation (`!`) that apply to each of their bits. ++ ++### Flag ++ ++A set of bits in a bits type that may have a unique name. ++ ++---- ++ ++Bits are not required to be exclusive to a flag. Bits are not required to be contiguous. ++ ++The following is a flag for `u8` with the name `A` that includes bit-0: ++ ++```rust ++const A = 0b0000_0001; ++``` ++ ++The following is a flag for `u8` with the name `B` that includes bit-0, and bit-5: ++ ++```rust ++const B = 0b0010_0001; ++``` ++ ++#### Named flag ++ ++A flag with a name. ++ ++---- ++ ++The following is a named flag, where the name is `A`: ++ ++```rust ++const A = 0b0000_0001; ++``` ++ ++#### Unnamed flag ++ ++A flag without a name. ++ ++---- ++ ++The following is an unnamed flag: ++ ++```rust ++const _ = 0b0000_0001; ++``` ++ ++#### Zero-bit flag ++ ++A flag with a set of zero bits. ++ ++---- ++ ++The following is a zero-bit flag: ++ ++```rust ++const ZERO = 0b0000_0000; ++``` ++ ++#### Single-bit flag ++ ++A flag with a set of one bit. ++ ++---- ++ ++The following are single-bit flags: ++ ++```rust ++const A = 0b0000_0001; ++const B = 0b0000_0010; ++``` ++ ++#### Multi-bit flag ++ ++A flag with a set of more than one bit. ++ ++---- ++ ++The following are multi-bit flags: ++ ++```rust ++const A = 0b0000_0011; ++const B = 0b1111_1111; ++``` ++ ++### Flags type ++ ++A set of defined flags over a specific bits type. ++ ++#### Known bit ++ ++A bit in any defined flag. ++ ++---- ++ ++In the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++ const C = 0b0000_0100; ++} ++``` ++ ++the known bits are: ++ ++```rust ++0b0000_0111 ++``` ++ ++#### Unknown bit ++ ++A bit not in any defined flag. ++ ++---- ++ ++In the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++ const C = 0b0000_0100; ++} ++``` ++ ++the unknown bits are: ++ ++```rust ++0b1111_1000 ++``` ++ ++### Flags value ++ ++An instance of a flags type using its specific bits value for storage. ++ ++The flags value of a flag is one where each of its bits is set, and all others are unset. ++ ++#### Contains ++ ++Whether all set bits in a source flags value are also set in a target flags value. ++ ++---- ++ ++Given the flags value: ++ ++```rust ++0b0000_0011 ++``` ++ ++the following flags values are contained: ++ ++```rust ++0b0000_0000 ++0b0000_0010 ++0b0000_0001 ++0b0000_0011 ++``` ++ ++but the following flags values are not contained: ++ ++```rust ++0b0000_1000 ++0b0000_0110 ++``` ++ ++#### Intersects ++ ++Whether any set bits in a source flags value are also set in a target flags value. ++ ++---- ++ ++Given the flags value: ++ ++```rust ++0b0000_0011 ++``` ++ ++the following flags intersect: ++ ++```rust ++0b0000_0010 ++0b0000_0001 ++0b1111_1111 ++``` ++ ++but the following flags values do not intersect: ++ ++```rust ++0b0000_0000 ++0b1111_0000 ++``` ++ ++#### Empty ++ ++Whether all bits in a flags value are unset. ++ ++---- ++ ++The following flags value is empty: ++ ++```rust ++0b0000_0000 ++``` ++ ++The following flags values are not empty: ++ ++```rust ++0b0000_0001 ++0b0110_0000 ++``` ++ ++#### All ++ ++Whether all defined flags are contained in a flags value. ++ ++---- ++ ++Given a flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++} ++``` ++ ++the following flags values all satisfy all: ++ ++```rust ++0b0000_0011 ++0b1000_0011 ++0b1111_1111 ++``` ++ ++### Operations ++ ++Examples in this section all use the given flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++ const C = 0b0000_1100; ++} ++``` ++ ++#### Truncate ++ ++Unset all unknown bits in a flags value. ++ ++---- ++ ++Given the flags value: ++ ++```rust ++0b1111_1111 ++``` ++ ++the result of truncation will be: ++ ++```rust ++0b0000_1111 ++``` ++ ++---- ++ ++Truncating doesn't guarantee that a non-empty result will contain any defined flags. Given the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0101; ++} ++``` ++ ++and the following flags value: ++ ++```rust ++0b0000_1110; ++``` ++ ++The result of truncation will be: ++ ++```rust ++0b0000_0100; ++``` ++ ++which intersects the flag `A`, but doesn't contain it. ++ ++This behavior is possible even when only operating with flags values containing defined flags. Given the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0101; ++ const B = 0b0000_0001; ++} ++``` ++ ++The result of `A ^ B` is `0b0000_0100`, which also doesn't contain any defined flag. ++ ++---- ++ ++If all known bits are in the set of at least one defined single-bit flag, then all operations that produce non-empty results will always contain defined flags. ++ ++#### Union ++ ++The bitwise or (`|`) of the bits in two flags values. ++ ++---- ++ ++The following are examples of the result of unioning flags values: ++ ++```rust ++0b0000_0001 | 0b0000_0010 = 0b0000_0011 ++0b0000_0000 | 0b1111_1111 = 0b1111_1111 ++``` ++ ++#### Intersection ++ ++The bitwise and (`&`) of the bits in two flags values. ++ ++---- ++ ++The following are examples of the result of intersecting flags values: ++ ++```rust ++0b0000_0001 & 0b0000_0010 = 0b0000_0000 ++0b1111_1100 & 0b1111_0111 = 0b1111_0100 ++0b1111_1111 & 0b1111_1111 = 0b1111_1111 ++``` ++ ++#### Symmetric difference ++ ++The bitwise exclusive-or (`^`) of the bits in two flags values. ++ ++---- ++ ++The following are examples of the symmetric difference between two flags values: ++ ++```rust ++0b0000_0001 ^ 0b0000_0010 = 0b0000_0011 ++0b0000_1111 ^ 0b0000_0011 = 0b0000_1100 ++0b1100_0000 ^ 0b0011_0000 = 0b1111_0000 ++``` ++ ++#### Complement ++ ++The bitwise negation (`!`) of the bits in a flags value, truncating the result. ++ ++---- ++ ++The following are examples of the complement of a flags value: ++ ++```rust ++!0b0000_0000 = 0b0000_1111 ++!0b0000_1111 = 0b0000_0000 ++!0b1111_1000 = 0b0000_0111 ++``` ++ ++#### Difference ++ ++The bitwise union (`|`) of the bits in one flags value and the bitwise negation (`!`) of the bits in another. ++ ++---- ++ ++This operation is not equivalent to the intersection of one flags value with the complement of another (`&!`). ++The former will truncate the result, where difference will not. ++ ++---- ++ ++The following are examples of the difference between two flags values: ++ ++```rust ++0b0000_0001 & !0b0000_0010 = 0b0000_0001 ++0b0000_1101 & !0b0000_0011 = 0b0000_1100 ++0b1111_1111 & !0b0000_0001 = 0b1111_1110 ++``` ++ ++### Iteration ++ ++Yield the bits of a source flags value in a set of contained flags values. ++ ++---- ++ ++To be most useful, each yielded flags value should set exactly the bits of a defined flag contained in the source. Any known bits that aren't in the set of any contained flag should be yielded together as a final flags value. ++ ++---- ++ ++Given the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++ const AB = 0b0000_0011; ++} ++``` ++ ++and the following flags value: ++ ++```rust ++0b0000_1111 ++``` ++ ++When iterated it may yield a flags value for `A` and `B`, then a final flag with the unknown bits: ++ ++```rust ++0b0000_0001 ++0b0000_0010 ++0b0000_1100 ++``` ++ ++It may also yield a flags value for `AB`, then a final flag with the unknown bits: ++ ++```rust ++0b0000_0011 ++0b0000_1100 ++``` ++ ++---- ++ ++Given the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0011; ++} ++``` ++ ++and the following flags value: ++ ++```rust ++0b0000_0001 ++``` ++ ++When iterated it will still yield a flags value for the known bit `0b0000_0001` even though it doesn't contain a flag. ++ ++### Formatting ++ ++Format and parse a flags value as text using the following grammar: ++ ++- _Flags:_ (_Whitespace_ _Flag_ _Whitespace_)`|`* ++- _Flag:_ _Name_ | _Hex Number_ ++- _Name:_ The name of any defined flag ++- _Hex Number_: `0x`([0-9a-fA-F])* ++- _Whitespace_: (\s)* ++ ++Flags values can be formatted as _Flags_ by iterating over them, formatting each yielded flags value as a _Flag_. Any yielded flags value that sets exactly the bits of a defined flag with a name should be formatted as a _Name_. Otherwise it must be formatted as a _Hex Number_. ++ ++Formatting and parsing supports three modes: ++ ++- **Retain**: Formatting and parsing roundtrips exactly the bits of the source flags value. This is the default behavior. ++- **Truncate**: Flags values are truncated before formatting, and truncated after parsing. ++- **Strict**: A _Flag_ may only be formatted and parsed as a _Name_. _Hex numbers_ are not allowed. A consequence of this is that unknown bits and any bits that aren't in a contained named flag will be ignored. This is recommended for flags values serialized across API boundaries, like web services. ++ ++Text that is empty or whitespace is an empty flags value. ++ ++---- ++ ++Given the following flags type: ++ ++```rust ++struct Flags { ++ const A = 0b0000_0001; ++ const B = 0b0000_0010; ++ const AB = 0b0000_0011; ++ const C = 0b0000_1100; ++} ++``` ++ ++The following are examples of how flags values can be formatted using any mode: ++ ++```rust ++0b0000_0000 = "" ++0b0000_0001 = "A" ++0b0000_0010 = "B" ++0b0000_0011 = "A | B" ++0b0000_0011 = "AB" ++0b0000_1111 = "A | B | C" ++``` ++ ++Truncate mode will unset any unknown bits: ++ ++```rust ++0b1000_0000 = "" ++0b1111_1111 = "A | B | C" ++0b0000_1000 = "0x8" ++``` ++ ++Retain mode will include any unknown bits as a final _Flag_: ++ ++```rust ++0b1000_0000 = "0x80" ++0b1111_1111 = "A | B | C | 0xf0" ++0b0000_1000 = "0x8" ++``` ++ ++Strict mode will unset any unknown bits, as well as bits not contained in any defined named flags: ++ ++```rust ++0b1000_0000 = "" ++0b1111_1111 = "A | B | C" ++0b0000_1000 = "" ++``` +diff --git a/vendor/bitflags/src/example_generated.rs b/vendor/bitflags/src/example_generated.rs +index cf188d9..abb1118 100644 +--- a/vendor/bitflags/src/example_generated.rs ++++ b/vendor/bitflags/src/example_generated.rs +@@ -1,14 +1,65 @@ + //! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS + //! CRATE**. ++//! ++//! Usually, when you call the `bitflags!` macro, only the `Flags` type would be visible. In this ++//! example, the `Field0`, `Iter`, and `IterRaw` types are also exposed so that you can explore ++//! their APIs. The `Field0` type can be accessed as `self.0` on an instance of `Flags`. + +-bitflags! { ++__declare_public_bitflags! { + /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). + /// Note that this struct is just for documentation purposes only, it must not be used outside + /// this crate. +- pub struct Flags: u32 { ++ pub struct Flags ++} ++ ++__declare_internal_bitflags! { ++ pub struct Field0: u32 ++} ++ ++__impl_internal_bitflags! { ++ Field0: u32, Flags { ++ // Field `A`. ++ /// ++ /// This flag has the value `0b00000001`. ++ const A = 0b00000001; ++ /// Field `B`. ++ /// ++ /// This flag has the value `0b00000010`. ++ const B = 0b00000010; ++ /// Field `C`. ++ /// ++ /// This flag has the value `0b00000100`. ++ const C = 0b00000100; ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ } ++} ++ ++__impl_public_bitflags_forward! { ++ Flags: u32, Field0 ++} ++ ++__impl_public_bitflags_ops! { ++ Flags ++} ++ ++__impl_public_bitflags_iter! { ++ Flags: u32, Flags ++} ++ ++__impl_public_bitflags_consts! { ++ Flags: u32 { ++ /// Field `A`. ++ /// ++ /// This flag has the value `0b00000001`. + const A = 0b00000001; ++ /// Field `B`. ++ /// ++ /// This flag has the value `0b00000010`. + const B = 0b00000010; ++ /// Field `C`. ++ /// ++ /// This flag has the value `0b00000100`. + const C = 0b00000100; +- const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); + } + } +diff --git a/vendor/bitflags/src/external.rs b/vendor/bitflags/src/external.rs +new file mode 100644 +index 0000000..716af83 +--- /dev/null ++++ b/vendor/bitflags/src/external.rs +@@ -0,0 +1,262 @@ ++//! Conditional trait implementations for external libraries. ++ ++/* ++How do I support a new external library? ++ ++Let's say we want to add support for `my_library`. ++ ++First, we create a module under `external`, like `serde` with any specialized code. ++Ideally, any utilities in here should just work off the `Flags` trait and maybe a ++few other assumed bounds. ++ ++Next, re-export the library from the `__private` module here. ++ ++Next, define a macro like so: ++ ++```rust ++#[macro_export] ++#[doc(hidden)] ++#[cfg(feature = "serde")] ++macro_rules! __impl_external_bitflags_my_library { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => { ++ // Implementation goes here ++ }; ++} ++ ++#[macro_export] ++#[doc(hidden)] ++#[cfg(not(feature = "my_library"))] ++macro_rules! __impl_external_bitflags_my_library { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => {}; ++} ++``` ++ ++Note that the macro is actually defined twice; once for when the `my_library` feature ++is available, and once for when it's not. This is because the `__impl_external_bitflags_my_library` ++macro is called in an end-user's library, not in `bitflags`. In an end-user's library we don't ++know whether or not a particular feature of `bitflags` is enabled, so we unconditionally call ++the macro, where the body of that macro depends on the feature flag. ++ ++Now, we add our macro call to the `__impl_external_bitflags` macro body: ++ ++```rust ++__impl_external_bitflags_my_library! { ++ $InternalBitFlags: $T, $PublicBitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag; ++ )* ++ } ++} ++``` ++*/ ++ ++pub(crate) mod __private { ++ #[cfg(feature = "serde")] ++ pub use serde; ++ ++ #[cfg(feature = "arbitrary")] ++ pub use arbitrary; ++ ++ #[cfg(feature = "bytemuck")] ++ pub use bytemuck; ++} ++ ++/// Implements traits from external libraries for the internal bitflags type. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_external_bitflags { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => { ++ // Any new library traits impls should be added here ++ // Use `serde` as an example: generate code when the feature is available, ++ // and a no-op when it isn't ++ ++ $crate::__impl_external_bitflags_serde! { ++ $InternalBitFlags: $T, $PublicBitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag; ++ )* ++ } ++ } ++ ++ $crate::__impl_external_bitflags_arbitrary! { ++ $InternalBitFlags: $T, $PublicBitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag; ++ )* ++ } ++ } ++ ++ $crate::__impl_external_bitflags_bytemuck! { ++ $InternalBitFlags: $T, $PublicBitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag; ++ )* ++ } ++ } ++ }; ++} ++ ++#[cfg(feature = "serde")] ++pub mod serde; ++ ++/// Implement `Serialize` and `Deserialize` for the internal bitflags type. ++#[macro_export] ++#[doc(hidden)] ++#[cfg(feature = "serde")] ++macro_rules! __impl_external_bitflags_serde { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => { ++ impl $crate::__private::serde::Serialize for $InternalBitFlags { ++ fn serialize( ++ &self, ++ serializer: S, ++ ) -> $crate::__private::core::result::Result { ++ $crate::serde::serialize( ++ &$PublicBitFlags::from_bits_retain(self.bits()), ++ serializer, ++ ) ++ } ++ } ++ ++ impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { ++ fn deserialize>( ++ deserializer: D, ++ ) -> $crate::__private::core::result::Result { ++ let flags: $PublicBitFlags = $crate::serde::deserialize(deserializer)?; ++ ++ Ok(flags.0) ++ } ++ } ++ }; ++} ++ ++#[macro_export] ++#[doc(hidden)] ++#[cfg(not(feature = "serde"))] ++macro_rules! __impl_external_bitflags_serde { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => {}; ++} ++ ++#[cfg(feature = "arbitrary")] ++pub mod arbitrary; ++ ++#[cfg(feature = "bytemuck")] ++mod bytemuck; ++ ++/// Implement `Arbitrary` for the internal bitflags type. ++#[macro_export] ++#[doc(hidden)] ++#[cfg(feature = "arbitrary")] ++macro_rules! __impl_external_bitflags_arbitrary { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => { ++ impl<'a> $crate::__private::arbitrary::Arbitrary<'a> for $InternalBitFlags { ++ fn arbitrary( ++ u: &mut $crate::__private::arbitrary::Unstructured<'a>, ++ ) -> $crate::__private::arbitrary::Result { ++ $crate::arbitrary::arbitrary::<$PublicBitFlags>(u).map(|flags| flags.0) ++ } ++ } ++ }; ++} ++ ++#[macro_export] ++#[doc(hidden)] ++#[cfg(not(feature = "arbitrary"))] ++macro_rules! __impl_external_bitflags_arbitrary { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => {}; ++} ++ ++/// Implement `Pod` and `Zeroable` for the internal bitflags type. ++#[macro_export] ++#[doc(hidden)] ++#[cfg(feature = "bytemuck")] ++macro_rules! __impl_external_bitflags_bytemuck { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => { ++ // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, ++ // and $T implements Pod ++ unsafe impl $crate::__private::bytemuck::Pod for $InternalBitFlags where ++ $T: $crate::__private::bytemuck::Pod ++ { ++ } ++ ++ // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, ++ // and $T implements Zeroable ++ unsafe impl $crate::__private::bytemuck::Zeroable for $InternalBitFlags where ++ $T: $crate::__private::bytemuck::Zeroable ++ { ++ } ++ }; ++} ++ ++#[macro_export] ++#[doc(hidden)] ++#[cfg(not(feature = "bytemuck"))] ++macro_rules! __impl_external_bitflags_bytemuck { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt; ++ )* ++ } ++ ) => {}; ++} +diff --git a/vendor/bitflags/src/external/arbitrary.rs b/vendor/bitflags/src/external/arbitrary.rs +new file mode 100644 +index 0000000..ea76f0a +--- /dev/null ++++ b/vendor/bitflags/src/external/arbitrary.rs +@@ -0,0 +1,33 @@ ++//! Specialized fuzzing for flags types using `arbitrary`. ++ ++use crate::Flags; ++ ++/** ++Generate some arbitrary flags value with only known bits set. ++*/ ++pub fn arbitrary<'a, B: Flags>(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result ++where ++ B::Bits: arbitrary::Arbitrary<'a>, ++{ ++ B::from_bits(u.arbitrary()?).ok_or_else(|| arbitrary::Error::IncorrectFormat) ++} ++ ++#[cfg(test)] ++mod tests { ++ use arbitrary::Arbitrary; ++ ++ bitflags! { ++ #[derive(Arbitrary)] ++ struct Color: u32 { ++ const RED = 0x1; ++ const GREEN = 0x2; ++ const BLUE = 0x4; ++ } ++ } ++ ++ #[test] ++ fn test_arbitrary() { ++ let mut unstructured = arbitrary::Unstructured::new(&[0_u8; 256]); ++ let _color = Color::arbitrary(&mut unstructured); ++ } ++} +diff --git a/vendor/bitflags/src/external/bytemuck.rs b/vendor/bitflags/src/external/bytemuck.rs +new file mode 100644 +index 0000000..a0cd68c +--- /dev/null ++++ b/vendor/bitflags/src/external/bytemuck.rs +@@ -0,0 +1,19 @@ ++#[cfg(test)] ++mod tests { ++ use bytemuck::{Pod, Zeroable}; ++ ++ bitflags! { ++ #[derive(Pod, Zeroable, Clone, Copy)] ++ #[repr(transparent)] ++ struct Color: u32 { ++ const RED = 0x1; ++ const GREEN = 0x2; ++ const BLUE = 0x4; ++ } ++ } ++ ++ #[test] ++ fn test_bytemuck() { ++ assert_eq!(0x1, bytemuck::cast::(Color::RED)); ++ } ++} +diff --git a/vendor/bitflags/src/external/serde.rs b/vendor/bitflags/src/external/serde.rs +new file mode 100644 +index 0000000..be4f2ed +--- /dev/null ++++ b/vendor/bitflags/src/external/serde.rs +@@ -0,0 +1,93 @@ ++//! Specialized serialization for flags types using `serde`. ++ ++use crate::{ ++ parser::{self, ParseHex, WriteHex}, ++ Flags, ++}; ++use core::{fmt, str}; ++use serde::{ ++ de::{Error, Visitor}, ++ Deserialize, Deserializer, Serialize, Serializer, ++}; ++ ++/** ++Serialize a set of flags as a human-readable string or their underlying bits. ++ ++Any unknown bits will be retained. ++*/ ++pub fn serialize(flags: &B, serializer: S) -> Result ++where ++ B::Bits: WriteHex + Serialize, ++{ ++ // Serialize human-readable flags as a string like `"A | B"` ++ if serializer.is_human_readable() { ++ serializer.collect_str(&parser::AsDisplay(flags)) ++ } ++ // Serialize non-human-readable flags directly as the underlying bits ++ else { ++ flags.bits().serialize(serializer) ++ } ++} ++ ++/** ++Deserialize a set of flags from a human-readable string or their underlying bits. ++ ++Any unknown bits will be retained. ++*/ ++pub fn deserialize<'de, B: Flags, D: Deserializer<'de>>(deserializer: D) -> Result ++where ++ B::Bits: ParseHex + Deserialize<'de>, ++{ ++ if deserializer.is_human_readable() { ++ // Deserialize human-readable flags by parsing them from strings like `"A | B"` ++ struct FlagsVisitor(core::marker::PhantomData); ++ ++ impl<'de, B: Flags> Visitor<'de> for FlagsVisitor ++ where ++ B::Bits: ParseHex, ++ { ++ type Value = B; ++ ++ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { ++ formatter.write_str("a string value of `|` separated flags") ++ } ++ ++ fn visit_str(self, flags: &str) -> Result { ++ parser::from_str(flags).map_err(|e| E::custom(e)) ++ } ++ } ++ ++ deserializer.deserialize_str(FlagsVisitor(Default::default())) ++ } else { ++ // Deserialize non-human-readable flags directly from the underlying bits ++ let bits = B::Bits::deserialize(deserializer)?; ++ ++ Ok(B::from_bits_retain(bits)) ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use serde_test::{assert_tokens, Configure, Token::*}; ++ bitflags! { ++ #[derive(serde_derive::Serialize, serde_derive::Deserialize, Debug, PartialEq, Eq)] ++ #[serde(transparent)] ++ struct SerdeFlags: u32 { ++ const A = 1; ++ const B = 2; ++ const C = 4; ++ const D = 8; ++ } ++ } ++ ++ #[test] ++ fn test_serde_bitflags_default() { ++ assert_tokens(&SerdeFlags::empty().readable(), &[Str("")]); ++ ++ assert_tokens(&SerdeFlags::empty().compact(), &[U32(0)]); ++ ++ assert_tokens(&(SerdeFlags::A | SerdeFlags::B).readable(), &[Str("A | B")]); ++ ++ assert_tokens(&(SerdeFlags::A | SerdeFlags::B).compact(), &[U32(1 | 2)]); ++ } ++} +diff --git a/vendor/bitflags/src/internal.rs b/vendor/bitflags/src/internal.rs +new file mode 100644 +index 0000000..87d01cc +--- /dev/null ++++ b/vendor/bitflags/src/internal.rs +@@ -0,0 +1,125 @@ ++//! Generate the internal `bitflags`-facing flags type. ++//! ++//! The code generated here is owned by `bitflags`, but still part of its public API. ++//! Changes to the types generated here need to be considered like any other public API change. ++ ++/// Declare the `bitflags`-facing bitflags struct. ++/// ++/// This type is part of the `bitflags` crate's public API, but not part of the user's. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __declare_internal_bitflags { ++ ( ++ $vis:vis struct $InternalBitFlags:ident: $T:ty ++ ) => { ++ // NOTE: The ABI of this type is _guaranteed_ to be the same as `T` ++ // This is relied on by some external libraries like `bytemuck` to make ++ // its `unsafe` trait impls sound. ++ #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] ++ #[repr(transparent)] ++ $vis struct $InternalBitFlags($T); ++ }; ++} ++ ++/// Implement functions on the private (bitflags-facing) bitflags type. ++/// ++/// Methods and trait implementations can be freely added here without breaking end-users. ++/// If we want to expose new functionality to `#[derive]`, this is the place to do it. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_internal_bitflags { ++ ( ++ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt = $value:expr; ++ )* ++ } ++ ) => { ++ // NOTE: This impl is also used to prevent using bits types from non-primitive types ++ // in the `bitflags` macro. If this approach is changed, this guard will need to be ++ // retained somehow ++ impl $crate::__private::PublicFlags for $PublicBitFlags { ++ type Primitive = $T; ++ type Internal = $InternalBitFlags; ++ } ++ ++ impl $crate::__private::core::default::Default for $InternalBitFlags { ++ #[inline] ++ fn default() -> Self { ++ $InternalBitFlags::empty() ++ } ++ } ++ ++ impl $crate::__private::core::fmt::Debug for $InternalBitFlags { ++ fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result { ++ if self.is_empty() { ++ // If no flags are set then write an empty hex flag to avoid ++ // writing an empty string. In some contexts, like serialization, ++ // an empty string is preferable, but it may be unexpected in ++ // others for a format not to produce any output. ++ // ++ // We can remove this `0x0` and remain compatible with `FromStr`, ++ // because an empty string will still parse to an empty set of flags, ++ // just like `0x0` does. ++ $crate::__private::core::write!(f, "{:#x}", <$T as $crate::Bits>::EMPTY) ++ } else { ++ $crate::__private::core::fmt::Display::fmt(self, f) ++ } ++ } ++ } ++ ++ impl $crate::__private::core::fmt::Display for $InternalBitFlags { ++ fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result { ++ $crate::parser::to_writer(&$PublicBitFlags(*self), f) ++ } ++ } ++ ++ impl $crate::__private::core::str::FromStr for $InternalBitFlags { ++ type Err = $crate::parser::ParseError; ++ ++ fn from_str(s: &str) -> $crate::__private::core::result::Result { ++ $crate::parser::from_str::<$PublicBitFlags>(s).map(|flags| flags.0) ++ } ++ } ++ ++ impl $crate::__private::core::convert::AsRef<$T> for $InternalBitFlags { ++ fn as_ref(&self) -> &$T { ++ &self.0 ++ } ++ } ++ ++ impl $crate::__private::core::convert::From<$T> for $InternalBitFlags { ++ fn from(bits: $T) -> Self { ++ Self::from_bits_retain(bits) ++ } ++ } ++ ++ // The internal flags type offers a similar API to the public one ++ ++ $crate::__impl_public_bitflags! { ++ $InternalBitFlags: $T, $PublicBitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag = $value; ++ )* ++ } ++ } ++ ++ $crate::__impl_public_bitflags_ops! { ++ $InternalBitFlags ++ } ++ ++ $crate::__impl_public_bitflags_iter! { ++ $InternalBitFlags: $T, $PublicBitFlags ++ } ++ ++ impl $InternalBitFlags { ++ /// Returns a mutable reference to the raw value of the flags currently stored. ++ #[inline] ++ pub fn bits_mut(&mut self) -> &mut $T { ++ &mut self.0 ++ } ++ } ++ }; ++} +diff --git a/vendor/bitflags/src/iter.rs b/vendor/bitflags/src/iter.rs +new file mode 100644 +index 0000000..7f7ce55 +--- /dev/null ++++ b/vendor/bitflags/src/iter.rs +@@ -0,0 +1,145 @@ ++/*! ++Yield the bits of a source flags value in a set of contained flags values. ++*/ ++ ++use crate::{Flag, Flags}; ++ ++/** ++An iterator over flags values. ++ ++This iterator will yield flags values for contained, defined flags first, with any remaining bits yielded ++as a final flags value. ++*/ ++pub struct Iter { ++ inner: IterNames, ++ done: bool, ++} ++ ++impl Iter { ++ pub(crate) fn new(flags: &B) -> Self { ++ Iter { ++ inner: IterNames::new(flags), ++ done: false, ++ } ++ } ++} ++ ++impl Iter { ++ // Used by the `bitflags` macro ++ #[doc(hidden)] ++ pub const fn __private_const_new(flags: &'static [Flag], source: B, remaining: B) -> Self { ++ Iter { ++ inner: IterNames::__private_const_new(flags, source, remaining), ++ done: false, ++ } ++ } ++} ++ ++impl Iterator for Iter { ++ type Item = B; ++ ++ fn next(&mut self) -> Option { ++ match self.inner.next() { ++ Some((_, flag)) => Some(flag), ++ None if !self.done => { ++ self.done = true; ++ ++ // After iterating through valid names, if there are any bits left over ++ // then return one final value that includes them. This makes `into_iter` ++ // and `from_iter` roundtrip ++ if !self.inner.remaining().is_empty() { ++ Some(B::from_bits_retain(self.inner.remaining.bits())) ++ } else { ++ None ++ } ++ } ++ None => None, ++ } ++ } ++} ++ ++/** ++An iterator over flags values. ++ ++This iterator only yields flags values for contained, defined, named flags. Any remaining bits ++won't be yielded, but can be found with the [`IterNames::remaining`] method. ++*/ ++pub struct IterNames { ++ flags: &'static [Flag], ++ idx: usize, ++ source: B, ++ remaining: B, ++} ++ ++impl IterNames { ++ pub(crate) fn new(flags: &B) -> Self { ++ IterNames { ++ flags: B::FLAGS, ++ idx: 0, ++ remaining: B::from_bits_retain(flags.bits()), ++ source: B::from_bits_retain(flags.bits()), ++ } ++ } ++} ++ ++impl IterNames { ++ // Used by the bitflags macro ++ #[doc(hidden)] ++ pub const fn __private_const_new(flags: &'static [Flag], source: B, remaining: B) -> Self { ++ IterNames { ++ flags, ++ idx: 0, ++ remaining, ++ source, ++ } ++ } ++ ++ /// Get a flags value of any remaining bits that haven't been yielded yet. ++ /// ++ /// Once the iterator has finished, this method can be used to ++ /// check whether or not there are any bits that didn't correspond ++ /// to a contained, defined, named flag remaining. ++ pub fn remaining(&self) -> &B { ++ &self.remaining ++ } ++} ++ ++impl Iterator for IterNames { ++ type Item = (&'static str, B); ++ ++ fn next(&mut self) -> Option { ++ while let Some(flag) = self.flags.get(self.idx) { ++ // Short-circuit if our state is empty ++ if self.remaining.is_empty() { ++ return None; ++ } ++ ++ self.idx += 1; ++ ++ // Skip unnamed flags ++ if flag.name().is_empty() { ++ continue; ++ } ++ ++ let bits = flag.value().bits(); ++ ++ // If the flag is set in the original source _and_ it has bits that haven't ++ // been covered by a previous flag yet then yield it. These conditions cover ++ // two cases for multi-bit flags: ++ // ++ // 1. When flags partially overlap, such as `0b00000001` and `0b00000101`, we'll ++ // yield both flags. ++ // 2. When flags fully overlap, such as in convenience flags that are a shorthand for others, ++ // we won't yield both flags. ++ if self.source.contains(B::from_bits_retain(bits)) ++ && self.remaining.intersects(B::from_bits_retain(bits)) ++ { ++ self.remaining.remove(B::from_bits_retain(bits)); ++ ++ return Some((flag.name(), B::from_bits_retain(bits))); ++ } ++ } ++ ++ None ++ } ++} +diff --git a/vendor/bitflags/src/lib.rs b/vendor/bitflags/src/lib.rs +index 935e432..a9a6aa4 100644 +--- a/vendor/bitflags/src/lib.rs ++++ b/vendor/bitflags/src/lib.rs +@@ -8,1722 +8,920 @@ + // option. This file may not be copied, modified, or distributed + // except according to those terms. + +-//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +-//! It can be used for creating typesafe wrappers around C APIs. +-//! +-//! The `bitflags!` macro generates `struct`s that manage a set of flags. The +-//! flags should only be defined for integer types, otherwise unexpected type +-//! errors may occur at compile time. +-//! +-//! # Example +-//! +-//! ``` +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! struct Flags: u32 { +-//! const A = 0b00000001; +-//! const B = 0b00000010; +-//! const C = 0b00000100; +-//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +-//! } +-//! } +-//! +-//! fn main() { +-//! let e1 = Flags::A | Flags::C; +-//! let e2 = Flags::B | Flags::C; +-//! assert_eq!((e1 | e2), Flags::ABC); // union +-//! assert_eq!((e1 & e2), Flags::C); // intersection +-//! assert_eq!((e1 - e2), Flags::A); // set difference +-//! assert_eq!(!e2, Flags::A); // set complement +-//! } +-//! ``` +-//! +-//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +-//! generated by the above `bitflags!` expansion. +-//! +-//! The generated `struct`s can also be extended with type and trait +-//! implementations: +-//! +-//! ``` +-//! use std::fmt; +-//! +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! struct Flags: u32 { +-//! const A = 0b00000001; +-//! const B = 0b00000010; +-//! } +-//! } +-//! +-//! impl Flags { +-//! pub fn clear(&mut self) { +-//! self.bits = 0; // The `bits` field can be accessed from within the +-//! // same module where the `bitflags!` macro was invoked. +-//! } +-//! } +-//! +-//! impl fmt::Display for Flags { +-//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +-//! write!(f, "hi!") +-//! } +-//! } +-//! +-//! fn main() { +-//! let mut flags = Flags::A | Flags::B; +-//! flags.clear(); +-//! assert!(flags.is_empty()); +-//! assert_eq!(format!("{}", flags), "hi!"); +-//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +-//! assert_eq!(format!("{:?}", Flags::B), "B"); +-//! } +-//! ``` +-//! +-//! # Visibility +-//! +-//! The generated structs and their associated flag constants are not exported +-//! out of the current module by default. A definition can be exported out of +-//! the current module by adding `pub` before `struct`: +-//! +-//! ``` +-//! mod example { +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! pub struct Flags1: u32 { +-//! const A = 0b00000001; +-//! } +-//! +-//! # pub +-//! struct Flags2: u32 { +-//! const B = 0b00000010; +-//! } +-//! } +-//! } +-//! +-//! fn main() { +-//! let flag1 = example::Flags1::A; +-//! let flag2 = example::Flags2::B; // error: const `B` is private +-//! } +-//! ``` +-//! +-//! # Attributes +-//! +-//! Attributes can be attached to the generated `struct`s by placing them +-//! before the `struct` keyword. +-//! +-//! ## Representations +-//! +-//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type +-//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype. +-//! +-//! ``` +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! #[repr(transparent)] +-//! struct Flags: u32 { +-//! const A = 0b00000001; +-//! const B = 0b00000010; +-//! const C = 0b00000100; +-//! } +-//! } +-//! ``` +-//! +-//! # Trait implementations +-//! +-//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +-//! traits are automatically derived for the `struct`s using the `derive` attribute. +-//! Additional traits can be derived by providing an explicit `derive` +-//! attribute on `struct`. +-//! +-//! The `Extend` and `FromIterator` traits are implemented for the `struct`s, +-//! too: `Extend` adds the union of the instances of the `struct` iterated over, +-//! while `FromIterator` calculates the union. +-//! +-//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also +-//! implemented by displaying the bits value of the internal struct. +-//! +-//! ## Operators +-//! +-//! The following operator traits are implemented for the generated `struct`s: +-//! +-//! - `BitOr` and `BitOrAssign`: union +-//! - `BitAnd` and `BitAndAssign`: intersection +-//! - `BitXor` and `BitXorAssign`: toggle +-//! - `Sub` and `SubAssign`: set difference +-//! - `Not`: set complement +-//! +-//! # Methods +-//! +-//! The following methods are defined for the generated `struct`s: +-//! +-//! - `empty`: an empty set of flags +-//! - `all`: the set of all defined flags +-//! - `bits`: the raw value of the flags currently stored +-//! - `from_bits`: convert from underlying bit representation, unless that +-//! representation contains bits that do not correspond to a +-//! defined flag +-//! - `from_bits_truncate`: convert from underlying bit representation, dropping +-//! any bits that do not correspond to defined flags +-//! - `from_bits_unchecked`: convert from underlying bit representation, keeping +-//! all bits (even those not corresponding to defined +-//! flags) +-//! - `is_empty`: `true` if no flags are currently stored +-//! - `is_all`: `true` if currently set flags exactly equal all defined flags +-//! - `intersects`: `true` if there are flags common to both `self` and `other` +-//! - `contains`: `true` if all of the flags in `other` are contained within `self` +-//! - `insert`: inserts the specified flags in-place +-//! - `remove`: removes the specified flags in-place +-//! - `toggle`: the specified flags will be inserted if not present, and removed +-//! if they are. +-//! - `set`: inserts or removes the specified flags depending on the passed value +-//! - `intersection`: returns a new set of flags, containing only the flags present +-//! in both `self` and `other` (the argument to the function). +-//! - `union`: returns a new set of flags, containing any flags present in +-//! either `self` or `other` (the argument to the function). +-//! - `difference`: returns a new set of flags, containing all flags present in +-//! `self` without any of the flags present in `other` (the +-//! argument to the function). +-//! - `symmetric_difference`: returns a new set of flags, containing all flags +-//! present in either `self` or `other` (the argument +-//! to the function), but not both. +-//! - `complement`: returns a new set of flags, containing all flags which are +-//! not set in `self`, but which are allowed for this type. +-//! +-//! ## Default +-//! +-//! The `Default` trait is not automatically implemented for the generated structs. +-//! +-//! If your default value is equal to `0` (which is the same value as calling `empty()` +-//! on the generated struct), you can simply derive `Default`: +-//! +-//! ``` +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! // Results in default value with bits: 0 +-//! #[derive(Default)] +-//! struct Flags: u32 { +-//! const A = 0b00000001; +-//! const B = 0b00000010; +-//! const C = 0b00000100; +-//! } +-//! } +-//! +-//! fn main() { +-//! let derived_default: Flags = Default::default(); +-//! assert_eq!(derived_default.bits(), 0); +-//! } +-//! ``` +-//! +-//! If your default value is not equal to `0` you need to implement `Default` yourself: +-//! +-//! ``` +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! struct Flags: u32 { +-//! const A = 0b00000001; +-//! const B = 0b00000010; +-//! const C = 0b00000100; +-//! } +-//! } +-//! +-//! // explicit `Default` implementation +-//! impl Default for Flags { +-//! fn default() -> Flags { +-//! Flags::A | Flags::C +-//! } +-//! } +-//! +-//! fn main() { +-//! let implemented_default: Flags = Default::default(); +-//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +-//! } +-//! ``` +-//! +-//! # Zero Flags +-//! +-//! Flags with a value equal to zero will have some strange behavior that one should be aware of. +-//! +-//! ``` +-//! use bitflags::bitflags; +-//! +-//! bitflags! { +-//! struct Flags: u32 { +-//! const NONE = 0b00000000; +-//! const SOME = 0b00000001; +-//! } +-//! } +-//! +-//! fn main() { +-//! let empty = Flags::empty(); +-//! let none = Flags::NONE; +-//! let some = Flags::SOME; +-//! +-//! // Zero flags are treated as always present +-//! assert!(empty.contains(Flags::NONE)); +-//! assert!(none.contains(Flags::NONE)); +-//! assert!(some.contains(Flags::NONE)); +-//! +-//! // Zero flags will be ignored when testing for emptiness +-//! assert!(none.is_empty()); +-//! } +-//! ``` +-//! +-//! Users should generally avoid defining a flag with a value of zero. +- +-#![cfg_attr(not(test), no_std)] +-#![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] ++/*! ++Generate types for C-style flags with ergonomic APIs. + +-#[doc(hidden)] +-pub extern crate core as _core; ++# Getting started + +-/// The macro used to generate the flag structures. +-/// +-/// See the [crate level docs](../bitflags/index.html) for complete documentation. +-/// +-/// # Example +-/// +-/// ``` +-/// use bitflags::bitflags; +-/// +-/// bitflags! { +-/// struct Flags: u32 { +-/// const A = 0b00000001; +-/// const B = 0b00000010; +-/// const C = 0b00000100; +-/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +-/// } +-/// } +-/// +-/// fn main() { +-/// let e1 = Flags::A | Flags::C; +-/// let e2 = Flags::B | Flags::C; +-/// assert_eq!((e1 | e2), Flags::ABC); // union +-/// assert_eq!((e1 & e2), Flags::C); // intersection +-/// assert_eq!((e1 - e2), Flags::A); // set difference +-/// assert_eq!(!e2, Flags::A); // set complement +-/// } +-/// ``` +-/// +-/// The generated `struct`s can also be extended with type and trait +-/// implementations: +-/// +-/// ``` +-/// use std::fmt; +-/// +-/// use bitflags::bitflags; +-/// +-/// bitflags! { +-/// struct Flags: u32 { +-/// const A = 0b00000001; +-/// const B = 0b00000010; +-/// } +-/// } +-/// +-/// impl Flags { +-/// pub fn clear(&mut self) { +-/// self.bits = 0; // The `bits` field can be accessed from within the +-/// // same module where the `bitflags!` macro was invoked. +-/// } +-/// } +-/// +-/// impl fmt::Display for Flags { +-/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +-/// write!(f, "hi!") +-/// } +-/// } +-/// +-/// fn main() { +-/// let mut flags = Flags::A | Flags::B; +-/// flags.clear(); +-/// assert!(flags.is_empty()); +-/// assert_eq!(format!("{}", flags), "hi!"); +-/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +-/// assert_eq!(format!("{:?}", Flags::B), "B"); +-/// } +-/// ``` +-#[macro_export(local_inner_macros)] +-macro_rules! bitflags { +- ( +- $(#[$outer:meta])* +- $vis:vis struct $BitFlags:ident: $T:ty { +- $( +- $(#[$inner:ident $($args:tt)*])* +- const $Flag:ident = $value:expr; +- )* +- } ++Add `bitflags` to your `Cargo.toml`: + +- $($t:tt)* +- ) => { +- $(#[$outer])* +- #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] +- $vis struct $BitFlags { +- bits: $T, +- } ++```toml ++[dependencies.bitflags] ++version = "2.6.0" ++``` + +- __impl_bitflags! { +- $BitFlags: $T { +- $( +- $(#[$inner $($args)*])* +- $Flag = $value; +- )* +- } +- } ++## Generating flags types + +- bitflags! { +- $($t)* +- } +- }; +- () => {}; +-} ++Use the [`bitflags`] macro to generate flags types: + +-// A helper macro to implement the `all` function. +-#[macro_export(local_inner_macros)] +-#[doc(hidden)] +-macro_rules! __impl_all_bitflags { +- ( +- $BitFlags:ident: $T:ty { +- $( +- $(#[$attr:ident $($args:tt)*])* +- $Flag:ident = $value:expr; +- )+ +- } +- ) => { +- // See `Debug::fmt` for why this approach is taken. +- #[allow(non_snake_case)] +- trait __BitFlags { +- $( +- const $Flag: $T = 0; +- )+ +- } +- #[allow(non_snake_case)] +- impl __BitFlags for $BitFlags { +- $( +- __impl_bitflags! { +- #[allow(deprecated)] +- $(? #[$attr $($args)*])* +- const $Flag: $T = Self::$Flag.bits; +- } +- )+ +- } +- Self { bits: $(::$Flag)|+ } +- }; +- ( +- $BitFlags:ident: $T:ty { } +- ) => { +- Self { bits: 0 } +- }; +-} ++```rust ++use bitflags::bitflags; + +-#[macro_export(local_inner_macros)] +-#[doc(hidden)] +-macro_rules! __impl_bitflags { +- ( +- $BitFlags:ident: $T:ty { +- $( +- $(#[$attr:ident $($args:tt)*])* +- $Flag:ident = $value:expr; +- )* +- } +- ) => { +- impl $crate::_core::fmt::Debug for $BitFlags { +- fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { +- // This convoluted approach is to handle #[cfg]-based flag +- // omission correctly. For example it needs to support: +- // +- // #[cfg(unix)] const A: Flag = /* ... */; +- // #[cfg(windows)] const B: Flag = /* ... */; +- +- // Unconditionally define a check for every flag, even disabled +- // ones. +- #[allow(non_snake_case)] +- trait __BitFlags { +- $( +- #[inline] +- fn $Flag(&self) -> bool { false } +- )* +- } ++bitflags! { ++ pub struct Flags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; ++ } ++} ++``` + +- // Conditionally override the check for just those flags that +- // are not #[cfg]ed away. +- #[allow(non_snake_case)] +- impl __BitFlags for $BitFlags { +- $( +- __impl_bitflags! { +- #[allow(deprecated)] +- #[inline] +- $(? #[$attr $($args)*])* +- fn $Flag(&self) -> bool { +- if Self::$Flag.bits == 0 && self.bits != 0 { +- false +- } else { +- self.bits & Self::$Flag.bits == Self::$Flag.bits +- } +- } +- } +- )* +- } ++See the docs for the `bitflags` macro for the full syntax. + +- let mut first = true; +- $( +- if ::$Flag(self) { +- if !first { +- f.write_str(" | ")?; +- } +- first = false; +- f.write_str($crate::_core::stringify!($Flag))?; +- } +- )* +- let extra_bits = self.bits & !Self::all().bits(); +- if extra_bits != 0 { +- if !first { +- f.write_str(" | ")?; +- } +- first = false; +- f.write_str("0x")?; +- $crate::_core::fmt::LowerHex::fmt(&extra_bits, f)?; +- } +- if first { +- f.write_str("(empty)")?; +- } +- Ok(()) +- } +- } +- impl $crate::_core::fmt::Binary for $BitFlags { +- fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { +- $crate::_core::fmt::Binary::fmt(&self.bits, f) +- } +- } +- impl $crate::_core::fmt::Octal for $BitFlags { +- fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { +- $crate::_core::fmt::Octal::fmt(&self.bits, f) +- } +- } +- impl $crate::_core::fmt::LowerHex for $BitFlags { +- fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { +- $crate::_core::fmt::LowerHex::fmt(&self.bits, f) +- } +- } +- impl $crate::_core::fmt::UpperHex for $BitFlags { +- fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { +- $crate::_core::fmt::UpperHex::fmt(&self.bits, f) +- } +- } ++Also see the [`example_generated`](./example_generated/index.html) module for an example of what the `bitflags` macro generates for a flags type. + +- #[allow(dead_code)] +- impl $BitFlags { +- $( +- $(#[$attr $($args)*])* +- pub const $Flag: Self = Self { bits: $value }; +- )* ++### Externally defined flags + +- /// Returns an empty set of flags. +- #[inline] +- pub const fn empty() -> Self { +- Self { bits: 0 } +- } ++If you're generating flags types for an external source, such as a C API, you can define ++an extra unnamed flag as a mask of all bits the external source may ever set. Usually this would be all bits (`!0`): + +- /// Returns the set containing all flags. +- #[inline] +- pub const fn all() -> Self { +- __impl_all_bitflags! { +- $BitFlags: $T { +- $( +- $(#[$attr $($args)*])* +- $Flag = $value; +- )* +- } +- } +- } ++```rust ++# use bitflags::bitflags; ++bitflags! { ++ pub struct Flags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; + +- /// Returns the raw value of the flags currently stored. +- #[inline] +- pub const fn bits(&self) -> $T { +- self.bits +- } ++ // The source may set any bits ++ const _ = !0; ++ } ++} ++``` + +- /// Convert from underlying bit representation, unless that +- /// representation contains bits that do not correspond to a flag. +- #[inline] +- pub const fn from_bits(bits: $T) -> $crate::_core::option::Option { +- if (bits & !Self::all().bits()) == 0 { +- $crate::_core::option::Option::Some(Self { bits }) +- } else { +- $crate::_core::option::Option::None +- } +- } ++Why should you do this? Generated methods like `all` and truncating operators like `!` only consider ++bits in defined flags. Adding an unnamed flag makes those methods consider additional bits, ++without generating additional constants for them. It helps compatibility when the external source ++may start setting additional bits at any time. The [known and unknown bits](#known-and-unknown-bits) ++section has more details on this behavior. + +- /// Convert from underlying bit representation, dropping any bits +- /// that do not correspond to flags. +- #[inline] +- pub const fn from_bits_truncate(bits: $T) -> Self { +- Self { bits: bits & Self::all().bits } +- } ++### Custom derives + +- /// Convert from underlying bit representation, preserving all +- /// bits (even those not corresponding to a defined flag). +- /// +- /// # Safety +- /// +- /// The caller of the `bitflags!` macro can chose to allow or +- /// disallow extra bits for their bitflags type. +- /// +- /// The caller of `from_bits_unchecked()` has to ensure that +- /// all bits correspond to a defined flag or that extra bits +- /// are valid for this bitflags type. +- #[inline] +- pub const unsafe fn from_bits_unchecked(bits: $T) -> Self { +- Self { bits } +- } ++You can derive some traits on generated flags types if you enable Cargo features. The following ++libraries are currently supported: + +- /// Returns `true` if no flags are currently stored. +- #[inline] +- pub const fn is_empty(&self) -> bool { +- self.bits() == Self::empty().bits() +- } ++- `serde`: Support `#[derive(Serialize, Deserialize)]`, using text for human-readable formats, ++and a raw number for binary formats. ++- `arbitrary`: Support `#[derive(Arbitrary)]`, only generating flags values with known bits. ++- `bytemuck`: Support `#[derive(Pod, Zeroable)]`, for casting between flags values and their ++underlying bits values. + +- /// Returns `true` if all flags are currently set. +- #[inline] +- pub const fn is_all(&self) -> bool { +- Self::all().bits | self.bits == self.bits +- } ++You can also define your own flags type outside of the [`bitflags`] macro and then use it to generate methods. ++This can be useful if you need a custom `#[derive]` attribute for a library that `bitflags` doesn't ++natively support: + +- /// Returns `true` if there are flags common to both `self` and `other`. +- #[inline] +- pub const fn intersects(&self, other: Self) -> bool { +- !(Self { bits: self.bits & other.bits}).is_empty() +- } ++```rust ++# use std::fmt::Debug as SomeTrait; ++# use bitflags::bitflags; ++#[derive(SomeTrait)] ++pub struct Flags(u32); + +- /// Returns `true` if all of the flags in `other` are contained within `self`. +- #[inline] +- pub const fn contains(&self, other: Self) -> bool { +- (self.bits & other.bits) == other.bits +- } ++bitflags! { ++ impl Flags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; ++ } ++} ++``` + +- /// Inserts the specified flags in-place. +- #[inline] +- pub fn insert(&mut self, other: Self) { +- self.bits |= other.bits; +- } ++### Adding custom methods + +- /// Removes the specified flags in-place. +- #[inline] +- pub fn remove(&mut self, other: Self) { +- self.bits &= !other.bits; +- } ++The [`bitflags`] macro supports attributes on generated flags types within the macro itself, while ++`impl` blocks can be added outside of it: + +- /// Toggles the specified flags in-place. +- #[inline] +- pub fn toggle(&mut self, other: Self) { +- self.bits ^= other.bits; +- } ++```rust ++# use bitflags::bitflags; ++bitflags! { ++ // Attributes can be applied to flags types ++ #[repr(transparent)] ++ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] ++ pub struct Flags: u32 { ++ const A = 0b00000001; ++ const B = 0b00000010; ++ const C = 0b00000100; ++ } ++} + +- /// Inserts or removes the specified flags depending on the passed value. +- #[inline] +- pub fn set(&mut self, other: Self, value: bool) { +- if value { +- self.insert(other); +- } else { +- self.remove(other); +- } +- } ++// Impl blocks can be added to flags types ++impl Flags { ++ pub fn as_u64(&self) -> u64 { ++ self.bits() as u64 ++ } ++} ++``` + +- /// Returns the intersection between the flags in `self` and +- /// `other`. +- /// +- /// Specifically, the returned set contains only the flags which are +- /// present in *both* `self` *and* `other`. +- /// +- /// This is equivalent to using the `&` operator (e.g. +- /// [`ops::BitAnd`]), as in `flags & other`. +- /// +- /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html +- #[inline] +- #[must_use] +- pub const fn intersection(self, other: Self) -> Self { +- Self { bits: self.bits & other.bits } +- } ++## Working with flags values + +- /// Returns the union of between the flags in `self` and `other`. +- /// +- /// Specifically, the returned set contains all flags which are +- /// present in *either* `self` *or* `other`, including any which are +- /// present in both (see [`Self::symmetric_difference`] if that +- /// is undesirable). +- /// +- /// This is equivalent to using the `|` operator (e.g. +- /// [`ops::BitOr`]), as in `flags | other`. +- /// +- /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html +- #[inline] +- #[must_use] +- pub const fn union(self, other: Self) -> Self { +- Self { bits: self.bits | other.bits } +- } ++Use generated constants and standard bitwise operators to interact with flags values: + +- /// Returns the difference between the flags in `self` and `other`. +- /// +- /// Specifically, the returned set contains all flags present in +- /// `self`, except for the ones present in `other`. +- /// +- /// It is also conceptually equivalent to the "bit-clear" operation: +- /// `flags & !other` (and this syntax is also supported). +- /// +- /// This is equivalent to using the `-` operator (e.g. +- /// [`ops::Sub`]), as in `flags - other`. +- /// +- /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html +- #[inline] +- #[must_use] +- pub const fn difference(self, other: Self) -> Self { +- Self { bits: self.bits & !other.bits } +- } ++```rust ++# use bitflags::bitflags; ++# bitflags! { ++# #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] ++# pub struct Flags: u32 { ++# const A = 0b00000001; ++# const B = 0b00000010; ++# const C = 0b00000100; ++# } ++# } ++// union ++let ab = Flags::A | Flags::B; + +- /// Returns the [symmetric difference][sym-diff] between the flags +- /// in `self` and `other`. +- /// +- /// Specifically, the returned set contains the flags present which +- /// are present in `self` or `other`, but that are not present in +- /// both. Equivalently, it contains the flags present in *exactly +- /// one* of the sets `self` and `other`. +- /// +- /// This is equivalent to using the `^` operator (e.g. +- /// [`ops::BitXor`]), as in `flags ^ other`. +- /// +- /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference +- /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html +- #[inline] +- #[must_use] +- pub const fn symmetric_difference(self, other: Self) -> Self { +- Self { bits: self.bits ^ other.bits } +- } ++// intersection ++let a = ab & Flags::A; + +- /// Returns the complement of this set of flags. +- /// +- /// Specifically, the returned set contains all the flags which are +- /// not set in `self`, but which are allowed for this type. +- /// +- /// Alternatively, it can be thought of as the set difference +- /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) +- /// +- /// This is equivalent to using the `!` operator (e.g. +- /// [`ops::Not`]), as in `!flags`. +- /// +- /// [`Self::all()`]: Self::all +- /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html +- #[inline] +- #[must_use] +- pub const fn complement(self) -> Self { +- Self::from_bits_truncate(!self.bits) +- } ++// difference ++let b = ab - Flags::A; + +- } ++// complement ++let c = !ab; ++``` + +- impl $crate::_core::ops::BitOr for $BitFlags { +- type Output = Self; ++See the docs for the [`Flags`] trait for more details on operators and how they behave. + +- /// Returns the union of the two sets of flags. +- #[inline] +- fn bitor(self, other: $BitFlags) -> Self { +- Self { bits: self.bits | other.bits } +- } +- } ++# Formatting and parsing + +- impl $crate::_core::ops::BitOrAssign for $BitFlags { +- /// Adds the set of flags. +- #[inline] +- fn bitor_assign(&mut self, other: Self) { +- self.bits |= other.bits; +- } +- } ++`bitflags` defines a text format that can be used to convert any flags value to and from strings. + +- impl $crate::_core::ops::BitXor for $BitFlags { +- type Output = Self; ++See the [`parser`] module for more details. + +- /// Returns the left flags, but with all the right flags toggled. +- #[inline] +- fn bitxor(self, other: Self) -> Self { +- Self { bits: self.bits ^ other.bits } +- } +- } ++# Specification + +- impl $crate::_core::ops::BitXorAssign for $BitFlags { +- /// Toggles the set of flags. +- #[inline] +- fn bitxor_assign(&mut self, other: Self) { +- self.bits ^= other.bits; +- } +- } ++The terminology and behavior of generated flags types is ++[specified in the source repository](https://github.com/bitflags/bitflags/blob/main/spec.md). ++Details are repeated in these docs where appropriate, but is exhaustively listed in the spec. Some ++things are worth calling out explicitly here. + +- impl $crate::_core::ops::BitAnd for $BitFlags { +- type Output = Self; ++## Flags types, flags values, flags + +- /// Returns the intersection between the two sets of flags. +- #[inline] +- fn bitand(self, other: Self) -> Self { +- Self { bits: self.bits & other.bits } +- } +- } ++The spec and these docs use consistent terminology to refer to things in the bitflags domain: + +- impl $crate::_core::ops::BitAndAssign for $BitFlags { +- /// Disables all flags disabled in the set. +- #[inline] +- fn bitand_assign(&mut self, other: Self) { +- self.bits &= other.bits; +- } +- } ++- **Bits type**: A type that defines a fixed number of bits at specific locations. ++- **Flag**: A set of bits in a bits type that may have a unique name. ++- **Flags type**: A set of defined flags over a specific bits type. ++- **Flags value**: An instance of a flags type using its specific bits value for storage. + +- impl $crate::_core::ops::Sub for $BitFlags { +- type Output = Self; ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct FlagsType: u8 { ++// -- Bits type ++// --------- Flags type ++ const A = 1; ++// ----- Flag ++ } ++} + +- /// Returns the set difference of the two sets of flags. +- #[inline] +- fn sub(self, other: Self) -> Self { +- Self { bits: self.bits & !other.bits } +- } +- } ++let flag = FlagsType::A; ++// ---- Flags value ++``` + +- impl $crate::_core::ops::SubAssign for $BitFlags { +- /// Disables all flags enabled in the set. +- #[inline] +- fn sub_assign(&mut self, other: Self) { +- self.bits &= !other.bits; +- } +- } ++## Known and unknown bits + +- impl $crate::_core::ops::Not for $BitFlags { +- type Output = Self; ++Any bits in a flag you define are called _known bits_. Any other bits are _unknown bits_. ++In the following flags type: + +- /// Returns the complement of this set of flags. +- #[inline] +- fn not(self) -> Self { +- Self { bits: !self.bits } & Self::all() +- } +- } +- +- impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { +- fn extend>(&mut self, iterator: T) { +- for item in iterator { +- self.insert(item) +- } +- } +- } +- +- impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { +- fn from_iter>(iterator: T) -> Self { +- let mut result = Self::empty(); +- result.extend(iterator); +- result +- } +- } +- }; ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ const C = 1 << 2; ++ } ++} ++``` + +- // Every attribute that the user writes on a const is applied to the +- // corresponding const that we generate, but within the implementation of +- // Debug and all() we want to ignore everything but #[cfg] attributes. In +- // particular, including a #[deprecated] attribute on those items would fail +- // to compile. +- // https://github.com/bitflags/bitflags/issues/109 +- // +- // Input: +- // +- // ? #[cfg(feature = "advanced")] +- // ? #[deprecated(note = "Use something else.")] +- // ? #[doc = r"High quality documentation."] +- // fn f() -> i32 { /* ... */ } +- // +- // Output: +- // +- // #[cfg(feature = "advanced")] +- // fn f() -> i32 { /* ... */ } +- ( +- $(#[$filtered:meta])* +- ? #[cfg $($cfgargs:tt)*] +- $(? #[$rest:ident $($restargs:tt)*])* +- fn $($item:tt)* +- ) => { +- __impl_bitflags! { +- $(#[$filtered])* +- #[cfg $($cfgargs)*] +- $(? #[$rest $($restargs)*])* +- fn $($item)* +- } +- }; +- ( +- $(#[$filtered:meta])* +- // $next != `cfg` +- ? #[$next:ident $($nextargs:tt)*] +- $(? #[$rest:ident $($restargs:tt)*])* +- fn $($item:tt)* +- ) => { +- __impl_bitflags! { +- $(#[$filtered])* +- // $next filtered out +- $(? #[$rest $($restargs)*])* +- fn $($item)* +- } +- }; +- ( +- $(#[$filtered:meta])* +- fn $($item:tt)* +- ) => { +- $(#[$filtered])* +- fn $($item)* +- }; ++The known bits are `0b0000_0111` and the unknown bits are `0b1111_1000`. + +- // Every attribute that the user writes on a const is applied to the +- // corresponding const that we generate, but within the implementation of +- // Debug and all() we want to ignore everything but #[cfg] attributes. In +- // particular, including a #[deprecated] attribute on those items would fail +- // to compile. +- // https://github.com/bitflags/bitflags/issues/109 +- // +- // const version +- // +- // Input: +- // +- // ? #[cfg(feature = "advanced")] +- // ? #[deprecated(note = "Use something else.")] +- // ? #[doc = r"High quality documentation."] +- // const f: i32 { /* ... */ } +- // +- // Output: +- // +- // #[cfg(feature = "advanced")] +- // const f: i32 { /* ... */ } +- ( +- $(#[$filtered:meta])* +- ? #[cfg $($cfgargs:tt)*] +- $(? #[$rest:ident $($restargs:tt)*])* +- const $($item:tt)* +- ) => { +- __impl_bitflags! { +- $(#[$filtered])* +- #[cfg $($cfgargs)*] +- $(? #[$rest $($restargs)*])* +- const $($item)* +- } +- }; +- ( +- $(#[$filtered:meta])* +- // $next != `cfg` +- ? #[$next:ident $($nextargs:tt)*] +- $(? #[$rest:ident $($restargs:tt)*])* +- const $($item:tt)* +- ) => { +- __impl_bitflags! { +- $(#[$filtered])* +- // $next filtered out +- $(? #[$rest $($restargs)*])* +- const $($item)* +- } +- }; +- ( +- $(#[$filtered:meta])* +- const $($item:tt)* +- ) => { +- $(#[$filtered])* +- const $($item)* +- }; +-} ++`bitflags` doesn't guarantee that a flags value will only ever have known bits set, but some operators ++will unset any unknown bits they encounter. In a future version of `bitflags`, all operators will ++unset unknown bits. + +-#[cfg(feature = "example_generated")] +-pub mod example_generated; ++If you're using `bitflags` for flags types defined externally, such as from C, you probably want all ++bits to be considered known, in case that external source changes. You can do this using an unnamed ++flag, as described in [externally defined flags](#externally-defined-flags). + +-#[cfg(test)] +-mod tests { +- use std::collections::hash_map::DefaultHasher; +- use std::hash::{Hash, Hasher}; +- +- bitflags! { +- #[doc = "> The first principle is that you must not fool yourself — and"] +- #[doc = "> you are the easiest person to fool."] +- #[doc = "> "] +- #[doc = "> - Richard Feynman"] +- #[derive(Default)] +- struct Flags: u32 { +- const A = 0b00000001; +- #[doc = " macros are way better at generating code than trans is"] +- const B = 0b00000010; +- const C = 0b00000100; +- #[doc = "* cmr bed"] +- #[doc = "* strcat table"] +- #[doc = " wait what?"] +- const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +- } ++## Zero-bit flags + +- struct _CfgFlags: u32 { +- #[cfg(unix)] +- const _CFG_A = 0b01; +- #[cfg(windows)] +- const _CFG_B = 0b01; +- #[cfg(unix)] +- const _CFG_C = Self::_CFG_A.bits | 0b10; +- } ++Flags with no bits set should be avoided because they interact strangely with [`Flags::contains`] ++and [`Flags::intersects`]. A zero-bit flag is always contained, but is never intersected. The ++names of zero-bit flags can be parsed, but are never formatted. + +- struct AnotherSetOfFlags: i8 { +- const ANOTHER_FLAG = -1_i8; +- } ++## Multi-bit flags + +- struct LongFlags: u32 { +- const LONG_A = 0b1111111111111111; +- } +- } ++Flags that set multiple bits should be avoided unless each bit is also in a single-bit flag. ++Take the following flags type as an example: + +- bitflags! { +- struct EmptyFlags: u32 { +- } ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ const B = 1 | 1 << 1; + } ++} ++``` + +- #[test] +- fn test_bits() { +- assert_eq!(Flags::empty().bits(), 0b00000000); +- assert_eq!(Flags::A.bits(), 0b00000001); +- assert_eq!(Flags::ABC.bits(), 0b00000111); ++The result of `Flags::A ^ Flags::B` is `0b0000_0010`, which doesn't correspond to either ++`Flags::A` or `Flags::B` even though it's still a known bit. ++*/ + +- assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); +- assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); ++#![cfg_attr(not(any(feature = "std", test)), no_std)] ++#![cfg_attr(not(test), forbid(unsafe_code))] ++#![cfg_attr(test, allow(mixed_script_confusables))] + +- assert_eq!(EmptyFlags::empty().bits(), 0b00000000); +- } ++#[doc(inline)] ++pub use traits::{Bits, Flag, Flags}; + +- #[test] +- fn test_from_bits() { +- assert_eq!(Flags::from_bits(0), Some(Flags::empty())); +- assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); +- assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); +- assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); +- assert_eq!(Flags::from_bits(0b1000), None); +- +- assert_eq!( +- AnotherSetOfFlags::from_bits(!0_i8), +- Some(AnotherSetOfFlags::ANOTHER_FLAG) +- ); +- +- assert_eq!(EmptyFlags::from_bits(0), Some(EmptyFlags::empty())); +- assert_eq!(EmptyFlags::from_bits(0b1), None); +- } ++pub mod iter; ++pub mod parser; + +- #[test] +- fn test_from_bits_truncate() { +- assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); +- assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); +- assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); +- assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); +- assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); +- assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); +- +- assert_eq!( +- AnotherSetOfFlags::from_bits_truncate(0_i8), +- AnotherSetOfFlags::empty() +- ); +- +- assert_eq!(EmptyFlags::from_bits_truncate(0), EmptyFlags::empty()); +- assert_eq!(EmptyFlags::from_bits_truncate(0b1), EmptyFlags::empty()); +- } ++mod traits; + +- #[test] +- fn test_from_bits_unchecked() { +- let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; +- assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty()); +- assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A); +- assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B); +- +- assert_eq!( +- unsafe { Flags::from_bits_unchecked(0b11) }, +- (Flags::A | Flags::B) +- ); +- assert_eq!( +- unsafe { Flags::from_bits_unchecked(0b1000) }, +- (extra | Flags::empty()) +- ); +- assert_eq!( +- unsafe { Flags::from_bits_unchecked(0b1001) }, +- (extra | Flags::A) +- ); +- +- let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) }; +- assert_eq!( +- unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, +- (extra | EmptyFlags::empty()) +- ); +- } ++#[doc(hidden)] ++pub mod __private { ++ #[allow(unused_imports)] ++ // Easier than conditionally checking any optional external dependencies ++ pub use crate::{external::__private::*, traits::__private::*}; + +- #[test] +- fn test_is_empty() { +- assert!(Flags::empty().is_empty()); +- assert!(!Flags::A.is_empty()); +- assert!(!Flags::ABC.is_empty()); ++ pub use core; ++} + +- assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); ++#[allow(unused_imports)] ++pub use external::*; + +- assert!(EmptyFlags::empty().is_empty()); +- assert!(EmptyFlags::all().is_empty()); +- } ++#[allow(deprecated)] ++pub use traits::BitFlags; + +- #[test] +- fn test_is_all() { +- assert!(Flags::all().is_all()); +- assert!(!Flags::A.is_all()); +- assert!(Flags::ABC.is_all()); ++/* ++How does the bitflags crate work? + +- let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; +- assert!(!extra.is_all()); +- assert!(!(Flags::A | extra).is_all()); +- assert!((Flags::ABC | extra).is_all()); ++This library generates a `struct` in the end-user's crate with a bunch of constants on it that represent flags. ++The difference between `bitflags` and a lot of other libraries is that we don't actually control the generated `struct` in the end. ++It's part of the end-user's crate, so it belongs to them. That makes it difficult to extend `bitflags` with new functionality ++because we could end up breaking valid code that was already written. + +- assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); ++Our solution is to split the type we generate into two: the public struct owned by the end-user, and an internal struct owned by `bitflags` (us). ++To give you an example, let's say we had a crate that called `bitflags!`: + +- assert!(EmptyFlags::all().is_all()); +- assert!(EmptyFlags::empty().is_all()); ++```rust ++bitflags! { ++ pub struct MyFlags: u32 { ++ const A = 1; ++ const B = 2; + } ++} ++``` + +- #[test] +- fn test_two_empties_do_not_intersect() { +- let e1 = Flags::empty(); +- let e2 = Flags::empty(); +- assert!(!e1.intersects(e2)); ++What they'd end up with looks something like this: + +- assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); +- } ++```rust ++pub struct MyFlags(::InternalBitFlags); + +- #[test] +- fn test_empty_does_not_intersect_with_full() { +- let e1 = Flags::empty(); +- let e2 = Flags::ABC; +- assert!(!e1.intersects(e2)); ++const _: () = { ++ #[repr(transparent)] ++ #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] ++ pub struct MyInternalBitFlags { ++ bits: u32, + } + +- #[test] +- fn test_disjoint_intersects() { +- let e1 = Flags::A; +- let e2 = Flags::B; +- assert!(!e1.intersects(e2)); ++ impl PublicFlags for MyFlags { ++ type Internal = InternalBitFlags; + } ++}; ++``` + +- #[test] +- fn test_overlapping_intersects() { +- let e1 = Flags::A; +- let e2 = Flags::A | Flags::B; +- assert!(e1.intersects(e2)); +- } ++If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalBitFlags`, ++and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user chooses to add one. + +- #[test] +- fn test_contains() { +- let e1 = Flags::A; +- let e2 = Flags::A | Flags::B; +- assert!(!e1.contains(e2)); +- assert!(e2.contains(e1)); +- assert!(Flags::ABC.contains(e2)); ++The public API is generated in the `__impl_public_flags!` macro, and the internal API is generated in ++the `__impl_internal_flags!` macro. + +- assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); ++The macros are split into 3 modules: + +- assert!(EmptyFlags::empty().contains(EmptyFlags::empty())); +- } ++- `public`: where the user-facing flags types are generated. ++- `internal`: where the `bitflags`-facing flags types are generated. ++- `external`: where external library traits are implemented conditionally. ++*/ + +- #[test] +- fn test_insert() { +- let mut e1 = Flags::A; +- let e2 = Flags::A | Flags::B; +- e1.insert(e2); +- assert_eq!(e1, e2); ++/** ++Generate a flags type. + +- let mut e3 = AnotherSetOfFlags::empty(); +- e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); +- assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); +- } ++# `struct` mode + +- #[test] +- fn test_remove() { +- let mut e1 = Flags::A | Flags::B; +- let e2 = Flags::A | Flags::C; +- e1.remove(e2); +- assert_eq!(e1, Flags::B); ++A declaration that begins with `$vis struct` will generate a `struct` for a flags type, along with ++methods and trait implementations for it. The body of the declaration defines flags as constants, ++where each constant is a flags value of the generated flags type. + +- let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; +- e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); +- assert_eq!(e3, AnotherSetOfFlags::empty()); +- } ++## Examples + +- #[test] +- fn test_operators() { +- let e1 = Flags::A | Flags::C; +- let e2 = Flags::B | Flags::C; +- assert_eq!((e1 | e2), Flags::ABC); // union +- assert_eq!((e1 & e2), Flags::C); // intersection +- assert_eq!((e1 - e2), Flags::A); // set difference +- assert_eq!(!e2, Flags::A); // set complement +- assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle +- let mut e3 = e1; +- e3.toggle(e2); +- assert_eq!(e3, Flags::A | Flags::B); +- +- let mut m4 = AnotherSetOfFlags::empty(); +- m4.toggle(AnotherSetOfFlags::empty()); +- assert_eq!(m4, AnotherSetOfFlags::empty()); +- } ++Generate a flags type using `u8` as the bits type: + +- #[test] +- fn test_operators_unchecked() { +- let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; +- let e1 = Flags::A | Flags::C | extra; +- let e2 = Flags::B | Flags::C; +- assert_eq!((e1 | e2), (Flags::ABC | extra)); // union +- assert_eq!((e1 & e2), Flags::C); // intersection +- assert_eq!((e1 - e2), (Flags::A | extra)); // set difference +- assert_eq!(!e2, Flags::A); // set complement +- assert_eq!(!e1, Flags::B); // set complement +- assert_eq!(e1 ^ e2, Flags::A | Flags::B | extra); // toggle +- let mut e3 = e1; +- e3.toggle(e2); +- assert_eq!(e3, Flags::A | Flags::B | extra); ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ const C = 0b0000_0100; + } ++} ++``` + +- #[test] +- fn test_set_ops_basic() { +- let ab = Flags::A.union(Flags::B); +- let ac = Flags::A.union(Flags::C); +- let bc = Flags::B.union(Flags::C); +- assert_eq!(ab.bits, 0b011); +- assert_eq!(bc.bits, 0b110); +- assert_eq!(ac.bits, 0b101); +- +- assert_eq!(ab, Flags::B.union(Flags::A)); +- assert_eq!(ac, Flags::C.union(Flags::A)); +- assert_eq!(bc, Flags::C.union(Flags::B)); +- +- assert_eq!(ac, Flags::A | Flags::C); +- assert_eq!(bc, Flags::B | Flags::C); +- assert_eq!(ab.union(bc), Flags::ABC); +- +- assert_eq!(ac, Flags::A | Flags::C); +- assert_eq!(bc, Flags::B | Flags::C); +- +- assert_eq!(ac.union(bc), ac | bc); +- assert_eq!(ac.union(bc), Flags::ABC); +- assert_eq!(bc.union(ac), Flags::ABC); +- +- assert_eq!(ac.intersection(bc), ac & bc); +- assert_eq!(ac.intersection(bc), Flags::C); +- assert_eq!(bc.intersection(ac), Flags::C); +- +- assert_eq!(ac.difference(bc), ac - bc); +- assert_eq!(bc.difference(ac), bc - ac); +- assert_eq!(ac.difference(bc), Flags::A); +- assert_eq!(bc.difference(ac), Flags::B); +- +- assert_eq!(bc.complement(), !bc); +- assert_eq!(bc.complement(), Flags::A); +- assert_eq!(ac.symmetric_difference(bc), Flags::A.union(Flags::B)); +- assert_eq!(bc.symmetric_difference(ac), Flags::A.union(Flags::B)); +- } ++Flags types are private by default and accept standard visibility modifiers. Flags themselves ++are always public: + +- #[test] +- fn test_set_ops_const() { +- // These just test that these compile and don't cause use-site panics +- // (would be possible if we had some sort of UB) +- const INTERSECT: Flags = Flags::all().intersection(Flags::C); +- const UNION: Flags = Flags::A.union(Flags::C); +- const DIFFERENCE: Flags = Flags::all().difference(Flags::A); +- const COMPLEMENT: Flags = Flags::C.complement(); +- const SYM_DIFFERENCE: Flags = UNION.symmetric_difference(DIFFERENCE); +- assert_eq!(INTERSECT, Flags::C); +- assert_eq!(UNION, Flags::A | Flags::C); +- assert_eq!(DIFFERENCE, Flags::all() - Flags::A); +- assert_eq!(COMPLEMENT, !Flags::C); +- assert_eq!(SYM_DIFFERENCE, (Flags::A | Flags::C) ^ (Flags::all() - Flags::A)); ++``` ++# use bitflags::bitflags; ++bitflags! { ++ pub struct Flags: u8 { ++ // Constants are always `pub` ++ const A = 1; + } ++} ++``` + +- #[test] +- fn test_set_ops_unchecked() { +- let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; +- let e1 = Flags::A.union(Flags::C).union(extra); +- let e2 = Flags::B.union(Flags::C); +- assert_eq!(e1.bits, 0b1101); +- assert_eq!(e1.union(e2), (Flags::ABC | extra)); +- assert_eq!(e1.intersection(e2), Flags::C); +- assert_eq!(e1.difference(e2), Flags::A | extra); +- assert_eq!(e2.difference(e1), Flags::B); +- assert_eq!(e2.complement(), Flags::A); +- assert_eq!(e1.complement(), Flags::B); +- assert_eq!(e1.symmetric_difference(e2), Flags::A | Flags::B | extra); // toggle +- } ++Flags may refer to other flags using their [`Flags::bits`] value: + +- #[test] +- fn test_set_ops_exhaustive() { +- // Define a flag that contains gaps to help exercise edge-cases, +- // especially around "unknown" flags (e.g. ones outside of `all()` +- // `from_bits_unchecked`). +- // - when lhs and rhs both have different sets of unknown flags. +- // - unknown flags at both ends, and in the middle +- // - cases with "gaps". +- bitflags! { +- struct Test: u16 { +- // Intentionally no `A` +- const B = 0b000000010; +- // Intentionally no `C` +- const D = 0b000001000; +- const E = 0b000010000; +- const F = 0b000100000; +- const G = 0b001000000; +- // Intentionally no `H` +- const I = 0b100000000; +- } +- } +- let iter_test_flags = +- || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) }); +- +- for a in iter_test_flags() { +- assert_eq!( +- a.complement(), +- Test::from_bits_truncate(!a.bits), +- "wrong result: !({:?})", +- a, +- ); +- assert_eq!(a.complement(), !a, "named != op: !({:?})", a); +- for b in iter_test_flags() { +- // Check that the named operations produce the expected bitwise +- // values. +- assert_eq!( +- a.union(b).bits, +- a.bits | b.bits, +- "wrong result: `{:?}` | `{:?}`", +- a, +- b, +- ); +- assert_eq!( +- a.intersection(b).bits, +- a.bits & b.bits, +- "wrong result: `{:?}` & `{:?}`", +- a, +- b, +- ); +- assert_eq!( +- a.symmetric_difference(b).bits, +- a.bits ^ b.bits, +- "wrong result: `{:?}` ^ `{:?}`", +- a, +- b, +- ); +- assert_eq!( +- a.difference(b).bits, +- a.bits & !b.bits, +- "wrong result: `{:?}` - `{:?}`", +- a, +- b, +- ); +- // Note: Difference is checked as both `a - b` and `b - a` +- assert_eq!( +- b.difference(a).bits, +- b.bits & !a.bits, +- "wrong result: `{:?}` - `{:?}`", +- b, +- a, +- ); +- // Check that the named set operations are equivalent to the +- // bitwise equivalents +- assert_eq!(a.union(b), a | b, "named != op: `{:?}` | `{:?}`", a, b,); +- assert_eq!( +- a.intersection(b), +- a & b, +- "named != op: `{:?}` & `{:?}`", +- a, +- b, +- ); +- assert_eq!( +- a.symmetric_difference(b), +- a ^ b, +- "named != op: `{:?}` ^ `{:?}`", +- a, +- b, +- ); +- assert_eq!(a.difference(b), a - b, "named != op: `{:?}` - `{:?}`", a, b,); +- // Note: Difference is checked as both `a - b` and `b - a` +- assert_eq!(b.difference(a), b - a, "named != op: `{:?}` - `{:?}`", b, a,); +- // Verify that the operations which should be symmetric are +- // actually symmetric. +- assert_eq!(a.union(b), b.union(a), "asymmetry: `{:?}` | `{:?}`", a, b,); +- assert_eq!( +- a.intersection(b), +- b.intersection(a), +- "asymmetry: `{:?}` & `{:?}`", +- a, +- b, +- ); +- assert_eq!( +- a.symmetric_difference(b), +- b.symmetric_difference(a), +- "asymmetry: `{:?}` ^ `{:?}`", +- a, +- b, +- ); +- } +- } ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ const AB = Flags::A.bits() | Flags::B.bits(); + } ++} ++``` ++ ++A single `bitflags` invocation may include zero or more flags type declarations: + +- #[test] +- fn test_set() { +- let mut e1 = Flags::A | Flags::C; +- e1.set(Flags::B, true); +- e1.set(Flags::C, false); ++``` ++# use bitflags::bitflags; ++bitflags! {} + +- assert_eq!(e1, Flags::A | Flags::B); ++bitflags! { ++ struct Flags1: u8 { ++ const A = 1; + } + +- #[test] +- fn test_assignment_operators() { +- let mut m1 = Flags::empty(); +- let e1 = Flags::A | Flags::C; +- // union +- m1 |= Flags::A; +- assert_eq!(m1, Flags::A); +- // intersection +- m1 &= e1; +- assert_eq!(m1, Flags::A); +- // set difference +- m1 -= m1; +- assert_eq!(m1, Flags::empty()); +- // toggle +- m1 ^= e1; +- assert_eq!(m1, e1); ++ struct Flags2: u8 { ++ const A = 1; + } ++} ++``` + +- #[test] +- fn test_const_fn() { +- const _M1: Flags = Flags::empty(); ++# `impl` mode + +- const M2: Flags = Flags::A; +- assert_eq!(M2, Flags::A); ++A declaration that begins with `impl` will only generate methods and trait implementations for the ++`struct` defined outside of the `bitflags` macro. + +- const M3: Flags = Flags::C; +- assert_eq!(M3, Flags::C); +- } ++The struct itself must be a newtype using the bits type as its field. + +- #[test] +- fn test_extend() { +- let mut flags; ++The syntax for `impl` mode is identical to `struct` mode besides the starting token. + +- flags = Flags::empty(); +- flags.extend([].iter().cloned()); +- assert_eq!(flags, Flags::empty()); ++## Examples + +- flags = Flags::empty(); +- flags.extend([Flags::A, Flags::B].iter().cloned()); +- assert_eq!(flags, Flags::A | Flags::B); ++Implement flags methods and traits for a custom flags type using `u8` as its underlying bits type: + +- flags = Flags::A; +- flags.extend([Flags::A, Flags::B].iter().cloned()); +- assert_eq!(flags, Flags::A | Flags::B); ++``` ++# use bitflags::bitflags; ++struct Flags(u8); + +- flags = Flags::B; +- flags.extend([Flags::A, Flags::ABC].iter().cloned()); +- assert_eq!(flags, Flags::ABC); ++bitflags! { ++ impl Flags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ const C = 0b0000_0100; + } ++} ++``` + +- #[test] +- fn test_from_iterator() { +- assert_eq!([].iter().cloned().collect::(), Flags::empty()); +- assert_eq!( +- [Flags::A, Flags::B].iter().cloned().collect::(), +- Flags::A | Flags::B +- ); +- assert_eq!( +- [Flags::A, Flags::ABC].iter().cloned().collect::(), +- Flags::ABC +- ); +- } ++# Named and unnamed flags + +- #[test] +- fn test_lt() { +- let mut a = Flags::empty(); +- let mut b = Flags::empty(); +- +- assert!(!(a < b) && !(b < a)); +- b = Flags::B; +- assert!(a < b); +- a = Flags::C; +- assert!(!(a < b) && b < a); +- b = Flags::C | Flags::B; +- assert!(a < b); +- } ++Constants in the body of a declaration are flags. The identifier of the constant is the name of ++the flag. If the identifier is `_`, then the flag is unnamed. Unnamed flags don't appear in the ++generated API, but affect how bits are truncated. + +- #[test] +- fn test_ord() { +- let mut a = Flags::empty(); +- let mut b = Flags::empty(); +- +- assert!(a <= b && a >= b); +- a = Flags::A; +- assert!(a > b && a >= b); +- assert!(b < a && b <= a); +- b = Flags::B; +- assert!(b > a && b >= a); +- assert!(a < b && a <= b); +- } ++## Examples + +- fn hash(t: &T) -> u64 { +- let mut s = DefaultHasher::new(); +- t.hash(&mut s); +- s.finish() +- } ++Adding an unnamed flag that makes all bits known: + +- #[test] +- fn test_hash() { +- let mut x = Flags::empty(); +- let mut y = Flags::empty(); +- assert_eq!(hash(&x), hash(&y)); +- x = Flags::all(); +- y = Flags::ABC; +- assert_eq!(hash(&x), hash(&y)); +- } ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const A = 1; ++ const B = 1 << 1; + +- #[test] +- fn test_default() { +- assert_eq!(Flags::empty(), Flags::default()); ++ const _ = !0; + } ++} ++``` + +- #[test] +- fn test_debug() { +- assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +- assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); +- assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); +- let extra = unsafe { Flags::from_bits_unchecked(0xb8) }; +- assert_eq!(format!("{:?}", extra), "0xb8"); +- assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8"); +- +- assert_eq!( +- format!("{:?}", Flags::ABC | extra), +- "A | B | C | ABC | 0xb8" +- ); +- +- assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)"); +- } ++Flags types may define multiple unnamed flags: + +- #[test] +- fn test_binary() { +- assert_eq!(format!("{:b}", Flags::ABC), "111"); +- assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); +- let extra = unsafe { Flags::from_bits_unchecked(0b1010000) }; +- assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111"); +- assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111"); ++``` ++# use bitflags::bitflags; ++bitflags! { ++ struct Flags: u8 { ++ const _ = 1; ++ const _ = 1 << 1; + } ++} ++``` ++*/ ++#[macro_export] ++macro_rules! bitflags { ++ ( ++ $(#[$outer:meta])* ++ $vis:vis struct $BitFlags:ident: $T:ty { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt = $value:expr; ++ )* ++ } + +- #[test] +- fn test_octal() { +- assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); +- assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); +- let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) }; +- assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777"); +- assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777"); +- } ++ $($t:tt)* ++ ) => { ++ // Declared in the scope of the `bitflags!` call ++ // This type appears in the end-user's API ++ $crate::__declare_public_bitflags! { ++ $(#[$outer])* ++ $vis struct $BitFlags ++ } + +- #[test] +- fn test_lowerhex() { +- assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); +- assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); +- let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; +- assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff"); +- assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff"); +- } ++ // Workaround for: https://github.com/bitflags/bitflags/issues/320 ++ $crate::__impl_public_bitflags_consts! { ++ $BitFlags: $T { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag = $value; ++ )* ++ } ++ } + +- #[test] +- fn test_upperhex() { +- assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); +- assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); +- let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; +- assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF"); +- assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF"); +- } ++ #[allow( ++ dead_code, ++ deprecated, ++ unused_doc_comments, ++ unused_attributes, ++ unused_mut, ++ unused_imports, ++ non_upper_case_globals, ++ clippy::assign_op_pattern, ++ clippy::indexing_slicing, ++ clippy::same_name_method, ++ clippy::iter_without_into_iter, ++ )] ++ const _: () = { ++ // Declared in a "hidden" scope that can't be reached directly ++ // These types don't appear in the end-user's API ++ $crate::__declare_internal_bitflags! { ++ $vis struct InternalBitFlags: $T ++ } ++ ++ $crate::__impl_internal_bitflags! { ++ InternalBitFlags: $T, $BitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag = $value; ++ )* ++ } ++ } + +- mod submodule { +- bitflags! { +- pub struct PublicFlags: i8 { +- const X = 0; ++ // This is where new library trait implementations can be added ++ $crate::__impl_external_bitflags! { ++ InternalBitFlags: $T, $BitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag; ++ )* ++ } + } + +- struct PrivateFlags: i8 { +- const Y = 0; ++ $crate::__impl_public_bitflags_forward! { ++ $BitFlags: $T, InternalBitFlags + } +- } + +- #[test] +- fn test_private() { +- let _ = PrivateFlags::Y; +- } +- } ++ $crate::__impl_public_bitflags_ops! { ++ $BitFlags ++ } + +- #[test] +- fn test_public() { +- let _ = submodule::PublicFlags::X; +- } ++ $crate::__impl_public_bitflags_iter! { ++ $BitFlags: $T, $BitFlags ++ } ++ }; + +- mod t1 { +- mod foo { +- pub type Bar = i32; ++ $crate::bitflags! { ++ $($t)* ++ } ++ }; ++ ( ++ $(#[$outer:meta])* ++ impl $BitFlags:ident: $T:ty { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt = $value:expr; ++ )* + } + +- bitflags! { +- /// baz +- struct Flags: foo::Bar { +- const A = 0b00000001; +- #[cfg(foo)] +- const B = 0b00000010; +- #[cfg(foo)] +- const C = 0b00000010; ++ $($t:tt)* ++ ) => { ++ $crate::__impl_public_bitflags_consts! { ++ $BitFlags: $T { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag = $value; ++ )* + } + } +- } + +- #[test] +- fn test_in_function() { +- bitflags! { +- struct Flags: u8 { +- const A = 1; +- #[cfg(any())] // false +- const B = 2; ++ #[allow( ++ dead_code, ++ deprecated, ++ unused_doc_comments, ++ unused_attributes, ++ unused_mut, ++ unused_imports, ++ non_upper_case_globals, ++ clippy::assign_op_pattern, ++ clippy::iter_without_into_iter, ++ )] ++ const _: () = { ++ $crate::__impl_public_bitflags! { ++ $(#[$outer])* ++ $BitFlags: $T, $BitFlags { ++ $( ++ $(#[$inner $($args)*])* ++ const $Flag = $value; ++ )* ++ } + } +- } +- assert_eq!(Flags::all(), Flags::A); +- assert_eq!(format!("{:?}", Flags::A), "A"); +- } + +- #[test] +- fn test_deprecated() { +- bitflags! { +- pub struct TestFlags: u32 { +- #[deprecated(note = "Use something else.")] +- const ONE = 1; ++ $crate::__impl_public_bitflags_ops! { ++ $BitFlags + } +- } +- } + +- #[test] +- fn test_pub_crate() { +- mod module { +- bitflags! { +- pub (crate) struct Test: u8 { +- const FOO = 1; +- } ++ $crate::__impl_public_bitflags_iter! { ++ $BitFlags: $T, $BitFlags + } ++ }; ++ ++ $crate::bitflags! { ++ $($t)* + } ++ }; ++ () => {}; ++} + +- assert_eq!(module::Test::FOO.bits(), 1); +- } ++/// Implement functions on bitflags types. ++/// ++/// We need to be careful about adding new methods and trait implementations here because they ++/// could conflict with items added by the end-user. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_bitflags { ++ ( ++ $(#[$outer:meta])* ++ $PublicBitFlags:ident: $T:ty { ++ fn empty() $empty:block ++ fn all() $all:block ++ fn bits($bits0:ident) $bits:block ++ fn from_bits($from_bits0:ident) $from_bits:block ++ fn from_bits_truncate($from_bits_truncate0:ident) $from_bits_truncate:block ++ fn from_bits_retain($from_bits_retain0:ident) $from_bits_retain:block ++ fn from_name($from_name0:ident) $from_name:block ++ fn is_empty($is_empty0:ident) $is_empty:block ++ fn is_all($is_all0:ident) $is_all:block ++ fn intersects($intersects0:ident, $intersects1:ident) $intersects:block ++ fn contains($contains0:ident, $contains1:ident) $contains:block ++ fn insert($insert0:ident, $insert1:ident) $insert:block ++ fn remove($remove0:ident, $remove1:ident) $remove:block ++ fn toggle($toggle0:ident, $toggle1:ident) $toggle:block ++ fn set($set0:ident, $set1:ident, $set2:ident) $set:block ++ fn intersection($intersection0:ident, $intersection1:ident) $intersection:block ++ fn union($union0:ident, $union1:ident) $union:block ++ fn difference($difference0:ident, $difference1:ident) $difference:block ++ fn symmetric_difference($symmetric_difference0:ident, $symmetric_difference1:ident) $symmetric_difference:block ++ fn complement($complement0:ident) $complement:block ++ } ++ ) => { ++ #[allow(dead_code, deprecated, unused_attributes)] ++ $(#[$outer])* ++ impl $PublicBitFlags { ++ /// Get a flags value with all bits unset. ++ #[inline] ++ pub const fn empty() -> Self { ++ $empty ++ } + +- #[test] +- fn test_pub_in_module() { +- mod module { +- mod submodule { +- bitflags! { +- // `pub (in super)` means only the module `module` will +- // be able to access this. +- pub (in super) struct Test: u8 { +- const FOO = 1; +- } +- } ++ /// Get a flags value with all known bits set. ++ #[inline] ++ pub const fn all() -> Self { ++ $all + } + +- mod test { +- // Note: due to `pub (in super)`, +- // this cannot be accessed directly by the testing code. +- pub(super) fn value() -> u8 { +- super::submodule::Test::FOO.bits() +- } ++ /// Get the underlying bits value. ++ /// ++ /// The returned value is exactly the bits set in this flags value. ++ #[inline] ++ pub const fn bits(&self) -> $T { ++ let $bits0 = self; ++ $bits + } + +- pub fn value() -> u8 { +- test::value() ++ /// Convert from a bits value. ++ /// ++ /// This method will return `None` if any unknown bits are set. ++ #[inline] ++ pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { ++ let $from_bits0 = bits; ++ $from_bits + } +- } + +- assert_eq!(module::value(), 1) +- } ++ /// Convert from a bits value, unsetting any unknown bits. ++ #[inline] ++ pub const fn from_bits_truncate(bits: $T) -> Self { ++ let $from_bits_truncate0 = bits; ++ $from_bits_truncate ++ } + +- #[test] +- fn test_zero_value_flags() { +- bitflags! { +- struct Flags: u32 { +- const NONE = 0b0; +- const SOME = 0b1; ++ /// Convert from a bits value exactly. ++ #[inline] ++ pub const fn from_bits_retain(bits: $T) -> Self { ++ let $from_bits_retain0 = bits; ++ $from_bits_retain + } +- } + +- assert!(Flags::empty().contains(Flags::NONE)); +- assert!(Flags::SOME.contains(Flags::NONE)); +- assert!(Flags::NONE.is_empty()); ++ /// Get a flags value with the bits of a flag with the given name set. ++ /// ++ /// This method will return `None` if `name` is empty or doesn't ++ /// correspond to any named flag. ++ #[inline] ++ pub fn from_name(name: &str) -> $crate::__private::core::option::Option { ++ let $from_name0 = name; ++ $from_name ++ } + +- assert_eq!(format!("{:?}", Flags::empty()), "NONE"); +- assert_eq!(format!("{:?}", Flags::SOME), "SOME"); +- } ++ /// Whether all bits in this flags value are unset. ++ #[inline] ++ pub const fn is_empty(&self) -> bool { ++ let $is_empty0 = self; ++ $is_empty ++ } + +- #[test] +- fn test_empty_bitflags() { +- bitflags! {} +- } ++ /// Whether all known bits in this flags value are set. ++ #[inline] ++ pub const fn is_all(&self) -> bool { ++ let $is_all0 = self; ++ $is_all ++ } + +- #[test] +- fn test_u128_bitflags() { +- bitflags! { +- struct Flags128: u128 { +- const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; +- const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; +- const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; +- const ABC = Self::A.bits | Self::B.bits | Self::C.bits; ++ /// Whether any set bits in a source flags value are also set in a target flags value. ++ #[inline] ++ pub const fn intersects(&self, other: Self) -> bool { ++ let $intersects0 = self; ++ let $intersects1 = other; ++ $intersects + } +- } + +- assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C); +- assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); +- assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); +- assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); +- assert_eq!( +- Flags128::ABC.bits, +- 0x8000_0000_0000_1000_0000_0000_0000_0001 +- ); +- assert_eq!(format!("{:?}", Flags128::A), "A"); +- assert_eq!(format!("{:?}", Flags128::B), "B"); +- assert_eq!(format!("{:?}", Flags128::C), "C"); +- assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC"); +- } ++ /// Whether all set bits in a source flags value are also set in a target flags value. ++ #[inline] ++ pub const fn contains(&self, other: Self) -> bool { ++ let $contains0 = self; ++ let $contains1 = other; ++ $contains ++ } + +- #[test] +- fn test_serde_bitflags_serialize() { +- let flags = SerdeFlags::A | SerdeFlags::B; ++ /// The bitwise or (`|`) of the bits in two flags values. ++ #[inline] ++ pub fn insert(&mut self, other: Self) { ++ let $insert0 = self; ++ let $insert1 = other; ++ $insert ++ } + +- let serialized = serde_json::to_string(&flags).unwrap(); ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `remove` won't truncate `other`, but the `!` operator will. ++ #[inline] ++ pub fn remove(&mut self, other: Self) { ++ let $remove0 = self; ++ let $remove1 = other; ++ $remove ++ } + +- assert_eq!(serialized, r#"{"bits":3}"#); +- } ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ #[inline] ++ pub fn toggle(&mut self, other: Self) { ++ let $toggle0 = self; ++ let $toggle1 = other; ++ $toggle ++ } + +- #[test] +- fn test_serde_bitflags_deserialize() { +- let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); ++ /// Call `insert` when `value` is `true` or `remove` when `value` is `false`. ++ #[inline] ++ pub fn set(&mut self, other: Self, value: bool) { ++ let $set0 = self; ++ let $set1 = other; ++ let $set2 = value; ++ $set ++ } + +- let expected = SerdeFlags::C | SerdeFlags::D; ++ /// The bitwise and (`&`) of the bits in two flags values. ++ #[inline] ++ #[must_use] ++ pub const fn intersection(self, other: Self) -> Self { ++ let $intersection0 = self; ++ let $intersection1 = other; ++ $intersection ++ } + +- assert_eq!(deserialized.bits, expected.bits); +- } ++ /// The bitwise or (`|`) of the bits in two flags values. ++ #[inline] ++ #[must_use] ++ pub const fn union(self, other: Self) -> Self { ++ let $union0 = self; ++ let $union1 = other; ++ $union ++ } + +- #[test] +- fn test_serde_bitflags_roundtrip() { +- let flags = SerdeFlags::A | SerdeFlags::B; ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `difference` won't truncate `other`, but the `!` operator will. ++ #[inline] ++ #[must_use] ++ pub const fn difference(self, other: Self) -> Self { ++ let $difference0 = self; ++ let $difference1 = other; ++ $difference ++ } + +- let deserialized: SerdeFlags = serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ #[inline] ++ #[must_use] ++ pub const fn symmetric_difference(self, other: Self) -> Self { ++ let $symmetric_difference0 = self; ++ let $symmetric_difference1 = other; ++ $symmetric_difference ++ } + +- assert_eq!(deserialized.bits, flags.bits); +- } ++ /// The bitwise negation (`!`) of the bits in a flags value, truncating the result. ++ #[inline] ++ #[must_use] ++ pub const fn complement(self) -> Self { ++ let $complement0 = self; ++ $complement ++ } ++ } ++ }; ++} + +- bitflags! { +- #[derive(serde::Serialize, serde::Deserialize)] +- struct SerdeFlags: u32 { +- const A = 1; +- const B = 2; +- const C = 4; +- const D = 8; ++/// A macro that processed the input to `bitflags!` and shuffles attributes around ++/// based on whether or not they're "expression-safe". ++/// ++/// This macro is a token-tree muncher that works on 2 levels: ++/// ++/// For each attribute, we explicitly match on its identifier, like `cfg` to determine ++/// whether or not it should be considered expression-safe. ++/// ++/// If you find yourself with an attribute that should be considered expression-safe ++/// and isn't, it can be added here. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __bitflags_expr_safe_attrs { ++ // Entrypoint: Move all flags and all attributes into `unprocessed` lists ++ // where they'll be munched one-at-a-time ++ ( ++ $(#[$inner:ident $($args:tt)*])* ++ { $e:expr } ++ ) => { ++ $crate::__bitflags_expr_safe_attrs! { ++ expr: { $e }, ++ attrs: { ++ // All attributes start here ++ unprocessed: [$(#[$inner $($args)*])*], ++ // Attributes that are safe on expressions go here ++ processed: [], ++ }, + } ++ }; ++ // Process the next attribute on the current flag ++ // `cfg`: The next flag should be propagated to expressions ++ // NOTE: You can copy this rules block and replace `cfg` with ++ // your attribute name that should be considered expression-safe ++ ( ++ expr: { $e:expr }, ++ attrs: { ++ unprocessed: [ ++ // cfg matched here ++ #[cfg $($args:tt)*] ++ $($attrs_rest:tt)* ++ ], ++ processed: [$($expr:tt)*], ++ }, ++ ) => { ++ $crate::__bitflags_expr_safe_attrs! { ++ expr: { $e }, ++ attrs: { ++ unprocessed: [ ++ $($attrs_rest)* ++ ], ++ processed: [ ++ $($expr)* ++ // cfg added here ++ #[cfg $($args)*] ++ ], ++ }, ++ } ++ }; ++ // Process the next attribute on the current flag ++ // `$other`: The next flag should not be propagated to expressions ++ ( ++ expr: { $e:expr }, ++ attrs: { ++ unprocessed: [ ++ // $other matched here ++ #[$other:ident $($args:tt)*] ++ $($attrs_rest:tt)* ++ ], ++ processed: [$($expr:tt)*], ++ }, ++ ) => { ++ $crate::__bitflags_expr_safe_attrs! { ++ expr: { $e }, ++ attrs: { ++ unprocessed: [ ++ $($attrs_rest)* ++ ], ++ processed: [ ++ // $other not added here ++ $($expr)* ++ ], ++ }, ++ } ++ }; ++ // Once all attributes on all flags are processed, generate the actual code ++ ( ++ expr: { $e:expr }, ++ attrs: { ++ unprocessed: [], ++ processed: [$(#[$expr:ident $($exprargs:tt)*])*], ++ }, ++ ) => { ++ $(#[$expr $($exprargs)*])* ++ { $e } + } + } ++ ++/// Implement a flag, which may be a wildcard `_`. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __bitflags_flag { ++ ( ++ { ++ name: _, ++ named: { $($named:tt)* }, ++ unnamed: { $($unnamed:tt)* }, ++ } ++ ) => { ++ $($unnamed)* ++ }; ++ ( ++ { ++ name: $Flag:ident, ++ named: { $($named:tt)* }, ++ unnamed: { $($unnamed:tt)* }, ++ } ++ ) => { ++ $($named)* ++ }; ++} ++ ++#[macro_use] ++mod public; ++#[macro_use] ++mod internal; ++#[macro_use] ++mod external; ++ ++#[cfg(feature = "example_generated")] ++pub mod example_generated; ++ ++#[cfg(test)] ++mod tests; +diff --git a/vendor/bitflags/src/parser.rs b/vendor/bitflags/src/parser.rs +new file mode 100644 +index 0000000..34b432d +--- /dev/null ++++ b/vendor/bitflags/src/parser.rs +@@ -0,0 +1,332 @@ ++/*! ++Parsing flags from text. ++ ++Format and parse a flags value as text using the following grammar: ++ ++- _Flags:_ (_Whitespace_ _Flag_ _Whitespace_)`|`* ++- _Flag:_ _Name_ | _Hex Number_ ++- _Name:_ The name of any defined flag ++- _Hex Number_: `0x`([0-9a-fA-F])* ++- _Whitespace_: (\s)* ++ ++As an example, this is how `Flags::A | Flags::B | 0x0c` can be represented as text: ++ ++```text ++A | B | 0x0c ++``` ++ ++Alternatively, it could be represented without whitespace: ++ ++```text ++A|B|0x0C ++``` ++ ++Note that identifiers are *case-sensitive*, so the following is *not equivalent*: ++ ++```text ++a|b|0x0C ++``` ++*/ ++ ++#![allow(clippy::let_unit_value)] ++ ++use core::fmt::{self, Write}; ++ ++use crate::{Bits, Flags}; ++ ++/** ++Write a flags value as text. ++ ++Any bits that aren't part of a contained flag will be formatted as a hex number. ++*/ ++pub fn to_writer(flags: &B, mut writer: impl Write) -> Result<(), fmt::Error> ++where ++ B::Bits: WriteHex, ++{ ++ // A formatter for bitflags that produces text output like: ++ // ++ // A | B | 0xf6 ++ // ++ // The names of set flags are written in a bar-separated-format, ++ // followed by a hex number of any remaining bits that are set ++ // but don't correspond to any flags. ++ ++ // Iterate over known flag values ++ let mut first = true; ++ let mut iter = flags.iter_names(); ++ for (name, _) in &mut iter { ++ if !first { ++ writer.write_str(" | ")?; ++ } ++ ++ first = false; ++ writer.write_str(name)?; ++ } ++ ++ // Append any extra bits that correspond to flags to the end of the format ++ let remaining = iter.remaining().bits(); ++ if remaining != B::Bits::EMPTY { ++ if !first { ++ writer.write_str(" | ")?; ++ } ++ ++ writer.write_str("0x")?; ++ remaining.write_hex(writer)?; ++ } ++ ++ fmt::Result::Ok(()) ++} ++ ++#[cfg(feature = "serde")] ++pub(crate) struct AsDisplay<'a, B>(pub(crate) &'a B); ++ ++#[cfg(feature = "serde")] ++impl<'a, B: Flags> fmt::Display for AsDisplay<'a, B> ++where ++ B::Bits: WriteHex, ++{ ++ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ to_writer(self.0, f) ++ } ++} ++ ++/** ++Parse a flags value from text. ++ ++This function will fail on any names that don't correspond to defined flags. ++Unknown bits will be retained. ++*/ ++pub fn from_str(input: &str) -> Result ++where ++ B::Bits: ParseHex, ++{ ++ let mut parsed_flags = B::empty(); ++ ++ // If the input is empty then return an empty set of flags ++ if input.trim().is_empty() { ++ return Ok(parsed_flags); ++ } ++ ++ for flag in input.split('|') { ++ let flag = flag.trim(); ++ ++ // If the flag is empty then we've got missing input ++ if flag.is_empty() { ++ return Err(ParseError::empty_flag()); ++ } ++ ++ // If the flag starts with `0x` then it's a hex number ++ // Parse it directly to the underlying bits type ++ let parsed_flag = if let Some(flag) = flag.strip_prefix("0x") { ++ let bits = ++ ::parse_hex(flag).map_err(|_| ParseError::invalid_hex_flag(flag))?; ++ ++ B::from_bits_retain(bits) ++ } ++ // Otherwise the flag is a name ++ // The generated flags type will determine whether ++ // or not it's a valid identifier ++ else { ++ B::from_name(flag).ok_or_else(|| ParseError::invalid_named_flag(flag))? ++ }; ++ ++ parsed_flags.insert(parsed_flag); ++ } ++ ++ Ok(parsed_flags) ++} ++ ++/** ++Write a flags value as text, ignoring any unknown bits. ++*/ ++pub fn to_writer_truncate(flags: &B, writer: impl Write) -> Result<(), fmt::Error> ++where ++ B::Bits: WriteHex, ++{ ++ to_writer(&B::from_bits_truncate(flags.bits()), writer) ++} ++ ++/** ++Parse a flags value from text. ++ ++This function will fail on any names that don't correspond to defined flags. ++Unknown bits will be ignored. ++*/ ++pub fn from_str_truncate(input: &str) -> Result ++where ++ B::Bits: ParseHex, ++{ ++ Ok(B::from_bits_truncate(from_str::(input)?.bits())) ++} ++ ++/** ++Write only the contained, defined, named flags in a flags value as text. ++*/ ++pub fn to_writer_strict(flags: &B, mut writer: impl Write) -> Result<(), fmt::Error> { ++ // This is a simplified version of `to_writer` that ignores ++ // any bits not corresponding to a named flag ++ ++ let mut first = true; ++ let mut iter = flags.iter_names(); ++ for (name, _) in &mut iter { ++ if !first { ++ writer.write_str(" | ")?; ++ } ++ ++ first = false; ++ writer.write_str(name)?; ++ } ++ ++ fmt::Result::Ok(()) ++} ++ ++/** ++Parse a flags value from text. ++ ++This function will fail on any names that don't correspond to defined flags. ++This function will fail to parse hex values. ++*/ ++pub fn from_str_strict(input: &str) -> Result { ++ // This is a simplified version of `from_str` that ignores ++ // any bits not corresponding to a named flag ++ ++ let mut parsed_flags = B::empty(); ++ ++ // If the input is empty then return an empty set of flags ++ if input.trim().is_empty() { ++ return Ok(parsed_flags); ++ } ++ ++ for flag in input.split('|') { ++ let flag = flag.trim(); ++ ++ // If the flag is empty then we've got missing input ++ if flag.is_empty() { ++ return Err(ParseError::empty_flag()); ++ } ++ ++ // If the flag starts with `0x` then it's a hex number ++ // These aren't supported in the strict parser ++ if flag.starts_with("0x") { ++ return Err(ParseError::invalid_hex_flag("unsupported hex flag value")); ++ } ++ ++ let parsed_flag = B::from_name(flag).ok_or_else(|| ParseError::invalid_named_flag(flag))?; ++ ++ parsed_flags.insert(parsed_flag); ++ } ++ ++ Ok(parsed_flags) ++} ++ ++/** ++Encode a value as a hex string. ++ ++Implementors of this trait should not write the `0x` prefix. ++*/ ++pub trait WriteHex { ++ /// Write the value as hex. ++ fn write_hex(&self, writer: W) -> fmt::Result; ++} ++ ++/** ++Parse a value from a hex string. ++*/ ++pub trait ParseHex { ++ /// Parse the value from hex. ++ fn parse_hex(input: &str) -> Result ++ where ++ Self: Sized; ++} ++ ++/// An error encountered while parsing flags from text. ++#[derive(Debug)] ++pub struct ParseError(ParseErrorKind); ++ ++#[derive(Debug)] ++#[allow(clippy::enum_variant_names)] ++enum ParseErrorKind { ++ EmptyFlag, ++ InvalidNamedFlag { ++ #[cfg(not(feature = "std"))] ++ got: (), ++ #[cfg(feature = "std")] ++ got: String, ++ }, ++ InvalidHexFlag { ++ #[cfg(not(feature = "std"))] ++ got: (), ++ #[cfg(feature = "std")] ++ got: String, ++ }, ++} ++ ++impl ParseError { ++ /// An invalid hex flag was encountered. ++ pub fn invalid_hex_flag(flag: impl fmt::Display) -> Self { ++ let _flag = flag; ++ ++ let got = { ++ #[cfg(feature = "std")] ++ { ++ _flag.to_string() ++ } ++ }; ++ ++ ParseError(ParseErrorKind::InvalidHexFlag { got }) ++ } ++ ++ /// A named flag that doesn't correspond to any on the flags type was encountered. ++ pub fn invalid_named_flag(flag: impl fmt::Display) -> Self { ++ let _flag = flag; ++ ++ let got = { ++ #[cfg(feature = "std")] ++ { ++ _flag.to_string() ++ } ++ }; ++ ++ ParseError(ParseErrorKind::InvalidNamedFlag { got }) ++ } ++ ++ /// A hex or named flag wasn't found between separators. ++ pub const fn empty_flag() -> Self { ++ ParseError(ParseErrorKind::EmptyFlag) ++ } ++} ++ ++impl fmt::Display for ParseError { ++ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ match &self.0 { ++ ParseErrorKind::InvalidNamedFlag { got } => { ++ let _got = got; ++ ++ write!(f, "unrecognized named flag")?; ++ ++ #[cfg(feature = "std")] ++ { ++ write!(f, " `{}`", _got)?; ++ } ++ } ++ ParseErrorKind::InvalidHexFlag { got } => { ++ let _got = got; ++ ++ write!(f, "invalid hex flag")?; ++ ++ #[cfg(feature = "std")] ++ { ++ write!(f, " `{}`", _got)?; ++ } ++ } ++ ParseErrorKind::EmptyFlag => { ++ write!(f, "encountered empty flag")?; ++ } ++ } ++ ++ Ok(()) ++ } ++} ++ ++#[cfg(feature = "std")] ++impl std::error::Error for ParseError {} +diff --git a/vendor/bitflags/src/public.rs b/vendor/bitflags/src/public.rs +new file mode 100644 +index 0000000..feecdd6 +--- /dev/null ++++ b/vendor/bitflags/src/public.rs +@@ -0,0 +1,578 @@ ++//! Generate the user-facing flags type. ++//! ++//! The code here belongs to the end-user, so new trait implementations and methods can't be ++//! added without potentially breaking users. ++ ++/// Declare the user-facing bitflags struct. ++/// ++/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __declare_public_bitflags { ++ ( ++ $(#[$outer:meta])* ++ $vis:vis struct $PublicBitFlags:ident ++ ) => { ++ $(#[$outer])* ++ $vis struct $PublicBitFlags(<$PublicBitFlags as $crate::__private::PublicFlags>::Internal); ++ }; ++} ++ ++/// Implement functions on the public (user-facing) bitflags type. ++/// ++/// We need to be careful about adding new methods and trait implementations here because they ++/// could conflict with items added by the end-user. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_public_bitflags_forward { ++ ( ++ $(#[$outer:meta])* ++ $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident ++ ) => { ++ $crate::__impl_bitflags! { ++ $(#[$outer])* ++ $PublicBitFlags: $T { ++ fn empty() { ++ Self($InternalBitFlags::empty()) ++ } ++ ++ fn all() { ++ Self($InternalBitFlags::all()) ++ } ++ ++ fn bits(f) { ++ f.0.bits() ++ } ++ ++ fn from_bits(bits) { ++ match $InternalBitFlags::from_bits(bits) { ++ $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), ++ $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, ++ } ++ } ++ ++ fn from_bits_truncate(bits) { ++ Self($InternalBitFlags::from_bits_truncate(bits)) ++ } ++ ++ fn from_bits_retain(bits) { ++ Self($InternalBitFlags::from_bits_retain(bits)) ++ } ++ ++ fn from_name(name) { ++ match $InternalBitFlags::from_name(name) { ++ $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), ++ $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, ++ } ++ } ++ ++ fn is_empty(f) { ++ f.0.is_empty() ++ } ++ ++ fn is_all(f) { ++ f.0.is_all() ++ } ++ ++ fn intersects(f, other) { ++ f.0.intersects(other.0) ++ } ++ ++ fn contains(f, other) { ++ f.0.contains(other.0) ++ } ++ ++ fn insert(f, other) { ++ f.0.insert(other.0) ++ } ++ ++ fn remove(f, other) { ++ f.0.remove(other.0) ++ } ++ ++ fn toggle(f, other) { ++ f.0.toggle(other.0) ++ } ++ ++ fn set(f, other, value) { ++ f.0.set(other.0, value) ++ } ++ ++ fn intersection(f, other) { ++ Self(f.0.intersection(other.0)) ++ } ++ ++ fn union(f, other) { ++ Self(f.0.union(other.0)) ++ } ++ ++ fn difference(f, other) { ++ Self(f.0.difference(other.0)) ++ } ++ ++ fn symmetric_difference(f, other) { ++ Self(f.0.symmetric_difference(other.0)) ++ } ++ ++ fn complement(f) { ++ Self(f.0.complement()) ++ } ++ } ++ } ++ }; ++} ++ ++/// Implement functions on the public (user-facing) bitflags type. ++/// ++/// We need to be careful about adding new methods and trait implementations here because they ++/// could conflict with items added by the end-user. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_public_bitflags { ++ ( ++ $(#[$outer:meta])* ++ $BitFlags:ident: $T:ty, $PublicBitFlags:ident { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt = $value:expr; ++ )* ++ } ++ ) => { ++ $crate::__impl_bitflags! { ++ $(#[$outer])* ++ $BitFlags: $T { ++ fn empty() { ++ Self(<$T as $crate::Bits>::EMPTY) ++ } ++ ++ fn all() { ++ let mut truncated = <$T as $crate::Bits>::EMPTY; ++ let mut i = 0; ++ ++ $( ++ $crate::__bitflags_expr_safe_attrs!( ++ $(#[$inner $($args)*])* ++ {{ ++ let flag = <$PublicBitFlags as $crate::Flags>::FLAGS[i].value().bits(); ++ ++ truncated = truncated | flag; ++ i += 1; ++ }} ++ ); ++ )* ++ ++ let _ = i; ++ Self::from_bits_retain(truncated) ++ } ++ ++ fn bits(f) { ++ f.0 ++ } ++ ++ fn from_bits(bits) { ++ let truncated = Self::from_bits_truncate(bits).0; ++ ++ if truncated == bits { ++ $crate::__private::core::option::Option::Some(Self(bits)) ++ } else { ++ $crate::__private::core::option::Option::None ++ } ++ } ++ ++ fn from_bits_truncate(bits) { ++ Self(bits & Self::all().bits()) ++ } ++ ++ fn from_bits_retain(bits) { ++ Self(bits) ++ } ++ ++ fn from_name(name) { ++ $( ++ $crate::__bitflags_flag!({ ++ name: $Flag, ++ named: { ++ $crate::__bitflags_expr_safe_attrs!( ++ $(#[$inner $($args)*])* ++ { ++ if name == $crate::__private::core::stringify!($Flag) { ++ return $crate::__private::core::option::Option::Some(Self($PublicBitFlags::$Flag.bits())); ++ } ++ } ++ ); ++ }, ++ unnamed: {}, ++ }); ++ )* ++ ++ let _ = name; ++ $crate::__private::core::option::Option::None ++ } ++ ++ fn is_empty(f) { ++ f.bits() == <$T as $crate::Bits>::EMPTY ++ } ++ ++ fn is_all(f) { ++ // NOTE: We check against `Self::all` here, not `Self::Bits::ALL` ++ // because the set of all flags may not use all bits ++ Self::all().bits() | f.bits() == f.bits() ++ } ++ ++ fn intersects(f, other) { ++ f.bits() & other.bits() != <$T as $crate::Bits>::EMPTY ++ } ++ ++ fn contains(f, other) { ++ f.bits() & other.bits() == other.bits() ++ } ++ ++ fn insert(f, other) { ++ *f = Self::from_bits_retain(f.bits()).union(other); ++ } ++ ++ fn remove(f, other) { ++ *f = Self::from_bits_retain(f.bits()).difference(other); ++ } ++ ++ fn toggle(f, other) { ++ *f = Self::from_bits_retain(f.bits()).symmetric_difference(other); ++ } ++ ++ fn set(f, other, value) { ++ if value { ++ f.insert(other); ++ } else { ++ f.remove(other); ++ } ++ } ++ ++ fn intersection(f, other) { ++ Self::from_bits_retain(f.bits() & other.bits()) ++ } ++ ++ fn union(f, other) { ++ Self::from_bits_retain(f.bits() | other.bits()) ++ } ++ ++ fn difference(f, other) { ++ Self::from_bits_retain(f.bits() & !other.bits()) ++ } ++ ++ fn symmetric_difference(f, other) { ++ Self::from_bits_retain(f.bits() ^ other.bits()) ++ } ++ ++ fn complement(f) { ++ Self::from_bits_truncate(!f.bits()) ++ } ++ } ++ } ++ }; ++} ++ ++/// Implement iterators on the public (user-facing) bitflags type. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_public_bitflags_iter { ++ ( ++ $(#[$outer:meta])* ++ $BitFlags:ident: $T:ty, $PublicBitFlags:ident ++ ) => { ++ $(#[$outer])* ++ impl $BitFlags { ++ /// Yield a set of contained flags values. ++ /// ++ /// Each yielded flags value will correspond to a defined named flag. Any unknown bits ++ /// will be yielded together as a final flags value. ++ #[inline] ++ pub const fn iter(&self) -> $crate::iter::Iter<$PublicBitFlags> { ++ $crate::iter::Iter::__private_const_new( ++ <$PublicBitFlags as $crate::Flags>::FLAGS, ++ $PublicBitFlags::from_bits_retain(self.bits()), ++ $PublicBitFlags::from_bits_retain(self.bits()), ++ ) ++ } ++ ++ /// Yield a set of contained named flags values. ++ /// ++ /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags. ++ /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded. ++ #[inline] ++ pub const fn iter_names(&self) -> $crate::iter::IterNames<$PublicBitFlags> { ++ $crate::iter::IterNames::__private_const_new( ++ <$PublicBitFlags as $crate::Flags>::FLAGS, ++ $PublicBitFlags::from_bits_retain(self.bits()), ++ $PublicBitFlags::from_bits_retain(self.bits()), ++ ) ++ } ++ } ++ ++ $(#[$outer:meta])* ++ impl $crate::__private::core::iter::IntoIterator for $BitFlags { ++ type Item = $PublicBitFlags; ++ type IntoIter = $crate::iter::Iter<$PublicBitFlags>; ++ ++ fn into_iter(self) -> Self::IntoIter { ++ self.iter() ++ } ++ } ++ }; ++} ++ ++/// Implement traits on the public (user-facing) bitflags type. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_public_bitflags_ops { ++ ( ++ $(#[$outer:meta])* ++ $PublicBitFlags:ident ++ ) => { ++ ++ $(#[$outer])* ++ impl $crate::__private::core::fmt::Binary for $PublicBitFlags { ++ fn fmt( ++ &self, ++ f: &mut $crate::__private::core::fmt::Formatter, ++ ) -> $crate::__private::core::fmt::Result { ++ let inner = self.0; ++ $crate::__private::core::fmt::Binary::fmt(&inner, f) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::fmt::Octal for $PublicBitFlags { ++ fn fmt( ++ &self, ++ f: &mut $crate::__private::core::fmt::Formatter, ++ ) -> $crate::__private::core::fmt::Result { ++ let inner = self.0; ++ $crate::__private::core::fmt::Octal::fmt(&inner, f) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::fmt::LowerHex for $PublicBitFlags { ++ fn fmt( ++ &self, ++ f: &mut $crate::__private::core::fmt::Formatter, ++ ) -> $crate::__private::core::fmt::Result { ++ let inner = self.0; ++ $crate::__private::core::fmt::LowerHex::fmt(&inner, f) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::fmt::UpperHex for $PublicBitFlags { ++ fn fmt( ++ &self, ++ f: &mut $crate::__private::core::fmt::Formatter, ++ ) -> $crate::__private::core::fmt::Result { ++ let inner = self.0; ++ $crate::__private::core::fmt::UpperHex::fmt(&inner, f) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitOr for $PublicBitFlags { ++ type Output = Self; ++ ++ /// The bitwise or (`|`) of the bits in two flags values. ++ #[inline] ++ fn bitor(self, other: $PublicBitFlags) -> Self { ++ self.union(other) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags { ++ /// The bitwise or (`|`) of the bits in two flags values. ++ #[inline] ++ fn bitor_assign(&mut self, other: Self) { ++ self.insert(other); ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitXor for $PublicBitFlags { ++ type Output = Self; ++ ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ #[inline] ++ fn bitxor(self, other: Self) -> Self { ++ self.symmetric_difference(other) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags { ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ #[inline] ++ fn bitxor_assign(&mut self, other: Self) { ++ self.toggle(other); ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitAnd for $PublicBitFlags { ++ type Output = Self; ++ ++ /// The bitwise and (`&`) of the bits in two flags values. ++ #[inline] ++ fn bitand(self, other: Self) -> Self { ++ self.intersection(other) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags { ++ /// The bitwise and (`&`) of the bits in two flags values. ++ #[inline] ++ fn bitand_assign(&mut self, other: Self) { ++ *self = Self::from_bits_retain(self.bits()).intersection(other); ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::Sub for $PublicBitFlags { ++ type Output = Self; ++ ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `difference` won't truncate `other`, but the `!` operator will. ++ #[inline] ++ fn sub(self, other: Self) -> Self { ++ self.difference(other) ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::SubAssign for $PublicBitFlags { ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `difference` won't truncate `other`, but the `!` operator will. ++ #[inline] ++ fn sub_assign(&mut self, other: Self) { ++ self.remove(other); ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::ops::Not for $PublicBitFlags { ++ type Output = Self; ++ ++ /// The bitwise negation (`!`) of the bits in a flags value, truncating the result. ++ #[inline] ++ fn not(self) -> Self { ++ self.complement() ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags { ++ /// The bitwise or (`|`) of the bits in each flags value. ++ fn extend>( ++ &mut self, ++ iterator: T, ++ ) { ++ for item in iterator { ++ self.insert(item) ++ } ++ } ++ } ++ ++ $(#[$outer])* ++ impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags { ++ /// The bitwise or (`|`) of the bits in each flags value. ++ fn from_iter>( ++ iterator: T, ++ ) -> Self { ++ use $crate::__private::core::iter::Extend; ++ ++ let mut result = Self::empty(); ++ result.extend(iterator); ++ result ++ } ++ } ++ }; ++} ++ ++/// Implement constants on the public (user-facing) bitflags type. ++#[macro_export] ++#[doc(hidden)] ++macro_rules! __impl_public_bitflags_consts { ++ ( ++ $(#[$outer:meta])* ++ $PublicBitFlags:ident: $T:ty { ++ $( ++ $(#[$inner:ident $($args:tt)*])* ++ const $Flag:tt = $value:expr; ++ )* ++ } ++ ) => { ++ $(#[$outer])* ++ impl $PublicBitFlags { ++ $( ++ $crate::__bitflags_flag!({ ++ name: $Flag, ++ named: { ++ $(#[$inner $($args)*])* ++ #[allow( ++ deprecated, ++ non_upper_case_globals, ++ )] ++ pub const $Flag: Self = Self::from_bits_retain($value); ++ }, ++ unnamed: {}, ++ }); ++ )* ++ } ++ ++ $(#[$outer])* ++ impl $crate::Flags for $PublicBitFlags { ++ const FLAGS: &'static [$crate::Flag<$PublicBitFlags>] = &[ ++ $( ++ $crate::__bitflags_flag!({ ++ name: $Flag, ++ named: { ++ $crate::__bitflags_expr_safe_attrs!( ++ $(#[$inner $($args)*])* ++ { ++ #[allow( ++ deprecated, ++ non_upper_case_globals, ++ )] ++ $crate::Flag::new($crate::__private::core::stringify!($Flag), $PublicBitFlags::$Flag) ++ } ++ ) ++ }, ++ unnamed: { ++ $crate::__bitflags_expr_safe_attrs!( ++ $(#[$inner $($args)*])* ++ { ++ #[allow( ++ deprecated, ++ non_upper_case_globals, ++ )] ++ $crate::Flag::new("", $PublicBitFlags::from_bits_retain($value)) ++ } ++ ) ++ }, ++ }), ++ )* ++ ]; ++ ++ type Bits = $T; ++ ++ fn bits(&self) -> $T { ++ $PublicBitFlags::bits(self) ++ } ++ ++ fn from_bits_retain(bits: $T) -> $PublicBitFlags { ++ $PublicBitFlags::from_bits_retain(bits) ++ } ++ } ++ }; ++} +diff --git a/vendor/bitflags/src/tests.rs b/vendor/bitflags/src/tests.rs +new file mode 100644 +index 0000000..ed52ad4 +--- /dev/null ++++ b/vendor/bitflags/src/tests.rs +@@ -0,0 +1,131 @@ ++mod all; ++mod bits; ++mod complement; ++mod contains; ++mod difference; ++mod empty; ++mod eq; ++mod extend; ++mod flags; ++mod fmt; ++mod from_bits; ++mod from_bits_retain; ++mod from_bits_truncate; ++mod from_name; ++mod insert; ++mod intersection; ++mod intersects; ++mod is_all; ++mod is_empty; ++mod iter; ++mod parser; ++mod remove; ++mod symmetric_difference; ++mod union; ++ ++bitflags! { ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestFlags: u8 { ++ /// 1 ++ const A = 1; ++ ++ /// 1 << 1 ++ const B = 1 << 1; ++ ++ /// 1 << 2 ++ const C = 1 << 2; ++ ++ /// 1 | (1 << 1) | (1 << 2) ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestFlagsInvert: u8 { ++ /// 1 | (1 << 1) | (1 << 2) ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ ++ /// 1 ++ const A = 1; ++ ++ /// 1 << 1 ++ const B = 1 << 1; ++ ++ /// 1 << 2 ++ const C = 1 << 2; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestZero: u8 { ++ /// 0 ++ const ZERO = 0; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestZeroOne: u8 { ++ /// 0 ++ const ZERO = 0; ++ ++ /// 1 ++ const ONE = 1; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestUnicode: u8 { ++ /// 1 ++ const 一 = 1; ++ ++ /// 2 ++ const 二 = 1 << 1; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestEmpty: u8 {} ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestOverlapping: u8 { ++ /// 1 | (1 << 1) ++ const AB = 1 | (1 << 1); ++ ++ /// (1 << 1) | (1 << 2) ++ const BC = (1 << 1) | (1 << 2); ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestOverlappingFull: u8 { ++ /// 1 ++ const A = 1; ++ ++ /// 1 ++ const B = 1; ++ ++ /// 1 ++ const C = 1; ++ ++ /// 2 ++ const D = 1 << 1; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestExternal: u8 { ++ /// 1 ++ const A = 1; ++ ++ /// 1 << 1 ++ const B = 1 << 1; ++ ++ /// 1 << 2 ++ const C = 1 << 2; ++ ++ /// 1 | (1 << 1) | (1 << 2) ++ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); ++ ++ /// External ++ const _ = !0; ++ } ++ ++ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] ++ pub struct TestExternalFull: u8 { ++ /// External ++ const _ = !0; ++ } ++} +diff --git a/vendor/bitflags/src/tests/all.rs b/vendor/bitflags/src/tests/all.rs +new file mode 100644 +index 0000000..cceb93a +--- /dev/null ++++ b/vendor/bitflags/src/tests/all.rs +@@ -0,0 +1,23 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(1 | 1 << 1 | 1 << 2, TestFlags::all); ++ ++ case(0, TestZero::all); ++ ++ case(0, TestEmpty::all); ++ ++ case(!0, TestExternal::all); ++} ++ ++#[track_caller] ++fn case(expected: T::Bits, inherent: impl FnOnce() -> T) ++where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!(expected, inherent().bits(), "T::all()"); ++ assert_eq!(expected, T::all().bits(), "Flags::all()"); ++} +diff --git a/vendor/bitflags/src/tests/bits.rs b/vendor/bitflags/src/tests/bits.rs +new file mode 100644 +index 0000000..678f153 +--- /dev/null ++++ b/vendor/bitflags/src/tests/bits.rs +@@ -0,0 +1,36 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(0, TestFlags::empty(), TestFlags::bits); ++ ++ case(1, TestFlags::A, TestFlags::bits); ++ case(1 | 1 << 1 | 1 << 2, TestFlags::ABC, TestFlags::bits); ++ ++ case(!0, TestFlags::from_bits_retain(u8::MAX), TestFlags::bits); ++ case(1 << 3, TestFlags::from_bits_retain(1 << 3), TestFlags::bits); ++ ++ case(1 << 3, TestZero::from_bits_retain(1 << 3), TestZero::bits); ++ ++ case(1 << 3, TestEmpty::from_bits_retain(1 << 3), TestEmpty::bits); ++ ++ case( ++ 1 << 4 | 1 << 6, ++ TestExternal::from_bits_retain(1 << 4 | 1 << 6), ++ TestExternal::bits, ++ ); ++} ++ ++#[track_caller] ++fn case( ++ expected: T::Bits, ++ value: T, ++ inherent: impl FnOnce(&T) -> T::Bits, ++) where ++ T::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!(expected, inherent(&value), "{:?}.bits()", value); ++ assert_eq!(expected, Flags::bits(&value), "Flags::bits({:?})", value); ++} +diff --git a/vendor/bitflags/src/tests/complement.rs b/vendor/bitflags/src/tests/complement.rs +new file mode 100644 +index 0000000..ac7a421 +--- /dev/null ++++ b/vendor/bitflags/src/tests/complement.rs +@@ -0,0 +1,53 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(0, TestFlags::all(), TestFlags::complement); ++ case(0, TestFlags::from_bits_retain(!0), TestFlags::complement); ++ ++ case(1 | 1 << 1, TestFlags::C, TestFlags::complement); ++ case( ++ 1 | 1 << 1, ++ TestFlags::C | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::complement, ++ ); ++ ++ case( ++ 1 | 1 << 1 | 1 << 2, ++ TestFlags::empty(), ++ TestFlags::complement, ++ ); ++ case( ++ 1 | 1 << 1 | 1 << 2, ++ TestFlags::from_bits_retain(1 << 3), ++ TestFlags::complement, ++ ); ++ ++ case(0, TestZero::empty(), TestZero::complement); ++ ++ case(0, TestEmpty::empty(), TestEmpty::complement); ++ ++ case(1 << 2, TestOverlapping::AB, TestOverlapping::complement); ++ ++ case(!0, TestExternal::empty(), TestExternal::complement); ++} ++ ++#[track_caller] ++fn case + Copy>( ++ expected: T::Bits, ++ value: T, ++ inherent: impl FnOnce(T) -> T, ++) where ++ T::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!(expected, inherent(value).bits(), "{:?}.complement()", value); ++ assert_eq!( ++ expected, ++ Flags::complement(value).bits(), ++ "Flags::complement({:?})", ++ value ++ ); ++ assert_eq!(expected, (!value).bits(), "!{:?}", value); ++} +diff --git a/vendor/bitflags/src/tests/contains.rs b/vendor/bitflags/src/tests/contains.rs +new file mode 100644 +index 0000000..12428dd +--- /dev/null ++++ b/vendor/bitflags/src/tests/contains.rs +@@ -0,0 +1,108 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::empty(), true), ++ (TestFlags::A, false), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ ], ++ TestFlags::contains, ++ ); ++ ++ case( ++ TestFlags::A, ++ &[ ++ (TestFlags::empty(), true), ++ (TestFlags::A, true), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::ABC, false), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ (TestFlags::from_bits_retain(1 | (1 << 3)), false), ++ ], ++ TestFlags::contains, ++ ); ++ ++ case( ++ TestFlags::ABC, ++ &[ ++ (TestFlags::empty(), true), ++ (TestFlags::A, true), ++ (TestFlags::B, true), ++ (TestFlags::C, true), ++ (TestFlags::ABC, true), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ ], ++ TestFlags::contains, ++ ); ++ ++ case( ++ TestFlags::from_bits_retain(1 << 3), ++ &[ ++ (TestFlags::empty(), true), ++ (TestFlags::A, false), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::from_bits_retain(1 << 3), true), ++ ], ++ TestFlags::contains, ++ ); ++ ++ case( ++ TestZero::ZERO, ++ &[(TestZero::ZERO, true)], ++ TestZero::contains, ++ ); ++ ++ case( ++ TestOverlapping::AB, ++ &[ ++ (TestOverlapping::AB, true), ++ (TestOverlapping::BC, false), ++ (TestOverlapping::from_bits_retain(1 << 1), true), ++ ], ++ TestOverlapping::contains, ++ ); ++ ++ case( ++ TestExternal::all(), ++ &[ ++ (TestExternal::A, true), ++ (TestExternal::B, true), ++ (TestExternal::C, true), ++ (TestExternal::from_bits_retain(1 << 5 | 1 << 7), true), ++ ], ++ TestExternal::contains, ++ ); ++} ++ ++#[track_caller] ++fn case( ++ value: T, ++ inputs: &[(T, bool)], ++ mut inherent: impl FnMut(&T, T) -> bool, ++) { ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent(&value, *input), ++ "{:?}.contains({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::contains(&value, *input), ++ "Flags::contains({:?}, {:?})", ++ value, ++ input ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/difference.rs b/vendor/bitflags/src/tests/difference.rs +new file mode 100644 +index 0000000..6ce9c0b +--- /dev/null ++++ b/vendor/bitflags/src/tests/difference.rs +@@ -0,0 +1,92 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::A | TestFlags::B, ++ &[ ++ (TestFlags::A, 1 << 1), ++ (TestFlags::B, 1), ++ (TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1), ++ ], ++ TestFlags::difference, ++ ); ++ ++ case( ++ TestFlags::from_bits_retain(1 | 1 << 3), ++ &[ ++ (TestFlags::A, 1 << 3), ++ (TestFlags::from_bits_retain(1 << 3), 1), ++ ], ++ TestFlags::difference, ++ ); ++ ++ case( ++ TestExternal::from_bits_retain(!0), ++ &[(TestExternal::A, 0b1111_1110)], ++ TestExternal::difference, ++ ); ++ ++ assert_eq!( ++ 0b1111_1110, ++ (TestExternal::from_bits_retain(!0) & !TestExternal::A).bits() ++ ); ++ ++ assert_eq!( ++ 0b1111_1110, ++ (TestFlags::from_bits_retain(!0).difference(TestFlags::A)).bits() ++ ); ++ ++ // The `!` operator unsets bits that don't correspond to known flags ++ assert_eq!( ++ 1 << 1 | 1 << 2, ++ (TestFlags::from_bits_retain(!0) & !TestFlags::A).bits() ++ ); ++} ++ ++#[track_caller] ++fn case + std::ops::SubAssign + Copy>( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent: impl FnMut(T, T) -> T, ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent(value, *input).bits(), ++ "{:?}.difference({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::difference(value, *input).bits(), ++ "Flags::difference({:?}, {:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ (value - *input).bits(), ++ "{:?} - {:?}", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ value -= *input; ++ value ++ } ++ .bits(), ++ "{:?} -= {:?}", ++ value, ++ input, ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/empty.rs b/vendor/bitflags/src/tests/empty.rs +new file mode 100644 +index 0000000..57fb1c7 +--- /dev/null ++++ b/vendor/bitflags/src/tests/empty.rs +@@ -0,0 +1,23 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(0, TestFlags::empty); ++ ++ case(0, TestZero::empty); ++ ++ case(0, TestEmpty::empty); ++ ++ case(0, TestExternal::empty); ++} ++ ++#[track_caller] ++fn case(expected: T::Bits, inherent: impl FnOnce() -> T) ++where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!(expected, inherent().bits(), "T::empty()"); ++ assert_eq!(expected, T::empty().bits(), "Flags::empty()"); ++} +diff --git a/vendor/bitflags/src/tests/eq.rs b/vendor/bitflags/src/tests/eq.rs +new file mode 100644 +index 0000000..9779af7 +--- /dev/null ++++ b/vendor/bitflags/src/tests/eq.rs +@@ -0,0 +1,10 @@ ++use super::*; ++ ++#[test] ++fn cases() { ++ assert_eq!(TestFlags::empty(), TestFlags::empty()); ++ assert_eq!(TestFlags::all(), TestFlags::all()); ++ ++ assert!(TestFlags::from_bits_retain(1) < TestFlags::from_bits_retain(2)); ++ assert!(TestFlags::from_bits_retain(2) > TestFlags::from_bits_retain(1)); ++} +diff --git a/vendor/bitflags/src/tests/extend.rs b/vendor/bitflags/src/tests/extend.rs +new file mode 100644 +index 0000000..869dc17 +--- /dev/null ++++ b/vendor/bitflags/src/tests/extend.rs +@@ -0,0 +1,42 @@ ++use super::*; ++ ++#[test] ++fn cases() { ++ let mut flags = TestFlags::empty(); ++ ++ flags.extend(TestFlags::A); ++ ++ assert_eq!(TestFlags::A, flags); ++ ++ flags.extend(TestFlags::A | TestFlags::B | TestFlags::C); ++ ++ assert_eq!(TestFlags::ABC, flags); ++ ++ flags.extend(TestFlags::from_bits_retain(1 << 5)); ++ ++ assert_eq!(TestFlags::ABC | TestFlags::from_bits_retain(1 << 5), flags); ++} ++ ++mod external { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ let mut flags = TestExternal::empty(); ++ ++ flags.extend(TestExternal::A); ++ ++ assert_eq!(TestExternal::A, flags); ++ ++ flags.extend(TestExternal::A | TestExternal::B | TestExternal::C); ++ ++ assert_eq!(TestExternal::ABC, flags); ++ ++ flags.extend(TestExternal::from_bits_retain(1 << 5)); ++ ++ assert_eq!( ++ TestExternal::ABC | TestExternal::from_bits_retain(1 << 5), ++ flags ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/flags.rs b/vendor/bitflags/src/tests/flags.rs +new file mode 100644 +index 0000000..7a625b3 +--- /dev/null ++++ b/vendor/bitflags/src/tests/flags.rs +@@ -0,0 +1,46 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ let flags = TestFlags::FLAGS ++ .iter() ++ .map(|flag| (flag.name(), flag.value().bits())) ++ .collect::>(); ++ ++ assert_eq!( ++ vec![ ++ ("A", 1u8), ++ ("B", 1 << 1), ++ ("C", 1 << 2), ++ ("ABC", 1 | 1 << 1 | 1 << 2), ++ ], ++ flags, ++ ); ++ ++ assert_eq!(0, TestEmpty::FLAGS.iter().count()); ++} ++ ++mod external { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ let flags = TestExternal::FLAGS ++ .iter() ++ .map(|flag| (flag.name(), flag.value().bits())) ++ .collect::>(); ++ ++ assert_eq!( ++ vec![ ++ ("A", 1u8), ++ ("B", 1 << 1), ++ ("C", 1 << 2), ++ ("ABC", 1 | 1 << 1 | 1 << 2), ++ ("", !0), ++ ], ++ flags, ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/fmt.rs b/vendor/bitflags/src/tests/fmt.rs +new file mode 100644 +index 0000000..ed45718 +--- /dev/null ++++ b/vendor/bitflags/src/tests/fmt.rs +@@ -0,0 +1,97 @@ ++use super::*; ++ ++#[test] ++fn cases() { ++ case(TestFlags::empty(), "TestFlags(0x0)", "0", "0", "0", "0"); ++ case(TestFlags::A, "TestFlags(A)", "1", "1", "1", "1"); ++ case( ++ TestFlags::all(), ++ "TestFlags(A | B | C)", ++ "7", ++ "7", ++ "7", ++ "111", ++ ); ++ case( ++ TestFlags::from_bits_retain(1 << 3), ++ "TestFlags(0x8)", ++ "8", ++ "8", ++ "10", ++ "1000", ++ ); ++ case( ++ TestFlags::A | TestFlags::from_bits_retain(1 << 3), ++ "TestFlags(A | 0x8)", ++ "9", ++ "9", ++ "11", ++ "1001", ++ ); ++ ++ case(TestZero::ZERO, "TestZero(0x0)", "0", "0", "0", "0"); ++ case( ++ TestZero::ZERO | TestZero::from_bits_retain(1), ++ "TestZero(0x1)", ++ "1", ++ "1", ++ "1", ++ "1", ++ ); ++ ++ case(TestZeroOne::ONE, "TestZeroOne(ONE)", "1", "1", "1", "1"); ++ ++ case( ++ TestOverlapping::from_bits_retain(1 << 1), ++ "TestOverlapping(0x2)", ++ "2", ++ "2", ++ "2", ++ "10", ++ ); ++ ++ case( ++ TestExternal::from_bits_retain(1 | 1 << 1 | 1 << 3), ++ "TestExternal(A | B | 0x8)", ++ "B", ++ "b", ++ "13", ++ "1011", ++ ); ++ ++ case( ++ TestExternal::all(), ++ "TestExternal(A | B | C | 0xf8)", ++ "FF", ++ "ff", ++ "377", ++ "11111111", ++ ); ++ ++ case( ++ TestExternalFull::all(), ++ "TestExternalFull(0xff)", ++ "FF", ++ "ff", ++ "377", ++ "11111111", ++ ); ++} ++ ++#[track_caller] ++fn case< ++ T: std::fmt::Debug + std::fmt::UpperHex + std::fmt::LowerHex + std::fmt::Octal + std::fmt::Binary, ++>( ++ value: T, ++ debug: &str, ++ uhex: &str, ++ lhex: &str, ++ oct: &str, ++ bin: &str, ++) { ++ assert_eq!(debug, format!("{:?}", value)); ++ assert_eq!(uhex, format!("{:X}", value)); ++ assert_eq!(lhex, format!("{:x}", value)); ++ assert_eq!(oct, format!("{:o}", value)); ++ assert_eq!(bin, format!("{:b}", value)); ++} +diff --git a/vendor/bitflags/src/tests/from_bits.rs b/vendor/bitflags/src/tests/from_bits.rs +new file mode 100644 +index 0000000..dada9af +--- /dev/null ++++ b/vendor/bitflags/src/tests/from_bits.rs +@@ -0,0 +1,45 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(Some(0), 0, TestFlags::from_bits); ++ case(Some(1), 1, TestFlags::from_bits); ++ case( ++ Some(1 | 1 << 1 | 1 << 2), ++ 1 | 1 << 1 | 1 << 2, ++ TestFlags::from_bits, ++ ); ++ ++ case(None, 1 << 3, TestFlags::from_bits); ++ case(None, 1 | 1 << 3, TestFlags::from_bits); ++ ++ case(Some(1 | 1 << 1), 1 | 1 << 1, TestOverlapping::from_bits); ++ ++ case(Some(1 << 1), 1 << 1, TestOverlapping::from_bits); ++ ++ case(Some(1 << 5), 1 << 5, TestExternal::from_bits); ++} ++ ++#[track_caller] ++fn case( ++ expected: Option, ++ input: T::Bits, ++ inherent: impl FnOnce(T::Bits) -> Option, ++) where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!( ++ expected, ++ inherent(input).map(|f| f.bits()), ++ "T::from_bits({:?})", ++ input ++ ); ++ assert_eq!( ++ expected, ++ T::from_bits(input).map(|f| f.bits()), ++ "Flags::from_bits({:?})", ++ input ++ ); ++} +diff --git a/vendor/bitflags/src/tests/from_bits_retain.rs b/vendor/bitflags/src/tests/from_bits_retain.rs +new file mode 100644 +index 0000000..1ae28a6 +--- /dev/null ++++ b/vendor/bitflags/src/tests/from_bits_retain.rs +@@ -0,0 +1,38 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(0, TestFlags::from_bits_retain); ++ case(1, TestFlags::from_bits_retain); ++ case(1 | 1 << 1 | 1 << 2, TestFlags::from_bits_retain); ++ ++ case(1 << 3, TestFlags::from_bits_retain); ++ case(1 | 1 << 3, TestFlags::from_bits_retain); ++ ++ case(1 | 1 << 1, TestOverlapping::from_bits_retain); ++ ++ case(1 << 1, TestOverlapping::from_bits_retain); ++ ++ case(1 << 5, TestExternal::from_bits_retain); ++} ++ ++#[track_caller] ++fn case(input: T::Bits, inherent: impl FnOnce(T::Bits) -> T) ++where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!( ++ input, ++ inherent(input).bits(), ++ "T::from_bits_retain({:?})", ++ input ++ ); ++ assert_eq!( ++ input, ++ T::from_bits_retain(input).bits(), ++ "Flags::from_bits_retain({:?})", ++ input ++ ); ++} +diff --git a/vendor/bitflags/src/tests/from_bits_truncate.rs b/vendor/bitflags/src/tests/from_bits_truncate.rs +new file mode 100644 +index 0000000..e4f3e53 +--- /dev/null ++++ b/vendor/bitflags/src/tests/from_bits_truncate.rs +@@ -0,0 +1,42 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(0, 0, TestFlags::from_bits_truncate); ++ case(1, 1, TestFlags::from_bits_truncate); ++ case( ++ 1 | 1 << 1 | 1 << 2, ++ 1 | 1 << 1 | 1 << 2, ++ TestFlags::from_bits_truncate, ++ ); ++ ++ case(0, 1 << 3, TestFlags::from_bits_truncate); ++ case(1, 1 | 1 << 3, TestFlags::from_bits_truncate); ++ ++ case(1 | 1 << 1, 1 | 1 << 1, TestOverlapping::from_bits_truncate); ++ ++ case(1 << 1, 1 << 1, TestOverlapping::from_bits_truncate); ++ ++ case(1 << 5, 1 << 5, TestExternal::from_bits_truncate); ++} ++ ++#[track_caller] ++fn case(expected: T::Bits, input: T::Bits, inherent: impl FnOnce(T::Bits) -> T) ++where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!( ++ expected, ++ inherent(input).bits(), ++ "T::from_bits_truncate({:?})", ++ input ++ ); ++ assert_eq!( ++ expected, ++ T::from_bits_truncate(input).bits(), ++ "Flags::from_bits_truncate({:?})", ++ input ++ ); ++} +diff --git a/vendor/bitflags/src/tests/from_name.rs b/vendor/bitflags/src/tests/from_name.rs +new file mode 100644 +index 0000000..1d9a4e4 +--- /dev/null ++++ b/vendor/bitflags/src/tests/from_name.rs +@@ -0,0 +1,42 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(Some(1), "A", TestFlags::from_name); ++ case(Some(1 << 1), "B", TestFlags::from_name); ++ case(Some(1 | 1 << 1 | 1 << 2), "ABC", TestFlags::from_name); ++ ++ case(None, "", TestFlags::from_name); ++ case(None, "a", TestFlags::from_name); ++ case(None, "0x1", TestFlags::from_name); ++ case(None, "A | B", TestFlags::from_name); ++ ++ case(Some(0), "ZERO", TestZero::from_name); ++ ++ case(Some(2), "二", TestUnicode::from_name); ++ ++ case(None, "_", TestExternal::from_name); ++ ++ case(None, "", TestExternal::from_name); ++} ++ ++#[track_caller] ++fn case(expected: Option, input: &str, inherent: impl FnOnce(&str) -> Option) ++where ++ ::Bits: std::fmt::Debug + PartialEq, ++{ ++ assert_eq!( ++ expected, ++ inherent(input).map(|f| f.bits()), ++ "T::from_name({:?})", ++ input ++ ); ++ assert_eq!( ++ expected, ++ T::from_name(input).map(|f| f.bits()), ++ "Flags::from_name({:?})", ++ input ++ ); ++} +diff --git a/vendor/bitflags/src/tests/insert.rs b/vendor/bitflags/src/tests/insert.rs +new file mode 100644 +index 0000000..b18cd17 +--- /dev/null ++++ b/vendor/bitflags/src/tests/insert.rs +@@ -0,0 +1,91 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::A, 1), ++ (TestFlags::A | TestFlags::B, 1 | 1 << 1), ++ (TestFlags::empty(), 0), ++ (TestFlags::from_bits_retain(1 << 3), 1 << 3), ++ ], ++ TestFlags::insert, ++ TestFlags::set, ++ ); ++ ++ case( ++ TestFlags::A, ++ &[ ++ (TestFlags::A, 1), ++ (TestFlags::empty(), 1), ++ (TestFlags::B, 1 | 1 << 1), ++ ], ++ TestFlags::insert, ++ TestFlags::set, ++ ); ++} ++ ++#[track_caller] ++fn case( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent_insert: impl FnMut(&mut T, T), ++ mut inherent_set: impl FnMut(&mut T, T, bool), ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ inherent_insert(&mut value, *input); ++ value ++ } ++ .bits(), ++ "{:?}.insert({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ Flags::insert(&mut value, *input); ++ value ++ } ++ .bits(), ++ "Flags::insert({:?}, {:?})", ++ value, ++ input ++ ); ++ ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ inherent_set(&mut value, *input, true); ++ value ++ } ++ .bits(), ++ "{:?}.set({:?}, true)", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ Flags::set(&mut value, *input, true); ++ value ++ } ++ .bits(), ++ "Flags::set({:?}, {:?}, true)", ++ value, ++ input ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/intersection.rs b/vendor/bitflags/src/tests/intersection.rs +new file mode 100644 +index 0000000..10a8ae9 +--- /dev/null ++++ b/vendor/bitflags/src/tests/intersection.rs +@@ -0,0 +1,79 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[(TestFlags::empty(), 0), (TestFlags::all(), 0)], ++ TestFlags::intersection, ++ ); ++ ++ case( ++ TestFlags::all(), ++ &[ ++ (TestFlags::all(), 1 | 1 << 1 | 1 << 2), ++ (TestFlags::A, 1), ++ (TestFlags::from_bits_retain(1 << 3), 0), ++ ], ++ TestFlags::intersection, ++ ); ++ ++ case( ++ TestFlags::from_bits_retain(1 << 3), ++ &[(TestFlags::from_bits_retain(1 << 3), 1 << 3)], ++ TestFlags::intersection, ++ ); ++ ++ case( ++ TestOverlapping::AB, ++ &[(TestOverlapping::BC, 1 << 1)], ++ TestOverlapping::intersection, ++ ); ++} ++ ++#[track_caller] ++fn case + std::ops::BitAndAssign + Copy>( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent: impl FnMut(T, T) -> T, ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent(value, *input).bits(), ++ "{:?}.intersection({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::intersection(value, *input).bits(), ++ "Flags::intersection({:?}, {:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ (value & *input).bits(), ++ "{:?} & {:?}", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ value &= *input; ++ value ++ } ++ .bits(), ++ "{:?} &= {:?}", ++ value, ++ input, ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/intersects.rs b/vendor/bitflags/src/tests/intersects.rs +new file mode 100644 +index 0000000..fe90798 +--- /dev/null ++++ b/vendor/bitflags/src/tests/intersects.rs +@@ -0,0 +1,91 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::empty(), false), ++ (TestFlags::A, false), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ ], ++ TestFlags::intersects, ++ ); ++ ++ case( ++ TestFlags::A, ++ &[ ++ (TestFlags::empty(), false), ++ (TestFlags::A, true), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::ABC, true), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ (TestFlags::from_bits_retain(1 | (1 << 3)), true), ++ ], ++ TestFlags::intersects, ++ ); ++ ++ case( ++ TestFlags::ABC, ++ &[ ++ (TestFlags::empty(), false), ++ (TestFlags::A, true), ++ (TestFlags::B, true), ++ (TestFlags::C, true), ++ (TestFlags::ABC, true), ++ (TestFlags::from_bits_retain(1 << 3), false), ++ ], ++ TestFlags::intersects, ++ ); ++ ++ case( ++ TestFlags::from_bits_retain(1 << 3), ++ &[ ++ (TestFlags::empty(), false), ++ (TestFlags::A, false), ++ (TestFlags::B, false), ++ (TestFlags::C, false), ++ (TestFlags::from_bits_retain(1 << 3), true), ++ ], ++ TestFlags::intersects, ++ ); ++ ++ case( ++ TestOverlapping::AB, ++ &[ ++ (TestOverlapping::AB, true), ++ (TestOverlapping::BC, true), ++ (TestOverlapping::from_bits_retain(1 << 1), true), ++ ], ++ TestOverlapping::intersects, ++ ); ++} ++ ++#[track_caller] ++fn case( ++ value: T, ++ inputs: &[(T, bool)], ++ mut inherent: impl FnMut(&T, T) -> bool, ++) { ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent(&value, *input), ++ "{:?}.intersects({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::intersects(&value, *input), ++ "Flags::intersects({:?}, {:?})", ++ value, ++ input ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/is_all.rs b/vendor/bitflags/src/tests/is_all.rs +new file mode 100644 +index 0000000..382a458 +--- /dev/null ++++ b/vendor/bitflags/src/tests/is_all.rs +@@ -0,0 +1,32 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(false, TestFlags::empty(), TestFlags::is_all); ++ case(false, TestFlags::A, TestFlags::is_all); ++ ++ case(true, TestFlags::ABC, TestFlags::is_all); ++ ++ case( ++ true, ++ TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::is_all, ++ ); ++ ++ case(true, TestZero::empty(), TestZero::is_all); ++ ++ case(true, TestEmpty::empty(), TestEmpty::is_all); ++} ++ ++#[track_caller] ++fn case(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) { ++ assert_eq!(expected, inherent(&value), "{:?}.is_all()", value); ++ assert_eq!( ++ expected, ++ Flags::is_all(&value), ++ "Flags::is_all({:?})", ++ value ++ ); ++} +diff --git a/vendor/bitflags/src/tests/is_empty.rs b/vendor/bitflags/src/tests/is_empty.rs +new file mode 100644 +index 0000000..92165f1 +--- /dev/null ++++ b/vendor/bitflags/src/tests/is_empty.rs +@@ -0,0 +1,31 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case(true, TestFlags::empty(), TestFlags::is_empty); ++ ++ case(false, TestFlags::A, TestFlags::is_empty); ++ case(false, TestFlags::ABC, TestFlags::is_empty); ++ case( ++ false, ++ TestFlags::from_bits_retain(1 << 3), ++ TestFlags::is_empty, ++ ); ++ ++ case(true, TestZero::empty(), TestZero::is_empty); ++ ++ case(true, TestEmpty::empty(), TestEmpty::is_empty); ++} ++ ++#[track_caller] ++fn case(expected: bool, value: T, inherent: impl FnOnce(&T) -> bool) { ++ assert_eq!(expected, inherent(&value), "{:?}.is_empty()", value); ++ assert_eq!( ++ expected, ++ Flags::is_empty(&value), ++ "Flags::is_empty({:?})", ++ value ++ ); ++} +diff --git a/vendor/bitflags/src/tests/iter.rs b/vendor/bitflags/src/tests/iter.rs +new file mode 100644 +index 0000000..54b1d27 +--- /dev/null ++++ b/vendor/bitflags/src/tests/iter.rs +@@ -0,0 +1,209 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++#[cfg(not(miri))] // Very slow in miri ++fn roundtrip() { ++ for a in 0u8..=255 { ++ for b in 0u8..=255 { ++ let f = TestFlags::from_bits_retain(a | b); ++ ++ assert_eq!(f, f.iter().collect::()); ++ assert_eq!( ++ TestFlags::from_bits_truncate(f.bits()), ++ f.iter_names().map(|(_, f)| f).collect::() ++ ); ++ ++ let f = TestExternal::from_bits_retain(a | b); ++ ++ assert_eq!(f, f.iter().collect::()); ++ } ++ } ++} ++ ++mod collect { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ assert_eq!(0, [].into_iter().collect::().bits()); ++ ++ assert_eq!(1, [TestFlags::A,].into_iter().collect::().bits()); ++ ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ [TestFlags::A, TestFlags::B | TestFlags::C,] ++ .into_iter() ++ .collect::() ++ .bits() ++ ); ++ ++ assert_eq!( ++ 1 | 1 << 3, ++ [ ++ TestFlags::from_bits_retain(1 << 3), ++ TestFlags::empty(), ++ TestFlags::A, ++ ] ++ .into_iter() ++ .collect::() ++ .bits() ++ ); ++ ++ assert_eq!( ++ 1 << 5 | 1 << 7, ++ [ ++ TestExternal::empty(), ++ TestExternal::from_bits_retain(1 << 5), ++ TestExternal::from_bits_retain(1 << 7), ++ ] ++ .into_iter() ++ .collect::() ++ .bits() ++ ); ++ } ++} ++ ++mod iter { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ case(&[], TestFlags::empty(), TestFlags::iter); ++ ++ case(&[1], TestFlags::A, TestFlags::iter); ++ case(&[1, 1 << 1], TestFlags::A | TestFlags::B, TestFlags::iter); ++ case( ++ &[1, 1 << 1, 1 << 3], ++ TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::iter, ++ ); ++ ++ case(&[1, 1 << 1, 1 << 2], TestFlags::ABC, TestFlags::iter); ++ case( ++ &[1, 1 << 1, 1 << 2, 1 << 3], ++ TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::iter, ++ ); ++ ++ case( ++ &[1 | 1 << 1 | 1 << 2], ++ TestFlagsInvert::ABC, ++ TestFlagsInvert::iter, ++ ); ++ ++ case(&[], TestZero::ZERO, TestZero::iter); ++ ++ case( ++ &[1, 1 << 1, 1 << 2, 0b1111_1000], ++ TestExternal::all(), ++ TestExternal::iter, ++ ); ++ } ++ ++ #[track_caller] ++ fn case + Copy>( ++ expected: &[T::Bits], ++ value: T, ++ inherent: impl FnOnce(&T) -> crate::iter::Iter, ++ ) where ++ T::Bits: std::fmt::Debug + PartialEq, ++ { ++ assert_eq!( ++ expected, ++ inherent(&value).map(|f| f.bits()).collect::>(), ++ "{:?}.iter()", ++ value ++ ); ++ assert_eq!( ++ expected, ++ Flags::iter(&value).map(|f| f.bits()).collect::>(), ++ "Flags::iter({:?})", ++ value ++ ); ++ assert_eq!( ++ expected, ++ value.into_iter().map(|f| f.bits()).collect::>(), ++ "{:?}.into_iter()", ++ value ++ ); ++ } ++} ++ ++mod iter_names { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ case(&[], TestFlags::empty(), TestFlags::iter_names); ++ ++ case(&[("A", 1)], TestFlags::A, TestFlags::iter_names); ++ case( ++ &[("A", 1), ("B", 1 << 1)], ++ TestFlags::A | TestFlags::B, ++ TestFlags::iter_names, ++ ); ++ case( ++ &[("A", 1), ("B", 1 << 1)], ++ TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::iter_names, ++ ); ++ ++ case( ++ &[("A", 1), ("B", 1 << 1), ("C", 1 << 2)], ++ TestFlags::ABC, ++ TestFlags::iter_names, ++ ); ++ case( ++ &[("A", 1), ("B", 1 << 1), ("C", 1 << 2)], ++ TestFlags::ABC | TestFlags::from_bits_retain(1 << 3), ++ TestFlags::iter_names, ++ ); ++ ++ case( ++ &[("ABC", 1 | 1 << 1 | 1 << 2)], ++ TestFlagsInvert::ABC, ++ TestFlagsInvert::iter_names, ++ ); ++ ++ case(&[], TestZero::ZERO, TestZero::iter_names); ++ ++ case( ++ &[("A", 1)], ++ TestOverlappingFull::A, ++ TestOverlappingFull::iter_names, ++ ); ++ case( ++ &[("A", 1), ("D", 1 << 1)], ++ TestOverlappingFull::A | TestOverlappingFull::D, ++ TestOverlappingFull::iter_names, ++ ); ++ } ++ ++ #[track_caller] ++ fn case( ++ expected: &[(&'static str, T::Bits)], ++ value: T, ++ inherent: impl FnOnce(&T) -> crate::iter::IterNames, ++ ) where ++ T::Bits: std::fmt::Debug + PartialEq, ++ { ++ assert_eq!( ++ expected, ++ inherent(&value) ++ .map(|(n, f)| (n, f.bits())) ++ .collect::>(), ++ "{:?}.iter_names()", ++ value ++ ); ++ assert_eq!( ++ expected, ++ Flags::iter_names(&value) ++ .map(|(n, f)| (n, f.bits())) ++ .collect::>(), ++ "Flags::iter_names({:?})", ++ value ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/parser.rs b/vendor/bitflags/src/tests/parser.rs +new file mode 100644 +index 0000000..fb27225 +--- /dev/null ++++ b/vendor/bitflags/src/tests/parser.rs +@@ -0,0 +1,332 @@ ++use super::*; ++ ++use crate::{parser::*, Flags}; ++ ++#[test] ++#[cfg(not(miri))] // Very slow in miri ++fn roundtrip() { ++ let mut s = String::new(); ++ ++ for a in 0u8..=255 { ++ for b in 0u8..=255 { ++ let f = TestFlags::from_bits_retain(a | b); ++ ++ s.clear(); ++ to_writer(&f, &mut s).unwrap(); ++ ++ assert_eq!(f, from_str::(&s).unwrap()); ++ } ++ } ++} ++ ++#[test] ++#[cfg(not(miri))] // Very slow in miri ++fn roundtrip_truncate() { ++ let mut s = String::new(); ++ ++ for a in 0u8..=255 { ++ for b in 0u8..=255 { ++ let f = TestFlags::from_bits_retain(a | b); ++ ++ s.clear(); ++ to_writer_truncate(&f, &mut s).unwrap(); ++ ++ assert_eq!( ++ TestFlags::from_bits_truncate(f.bits()), ++ from_str_truncate::(&s).unwrap() ++ ); ++ } ++ } ++} ++ ++#[test] ++#[cfg(not(miri))] // Very slow in miri ++fn roundtrip_strict() { ++ let mut s = String::new(); ++ ++ for a in 0u8..=255 { ++ for b in 0u8..=255 { ++ let f = TestFlags::from_bits_retain(a | b); ++ ++ s.clear(); ++ to_writer_strict(&f, &mut s).unwrap(); ++ ++ let mut strict = TestFlags::empty(); ++ for (_, flag) in f.iter_names() { ++ strict |= flag; ++ } ++ let f = strict; ++ ++ if let Ok(s) = from_str_strict::(&s) { ++ assert_eq!(f, s); ++ } ++ } ++ } ++} ++ ++mod from_str { ++ use super::*; ++ ++ #[test] ++ fn valid() { ++ assert_eq!(0, from_str::("").unwrap().bits()); ++ ++ assert_eq!(1, from_str::("A").unwrap().bits()); ++ assert_eq!(1, from_str::(" A ").unwrap().bits()); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str::("A | B | C").unwrap().bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str::("A\n|\tB\r\n| C ").unwrap().bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str::("A|B|C").unwrap().bits() ++ ); ++ ++ assert_eq!(1 << 3, from_str::("0x8").unwrap().bits()); ++ assert_eq!(1 | 1 << 3, from_str::("A | 0x8").unwrap().bits()); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 3, ++ from_str::("0x1 | 0x8 | B").unwrap().bits() ++ ); ++ ++ assert_eq!( ++ 1 | 1 << 1, ++ from_str::("一 | 二").unwrap().bits() ++ ); ++ } ++ ++ #[test] ++ fn invalid() { ++ assert!(from_str::("a") ++ .unwrap_err() ++ .to_string() ++ .starts_with("unrecognized named flag")); ++ assert!(from_str::("A & B") ++ .unwrap_err() ++ .to_string() ++ .starts_with("unrecognized named flag")); ++ ++ assert!(from_str::("0xg") ++ .unwrap_err() ++ .to_string() ++ .starts_with("invalid hex flag")); ++ assert!(from_str::("0xffffffffffff") ++ .unwrap_err() ++ .to_string() ++ .starts_with("invalid hex flag")); ++ } ++} ++ ++mod to_writer { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ assert_eq!("", write(TestFlags::empty())); ++ assert_eq!("A", write(TestFlags::A)); ++ assert_eq!("A | B | C", write(TestFlags::all())); ++ assert_eq!("0x8", write(TestFlags::from_bits_retain(1 << 3))); ++ assert_eq!( ++ "A | 0x8", ++ write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) ++ ); ++ ++ assert_eq!("", write(TestZero::ZERO)); ++ ++ assert_eq!("ABC", write(TestFlagsInvert::all())); ++ ++ assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1))); ++ ++ assert_eq!("A", write(TestOverlappingFull::C)); ++ assert_eq!( ++ "A | D", ++ write(TestOverlappingFull::C | TestOverlappingFull::D) ++ ); ++ } ++ ++ fn write(value: F) -> String ++ where ++ F::Bits: crate::parser::WriteHex, ++ { ++ let mut s = String::new(); ++ ++ to_writer(&value, &mut s).unwrap(); ++ s ++ } ++} ++ ++mod from_str_truncate { ++ use super::*; ++ ++ #[test] ++ fn valid() { ++ assert_eq!(0, from_str_truncate::("").unwrap().bits()); ++ ++ assert_eq!(1, from_str_truncate::("A").unwrap().bits()); ++ assert_eq!(1, from_str_truncate::(" A ").unwrap().bits()); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_truncate::("A | B | C").unwrap().bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_truncate::("A\n|\tB\r\n| C ") ++ .unwrap() ++ .bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_truncate::("A|B|C").unwrap().bits() ++ ); ++ ++ assert_eq!(0, from_str_truncate::("0x8").unwrap().bits()); ++ assert_eq!(1, from_str_truncate::("A | 0x8").unwrap().bits()); ++ assert_eq!( ++ 1 | 1 << 1, ++ from_str_truncate::("0x1 | 0x8 | B") ++ .unwrap() ++ .bits() ++ ); ++ ++ assert_eq!( ++ 1 | 1 << 1, ++ from_str_truncate::("一 | 二").unwrap().bits() ++ ); ++ } ++} ++ ++mod to_writer_truncate { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ assert_eq!("", write(TestFlags::empty())); ++ assert_eq!("A", write(TestFlags::A)); ++ assert_eq!("A | B | C", write(TestFlags::all())); ++ assert_eq!("", write(TestFlags::from_bits_retain(1 << 3))); ++ assert_eq!( ++ "A", ++ write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) ++ ); ++ ++ assert_eq!("", write(TestZero::ZERO)); ++ ++ assert_eq!("ABC", write(TestFlagsInvert::all())); ++ ++ assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1))); ++ ++ assert_eq!("A", write(TestOverlappingFull::C)); ++ assert_eq!( ++ "A | D", ++ write(TestOverlappingFull::C | TestOverlappingFull::D) ++ ); ++ } ++ ++ fn write(value: F) -> String ++ where ++ F::Bits: crate::parser::WriteHex, ++ { ++ let mut s = String::new(); ++ ++ to_writer_truncate(&value, &mut s).unwrap(); ++ s ++ } ++} ++ ++mod from_str_strict { ++ use super::*; ++ ++ #[test] ++ fn valid() { ++ assert_eq!(0, from_str_strict::("").unwrap().bits()); ++ ++ assert_eq!(1, from_str_strict::("A").unwrap().bits()); ++ assert_eq!(1, from_str_strict::(" A ").unwrap().bits()); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_strict::("A | B | C").unwrap().bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_strict::("A\n|\tB\r\n| C ") ++ .unwrap() ++ .bits() ++ ); ++ assert_eq!( ++ 1 | 1 << 1 | 1 << 2, ++ from_str_strict::("A|B|C").unwrap().bits() ++ ); ++ ++ assert_eq!( ++ 1 | 1 << 1, ++ from_str_strict::("一 | 二").unwrap().bits() ++ ); ++ } ++ ++ #[test] ++ fn invalid() { ++ assert!(from_str_strict::("a") ++ .unwrap_err() ++ .to_string() ++ .starts_with("unrecognized named flag")); ++ assert!(from_str_strict::("A & B") ++ .unwrap_err() ++ .to_string() ++ .starts_with("unrecognized named flag")); ++ ++ assert!(from_str_strict::("0x1") ++ .unwrap_err() ++ .to_string() ++ .starts_with("invalid hex flag")); ++ assert!(from_str_strict::("0xg") ++ .unwrap_err() ++ .to_string() ++ .starts_with("invalid hex flag")); ++ assert!(from_str_strict::("0xffffffffffff") ++ .unwrap_err() ++ .to_string() ++ .starts_with("invalid hex flag")); ++ } ++} ++ ++mod to_writer_strict { ++ use super::*; ++ ++ #[test] ++ fn cases() { ++ assert_eq!("", write(TestFlags::empty())); ++ assert_eq!("A", write(TestFlags::A)); ++ assert_eq!("A | B | C", write(TestFlags::all())); ++ assert_eq!("", write(TestFlags::from_bits_retain(1 << 3))); ++ assert_eq!( ++ "A", ++ write(TestFlags::A | TestFlags::from_bits_retain(1 << 3)) ++ ); ++ ++ assert_eq!("", write(TestZero::ZERO)); ++ ++ assert_eq!("ABC", write(TestFlagsInvert::all())); ++ ++ assert_eq!("", write(TestOverlapping::from_bits_retain(1))); ++ ++ assert_eq!("A", write(TestOverlappingFull::C)); ++ assert_eq!( ++ "A | D", ++ write(TestOverlappingFull::C | TestOverlappingFull::D) ++ ); ++ } ++ ++ fn write(value: F) -> String ++ where ++ F::Bits: crate::parser::WriteHex, ++ { ++ let mut s = String::new(); ++ ++ to_writer_strict(&value, &mut s).unwrap(); ++ s ++ } ++} +diff --git a/vendor/bitflags/src/tests/remove.rs b/vendor/bitflags/src/tests/remove.rs +new file mode 100644 +index 0000000..574b1ed +--- /dev/null ++++ b/vendor/bitflags/src/tests/remove.rs +@@ -0,0 +1,100 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::A, 0), ++ (TestFlags::empty(), 0), ++ (TestFlags::from_bits_retain(1 << 3), 0), ++ ], ++ TestFlags::remove, ++ TestFlags::set, ++ ); ++ ++ case( ++ TestFlags::A, ++ &[ ++ (TestFlags::A, 0), ++ (TestFlags::empty(), 1), ++ (TestFlags::B, 1), ++ ], ++ TestFlags::remove, ++ TestFlags::set, ++ ); ++ ++ case( ++ TestFlags::ABC, ++ &[ ++ (TestFlags::A, 1 << 1 | 1 << 2), ++ (TestFlags::A | TestFlags::C, 1 << 1), ++ ], ++ TestFlags::remove, ++ TestFlags::set, ++ ); ++} ++ ++#[track_caller] ++fn case( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent_remove: impl FnMut(&mut T, T), ++ mut inherent_set: impl FnMut(&mut T, T, bool), ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ inherent_remove(&mut value, *input); ++ value ++ } ++ .bits(), ++ "{:?}.remove({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ Flags::remove(&mut value, *input); ++ value ++ } ++ .bits(), ++ "Flags::remove({:?}, {:?})", ++ value, ++ input ++ ); ++ ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ inherent_set(&mut value, *input, false); ++ value ++ } ++ .bits(), ++ "{:?}.set({:?}, false)", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ Flags::set(&mut value, *input, false); ++ value ++ } ++ .bits(), ++ "Flags::set({:?}, {:?}, false)", ++ value, ++ input ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/symmetric_difference.rs b/vendor/bitflags/src/tests/symmetric_difference.rs +new file mode 100644 +index 0000000..75e9123 +--- /dev/null ++++ b/vendor/bitflags/src/tests/symmetric_difference.rs +@@ -0,0 +1,110 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::empty(), 0), ++ (TestFlags::all(), 1 | 1 << 1 | 1 << 2), ++ (TestFlags::from_bits_retain(1 << 3), 1 << 3), ++ ], ++ TestFlags::symmetric_difference, ++ TestFlags::toggle, ++ ); ++ ++ case( ++ TestFlags::A, ++ &[ ++ (TestFlags::empty(), 1), ++ (TestFlags::A, 0), ++ (TestFlags::all(), 1 << 1 | 1 << 2), ++ ], ++ TestFlags::symmetric_difference, ++ TestFlags::toggle, ++ ); ++ ++ case( ++ TestFlags::A | TestFlags::B | TestFlags::from_bits_retain(1 << 3), ++ &[ ++ (TestFlags::ABC, 1 << 2 | 1 << 3), ++ (TestFlags::from_bits_retain(1 << 3), 1 | 1 << 1), ++ ], ++ TestFlags::symmetric_difference, ++ TestFlags::toggle, ++ ); ++} ++ ++#[track_caller] ++fn case + std::ops::BitXorAssign + Copy>( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent_sym_diff: impl FnMut(T, T) -> T, ++ mut inherent_toggle: impl FnMut(&mut T, T), ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent_sym_diff(value, *input).bits(), ++ "{:?}.symmetric_difference({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::symmetric_difference(value, *input).bits(), ++ "Flags::symmetric_difference({:?}, {:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ (value ^ *input).bits(), ++ "{:?} ^ {:?}", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ value ^= *input; ++ value ++ } ++ .bits(), ++ "{:?} ^= {:?}", ++ value, ++ input, ++ ); ++ ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ inherent_toggle(&mut value, *input); ++ value ++ } ++ .bits(), ++ "{:?}.toggle({:?})", ++ value, ++ input, ++ ); ++ ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ Flags::toggle(&mut value, *input); ++ value ++ } ++ .bits(), ++ "{:?}.toggle({:?})", ++ value, ++ input, ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/tests/union.rs b/vendor/bitflags/src/tests/union.rs +new file mode 100644 +index 0000000..6190681 +--- /dev/null ++++ b/vendor/bitflags/src/tests/union.rs +@@ -0,0 +1,71 @@ ++use super::*; ++ ++use crate::Flags; ++ ++#[test] ++fn cases() { ++ case( ++ TestFlags::empty(), ++ &[ ++ (TestFlags::A, 1), ++ (TestFlags::all(), 1 | 1 << 1 | 1 << 2), ++ (TestFlags::empty(), 0), ++ (TestFlags::from_bits_retain(1 << 3), 1 << 3), ++ ], ++ TestFlags::union, ++ ); ++ ++ case( ++ TestFlags::A | TestFlags::C, ++ &[ ++ (TestFlags::A | TestFlags::B, 1 | 1 << 1 | 1 << 2), ++ (TestFlags::A, 1 | 1 << 2), ++ ], ++ TestFlags::union, ++ ); ++} ++ ++#[track_caller] ++fn case + std::ops::BitOrAssign + Copy>( ++ value: T, ++ inputs: &[(T, T::Bits)], ++ mut inherent: impl FnMut(T, T) -> T, ++) where ++ T::Bits: std::fmt::Debug + PartialEq + Copy, ++{ ++ for (input, expected) in inputs { ++ assert_eq!( ++ *expected, ++ inherent(value, *input).bits(), ++ "{:?}.union({:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ Flags::union(value, *input).bits(), ++ "Flags::union({:?}, {:?})", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ (value | *input).bits(), ++ "{:?} | {:?}", ++ value, ++ input ++ ); ++ assert_eq!( ++ *expected, ++ { ++ let mut value = value; ++ value |= *input; ++ value ++ } ++ .bits(), ++ "{:?} |= {:?}", ++ value, ++ input, ++ ); ++ } ++} +diff --git a/vendor/bitflags/src/traits.rs b/vendor/bitflags/src/traits.rs +new file mode 100644 +index 0000000..3905d7d +--- /dev/null ++++ b/vendor/bitflags/src/traits.rs +@@ -0,0 +1,431 @@ ++use core::{ ++ fmt, ++ ops::{BitAnd, BitOr, BitXor, Not}, ++}; ++ ++use crate::{ ++ iter, ++ parser::{ParseError, ParseHex, WriteHex}, ++}; ++ ++/** ++A defined flags value that may be named or unnamed. ++*/ ++#[derive(Debug)] ++pub struct Flag { ++ name: &'static str, ++ value: B, ++} ++ ++impl Flag { ++ /** ++ Define a flag. ++ ++ If `name` is non-empty then the flag is named, otherwise it's unnamed. ++ */ ++ pub const fn new(name: &'static str, value: B) -> Self { ++ Flag { name, value } ++ } ++ ++ /** ++ Get the name of this flag. ++ ++ If the flag is unnamed then the returned string will be empty. ++ */ ++ pub const fn name(&self) -> &'static str { ++ self.name ++ } ++ ++ /** ++ Get the flags value of this flag. ++ */ ++ pub const fn value(&self) -> &B { ++ &self.value ++ } ++ ++ /** ++ Whether the flag is named. ++ ++ If [`Flag::name`] returns a non-empty string then this method will return `true`. ++ */ ++ pub const fn is_named(&self) -> bool { ++ !self.name.is_empty() ++ } ++ ++ /** ++ Whether the flag is unnamed. ++ ++ If [`Flag::name`] returns a non-empty string then this method will return `false`. ++ */ ++ pub const fn is_unnamed(&self) -> bool { ++ self.name.is_empty() ++ } ++} ++ ++/** ++A set of defined flags using a bits type as storage. ++ ++## Implementing `Flags` ++ ++This trait is implemented by the [`bitflags`](macro.bitflags.html) macro: ++ ++``` ++use bitflags::bitflags; ++ ++bitflags! { ++ struct MyFlags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ } ++} ++``` ++ ++It can also be implemented manually: ++ ++``` ++use bitflags::{Flag, Flags}; ++ ++struct MyFlags(u8); ++ ++impl Flags for MyFlags { ++ const FLAGS: &'static [Flag] = &[ ++ Flag::new("A", MyFlags(1)), ++ Flag::new("B", MyFlags(1 << 1)), ++ ]; ++ ++ type Bits = u8; ++ ++ fn from_bits_retain(bits: Self::Bits) -> Self { ++ MyFlags(bits) ++ } ++ ++ fn bits(&self) -> Self::Bits { ++ self.0 ++ } ++} ++``` ++ ++## Using `Flags` ++ ++The `Flags` trait can be used generically to work with any flags types. In this example, ++we can count the number of defined named flags: ++ ++``` ++# use bitflags::{bitflags, Flags}; ++fn defined_flags() -> usize { ++ F::FLAGS.iter().filter(|f| f.is_named()).count() ++} ++ ++bitflags! { ++ struct MyFlags: u8 { ++ const A = 1; ++ const B = 1 << 1; ++ const C = 1 << 2; ++ ++ const _ = !0; ++ } ++} ++ ++assert_eq!(3, defined_flags::()); ++``` ++*/ ++pub trait Flags: Sized + 'static { ++ /// The set of defined flags. ++ const FLAGS: &'static [Flag]; ++ ++ /// The underlying bits type. ++ type Bits: Bits; ++ ++ /// Get a flags value with all bits unset. ++ fn empty() -> Self { ++ Self::from_bits_retain(Self::Bits::EMPTY) ++ } ++ ++ /// Get a flags value with all known bits set. ++ fn all() -> Self { ++ let mut truncated = Self::Bits::EMPTY; ++ ++ for flag in Self::FLAGS.iter() { ++ truncated = truncated | flag.value().bits(); ++ } ++ ++ Self::from_bits_retain(truncated) ++ } ++ ++ /// Get the underlying bits value. ++ /// ++ /// The returned value is exactly the bits set in this flags value. ++ fn bits(&self) -> Self::Bits; ++ ++ /// Convert from a bits value. ++ /// ++ /// This method will return `None` if any unknown bits are set. ++ fn from_bits(bits: Self::Bits) -> Option { ++ let truncated = Self::from_bits_truncate(bits); ++ ++ if truncated.bits() == bits { ++ Some(truncated) ++ } else { ++ None ++ } ++ } ++ ++ /// Convert from a bits value, unsetting any unknown bits. ++ fn from_bits_truncate(bits: Self::Bits) -> Self { ++ Self::from_bits_retain(bits & Self::all().bits()) ++ } ++ ++ /// Convert from a bits value exactly. ++ fn from_bits_retain(bits: Self::Bits) -> Self; ++ ++ /// Get a flags value with the bits of a flag with the given name set. ++ /// ++ /// This method will return `None` if `name` is empty or doesn't ++ /// correspond to any named flag. ++ fn from_name(name: &str) -> Option { ++ // Don't parse empty names as empty flags ++ if name.is_empty() { ++ return None; ++ } ++ ++ for flag in Self::FLAGS { ++ if flag.name() == name { ++ return Some(Self::from_bits_retain(flag.value().bits())); ++ } ++ } ++ ++ None ++ } ++ ++ /// Yield a set of contained flags values. ++ /// ++ /// Each yielded flags value will correspond to a defined named flag. Any unknown bits ++ /// will be yielded together as a final flags value. ++ fn iter(&self) -> iter::Iter { ++ iter::Iter::new(self) ++ } ++ ++ /// Yield a set of contained named flags values. ++ /// ++ /// This method is like [`Flags::iter`], except only yields bits in contained named flags. ++ /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded. ++ fn iter_names(&self) -> iter::IterNames { ++ iter::IterNames::new(self) ++ } ++ ++ /// Whether all bits in this flags value are unset. ++ fn is_empty(&self) -> bool { ++ self.bits() == Self::Bits::EMPTY ++ } ++ ++ /// Whether all known bits in this flags value are set. ++ fn is_all(&self) -> bool { ++ // NOTE: We check against `Self::all` here, not `Self::Bits::ALL` ++ // because the set of all flags may not use all bits ++ Self::all().bits() | self.bits() == self.bits() ++ } ++ ++ /// Whether any set bits in a source flags value are also set in a target flags value. ++ fn intersects(&self, other: Self) -> bool ++ where ++ Self: Sized, ++ { ++ self.bits() & other.bits() != Self::Bits::EMPTY ++ } ++ ++ /// Whether all set bits in a source flags value are also set in a target flags value. ++ fn contains(&self, other: Self) -> bool ++ where ++ Self: Sized, ++ { ++ self.bits() & other.bits() == other.bits() ++ } ++ ++ /// The bitwise or (`|`) of the bits in two flags values. ++ fn insert(&mut self, other: Self) ++ where ++ Self: Sized, ++ { ++ *self = Self::from_bits_retain(self.bits()).union(other); ++ } ++ ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `remove` won't truncate `other`, but the `!` operator will. ++ fn remove(&mut self, other: Self) ++ where ++ Self: Sized, ++ { ++ *self = Self::from_bits_retain(self.bits()).difference(other); ++ } ++ ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ fn toggle(&mut self, other: Self) ++ where ++ Self: Sized, ++ { ++ *self = Self::from_bits_retain(self.bits()).symmetric_difference(other); ++ } ++ ++ /// Call [`Flags::insert`] when `value` is `true` or [`Flags::remove`] when `value` is `false`. ++ fn set(&mut self, other: Self, value: bool) ++ where ++ Self: Sized, ++ { ++ if value { ++ self.insert(other); ++ } else { ++ self.remove(other); ++ } ++ } ++ ++ /// The bitwise and (`&`) of the bits in two flags values. ++ #[must_use] ++ fn intersection(self, other: Self) -> Self { ++ Self::from_bits_retain(self.bits() & other.bits()) ++ } ++ ++ /// The bitwise or (`|`) of the bits in two flags values. ++ #[must_use] ++ fn union(self, other: Self) -> Self { ++ Self::from_bits_retain(self.bits() | other.bits()) ++ } ++ ++ /// The intersection of a source flags value with the complement of a target flags value (`&!`). ++ /// ++ /// This method is not equivalent to `self & !other` when `other` has unknown bits set. ++ /// `difference` won't truncate `other`, but the `!` operator will. ++ #[must_use] ++ fn difference(self, other: Self) -> Self { ++ Self::from_bits_retain(self.bits() & !other.bits()) ++ } ++ ++ /// The bitwise exclusive-or (`^`) of the bits in two flags values. ++ #[must_use] ++ fn symmetric_difference(self, other: Self) -> Self { ++ Self::from_bits_retain(self.bits() ^ other.bits()) ++ } ++ ++ /// The bitwise negation (`!`) of the bits in a flags value, truncating the result. ++ #[must_use] ++ fn complement(self) -> Self { ++ Self::from_bits_truncate(!self.bits()) ++ } ++} ++ ++/** ++A bits type that can be used as storage for a flags type. ++*/ ++pub trait Bits: ++ Clone ++ + Copy ++ + PartialEq ++ + BitAnd ++ + BitOr ++ + BitXor ++ + Not ++ + Sized ++ + 'static ++{ ++ /// A value with all bits unset. ++ const EMPTY: Self; ++ ++ /// A value with all bits set. ++ const ALL: Self; ++} ++ ++// Not re-exported: prevent custom `Bits` impls being used in the `bitflags!` macro, ++// or they may fail to compile based on crate features ++pub trait Primitive {} ++ ++macro_rules! impl_bits { ++ ($($u:ty, $i:ty,)*) => { ++ $( ++ impl Bits for $u { ++ const EMPTY: $u = 0; ++ const ALL: $u = <$u>::MAX; ++ } ++ ++ impl Bits for $i { ++ const EMPTY: $i = 0; ++ const ALL: $i = <$u>::MAX as $i; ++ } ++ ++ impl ParseHex for $u { ++ fn parse_hex(input: &str) -> Result { ++ <$u>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input)) ++ } ++ } ++ ++ impl ParseHex for $i { ++ fn parse_hex(input: &str) -> Result { ++ <$i>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input)) ++ } ++ } ++ ++ impl WriteHex for $u { ++ fn write_hex(&self, mut writer: W) -> fmt::Result { ++ write!(writer, "{:x}", self) ++ } ++ } ++ ++ impl WriteHex for $i { ++ fn write_hex(&self, mut writer: W) -> fmt::Result { ++ write!(writer, "{:x}", self) ++ } ++ } ++ ++ impl Primitive for $i {} ++ impl Primitive for $u {} ++ )* ++ } ++} ++ ++impl_bits! { ++ u8, i8, ++ u16, i16, ++ u32, i32, ++ u64, i64, ++ u128, i128, ++ usize, isize, ++} ++ ++/// A trait for referencing the `bitflags`-owned internal type ++/// without exposing it publicly. ++pub trait PublicFlags { ++ /// The type of the underlying storage. ++ type Primitive: Primitive; ++ ++ /// The type of the internal field on the generated flags type. ++ type Internal; ++} ++ ++#[doc(hidden)] ++#[deprecated(note = "use the `Flags` trait instead")] ++pub trait BitFlags: ImplementedByBitFlagsMacro + Flags { ++ /// An iterator over enabled flags in an instance of the type. ++ type Iter: Iterator; ++ ++ /// An iterator over the raw names and bits for enabled flags in an instance of the type. ++ type IterNames: Iterator; ++} ++ ++#[allow(deprecated)] ++impl BitFlags for B { ++ type Iter = iter::Iter; ++ type IterNames = iter::IterNames; ++} ++ ++impl ImplementedByBitFlagsMacro for B {} ++ ++/// A marker trait that signals that an implementation of `BitFlags` came from the `bitflags!` macro. ++/// ++/// There's nothing stopping an end-user from implementing this trait, but we don't guarantee their ++/// manual implementations won't break between non-breaking releases. ++#[doc(hidden)] ++pub trait ImplementedByBitFlagsMacro {} ++ ++pub(crate) mod __private { ++ pub use super::{ImplementedByBitFlagsMacro, PublicFlags}; ++} +diff --git a/vendor/kvm-bindings/.cargo-checksum.json b/vendor/kvm-bindings/.cargo-checksum.json +index 9944086..6656d95 100644 +--- a/vendor/kvm-bindings/.cargo-checksum.json ++++ b/vendor/kvm-bindings/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{"CHANGELOG.md":"c742b232063943cfd45dd3ff7df62b0bce00784511164ab20b4017ca041a611d","CODEOWNERS":"62b997d5af358adec513e1935849d6b73e554fd4104d97a9eeff6469c9f4626a","CONTRIBUTING.md":"84f38736580c3af04df0b97cf34571e77978f43cfc489d1c8c5064bfe01baf24","Cargo.toml":"09337c66dedeb94ee13defbca7aa839c292288e98a6551c78b633b39404c70e0","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"18ff206a6a7e68d85a4888a059c8a41c1e0da9767b083f014283841bdb3c66d8","coverage_config_aarch64.json":"a7d2462cd08e66d5d5514f24aa0ae986e250373c5aad9efc31baa772418f2a3e","coverage_config_x86_64.json":"aa7a04c235220aeae61d8c1cd32e4137fb53655eb7a333637b12ffcdbf155da7","src/arm64/bindings.rs":"101c79b26cd3ab3e811d88d0b298e8afaef70a55dd8c6aac9537e6c470e5b037","src/arm64/fam_wrappers.rs":"2365bafdccf8277cc5d3bdc1521a99b2dc3b91078d0249db089fb5e78481b646","src/arm64/mod.rs":"9a561c94e93d18545ff7b8d6a305282b4a84b6d3d9775ef130852f620e91ef10","src/lib.rs":"2c76f28c5f3c96e2dc2fe74d75dc3277d9f78a8e4a10c63b502df7cc293c9847","src/x86/bindings.rs":"4f6804416948ed0e2ac87698792aaef150c67b9b648599f2baa16f4bed0a5561","src/x86/fam_wrappers.rs":"988b2ca59167735a6f46757cbc5895a46bdffe87f41f47b658f881c41c89e48b","src/x86/mod.rs":"ab41afcb1fad5f42d8f2f05e1c1a0058c2dd684bed220ff803ffc4472d4b1c6d"},"package":"efe70e65a5b092161d17f5005b66e5eefe7a94a70c332e755036fc4af78c4e79"} +\ No newline at end of file ++{"files":{"CHANGELOG.md":"bc900de5c5906a64c27a4014abfc58244e2196553703d7687ccd03acfd67a000","CODEOWNERS":"62b997d5af358adec513e1935849d6b73e554fd4104d97a9eeff6469c9f4626a","CONTRIBUTING.md":"9d1c96521cce7702a2ebabfb8c5c6097bcbb358d26afc38309f4b00e265b0749","Cargo.toml":"701c9704001b5fd5ccdfb56193bacdb4c1800e55bca2bbdfec09853116689f75","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"98a870b95d6a0e18f8a5680c256a6e593b49da3c99dcb553ea799d6dbdd43d5e","coverage_config_aarch64.json":"5ae2dff2fea112600df1d55965069d2989dfe14ff4c4a61b9d1365425547a80c","coverage_config_x86_64.json":"c503723b84089ef6ad8039cab4a0d772b9eb18c0e6957f9b4a226f697469e33d","src/arm64/bindings.rs":"8c0c3b89882eeaab9b1e604a8591a7eec982d40f7d58978f64cafcccdd879745","src/arm64/fam_wrappers.rs":"2365bafdccf8277cc5d3bdc1521a99b2dc3b91078d0249db089fb5e78481b646","src/arm64/mod.rs":"af4122ee21aff99afd58120c83c02a6a23568c5195e0e97fff694504c76fadc5","src/arm64/serialize.rs":"bacc64c2ba72fc3dfb9a49c3e5669afdd14fa081d85b3267f26efbe91374d12a","src/lib.rs":"4bf542d81e1b1c9a2a2ab35b15314230ad59256627a71d99423050ccd253857c","src/riscv64/bindings.rs":"fe13450d6e60236e16bcfc7cdbdc564e459e754e2a0e08f44f59bd4e65b9959d","src/riscv64/fam_wrappers.rs":"98755a7ed47a344e956c5551edb1c467ce18d7df92c0c5d1155ce407ec8ffc85","src/riscv64/mod.rs":"9a62d6e8cc256a1fea175b6242e7a6164fd2dc649bcbfcc9acf4a9b388f457d3","src/riscv64/serialize.rs":"627b6bbfcad52297efd819faf2f60af33223ab0052bd6a869aba7cf0600c5c61","src/serialize.rs":"2a607d3ad52375c125bfacea4f7d24d5ce9a02e624bb18263b8759efb6c0ee39","src/x86_64/bindings.rs":"364d0036e68049e21d4ed4520a915578846728054c78e427998d16f3cc49c1b9","src/x86_64/fam_wrappers.rs":"a1077319b084992e7da7168499d94cafc21a67d6d97729b82d967dbf46950804","src/x86_64/mod.rs":"75c69f6c067ff49f5babe43b3ab3951cc993db300da09df84b9bc8b026f01a71","src/x86_64/serialize.rs":"84d8e7ed5e440a3263cbda60cf2398afcf059fa04cc3b60e19915ead7f86c780"},"package":"fa4933174d0cc4b77b958578cd45784071cc5ae212c2d78fbd755aaaa6dfa71a"} +\ No newline at end of file +diff --git a/vendor/kvm-bindings/CHANGELOG.md b/vendor/kvm-bindings/CHANGELOG.md +index d87e538..8b76c69 100644 +--- a/vendor/kvm-bindings/CHANGELOG.md ++++ b/vendor/kvm-bindings/CHANGELOG.md +@@ -1,4 +1,68 @@ + # Changelog ++## [Unreleased] ++ ++### Added ++ ++### Changed ++ ++### Removed ++ ++## [0.10.0] ++ ++### Added ++ ++- RISC-V KVM bindings for Linux kernel v6.9, including serialization support. ++ ++## [0.9.1] ++ ++### Changed ++ ++- Fixed and validated manual (De)Serialize implementations to work with ++ `serde_json` crate. ++ ++## [0.9.0] ++ ++### Changed ++ ++- Replaced the v6.2 bindings of arm64, x86\_64 with the v6.9 ones. ++ ++### Removed ++ ++- Removed v6.2 bindings. ++ ++## [0.8.2] ++ ++### Changed ++ ++- Improve performance of bindings deserialization by \~5% by avoiding ++ a temporary allocation. ++ ++## [0.8.1] ++ ++### Fixed ++ ++- Implement `Default` for `kvm_xsave2`, which fixes usage of `Xsave` ++ unconditionally causing compile errors in downstream crates. ++ ++## [0.8.0] ++ ++### Added ++ ++- An opt-in feature `serde` that enables [`serde`](https://serde.rs)-based ++ (de)serialization of various bindings. ++ ++## [0.7.0] ++ ++### Changed ++- API change in the bindings from upstream kernel changes: ++ * system\_event has been made into a new union ++- The x86 module has been renamed to x86\_64 for consistency (matches the kernel ++ architecture directory name) ++- Added all features to the generated docs.rs documentation. ++ ++### Removed ++ ++- Dropped "x86" (32-bit) x86 support + + ## [0.6.0] + +diff --git a/vendor/kvm-bindings/CONTRIBUTING.md b/vendor/kvm-bindings/CONTRIBUTING.md +index 26b39df..e275fa8 100644 +--- a/vendor/kvm-bindings/CONTRIBUTING.md ++++ b/vendor/kvm-bindings/CONTRIBUTING.md +@@ -4,9 +4,9 @@ + + ### Bindgen + The bindings are currently generated using +-[bindgen](https://crates.io/crates/bindgen) version 0.59.1: ++[bindgen](https://crates.io/crates/bindgen) version 0.64.0: + ```bash +-cargo install bindgen --vers 0.59.1 ++cargo install bindgen-cli --vers 0.64.0 + ``` + + ### Linux Kernel +@@ -17,48 +17,50 @@ repository on your machine: + git clone https://github.com/torvalds/linux.git + ``` + +-## Add a new architecture ++## Updating bindings / adding a new architecture ++ + When adding a new architecture, the bindings must be generated for all existing + versions for consistency reasons. + +-### Example for arm64 and version 5.13 ++### Example for arm64 and kernel version 6.9 + + For this example we assume that you have both linux and kvm-bindings + repositories in your root. + + ```bash +-# Step 1: Create a new module using the name of the architecture in src/ +-cd kvm-bindings ++# Step 1 (if adding a new architecture): Create a new module using the name of the architecture in src/ ++pushd kvm-bindings + mkdir src/arm64 +-cd ~ ++popd + + # linux is the repository that you cloned at the previous step. +-cd linux ++pushd linux + # Step 2: Checkout the version you want to generate the bindings for. +-git checkout v5.13 ++git checkout v6.9 + + # Step 3: Generate the bindings. + # This will generate the headers for the targeted architecture and place them +-# in the user specified directory. In this case, we generate them in the +-# arm64_v5_13_headers directory. +-make headers_install ARCH=arm64 INSTALL_HDR_PATH=arm64_v5_13_headers +-cd arm64_v5_13_headers +-bindgen include/linux/kvm.h -o bindings_v5_13_0.rs \ +- --with-derive-default \ +- --with-derive-partialeq \ +- -- -Iinclude +-cd ~ ++# in the user specified directory ++ ++export ARCH=arm64 ++make headers_install ARCH=$ARCH INSTALL_HDR_PATH="$ARCH"_headers ++pushd "$ARCH"_headers ++bindgen include/linux/kvm.h -o bindings.rs \ ++ --impl-debug --with-derive-default \ ++ --with-derive-partialeq --impl-partialeq \ ++ -- -Iinclude ++popd + + # Step 4: Copy the generated file to the arm64 module. +-cp linux/arm64_v5_13_headers/bindings_v5_13_0.rs ++popd ++cp linux/"$ARCH"_headers/bindings.rs kvm-bindings/src/arm64 ++ + ``` + +-Steps 2, 3 and 4 must be repeated for each of the existing KVM versions. Don't +-forget to change the name of the bindings file using the appropriate version. ++Steps 2, 3 and 4 must be repeated for all existing architectures. + +-Now that we have the bindings generated, we can copy the module file from +-one of the existing modules as this is only changed when a new version is +-added. ++Now that we have the bindings generated, for a new architecture we can copy the ++module file from one of the existing modules. + + ```bash + cp arm/mod.rs arm64/ +@@ -66,6 +68,32 @@ cp arm/mod.rs arm64/ + + Also, you will need to add the new architecture to `kvm-bindings/lib.rs`. + ++When regenerating bindings, care must be taken to re-add various `zerocopy` ++derives under the `serde` feature. All items that require derives are ++listed in the `x86_64/serialize.rs` and `arm64/serialize.rs` inside the ++`serde_impls!` macro invocation, and missing derives will cause these ++modules to fail compilation. For all items listed here, the following ++derive should be present: ++ ++```rs ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++``` ++ ++Any types whose name contains a suffix akin to `__bindgen_ty_` and ++which is contained in any struct listed in `serialize.rs` will also need ++to have this derive added (otherwise compilation will fail). Note that ++these types are not explicitly listed in `serialize.rs`, as their names ++can change across `bindgen.rs` versions. ++ ++Lastly, in `x86_64/bindings.rs`, the derives also need to be added to ++`struct __BindgenBitfieldUnit` and `struct __IncompleteArrayField`. ++Additionally, these structs need to have their layout changed from `#[repr(C)]` ++to `#[repr(transparent)]`. This is needed because `zerocopy` traits can only be ++derived on generic structures that are `repr(transparent)` or `repr(packed)`. ++ + ### Future Improvements + All the above steps are scriptable, so in the next iteration I will add a + script to generate the bindings. +diff --git a/vendor/kvm-bindings/Cargo.toml b/vendor/kvm-bindings/Cargo.toml +index 6734ae3..6bc5db7 100644 +--- a/vendor/kvm-bindings/Cargo.toml ++++ b/vendor/kvm-bindings/Cargo.toml +@@ -11,17 +11,54 @@ + + [package] + name = "kvm-bindings" +-version = "0.6.0" ++version = "0.10.0" + authors = ["Amazon firecracker team "] ++build = false ++autobins = false ++autoexamples = false ++autotests = false ++autobenches = false + description = "Rust FFI bindings to KVM generated using bindgen." + readme = "README.md" + keywords = ["kvm"] + license = "Apache-2.0" + repository = "https://github.com/rust-vmm/kvm-bindings" + ++[package.metadata.docs.rs] ++all-features = true ++rustdoc-args = [ ++ "--cfg", ++ "docsrs", ++] ++ ++[lib] ++name = "kvm_bindings" ++path = "src/lib.rs" ++ ++[dependencies.serde] ++version = "1.0.0" ++features = ["derive"] ++optional = true ++ + [dependencies.vmm-sys-util] +-version = "0.11.0" ++version = "0.12.1" + optional = true + ++[dependencies.zerocopy] ++version = "0.7.32" ++features = ["derive"] ++optional = true ++ ++[dev-dependencies.bincode] ++version = "1.3.3" ++ ++[dev-dependencies.serde_json] ++version = "1.0.125" ++ + [features] + fam-wrappers = ["vmm-sys-util"] ++serde = [ ++ "dep:serde", ++ "serde/derive", ++ "dep:zerocopy", ++] +diff --git a/vendor/kvm-bindings/README.md b/vendor/kvm-bindings/README.md +index 4126a6b..dc83c54 100644 +--- a/vendor/kvm-bindings/README.md ++++ b/vendor/kvm-bindings/README.md +@@ -1,14 +1,12 @@ +-[![Build Status](https://travis-ci.org/rust-vmm/kvm-bindings.svg?branch=master)](https://travis-ci.org/rust-vmm/kvm-bindings) + [![Crates.io](https://img.shields.io/crates/v/kvm-bindings.svg)](https://crates.io/crates/kvm-bindings) + ![](https://img.shields.io/crates/l/kvm-bindings.svg) + # kvm-bindings + Rust FFI bindings to KVM, generated using + [bindgen](https://crates.io/crates/bindgen). It currently has support for the + following target architectures: +-- x86 + - x86_64 +-- arm + - arm64 ++- riscv64 + + The bindings exported by this crate are statically generated using header files + associated with a specific kernel version, and are not automatically synced with +@@ -19,7 +17,7 @@ kernel version they are using. For example, the `immediate_exit` field from the + capability is available. Using invalid fields or features may lead to undefined + behaviour. + +-# Usage ++## Usage + First, add the following to your `Cargo.toml`: + ```toml + kvm-bindings = "0.3" +@@ -37,7 +35,19 @@ this crate. Example: + kvm-bindings = { version = "0.3", features = ["fam-wrappers"]} + ``` + +-# Dependencies ++## Dependencies + The crate has an `optional` dependency to + [vmm-sys-util](https://crates.io/crates/vmm-sys-util) when enabling the + `fam-wrappers` feature. ++ ++It also has an optional dependency on [`serde`](serde.rs) when enabling the ++`serde` feature, to allow serialization of bindings. Serialization of ++bindings happens as opaque binary blobs via [`zerocopy`](https://google.github.io/comprehensive-rust/bare-metal/useful-crates/zerocopy.html). ++Due to the kernel's ABI compatibility, this means that bindings serialized ++in version `x` of `kvm-bindings` can be deserialized in version `y` of the ++crate, even if the bindings have had been regenerated in the meantime. ++ ++## Regenerating Bindings ++ ++Please see [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to generate the bindings ++or add support for new architectures. +\ No newline at end of file +diff --git a/vendor/kvm-bindings/coverage_config_aarch64.json b/vendor/kvm-bindings/coverage_config_aarch64.json +index 54fd8ea..df5b99f 100644 +--- a/vendor/kvm-bindings/coverage_config_aarch64.json ++++ b/vendor/kvm-bindings/coverage_config_aarch64.json +@@ -1,5 +1,5 @@ + { + "coverage_score": 60.9, + "exclude_path": "", +- "crate_features": "fam-wrappers" ++ "crate_features": "fam-wrappers,serde" + } +diff --git a/vendor/kvm-bindings/coverage_config_x86_64.json b/vendor/kvm-bindings/coverage_config_x86_64.json +index b8228fd..9011c22 100644 +--- a/vendor/kvm-bindings/coverage_config_x86_64.json ++++ b/vendor/kvm-bindings/coverage_config_x86_64.json +@@ -1,5 +1,5 @@ + { +- "coverage_score": 68.3, +- "exclude_path": "", +- "crate_features": "fam-wrappers" ++ "coverage_score": 79.17, ++ "exclude_path": ".*bindings\\.rs", ++ "crate_features": "fam-wrappers,serde" + } +diff --git a/vendor/kvm-bindings/src/arm64/bindings.rs b/vendor/kvm-bindings/src/arm64/bindings.rs +index 9159746..20c53a5 100644 +--- a/vendor/kvm-bindings/src/arm64/bindings.rs ++++ b/vendor/kvm-bindings/src/arm64/bindings.rs +@@ -1,4 +1,4 @@ +-/* automatically generated by rust-bindgen 0.59.1 */ ++/* automatically generated by rust-bindgen 0.64.0 */ + + #[repr(C)] + #[derive(Default)] +@@ -31,6 +31,7 @@ impl ::std::fmt::Debug for __IncompleteArrayField { + } + } + pub const __BITS_PER_LONG: u32 = 64; ++pub const __BITS_PER_LONG_LONG: u32 = 64; + pub const __FD_SETSIZE: u32 = 1024; + pub const _IOC_NRBITS: u32 = 8; + pub const _IOC_TYPEBITS: u32 = 8; +@@ -78,6 +79,8 @@ pub const PSCI_0_2_AFFINITY_LEVEL_ON_PENDING: u32 = 2; + pub const PSCI_0_2_TOS_UP_MIGRATE: u32 = 0; + pub const PSCI_0_2_TOS_UP_NO_MIGRATE: u32 = 1; + pub const PSCI_0_2_TOS_MP: u32 = 2; ++pub const PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET: u32 = 0; ++pub const PSCI_1_1_RESET_TYPE_VENDOR_START: u32 = 2147483648; + pub const PSCI_VERSION_MAJOR_SHIFT: u32 = 16; + pub const PSCI_VERSION_MINOR_MASK: u32 = 65535; + pub const PSCI_VERSION_MAJOR_MASK: i32 = -65536; +@@ -146,6 +149,50 @@ pub const HWCAP2_DGH: u32 = 32768; + pub const HWCAP2_RNG: u32 = 65536; + pub const HWCAP2_BTI: u32 = 131072; + pub const HWCAP2_MTE: u32 = 262144; ++pub const HWCAP2_ECV: u32 = 524288; ++pub const HWCAP2_AFP: u32 = 1048576; ++pub const HWCAP2_RPRES: u32 = 2097152; ++pub const HWCAP2_MTE3: u32 = 4194304; ++pub const HWCAP2_SME: u32 = 8388608; ++pub const HWCAP2_SME_I16I64: u32 = 16777216; ++pub const HWCAP2_SME_F64F64: u32 = 33554432; ++pub const HWCAP2_SME_I8I32: u32 = 67108864; ++pub const HWCAP2_SME_F16F32: u32 = 134217728; ++pub const HWCAP2_SME_B16F32: u32 = 268435456; ++pub const HWCAP2_SME_F32F32: u32 = 536870912; ++pub const HWCAP2_SME_FA64: u32 = 1073741824; ++pub const HWCAP2_WFXT: u32 = 2147483648; ++pub const HWCAP2_EBF16: u64 = 4294967296; ++pub const HWCAP2_SVE_EBF16: u64 = 8589934592; ++pub const HWCAP2_CSSC: u64 = 17179869184; ++pub const HWCAP2_RPRFM: u64 = 34359738368; ++pub const HWCAP2_SVE2P1: u64 = 68719476736; ++pub const HWCAP2_SME2: u64 = 137438953472; ++pub const HWCAP2_SME2P1: u64 = 274877906944; ++pub const HWCAP2_SME_I16I32: u64 = 549755813888; ++pub const HWCAP2_SME_BI32I32: u64 = 1099511627776; ++pub const HWCAP2_SME_B16B16: u64 = 2199023255552; ++pub const HWCAP2_SME_F16F16: u64 = 4398046511104; ++pub const HWCAP2_MOPS: u64 = 8796093022208; ++pub const HWCAP2_HBC: u64 = 17592186044416; ++pub const HWCAP2_SVE_B16B16: u64 = 35184372088832; ++pub const HWCAP2_LRCPC3: u64 = 70368744177664; ++pub const HWCAP2_LSE128: u64 = 140737488355328; ++pub const HWCAP2_FPMR: u64 = 281474976710656; ++pub const HWCAP2_LUT: u64 = 562949953421312; ++pub const HWCAP2_FAMINMAX: u64 = 1125899906842624; ++pub const HWCAP2_F8CVT: u64 = 2251799813685248; ++pub const HWCAP2_F8FMA: u64 = 4503599627370496; ++pub const HWCAP2_F8DP4: u64 = 9007199254740992; ++pub const HWCAP2_F8DP2: u64 = 18014398509481984; ++pub const HWCAP2_F8E4M3: u64 = 36028797018963968; ++pub const HWCAP2_F8E5M2: u64 = 72057594037927936; ++pub const HWCAP2_SME_LUTV2: u64 = 144115188075855872; ++pub const HWCAP2_SME_F8F16: u64 = 288230376151711744; ++pub const HWCAP2_SME_F8F32: u64 = 576460752303423488; ++pub const HWCAP2_SME_SF8FMA: u64 = 1152921504606846976; ++pub const HWCAP2_SME_SF8DP4: u64 = 2305843009213693952; ++pub const HWCAP2_SME_SF8DP2: u64 = 4611686018427387904; + pub const __SVE_VQ_BYTES: u32 = 16; + pub const __SVE_VQ_MIN: u32 = 1; + pub const __SVE_VQ_MAX: u32 = 512; +@@ -195,7 +242,10 @@ pub const SVE_PT_REGS_FPSIMD: u32 = 0; + pub const SVE_PT_REGS_SVE: u32 = 1; + pub const SVE_PT_VL_INHERIT: u32 = 2; + pub const SVE_PT_VL_ONEXEC: u32 = 4; ++pub const ZA_PT_VL_INHERIT: u32 = 2; ++pub const ZA_PT_VL_ONEXEC: u32 = 4; + pub const KVM_COALESCED_MMIO_PAGE_OFFSET: u32 = 1; ++pub const KVM_DIRTY_LOG_PAGE_OFFSET: u32 = 64; + pub const KVM_ARM_TARGET_AEM_V8: u32 = 0; + pub const KVM_ARM_TARGET_FOUNDATION_V8: u32 = 1; + pub const KVM_ARM_TARGET_CORTEX_A57: u32 = 2; +@@ -204,9 +254,7 @@ pub const KVM_ARM_TARGET_CORTEX_A53: u32 = 4; + pub const KVM_ARM_TARGET_GENERIC_V8: u32 = 5; + pub const KVM_ARM_NUM_TARGETS: u32 = 6; + pub const KVM_ARM_DEVICE_TYPE_SHIFT: u32 = 0; +-pub const KVM_ARM_DEVICE_TYPE_MASK: u32 = 65535; + pub const KVM_ARM_DEVICE_ID_SHIFT: u32 = 16; +-pub const KVM_ARM_DEVICE_ID_MASK: u32 = 4294901760; + pub const KVM_ARM_DEVICE_VGIC_V2: u32 = 0; + pub const KVM_VGIC_V2_ADDR_TYPE_DIST: u32 = 0; + pub const KVM_VGIC_V2_ADDR_TYPE_CPU: u32 = 1; +@@ -223,11 +271,18 @@ pub const KVM_ARM_VCPU_PMU_V3: u32 = 3; + pub const KVM_ARM_VCPU_SVE: u32 = 4; + pub const KVM_ARM_VCPU_PTRAUTH_ADDRESS: u32 = 5; + pub const KVM_ARM_VCPU_PTRAUTH_GENERIC: u32 = 6; ++pub const KVM_ARM_VCPU_HAS_EL2: u32 = 7; + pub const KVM_ARM_MAX_DBG_REGS: u32 = 16; ++pub const KVM_DEBUG_ARCH_HSR_HIGH_VALID: u32 = 1; + pub const KVM_GUESTDBG_USE_SW_BP: u32 = 65536; + pub const KVM_GUESTDBG_USE_HW: u32 = 131072; ++pub const KVM_ARM_DEV_EL1_VTIMER: u32 = 1; ++pub const KVM_ARM_DEV_EL1_PTIMER: u32 = 2; ++pub const KVM_ARM_DEV_PMU: u32 = 4; + pub const KVM_PMU_EVENT_ALLOW: u32 = 0; + pub const KVM_PMU_EVENT_DENY: u32 = 1; ++pub const KVM_ARM_TAGS_TO_GUEST: u32 = 0; ++pub const KVM_ARM_TAGS_FROM_GUEST: u32 = 1; + pub const KVM_REG_ARM_COPROC_MASK: u32 = 268369920; + pub const KVM_REG_ARM_COPROC_SHIFT: u32 = 16; + pub const KVM_REG_ARM_CORE: u32 = 1048576; +@@ -257,6 +312,9 @@ pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: u32 = 1; + pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: u32 = 2; + pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: u32 = 3; + pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED: u32 = 16; ++pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL: u32 = 0; ++pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL: u32 = 1; ++pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED: u32 = 2; + pub const KVM_REG_ARM64_SVE: u32 = 1376256; + pub const KVM_REG_ARM64_SVE_ZREG_BASE: u32 = 0; + pub const KVM_REG_ARM64_SVE_PREG_BASE: u32 = 1024; +@@ -267,6 +325,9 @@ pub const KVM_ARM64_SVE_MAX_SLICES: u32 = 32; + pub const KVM_ARM64_SVE_VQ_MIN: u32 = 1; + pub const KVM_ARM64_SVE_VQ_MAX: u32 = 512; + pub const KVM_ARM64_SVE_VLS_WORDS: u32 = 8; ++pub const KVM_REG_ARM_FW_FEAT_BMAP: u32 = 1441792; ++pub const KVM_ARM_VM_SMCCC_CTRL: u32 = 0; ++pub const KVM_ARM_VM_SMCCC_FILTER: u32 = 0; + pub const KVM_DEV_ARM_VGIC_GRP_ADDR: u32 = 0; + pub const KVM_DEV_ARM_VGIC_GRP_DIST_REGS: u32 = 1; + pub const KVM_DEV_ARM_VGIC_GRP_CPU_REGS: u32 = 2; +@@ -296,9 +357,12 @@ pub const KVM_ARM_VCPU_PMU_V3_CTRL: u32 = 0; + pub const KVM_ARM_VCPU_PMU_V3_IRQ: u32 = 0; + pub const KVM_ARM_VCPU_PMU_V3_INIT: u32 = 1; + pub const KVM_ARM_VCPU_PMU_V3_FILTER: u32 = 2; ++pub const KVM_ARM_VCPU_PMU_V3_SET_PMU: u32 = 3; + pub const KVM_ARM_VCPU_TIMER_CTRL: u32 = 1; + pub const KVM_ARM_VCPU_TIMER_IRQ_VTIMER: u32 = 0; + pub const KVM_ARM_VCPU_TIMER_IRQ_PTIMER: u32 = 1; ++pub const KVM_ARM_VCPU_TIMER_IRQ_HVTIMER: u32 = 2; ++pub const KVM_ARM_VCPU_TIMER_IRQ_HPTIMER: u32 = 3; + pub const KVM_ARM_VCPU_PVTIME_CTRL: u32 = 2; + pub const KVM_ARM_VCPU_PVTIME_IPA: u32 = 0; + pub const KVM_ARM_IRQ_VCPU2_SHIFT: u32 = 28; +@@ -321,44 +385,17 @@ pub const KVM_PSCI_RET_SUCCESS: u32 = 0; + pub const KVM_PSCI_RET_NI: i32 = -1; + pub const KVM_PSCI_RET_INVAL: i32 = -2; + pub const KVM_PSCI_RET_DENIED: i32 = -3; ++pub const KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2: u32 = 1; ++pub const KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED: u32 = 1; ++pub const KVM_HYPERCALL_EXIT_SMC: u32 = 1; ++pub const KVM_HYPERCALL_EXIT_16BIT: u32 = 2; ++pub const KVM_ARM_FEATURE_ID_RANGE: u32 = 0; ++pub const KVM_ARM_FEATURE_ID_RANGE_SIZE: u32 = 192; + pub const KVM_API_VERSION: u32 = 12; +-pub const KVM_TRC_SHIFT: u32 = 16; +-pub const KVM_TRC_ENTRYEXIT: u32 = 65536; +-pub const KVM_TRC_HANDLER: u32 = 131072; +-pub const KVM_TRC_VMENTRY: u32 = 65537; +-pub const KVM_TRC_VMEXIT: u32 = 65538; +-pub const KVM_TRC_PAGE_FAULT: u32 = 131073; +-pub const KVM_TRC_HEAD_SIZE: u32 = 12; +-pub const KVM_TRC_CYCLE_SIZE: u32 = 8; +-pub const KVM_TRC_EXTRA_MAX: u32 = 7; +-pub const KVM_TRC_INJ_VIRQ: u32 = 131074; +-pub const KVM_TRC_REDELIVER_EVT: u32 = 131075; +-pub const KVM_TRC_PEND_INTR: u32 = 131076; +-pub const KVM_TRC_IO_READ: u32 = 131077; +-pub const KVM_TRC_IO_WRITE: u32 = 131078; +-pub const KVM_TRC_CR_READ: u32 = 131079; +-pub const KVM_TRC_CR_WRITE: u32 = 131080; +-pub const KVM_TRC_DR_READ: u32 = 131081; +-pub const KVM_TRC_DR_WRITE: u32 = 131082; +-pub const KVM_TRC_MSR_READ: u32 = 131083; +-pub const KVM_TRC_MSR_WRITE: u32 = 131084; +-pub const KVM_TRC_CPUID: u32 = 131085; +-pub const KVM_TRC_INTR: u32 = 131086; +-pub const KVM_TRC_NMI: u32 = 131087; +-pub const KVM_TRC_VMMCALL: u32 = 131088; +-pub const KVM_TRC_HLT: u32 = 131089; +-pub const KVM_TRC_CLTS: u32 = 131090; +-pub const KVM_TRC_LMSW: u32 = 131091; +-pub const KVM_TRC_APIC_ACCESS: u32 = 131092; +-pub const KVM_TRC_TDP_FAULT: u32 = 131093; +-pub const KVM_TRC_GTLB_WRITE: u32 = 131094; +-pub const KVM_TRC_STLB_WRITE: u32 = 131095; +-pub const KVM_TRC_STLB_INVAL: u32 = 131096; +-pub const KVM_TRC_PPC_INSTR: u32 = 131097; + pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1; + pub const KVM_MEM_READONLY: u32 = 2; ++pub const KVM_MEM_GUEST_MEMFD: u32 = 4; + pub const KVM_PIT_SPEAKER_DUMMY: u32 = 1; +-pub const KVM_S390_CMMA_PEEK: u32 = 1; + pub const KVM_EXIT_HYPERV_SYNIC: u32 = 1; + pub const KVM_EXIT_HYPERV_HCALL: u32 = 2; + pub const KVM_EXIT_HYPERV_SYNDBG: u32 = 3; +@@ -400,30 +437,31 @@ pub const KVM_EXIT_DIRTY_RING_FULL: u32 = 31; + pub const KVM_EXIT_AP_RESET_HOLD: u32 = 32; + pub const KVM_EXIT_X86_BUS_LOCK: u32 = 33; + pub const KVM_EXIT_XEN: u32 = 34; ++pub const KVM_EXIT_RISCV_SBI: u32 = 35; ++pub const KVM_EXIT_RISCV_CSR: u32 = 36; ++pub const KVM_EXIT_NOTIFY: u32 = 37; ++pub const KVM_EXIT_LOONGARCH_IOCSR: u32 = 38; ++pub const KVM_EXIT_MEMORY_FAULT: u32 = 39; + pub const KVM_INTERNAL_ERROR_EMULATION: u32 = 1; + pub const KVM_INTERNAL_ERROR_SIMUL_EX: u32 = 2; + pub const KVM_INTERNAL_ERROR_DELIVERY_EV: u32 = 3; + pub const KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON: u32 = 4; ++pub const KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES: u32 = 1; + pub const KVM_EXIT_IO_IN: u32 = 0; + pub const KVM_EXIT_IO_OUT: u32 = 1; +-pub const KVM_S390_RESET_POR: u32 = 1; +-pub const KVM_S390_RESET_CLEAR: u32 = 2; +-pub const KVM_S390_RESET_SUBSYSTEM: u32 = 4; +-pub const KVM_S390_RESET_CPU_INIT: u32 = 8; +-pub const KVM_S390_RESET_IPL: u32 = 16; + pub const KVM_SYSTEM_EVENT_SHUTDOWN: u32 = 1; + pub const KVM_SYSTEM_EVENT_RESET: u32 = 2; + pub const KVM_SYSTEM_EVENT_CRASH: u32 = 3; ++pub const KVM_SYSTEM_EVENT_WAKEUP: u32 = 4; ++pub const KVM_SYSTEM_EVENT_SUSPEND: u32 = 5; ++pub const KVM_SYSTEM_EVENT_SEV_TERM: u32 = 6; + pub const KVM_MSR_EXIT_REASON_INVAL: u32 = 1; + pub const KVM_MSR_EXIT_REASON_UNKNOWN: u32 = 2; + pub const KVM_MSR_EXIT_REASON_FILTER: u32 = 4; ++pub const KVM_MSR_EXIT_REASON_VALID_MASK: u32 = 7; ++pub const KVM_NOTIFY_CONTEXT_INVALID: u32 = 1; ++pub const KVM_MEMORY_EXIT_FLAG_PRIVATE: u32 = 8; + pub const SYNC_REGS_SIZE_BYTES: u32 = 2048; +-pub const KVM_S390_MEMOP_LOGICAL_READ: u32 = 0; +-pub const KVM_S390_MEMOP_LOGICAL_WRITE: u32 = 1; +-pub const KVM_S390_MEMOP_SIDA_READ: u32 = 2; +-pub const KVM_S390_MEMOP_SIDA_WRITE: u32 = 3; +-pub const KVM_S390_MEMOP_F_CHECK_ONLY: u32 = 1; +-pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: u32 = 2; + pub const KVM_MP_STATE_RUNNABLE: u32 = 0; + pub const KVM_MP_STATE_UNINITIALIZED: u32 = 1; + pub const KVM_MP_STATE_INIT_RECEIVED: u32 = 2; +@@ -434,28 +472,7 @@ pub const KVM_MP_STATE_CHECK_STOP: u32 = 6; + pub const KVM_MP_STATE_OPERATING: u32 = 7; + pub const KVM_MP_STATE_LOAD: u32 = 8; + pub const KVM_MP_STATE_AP_RESET_HOLD: u32 = 9; +-pub const KVM_S390_SIGP_STOP: u32 = 4294836224; +-pub const KVM_S390_PROGRAM_INT: u32 = 4294836225; +-pub const KVM_S390_SIGP_SET_PREFIX: u32 = 4294836226; +-pub const KVM_S390_RESTART: u32 = 4294836227; +-pub const KVM_S390_INT_PFAULT_INIT: u32 = 4294836228; +-pub const KVM_S390_INT_PFAULT_DONE: u32 = 4294836229; +-pub const KVM_S390_MCHK: u32 = 4294840320; +-pub const KVM_S390_INT_CLOCK_COMP: u32 = 4294905860; +-pub const KVM_S390_INT_CPU_TIMER: u32 = 4294905861; +-pub const KVM_S390_INT_VIRTIO: u32 = 4294911491; +-pub const KVM_S390_INT_SERVICE: u32 = 4294910977; +-pub const KVM_S390_INT_EMERGENCY: u32 = 4294906369; +-pub const KVM_S390_INT_EXTERNAL_CALL: u32 = 4294906370; +-pub const KVM_S390_INT_IO_MIN: u32 = 0; +-pub const KVM_S390_INT_IO_MAX: u32 = 4294836223; +-pub const KVM_S390_INT_IO_AI_MASK: u32 = 67108864; +-pub const KVM_S390_PGM_FLAGS_ILC_VALID: u32 = 1; +-pub const KVM_S390_PGM_FLAGS_ILC_0: u32 = 2; +-pub const KVM_S390_PGM_FLAGS_ILC_1: u32 = 4; +-pub const KVM_S390_PGM_FLAGS_ILC_MASK: u32 = 6; +-pub const KVM_S390_PGM_FLAGS_NO_REWIND: u32 = 8; +-pub const KVM_S390_STOP_FLAG_STORE_STATUS: u32 = 1; ++pub const KVM_MP_STATE_SUSPENDED: u32 = 10; + pub const KVM_GUESTDBG_ENABLE: u32 = 1; + pub const KVM_GUESTDBG_SINGLESTEP: u32 = 2; + pub const KVM_X86_DISABLE_EXITS_MWAIT: u32 = 1; +@@ -463,11 +480,6 @@ pub const KVM_X86_DISABLE_EXITS_HLT: u32 = 2; + pub const KVM_X86_DISABLE_EXITS_PAUSE: u32 = 4; + pub const KVM_X86_DISABLE_EXITS_CSTATE: u32 = 8; + pub const KVM_X86_DISABLE_VALID_EXITS: u32 = 15; +-pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: u32 = 1; +-pub const KVM_PPC_PAGE_SIZES_MAX_SZ: u32 = 8; +-pub const KVM_PPC_PAGE_SIZES_REAL: u32 = 1; +-pub const KVM_PPC_1T_SEGMENTS: u32 = 2; +-pub const KVM_PPC_NO_HASH: u32 = 4; + pub const KVMIO: u32 = 174; + pub const KVM_VM_S390_UCONTROL: u32 = 1; + pub const KVM_VM_PPC_HV: u32 = 1; +@@ -662,13 +674,53 @@ pub const KVM_CAP_SET_GUEST_DEBUG2: u32 = 195; + pub const KVM_CAP_SGX_ATTRIBUTE: u32 = 196; + pub const KVM_CAP_VM_COPY_ENC_CONTEXT_FROM: u32 = 197; + pub const KVM_CAP_PTP_KVM: u32 = 198; ++pub const KVM_CAP_HYPERV_ENFORCE_CPUID: u32 = 199; ++pub const KVM_CAP_SREGS2: u32 = 200; ++pub const KVM_CAP_EXIT_HYPERCALL: u32 = 201; ++pub const KVM_CAP_PPC_RPT_INVALIDATE: u32 = 202; ++pub const KVM_CAP_BINARY_STATS_FD: u32 = 203; ++pub const KVM_CAP_EXIT_ON_EMULATION_FAILURE: u32 = 204; ++pub const KVM_CAP_ARM_MTE: u32 = 205; ++pub const KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM: u32 = 206; ++pub const KVM_CAP_VM_GPA_BITS: u32 = 207; ++pub const KVM_CAP_XSAVE2: u32 = 208; ++pub const KVM_CAP_SYS_ATTRIBUTES: u32 = 209; ++pub const KVM_CAP_PPC_AIL_MODE_3: u32 = 210; ++pub const KVM_CAP_S390_MEM_OP_EXTENSION: u32 = 211; ++pub const KVM_CAP_PMU_CAPABILITY: u32 = 212; ++pub const KVM_CAP_DISABLE_QUIRKS2: u32 = 213; ++pub const KVM_CAP_VM_TSC_CONTROL: u32 = 214; ++pub const KVM_CAP_SYSTEM_EVENT_DATA: u32 = 215; ++pub const KVM_CAP_ARM_SYSTEM_SUSPEND: u32 = 216; ++pub const KVM_CAP_S390_PROTECTED_DUMP: u32 = 217; ++pub const KVM_CAP_X86_TRIPLE_FAULT_EVENT: u32 = 218; ++pub const KVM_CAP_X86_NOTIFY_VMEXIT: u32 = 219; ++pub const KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: u32 = 220; ++pub const KVM_CAP_S390_ZPCI_OP: u32 = 221; ++pub const KVM_CAP_S390_CPU_TOPOLOGY: u32 = 222; ++pub const KVM_CAP_DIRTY_LOG_RING_ACQ_REL: u32 = 223; ++pub const KVM_CAP_S390_PROTECTED_ASYNC_DISABLE: u32 = 224; ++pub const KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP: u32 = 225; ++pub const KVM_CAP_PMU_EVENT_MASKED_EVENTS: u32 = 226; ++pub const KVM_CAP_COUNTER_OFFSET: u32 = 227; ++pub const KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE: u32 = 228; ++pub const KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES: u32 = 229; ++pub const KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES: u32 = 230; ++pub const KVM_CAP_USER_MEMORY2: u32 = 231; ++pub const KVM_CAP_MEMORY_FAULT_INFO: u32 = 232; ++pub const KVM_CAP_MEMORY_ATTRIBUTES: u32 = 233; ++pub const KVM_CAP_GUEST_MEMFD: u32 = 234; ++pub const KVM_CAP_VM_TYPES: u32 = 235; + pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1; + pub const KVM_IRQ_ROUTING_MSI: u32 = 2; + pub const KVM_IRQ_ROUTING_S390_ADAPTER: u32 = 3; + pub const KVM_IRQ_ROUTING_HV_SINT: u32 = 4; ++pub const KVM_IRQ_ROUTING_XEN_EVTCHN: u32 = 5; + pub const KVM_IRQFD_FLAG_DEASSIGN: u32 = 1; + pub const KVM_IRQFD_FLAG_RESAMPLE: u32 = 2; + pub const KVM_CLOCK_TSC_STABLE: u32 = 2; ++pub const KVM_CLOCK_REALTIME: u32 = 4; ++pub const KVM_CLOCK_HOST_TSC: u32 = 8; + pub const KVM_MMU_FSL_BOOKE_NOHV: u32 = 0; + pub const KVM_MMU_FSL_BOOKE_HV: u32 = 1; + pub const KVM_REG_ARCH_MASK: i64 = -72057594037927936; +@@ -681,6 +733,7 @@ pub const KVM_REG_S390: u64 = 5764607523034234880; + pub const KVM_REG_ARM64: u64 = 6917529027641081856; + pub const KVM_REG_MIPS: u64 = 8070450532247928832; + pub const KVM_REG_RISCV: i64 = -9223372036854775808; ++pub const KVM_REG_LOONGARCH: i64 = -8070450532247928832; + pub const KVM_REG_SIZE_SHIFT: u32 = 52; + pub const KVM_REG_SIZE_MASK: u64 = 67553994410557440; + pub const KVM_REG_SIZE_U8: u32 = 0; +@@ -694,46 +747,45 @@ pub const KVM_REG_SIZE_U1024: u64 = 31525197391593472; + pub const KVM_REG_SIZE_U2048: u64 = 36028797018963968; + pub const KVM_MSI_VALID_DEVID: u32 = 1; + pub const KVM_CREATE_DEVICE_TEST: u32 = 1; ++pub const KVM_DEV_VFIO_FILE: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_ADD: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_DEL: u32 = 2; + pub const KVM_DEV_VFIO_GROUP: u32 = 1; + pub const KVM_DEV_VFIO_GROUP_ADD: u32 = 1; + pub const KVM_DEV_VFIO_GROUP_DEL: u32 = 2; + pub const KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: u32 = 3; + pub const KVM_S390_STORE_STATUS_NOADDR: i32 = -1; + pub const KVM_S390_STORE_STATUS_PREFIXED: i32 = -2; +-pub const KVM_XEN_ATTR_TYPE_LONG_MODE: u32 = 0; +-pub const KVM_XEN_ATTR_TYPE_SHARED_INFO: u32 = 1; +-pub const KVM_XEN_ATTR_TYPE_UPCALL_VECTOR: u32 = 2; +-pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO: u32 = 0; +-pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: u32 = 1; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR: u32 = 2; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: u32 = 3; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA: u32 = 4; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST: u32 = 5; +-pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: u32 = 1; +-pub const KVM_DEV_ASSIGN_PCI_2_3: u32 = 2; +-pub const KVM_DEV_ASSIGN_MASK_INTX: u32 = 4; +-pub const KVM_DEV_IRQ_HOST_INTX: u32 = 1; +-pub const KVM_DEV_IRQ_HOST_MSI: u32 = 2; +-pub const KVM_DEV_IRQ_HOST_MSIX: u32 = 4; +-pub const KVM_DEV_IRQ_GUEST_INTX: u32 = 256; +-pub const KVM_DEV_IRQ_GUEST_MSI: u32 = 512; +-pub const KVM_DEV_IRQ_GUEST_MSIX: u32 = 1024; +-pub const KVM_DEV_IRQ_HOST_MASK: u32 = 255; +-pub const KVM_DEV_IRQ_GUEST_MASK: u32 = 65280; +-pub const KVM_MAX_MSIX_PER_DEV: u32 = 256; +-pub const KVM_X2APIC_API_USE_32BIT_IDS: u32 = 1; +-pub const KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK: u32 = 2; +-pub const KVM_ARM_DEV_EL1_VTIMER: u32 = 1; +-pub const KVM_ARM_DEV_EL1_PTIMER: u32 = 2; +-pub const KVM_ARM_DEV_PMU: u32 = 4; +-pub const KVM_HYPERV_CONN_ID_MASK: u32 = 16777215; +-pub const KVM_HYPERV_EVENTFD_DEASSIGN: u32 = 1; + pub const KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE: u32 = 1; + pub const KVM_DIRTY_LOG_INITIALLY_SET: u32 = 2; +-pub const KVM_DIRTY_LOG_PAGE_OFFSET: u32 = 0; + pub const KVM_DIRTY_GFN_F_MASK: u32 = 3; + pub const KVM_BUS_LOCK_DETECTION_OFF: u32 = 1; + pub const KVM_BUS_LOCK_DETECTION_EXIT: u32 = 2; ++pub const KVM_PMU_CAP_DISABLE: u32 = 1; ++pub const KVM_STATS_TYPE_SHIFT: u32 = 0; ++pub const KVM_STATS_TYPE_MASK: u32 = 15; ++pub const KVM_STATS_TYPE_CUMULATIVE: u32 = 0; ++pub const KVM_STATS_TYPE_INSTANT: u32 = 1; ++pub const KVM_STATS_TYPE_PEAK: u32 = 2; ++pub const KVM_STATS_TYPE_LINEAR_HIST: u32 = 3; ++pub const KVM_STATS_TYPE_LOG_HIST: u32 = 4; ++pub const KVM_STATS_TYPE_MAX: u32 = 4; ++pub const KVM_STATS_UNIT_SHIFT: u32 = 4; ++pub const KVM_STATS_UNIT_MASK: u32 = 240; ++pub const KVM_STATS_UNIT_NONE: u32 = 0; ++pub const KVM_STATS_UNIT_BYTES: u32 = 16; ++pub const KVM_STATS_UNIT_SECONDS: u32 = 32; ++pub const KVM_STATS_UNIT_CYCLES: u32 = 48; ++pub const KVM_STATS_UNIT_BOOLEAN: u32 = 64; ++pub const KVM_STATS_UNIT_MAX: u32 = 64; ++pub const KVM_STATS_BASE_SHIFT: u32 = 8; ++pub const KVM_STATS_BASE_MASK: u32 = 3840; ++pub const KVM_STATS_BASE_POW10: u32 = 0; ++pub const KVM_STATS_BASE_POW2: u32 = 256; ++pub const KVM_STATS_BASE_MAX: u32 = 256; ++pub const KVM_X86_NOTIFY_VMEXIT_ENABLED: u32 = 1; ++pub const KVM_X86_NOTIFY_VMEXIT_USER: u32 = 2; ++pub const KVM_MEMORY_ATTRIBUTE_PRIVATE: u32 = 8; + pub type __s8 = ::std::os::raw::c_schar; + pub type __u8 = ::std::os::raw::c_uchar; + pub type __s16 = ::std::os::raw::c_short; +@@ -749,6 +801,8 @@ pub struct __kernel_fd_set { + } + #[test] + fn bindgen_test_layout___kernel_fd_set() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fd_set> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__kernel_fd_set>(), + 128usize, +@@ -760,7 +814,7 @@ fn bindgen_test_layout___kernel_fd_set() { + concat!("Alignment of ", stringify!(__kernel_fd_set)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -799,6 +853,8 @@ pub struct __kernel_fsid_t { + } + #[test] + fn bindgen_test_layout___kernel_fsid_t() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fsid_t> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__kernel_fsid_t>(), + 8usize, +@@ -810,7 +866,7 @@ fn bindgen_test_layout___kernel_fsid_t() { + concat!("Alignment of ", stringify!(__kernel_fsid_t)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -831,6 +887,8 @@ pub type __kernel_clockid_t = ::std::os::raw::c_int; + pub type __kernel_caddr_t = *mut ::std::os::raw::c_char; + pub type __kernel_uid16_t = ::std::os::raw::c_ushort; + pub type __kernel_gid16_t = ::std::os::raw::c_ushort; ++pub type __s128 = i128; ++pub type __u128 = u128; + pub type __le16 = __u16; + pub type __be16 = __u16; + pub type __le32 = __u32; +@@ -842,6 +900,10 @@ pub type __wsum = __u32; + pub type __poll_t = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct user_pt_regs { + pub regs: [__u64; 31usize], + pub sp: __u64, +@@ -850,6 +912,8 @@ pub struct user_pt_regs { + } + #[test] + fn bindgen_test_layout_user_pt_regs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 272usize, +@@ -861,7 +925,7 @@ fn bindgen_test_layout_user_pt_regs() { + concat!("Alignment of ", stringify!(user_pt_regs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -871,7 +935,7 @@ fn bindgen_test_layout_user_pt_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sp as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sp) as usize - ptr as usize }, + 248usize, + concat!( + "Offset of field: ", +@@ -881,7 +945,7 @@ fn bindgen_test_layout_user_pt_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pc as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pc) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", +@@ -891,7 +955,7 @@ fn bindgen_test_layout_user_pt_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pstate as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pstate) as usize - ptr as usize }, + 264usize, + concat!( + "Offset of field: ", +@@ -904,6 +968,10 @@ fn bindgen_test_layout_user_pt_regs() { + #[repr(C)] + #[repr(align(16))] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct user_fpsimd_state { + pub vregs: [__uint128_t; 32usize], + pub fpsr: __u32, +@@ -912,6 +980,8 @@ pub struct user_fpsimd_state { + } + #[test] + fn bindgen_test_layout_user_fpsimd_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 528usize, +@@ -923,7 +993,7 @@ fn bindgen_test_layout_user_fpsimd_state() { + concat!("Alignment of ", stringify!(user_fpsimd_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vregs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vregs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -933,7 +1003,7 @@ fn bindgen_test_layout_user_fpsimd_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fpsr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fpsr) as usize - ptr as usize }, + 512usize, + concat!( + "Offset of field: ", +@@ -943,7 +1013,7 @@ fn bindgen_test_layout_user_fpsimd_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fpcr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fpcr) as usize - ptr as usize }, + 516usize, + concat!( + "Offset of field: ", +@@ -953,7 +1023,7 @@ fn bindgen_test_layout_user_fpsimd_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).__reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).__reserved) as usize - ptr as usize }, + 520usize, + concat!( + "Offset of field: ", +@@ -979,6 +1049,9 @@ pub struct user_hwdebug_state__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -993,9 +1066,7 @@ fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).addr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1005,9 +1076,7 @@ fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ctrl as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ctrl) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1017,9 +1086,7 @@ fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -1031,6 +1098,8 @@ fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() { + } + #[test] + fn bindgen_test_layout_user_hwdebug_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 264usize, +@@ -1042,7 +1111,7 @@ fn bindgen_test_layout_user_hwdebug_state() { + concat!("Alignment of ", stringify!(user_hwdebug_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_info as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_info) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1052,7 +1121,7 @@ fn bindgen_test_layout_user_hwdebug_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -1062,7 +1131,7 @@ fn bindgen_test_layout_user_hwdebug_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_regs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1084,6 +1153,8 @@ pub struct user_sve_header { + } + #[test] + fn bindgen_test_layout_user_sve_header() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1095,7 +1166,7 @@ fn bindgen_test_layout_user_sve_header() { + concat!("Alignment of ", stringify!(user_sve_header)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1105,7 +1176,7 @@ fn bindgen_test_layout_user_sve_header() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).max_size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).max_size) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -1115,7 +1186,7 @@ fn bindgen_test_layout_user_sve_header() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vl as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vl) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1125,7 +1196,7 @@ fn bindgen_test_layout_user_sve_header() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).max_vl as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).max_vl) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", +@@ -1135,7 +1206,7 @@ fn bindgen_test_layout_user_sve_header() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -1145,7 +1216,7 @@ fn bindgen_test_layout_user_sve_header() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).__reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).__reserved) as usize - ptr as usize }, + 14usize, + concat!( + "Offset of field: ", +@@ -1163,6 +1234,8 @@ pub struct user_pac_mask { + } + #[test] + fn bindgen_test_layout_user_pac_mask() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1174,7 +1247,7 @@ fn bindgen_test_layout_user_pac_mask() { + concat!("Alignment of ", stringify!(user_pac_mask)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data_mask as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data_mask) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1184,7 +1257,7 @@ fn bindgen_test_layout_user_pac_mask() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).insn_mask as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_mask) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1205,6 +1278,9 @@ pub struct user_pac_address_keys { + } + #[test] + fn bindgen_test_layout_user_pac_address_keys() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, +@@ -1216,7 +1292,7 @@ fn bindgen_test_layout_user_pac_address_keys() { + concat!("Alignment of ", stringify!(user_pac_address_keys)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apiakey as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apiakey) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1226,7 +1302,7 @@ fn bindgen_test_layout_user_pac_address_keys() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apibkey as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apibkey) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -1236,7 +1312,7 @@ fn bindgen_test_layout_user_pac_address_keys() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apdakey as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apdakey) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", +@@ -1246,7 +1322,7 @@ fn bindgen_test_layout_user_pac_address_keys() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apdbkey as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apdbkey) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", +@@ -1264,6 +1340,9 @@ pub struct user_pac_generic_keys { + } + #[test] + fn bindgen_test_layout_user_pac_generic_keys() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1275,7 +1354,7 @@ fn bindgen_test_layout_user_pac_generic_keys() { + concat!("Alignment of ", stringify!(user_pac_generic_keys)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apgakey as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apgakey) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1286,8 +1365,97 @@ fn bindgen_test_layout_user_pac_generic_keys() { + ); + } + #[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct user_za_header { ++ pub size: __u32, ++ pub max_size: __u32, ++ pub vl: __u16, ++ pub max_vl: __u16, ++ pub flags: __u16, ++ pub __reserved: __u16, ++} ++#[test] ++fn bindgen_test_layout_user_za_header() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(user_za_header)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(user_za_header)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).max_size) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(max_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vl) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(vl) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).max_vl) as usize - ptr as usize }, ++ 10usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(max_vl) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__reserved) as usize - ptr as usize }, ++ 14usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_za_header), ++ "::", ++ stringify!(__reserved) ++ ) ++ ); ++} ++#[repr(C)] + #[repr(align(16))] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_regs { + pub regs: user_pt_regs, + pub sp_el1: __u64, +@@ -1298,6 +1466,8 @@ pub struct kvm_regs { + } + #[test] + fn bindgen_test_layout_kvm_regs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 864usize, +@@ -1309,7 +1479,7 @@ fn bindgen_test_layout_kvm_regs() { + concat!("Alignment of ", stringify!(kvm_regs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1319,7 +1489,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sp_el1 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sp_el1) as usize - ptr as usize }, + 272usize, + concat!( + "Offset of field: ", +@@ -1329,7 +1499,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).elr_el1 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).elr_el1) as usize - ptr as usize }, + 280usize, + concat!( + "Offset of field: ", +@@ -1339,7 +1509,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).spsr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).spsr) as usize - ptr as usize }, + 288usize, + concat!( + "Offset of field: ", +@@ -1349,7 +1519,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fp_regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fp_regs) as usize - ptr as usize }, + 336usize, + concat!( + "Offset of field: ", +@@ -1361,12 +1531,18 @@ fn bindgen_test_layout_kvm_regs() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_init { + pub target: __u32, + pub features: [__u32; 7usize], + } + #[test] + fn bindgen_test_layout_kvm_vcpu_init() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -1378,7 +1554,7 @@ fn bindgen_test_layout_kvm_vcpu_init() { + concat!("Alignment of ", stringify!(kvm_vcpu_init)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).target as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).target) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1388,7 +1564,7 @@ fn bindgen_test_layout_kvm_vcpu_init() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).features as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).features) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -1440,6 +1616,8 @@ pub struct kvm_guest_debug_arch { + } + #[test] + fn bindgen_test_layout_kvm_guest_debug_arch() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 512usize, +@@ -1451,7 +1629,7 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + concat!("Alignment of ", stringify!(kvm_guest_debug_arch)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_bcr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_bcr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1461,7 +1639,7 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_bvr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_bvr) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", +@@ -1471,7 +1649,7 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_wcr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_wcr) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", +@@ -1481,7 +1659,7 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dbg_wvr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dbg_wvr) as usize - ptr as usize }, + 384usize, + concat!( + "Offset of field: ", +@@ -1495,10 +1673,13 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_debug_exit_arch { + pub hsr: __u32, ++ pub hsr_high: __u32, + pub far: __u64, + } + #[test] + fn bindgen_test_layout_kvm_debug_exit_arch() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1510,7 +1691,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + concat!("Alignment of ", stringify!(kvm_debug_exit_arch)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hsr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hsr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1520,7 +1701,17 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).far as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hsr_high) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_debug_exit_arch), ++ "::", ++ stringify!(hsr_high) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).far) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1537,6 +1728,8 @@ pub struct kvm_sync_regs { + } + #[test] + fn bindgen_test_layout_kvm_sync_regs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -1548,7 +1741,7 @@ fn bindgen_test_layout_kvm_sync_regs() { + concat!("Alignment of ", stringify!(kvm_sync_regs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).device_irq_level as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).device_irq_level) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1568,6 +1761,8 @@ pub struct kvm_pmu_event_filter { + } + #[test] + fn bindgen_test_layout_kvm_pmu_event_filter() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -1579,7 +1774,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + concat!("Alignment of ", stringify!(kvm_pmu_event_filter)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).base_event as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base_event) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1589,7 +1784,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nevents as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nevents) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -1599,7 +1794,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).action as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).action) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -1609,7 +1804,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 5usize, + concat!( + "Offset of field: ", +@@ -1636,6 +1831,9 @@ pub struct kvm_vcpu_events__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1647,10 +1845,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).serror_pending as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).serror_pending) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1660,10 +1855,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).serror_has_esr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).serror_has_esr) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -1673,10 +1865,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ext_dabt_pending as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ext_dabt_pending) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -1686,9 +1875,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -1698,10 +1885,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).serror_esr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).serror_esr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1713,6 +1897,8 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, +@@ -1724,7 +1910,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + concat!("Alignment of ", stringify!(kvm_vcpu_events)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exception as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1734,7 +1920,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -1745,215 +1931,254 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ); + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_user_trace_setup { +- pub buf_size: __u32, +- pub buf_nr: __u32, ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_arm_copy_mte_tags { ++ pub guest_ipa: __u64, ++ pub length: __u64, ++ pub addr: *mut ::std::os::raw::c_void, ++ pub flags: __u64, ++ pub reserved: [__u64; 2usize], + } + #[test] +-fn bindgen_test_layout_kvm_user_trace_setup() { ++fn bindgen_test_layout_kvm_arm_copy_mte_tags() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_user_trace_setup)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_arm_copy_mte_tags)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_user_trace_setup)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_arm_copy_mte_tags)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf_size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_ipa) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_user_trace_setup), ++ stringify!(kvm_arm_copy_mte_tags), + "::", +- stringify!(buf_size) ++ stringify!(guest_ipa) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf_nr as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_arm_copy_mte_tags), ++ "::", ++ stringify!(length) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_arm_copy_mte_tags), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_arm_copy_mte_tags), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_user_trace_setup), ++ stringify!(kvm_arm_copy_mte_tags), + "::", +- stringify!(buf_nr) ++ stringify!(reserved) + ) + ); + } ++impl Default for kvm_arm_copy_mte_tags { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_breakpoint { +- pub enabled: __u32, +- pub padding: __u32, +- pub address: __u64, ++pub struct kvm_arm_counter_offset { ++ pub counter_offset: __u64, ++ pub reserved: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_breakpoint() { ++fn bindgen_test_layout_kvm_arm_counter_offset() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_breakpoint)) ++ concat!("Size of: ", stringify!(kvm_arm_counter_offset)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_breakpoint)) ++ concat!("Alignment of ", stringify!(kvm_arm_counter_offset)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).counter_offset) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_breakpoint), +- "::", +- stringify!(enabled) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_breakpoint), ++ stringify!(kvm_arm_counter_offset), + "::", +- stringify!(padding) ++ stringify!(counter_offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_breakpoint), ++ stringify!(kvm_arm_counter_offset), + "::", +- stringify!(address) ++ stringify!(reserved) + ) + ); + } ++pub const KVM_REG_ARM_STD_BIT_TRNG_V1_0: _bindgen_ty_1 = 0; ++pub type _bindgen_ty_1 = ::std::os::raw::c_uint; ++pub const KVM_REG_ARM_STD_HYP_BIT_PV_TIME: _bindgen_ty_2 = 0; ++pub type _bindgen_ty_2 = ::std::os::raw::c_uint; ++pub const KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT: _bindgen_ty_3 = 0; ++pub const KVM_REG_ARM_VENDOR_HYP_BIT_PTP: _bindgen_ty_3 = 1; ++pub type _bindgen_ty_3 = ::std::os::raw::c_uint; ++pub const kvm_smccc_filter_action_KVM_SMCCC_FILTER_HANDLE: kvm_smccc_filter_action = 0; ++pub const kvm_smccc_filter_action_KVM_SMCCC_FILTER_DENY: kvm_smccc_filter_action = 1; ++pub const kvm_smccc_filter_action_KVM_SMCCC_FILTER_FWD_TO_USER: kvm_smccc_filter_action = 2; ++pub type kvm_smccc_filter_action = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_debug_guest { +- pub enabled: __u32, +- pub pad: __u32, +- pub breakpoints: [kvm_breakpoint; 4usize], +- pub singlestep: __u32, ++pub struct kvm_smccc_filter { ++ pub base: __u32, ++ pub nr_functions: __u32, ++ pub action: __u8, ++ pub pad: [__u8; 15usize], + } + #[test] +-fn bindgen_test_layout_kvm_debug_guest() { ++fn bindgen_test_layout_kvm_smccc_filter() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 80usize, +- concat!("Size of: ", stringify!(kvm_debug_guest)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_smccc_filter)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_debug_guest)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_smccc_filter)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_smccc_filter), + "::", +- stringify!(enabled) ++ stringify!(base) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr_functions) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_smccc_filter), + "::", +- stringify!(pad) ++ stringify!(nr_functions) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).breakpoints as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).action) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_smccc_filter), + "::", +- stringify!(breakpoints) ++ stringify!(action) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).singlestep as *const _ as usize }, +- 72usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 9usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_smccc_filter), + "::", +- stringify!(singlestep) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_memory_region { +- pub slot: __u32, +- pub flags: __u32, +- pub guest_phys_addr: __u64, +- pub memory_size: __u64, ++pub struct reg_mask_range { ++ pub addr: __u64, ++ pub range: __u32, ++ pub reserved: [__u32; 13usize], + } + #[test] +-fn bindgen_test_layout_kvm_memory_region() { ++fn bindgen_test_layout_reg_mask_range() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_memory_region)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(reg_mask_range)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_memory_region)) ++ concat!("Alignment of ", stringify!(reg_mask_range)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), +- "::", +- stringify!(slot) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(reg_mask_range), + "::", +- stringify!(flags) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_phys_addr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).range) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(reg_mask_range), + "::", +- stringify!(guest_phys_addr) ++ stringify!(range) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).memory_size as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(reg_mask_range), + "::", +- stringify!(memory_size) ++ stringify!(reserved) + ) + ); + } +@@ -1968,6 +2193,9 @@ pub struct kvm_userspace_memory_region { + } + #[test] + fn bindgen_test_layout_kvm_userspace_memory_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -1979,9 +2207,7 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + concat!("Alignment of ", stringify!(kvm_userspace_memory_region)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).slot as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1991,9 +2217,7 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).flags as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2003,10 +2227,7 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_phys_addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2016,9 +2237,7 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).memory_size as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2028,10 +2247,7 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).userspace_addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -2042,76 +2258,203 @@ fn bindgen_test_layout_kvm_userspace_memory_region() { + ); + } + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_irq_level { +- pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1, +- pub level: __u32, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_irq_level__bindgen_ty_1 { +- pub irq: __u32, +- pub status: __s32, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_userspace_memory_region2 { ++ pub slot: __u32, ++ pub flags: __u32, ++ pub guest_phys_addr: __u64, ++ pub memory_size: __u64, ++ pub userspace_addr: __u64, ++ pub guest_memfd_offset: __u64, ++ pub guest_memfd: __u32, ++ pub pad1: __u32, ++ pub pad2: [__u64; 14usize], + } + #[test] +-fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_userspace_memory_region2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 160usize, ++ concat!("Size of: ", stringify!(kvm_userspace_memory_region2)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_userspace_memory_region2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irq as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_level__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(irq) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).status as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_level__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(status) ++ stringify!(flags) + ) + ); +-} +-impl Default for kvm_irq_level__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_level() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, + 8usize, +- concat!("Size of: ", stringify!(kvm_irq_level)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_level)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).level as *const _ as usize }, +- 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(memory_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(userspace_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd_offset) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_memfd_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_memfd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(pad1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(pad2) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_level { ++ pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1, ++ pub level: __u32, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_level__bindgen_ty_1 { ++ pub irq: __u32, ++ pub status: __s32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_level__bindgen_ty_1), ++ "::", ++ stringify!(irq) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_level__bindgen_ty_1), ++ "::", ++ stringify!(status) ++ ) ++ ); ++} ++impl Default for kvm_irq_level__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_level__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_level__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_level)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).level) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", + stringify!(kvm_irq_level), +@@ -2129,6 +2472,15 @@ impl Default for kvm_irq_level { + } + } + } ++impl ::std::fmt::Debug for kvm_irq_level { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_level {{ __bindgen_anon_1: {:?}, level: {:?} }}", ++ self.__bindgen_anon_1, self.level ++ ) ++ } ++} + #[repr(C)] + #[derive(Copy, Clone)] + pub struct kvm_irqchip { +@@ -2143,6 +2495,9 @@ pub union kvm_irqchip__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 512usize, +@@ -2154,7 +2509,7 @@ fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dummy as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dummy) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2173,8 +2528,15 @@ impl Default for kvm_irqchip__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_irqchip__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irqchip__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] + fn bindgen_test_layout_kvm_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 520usize, +@@ -2186,7 +2548,7 @@ fn bindgen_test_layout_kvm_irqchip() { + concat!("Alignment of ", stringify!(kvm_irqchip)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).chip_id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).chip_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2196,7 +2558,7 @@ fn bindgen_test_layout_kvm_irqchip() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2206,7 +2568,7 @@ fn bindgen_test_layout_kvm_irqchip() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).chip as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).chip) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2225,6 +2587,15 @@ impl Default for kvm_irqchip { + } + } + } ++impl ::std::fmt::Debug for kvm_irqchip { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irqchip {{ chip_id: {:?}, pad: {:?}, chip: {:?} }}", ++ self.chip_id, self.pad, self.chip ++ ) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_pit_config { +@@ -2233,6 +2604,8 @@ pub struct kvm_pit_config { + } + #[test] + fn bindgen_test_layout_kvm_pit_config() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, +@@ -2244,7 +2617,7 @@ fn bindgen_test_layout_kvm_pit_config() { + concat!("Alignment of ", stringify!(kvm_pit_config)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2254,7 +2627,7 @@ fn bindgen_test_layout_kvm_pit_config() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2265,384 +2638,156 @@ fn bindgen_test_layout_kvm_pit_config() { + ); + } + #[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_hyperv_exit { ++ pub type_: __u32, ++ pub pad1: __u32, ++ pub u: kvm_hyperv_exit__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_hyperv_exit__bindgen_ty_1 { ++ pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1, ++ pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2, ++ pub syndbg: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3, ++} ++#[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_skeys { +- pub start_gfn: __u64, +- pub count: __u64, +- pub skeydata_addr: __u64, +- pub flags: __u32, +- pub reserved: [__u32; 9usize], ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 { ++ pub msr: __u32, ++ pub pad2: __u32, ++ pub control: __u64, ++ pub evt_page: __u64, ++ pub msg_page: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_s390_skeys() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_s390_skeys)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_skeys)) +- ); ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).start_gfn as *const _ as usize }, +- 0usize, ++ ::std::mem::size_of::(), ++ 32usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_skeys), +- "::", +- stringify!(start_gfn) ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).count as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_skeys), +- "::", +- stringify!(count) ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).skeydata_addr as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(skeydata_addr) ++ stringify!(msr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(pad2) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(reserved) ++ stringify!(control) + ) + ); +-} +-#[doc = " kvm_s390_cmma_log - Used for CMMA migration."] +-#[doc = ""] +-#[doc = " Used both for input and output."] +-#[doc = ""] +-#[doc = " @start_gfn: Guest page number to start from."] +-#[doc = " @count: Size of the result buffer."] +-#[doc = " @flags: Control operation mode via KVM_S390_CMMA_* flags"] +-#[doc = " @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty"] +-#[doc = " pages are still remaining."] +-#[doc = " @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set"] +-#[doc = " in the PGSTE."] +-#[doc = " @values: Pointer to the values buffer."] +-#[doc = ""] +-#[doc = " Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls."] +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_cmma_log { +- pub start_gfn: __u64, +- pub count: __u32, +- pub flags: __u32, +- pub __bindgen_anon_1: kvm_s390_cmma_log__bindgen_ty_1, +- pub values: __u64, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_cmma_log__bindgen_ty_1 { +- pub remaining: __u64, +- pub mask: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_cmma_log__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_s390_cmma_log__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_cmma_log__bindgen_ty_1)) +- ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).remaining as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).evt_page) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(remaining) ++ stringify!(evt_page) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).mask as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msg_page) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(mask) ++ stringify!(msg_page) + ) + ); + } +-impl Default for kvm_s390_cmma_log__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 { ++ pub input: __u64, ++ pub result: __u64, ++ pub params: [__u64; 2usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_cmma_log() { ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 32usize, +- concat!("Size of: ", stringify!(kvm_s390_cmma_log)) ++ concat!( ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_cmma_log)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).start_gfn as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_cmma_log), +- "::", +- stringify!(start_gfn) ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).count as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(count) ++ stringify!(input) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(flags) ++ stringify!(result) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).values as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(values) +- ) +- ); +-} +-impl Default for kvm_s390_cmma_log { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_hyperv_exit { +- pub type_: __u32, +- pub pad1: __u32, +- pub u: kvm_hyperv_exit__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_hyperv_exit__bindgen_ty_1 { +- pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1, +- pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2, +- pub syndbg: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3, +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 { +- pub msr: __u32, +- pub pad2: __u32, +- pub control: __u64, +- pub evt_page: __u64, +- pub msg_page: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!( +- "Size of: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msr as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(msr) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad2 as *const _ +- as usize +- }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(pad2) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).control +- as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(control) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).evt_page +- as *const _ as usize +- }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(evt_page) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msg_page +- as *const _ as usize +- }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(msg_page) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 { +- pub input: __u64, +- pub result: __u64, +- pub params: [__u64; 2usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!( +- "Size of: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) +- ) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).input +- as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), +- "::", +- stringify!(input) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).result +- as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), +- "::", +- stringify!(result) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).params +- as *const _ as usize +- }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), +- "::", +- stringify!(params) ++ stringify!(params) + ) + ); + } +@@ -2659,6 +2804,9 @@ pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3 { + } + #[test] + fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 48usize, +@@ -2676,10 +2824,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2689,10 +2834,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad2 as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2702,10 +2844,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).control +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2715,10 +2854,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).status +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2728,10 +2864,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).send_page +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).send_page) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -2741,10 +2874,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).recv_page +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).recv_page) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", +@@ -2754,10 +2884,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pending_page +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pending_page) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", +@@ -2769,6 +2896,9 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { + } + #[test] + fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 48usize, +@@ -2780,9 +2910,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).synic as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).synic) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2792,9 +2920,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hcall as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2804,9 +2930,7 @@ fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).syndbg as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).syndbg) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2825,8 +2949,15 @@ impl Default for kvm_hyperv_exit__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_hyperv_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_hyperv_exit__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] + fn bindgen_test_layout_kvm_hyperv_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 56usize, +@@ -2838,7 +2969,7 @@ fn bindgen_test_layout_kvm_hyperv_exit() { + concat!("Alignment of ", stringify!(kvm_hyperv_exit)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2848,7 +2979,7 @@ fn bindgen_test_layout_kvm_hyperv_exit() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad1 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2858,7 +2989,7 @@ fn bindgen_test_layout_kvm_hyperv_exit() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2877,6 +3008,15 @@ impl Default for kvm_hyperv_exit { + } + } + } ++impl ::std::fmt::Debug for kvm_hyperv_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_hyperv_exit {{ type: {:?}, pad1: {:?}, u: {:?} }}", ++ self.type_, self.pad1, self.u ++ ) ++ } ++} + #[repr(C)] + #[derive(Copy, Clone)] + pub struct kvm_xen_exit { +@@ -2899,6 +3039,9 @@ pub struct kvm_xen_exit__bindgen_ty_1__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 72usize, +@@ -2916,10 +3059,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).longmode +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2929,10 +3069,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).cpl as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cpl) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2942,10 +3079,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).input as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2955,10 +3089,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).result as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2968,10 +3099,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).params as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -2983,6 +3111,9 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { + } + #[test] + fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 72usize, +@@ -2994,9 +3125,7 @@ fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_xen_exit__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hcall as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3015,8 +3144,15 @@ impl Default for kvm_xen_exit__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_xen_exit__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] + fn bindgen_test_layout_kvm_xen_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 80usize, +@@ -3028,7 +3164,7 @@ fn bindgen_test_layout_kvm_xen_exit() { + concat!("Alignment of ", stringify!(kvm_xen_exit)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3038,7 +3174,7 @@ fn bindgen_test_layout_kvm_xen_exit() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3057,6 +3193,15 @@ impl Default for kvm_xen_exit { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_exit {{ type: {:?}, u: {:?} }}", ++ self.type_, self.u ++ ) ++ } ++} + #[repr(C)] + #[derive(Copy, Clone)] + pub struct kvm_run { +@@ -3083,24 +3228,30 @@ pub union kvm_run__bindgen_ty_1 { + pub io: kvm_run__bindgen_ty_1__bindgen_ty_4, + pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5, + pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6, +- pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_7, +- pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_8, +- pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_9, ++ pub iocsr_io: kvm_run__bindgen_ty_1__bindgen_ty_7, ++ pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_8, ++ pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_9, ++ pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_10, + pub s390_reset_flags: __u64, +- pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_10, +- pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_11, +- pub internal: kvm_run__bindgen_ty_1__bindgen_ty_12, +- pub osi: kvm_run__bindgen_ty_1__bindgen_ty_13, +- pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_14, +- pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_15, +- pub epr: kvm_run__bindgen_ty_1__bindgen_ty_16, +- pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_17, +- pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_18, +- pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_19, ++ pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_11, ++ pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_12, ++ pub internal: kvm_run__bindgen_ty_1__bindgen_ty_13, ++ pub emulation_failure: kvm_run__bindgen_ty_1__bindgen_ty_14, ++ pub osi: kvm_run__bindgen_ty_1__bindgen_ty_15, ++ pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_16, ++ pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_17, ++ pub epr: kvm_run__bindgen_ty_1__bindgen_ty_18, ++ pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_19, ++ pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_20, ++ pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_21, + pub hyperv: kvm_hyperv_exit, +- pub arm_nisv: kvm_run__bindgen_ty_1__bindgen_ty_20, +- pub msr: kvm_run__bindgen_ty_1__bindgen_ty_21, ++ pub arm_nisv: kvm_run__bindgen_ty_1__bindgen_ty_22, ++ pub msr: kvm_run__bindgen_ty_1__bindgen_ty_23, + pub xen: kvm_xen_exit, ++ pub riscv_sbi: kvm_run__bindgen_ty_1__bindgen_ty_24, ++ pub riscv_csr: kvm_run__bindgen_ty_1__bindgen_ty_25, ++ pub notify: kvm_run__bindgen_ty_1__bindgen_ty_26, ++ pub memory_fault: kvm_run__bindgen_ty_1__bindgen_ty_27, + pub padding: [::std::os::raw::c_char; 256usize], + } + #[repr(C)] +@@ -3110,6 +3261,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -3124,10 +3278,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hardware_exit_reason +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hardware_exit_reason) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3145,6 +3296,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -3160,8 +3314,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { + ); + assert_eq!( + unsafe { +- &(*(::std::ptr::null::())) +- .hardware_entry_failure_reason as *const _ as usize ++ ::std::ptr::addr_of!((*ptr).hardware_entry_failure_reason) as usize - ptr as usize + }, + 0usize, + concat!( +@@ -3172,9 +3325,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).cpu as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cpu) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3192,6 +3343,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -3206,10 +3360,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).exception as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3219,10 +3370,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).error_code as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).error_code) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -3243,6 +3391,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -3257,10 +3408,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).direction as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).direction) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3270,10 +3418,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).size as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3283,10 +3428,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).port as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -3296,10 +3438,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).count as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -3309,10 +3448,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data_offset as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3329,6 +3465,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -3343,10 +3482,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).arch as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3366,6 +3502,9 @@ pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 { + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, +@@ -3380,10 +3519,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).phys_addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3393,10 +3529,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3406,9 +3539,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).len as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -3418,10 +3549,7 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -3434,17 +3562,19 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 { +- pub nr: __u64, +- pub args: [__u64; 6usize], +- pub ret: __u64, +- pub longmode: __u32, +- pub pad: __u32, ++ pub phys_addr: __u64, ++ pub data: [__u8; 8usize], ++ pub len: __u32, ++ pub is_write: __u8, + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 72usize, ++ 24usize, + concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)) + ); + assert_eq!( +@@ -3456,80 +3586,127 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(nr) ++ stringify!(phys_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).args as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(args) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ret as *const _ as usize +- }, +- 56usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(ret) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).longmode as *const _ +- as usize +- }, +- 64usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", ++ stringify!(is_write) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ pub nr: __u64, ++ pub args: [__u64; 6usize], ++ pub ret: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ pub longmode: __u32, ++ pub flags: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), ++ "::", + stringify!(longmode) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 68usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(flags) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 { +- pub rip: __u64, +- pub is_write: __u32, +- pub pad: __u32, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 16usize, ++ 72usize, + concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)) + ); + assert_eq!( +@@ -3541,114 +3718,121 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).rip as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), + "::", +- stringify!(rip) ++ stringify!(nr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), + "::", +- stringify!(is_write) ++ stringify!(args) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 56usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), + "::", +- stringify!(pad) ++ stringify!(ret) + ) + ); + } ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_8 {{ nr: {:?}, args: {:?}, ret: {:?}, __bindgen_anon_1: {:?} }}" , self . nr , self . args , self . ret , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 { +- pub icptcode: __u8, +- pub ipa: __u16, +- pub ipb: __u32, ++ pub rip: __u64, ++ pub is_write: __u32, ++ pub pad: __u32, + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 8usize, ++ 16usize, + concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)) + ); + assert_eq!( + ::std::mem::align_of::(), +- 4usize, ++ 8usize, + concat!( + "Alignment of ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).icptcode as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rip) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(icptcode) ++ stringify!(rip) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipa as *const _ as usize +- }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(ipa) ++ stringify!(is_write) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipb as *const _ as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(ipb) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 { +- pub trans_exc_code: __u64, +- pub pgm_code: __u32, ++ pub icptcode: __u8, ++ pub ipa: __u16, ++ pub ipb: __u32, + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 16usize, ++ 8usize, + concat!( + "Size of: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) +@@ -3656,51 +3840,57 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() { + ); + assert_eq!( + ::std::mem::align_of::(), +- 8usize, ++ 4usize, + concat!( + "Alignment of ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_exc_code +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).icptcode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), + "::", +- stringify!(trans_exc_code) ++ stringify!(icptcode) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pgm_code as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ipa) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), + "::", +- stringify!(pgm_code) ++ stringify!(ipa) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ "::", ++ stringify!(ipb) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 { +- pub dcrn: __u32, +- pub data: __u32, +- pub is_write: __u8, ++ pub trans_exc_code: __u64, ++ pub pgm_code: __u32, + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 12usize, ++ 16usize, + concat!( + "Size of: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) +@@ -3708,64 +3898,48 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() { + ); + assert_eq!( + ::std::mem::align_of::(), +- 4usize, ++ 8usize, + concat!( + "Alignment of ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dcrn as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_exc_code) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), + "::", +- stringify!(dcrn) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), +- "::", +- stringify!(data) ++ stringify!(trans_exc_code) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pgm_code) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), + "::", +- stringify!(is_write) ++ stringify!(pgm_code) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 { +- pub suberror: __u32, +- pub ndata: __u32, +- pub data: [__u64; 16usize], ++ pub dcrn: __u32, ++ pub data: __u32, ++ pub is_write: __u8, + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 136usize, ++ 12usize, + concat!( + "Size of: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) +@@ -3773,62 +3947,58 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() { + ); + assert_eq!( + ::std::mem::align_of::(), +- 8usize, ++ 4usize, + concat!( + "Alignment of ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).suberror as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dcrn) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(suberror) ++ stringify!(dcrn) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ndata as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(ndata) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(data) ++ stringify!(is_write) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 { +- pub gprs: [__u64; 32usize], ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub data: [__u64; 16usize], + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 256usize, ++ 136usize, + concat!( + "Size of: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) +@@ -3843,200 +4013,252 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gprs as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), + "::", +- stringify!(gprs) ++ stringify!(suberror) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ "::", ++ stringify!(ndata) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ "::", ++ stringify!(data) + ) + ); + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[derive(Copy, Clone)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 { +- pub nr: __u64, +- pub ret: __u64, +- pub args: [__u64; 9usize], ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub flags: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1 { ++ pub insn_size: __u8, ++ pub insn_bytes: [__u8; 15usize], + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 88usize, ++ ::std::mem::size_of::(), ++ 16usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ ::std::mem::align_of::(), ++ 1usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_size) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(nr) ++ stringify!(insn_size) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ret as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_bytes) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(ret) ++ stringify!(insn_bytes) + ) + ); ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1() { + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).args as *const _ +- as usize +- }, ++ ::std::mem::size_of::(), + 16usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), +- "::", +- stringify!(args) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 { +- pub subchannel_id: __u16, +- pub subchannel_nr: __u16, +- pub io_int_parm: __u32, +- pub io_int_word: __u32, +- pub ipb: __u32, +- pub dequeued: __u8, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 20usize, ++ ::std::mem::size_of::(), ++ 32usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).subchannel_id +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(subchannel_id) ++ stringify!(suberror) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).subchannel_nr +- as *const _ as usize +- }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(subchannel_nr) ++ stringify!(ndata) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).io_int_parm as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(io_int_parm) ++ stringify!(flags) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).io_int_word as *const _ +- as usize +- }, +- 8usize, ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_14 {{ suberror: {:?}, ndata: {:?}, flags: {:?}, __bindgen_anon_1: {:?} }}" , self . suberror , self . ndata , self . flags , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 { ++ pub gprs: [__u64; 32usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 256usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), +- "::", +- stringify!(io_int_word) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipb as *const _ +- as usize +- }, +- 12usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), +- "::", +- stringify!(ipb) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dequeued as *const _ +- as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).gprs) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), + "::", +- stringify!(dequeued) ++ stringify!(gprs) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] + pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 { +- pub epr: __u32, ++ pub nr: __u64, ++ pub ret: __u64, ++ pub args: [__u64; 9usize], + } + #[test] + fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), +- 4usize, ++ 88usize, + concat!( + "Size of: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) +@@ -4044,3498 +4266,1328 @@ fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() { + ); + assert_eq!( + ::std::mem::align_of::(), +- 4usize, ++ 8usize, + concat!( + "Alignment of ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).epr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(epr) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 { +- pub type_: __u32, +- pub flags: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) ++ stringify!(nr) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).type_ as *const _ +- as usize +- }, +- 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(type_) ++ stringify!(ret) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).flags as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(flags) ++ stringify!(args) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 { +- pub addr: __u64, +- pub ar: __u8, +- pub reserved: __u8, +- pub fc: __u8, +- pub sel1: __u8, +- pub sel2: __u16, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 { ++ pub subchannel_id: __u16, ++ pub subchannel_nr: __u16, ++ pub io_int_parm: __u32, ++ pub io_int_word: __u32, ++ pub ipb: __u32, ++ pub dequeued: __u8, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, ++ ::std::mem::size_of::(), ++ 20usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(addr) ++ stringify!(subchannel_id) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ar as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_nr) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(ar) ++ stringify!(subchannel_nr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ +- as usize +- }, +- 9usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_parm) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(reserved) ++ stringify!(io_int_parm) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fc as *const _ as usize +- }, +- 10usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_word) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(fc) ++ stringify!(io_int_word) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).sel1 as *const _ +- as usize +- }, +- 11usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(sel1) ++ stringify!(ipb) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).sel2 as *const _ +- as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dequeued) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(sel2) ++ stringify!(dequeued) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 { +- pub vector: __u8, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 { ++ pub epr: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 1usize, ++ ::std::mem::size_of::(), ++ 4usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 1usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vector as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), + "::", +- stringify!(vector) ++ stringify!(epr) + ) + ); + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_20 { +- pub esr_iss: __u64, +- pub fault_ipa: __u64, ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ pub type_: __u32, ++ pub ndata: __u32, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ pub flags: __u64, ++ pub data: [__u64; 16usize], + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_20() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, ++ ::std::mem::size_of::(), ++ 128usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).esr_iss as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), + "::", +- stringify!(esr_iss) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fault_ipa as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), + "::", +- stringify!(fault_ipa) ++ stringify!(data) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_21 { +- pub error: __u8, +- pub pad: [__u8; 7usize], +- pub reason: __u32, +- pub index: __u32, +- pub data: __u64, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_21() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, ++ ::std::mem::size_of::(), ++ 136usize, + concat!( + "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).error as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), +- "::", +- stringify!(error) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ +- as usize +- }, +- 1usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), + "::", +- stringify!(pad) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reason as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), + "::", +- stringify!(reason) ++ stringify!(ndata) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).index as *const _ +- as usize +- }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), +- "::", +- stringify!(index) +- ) +- ); ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_19 {{ type: {:?}, ndata: {:?}, __bindgen_anon_1: {:?} }}" , self . type_ , self . ndata , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_20 { ++ pub addr: __u64, ++ pub ar: __u8, ++ pub reserved: __u8, ++ pub fc: __u8, ++ pub sel1: __u8, ++ pub sel2: __u16, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_20() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, ++ ::std::mem::size_of::(), + 16usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), +- "::", +- stringify!(data) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) + ) + ); +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 256usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hw as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(hw) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fail_entry as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(fail_entry) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ex as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ar) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(ex) ++ stringify!(ar) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 9usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(io) ++ stringify!(reserved) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).debug as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fc) as usize - ptr as usize }, ++ 10usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(debug) ++ stringify!(fc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mmio as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sel1) as usize - ptr as usize }, ++ 11usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(mmio) ++ stringify!(sel1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hypercall as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sel2) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(hypercall) ++ stringify!(sel2) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_21 { ++ pub vector: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_21() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).tpr_access as *const _ as usize +- }, +- 0usize, ++ ::std::mem::size_of::(), ++ 1usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(tpr_access) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).s390_sieic as *const _ as usize +- }, +- 0usize, ++ ::std::mem::align_of::(), ++ 1usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_sieic) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).s390_reset_flags as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), + "::", +- stringify!(s390_reset_flags) ++ stringify!(vector) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_22 { ++ pub esr_iss: __u64, ++ pub fault_ipa: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_22() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).s390_ucontrol as *const _ as usize +- }, +- 0usize, ++ ::std::mem::size_of::(), ++ 16usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_ucontrol) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dcr as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(dcr) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).internal as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).esr_iss) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), + "::", +- stringify!(internal) ++ stringify!(esr_iss) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).osi as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fault_ipa) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), + "::", +- stringify!(osi) ++ stringify!(fault_ipa) + ) + ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).papr_hcall as *const _ as usize +- }, +- 0usize, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_23 { ++ pub error: __u8, ++ pub pad: [__u8; 7usize], ++ pub reason: __u32, ++ pub index: __u32, ++ pub data: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_23() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(papr_hcall) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s390_tsch as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_tsch) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).epr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).error) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(epr) ++ stringify!(error) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).system_event as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(system_event) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s390_stsi as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reason) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(s390_stsi) ++ stringify!(reason) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).eoi as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).index) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(eoi) ++ stringify!(index) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hyperv as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(hyperv) ++ stringify!(data) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_24 { ++ pub extension_id: ::std::os::raw::c_ulong, ++ pub function_id: ::std::os::raw::c_ulong, ++ pub args: [::std::os::raw::c_ulong; 6usize], ++ pub ret: [::std::os::raw::c_ulong; 2usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_24() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 80usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).arm_nisv as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).extension_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(arm_nisv) ++ stringify!(extension_id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).msr as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).function_id) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(msr) ++ stringify!(function_id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).xen as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(xen) ++ stringify!(args) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 64usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(padding) ++ stringify!(ret) + ) + ); + } +-impl Default for kvm_run__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_run__bindgen_ty_2 { +- pub regs: kvm_sync_regs, +- pub padding: [::std::os::raw::c_char; 2048usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_25 { ++ pub csr_num: ::std::os::raw::c_ulong, ++ pub new_value: ::std::os::raw::c_ulong, ++ pub write_mask: ::std::os::raw::c_ulong, ++ pub ret_value: ::std::os::raw::c_ulong, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_2() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_25() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 2048usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).csr_num) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_2), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(regs) ++ stringify!(csr_num) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).new_value) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_2), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(padding) ++ stringify!(new_value) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).write_mask) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(write_mask) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret_value) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(ret_value) + ) + ); + } +-impl Default for kvm_run__bindgen_ty_2 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_26 { ++ pub flags: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_26() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 2352usize, +- concat!("Size of: ", stringify!(kvm_run)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_run)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).request_interrupt_window as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26), + "::", +- stringify!(request_interrupt_window) ++ stringify!(flags) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_27 { ++ pub flags: __u64, ++ pub gpa: __u64, ++ pub size: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_27() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).immediate_exit as *const _ as usize }, +- 1usize, ++ ::std::mem::size_of::(), ++ 24usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(immediate_exit) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding1 as *const _ as usize }, +- 2usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", +- stringify!(padding1) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exit_reason as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gpa) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", +- stringify!(exit_reason) ++ stringify!(gpa) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ready_for_interrupt_injection as *const _ as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", +- stringify!(ready_for_interrupt_injection) ++ stringify!(size) + ) + ); ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1)) ++ ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).if_flag as *const _ as usize }, +- 13usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hw) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(if_flag) ++ stringify!(hw) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 14usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fail_entry) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(fail_entry) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr8 as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ex) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(cr8) ++ stringify!(ex) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apic_base as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(apic_base) ++ stringify!(io) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).kvm_valid_regs as *const _ as usize }, +- 288usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).debug) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(kvm_valid_regs) ++ stringify!(debug) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).kvm_dirty_regs as *const _ as usize }, +- 296usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).mmio) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(kvm_dirty_regs) ++ stringify!(mmio) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s as *const _ as usize }, +- 304usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).iocsr_io) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(s) ++ stringify!(iocsr_io) + ) + ); +-} +-impl Default for kvm_run { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_coalesced_mmio_zone { +- pub addr: __u64, +- pub size: __u32, +- pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_coalesced_mmio_zone__bindgen_ty_1 { +- pub pad: __u32, +- pub pio: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!( +- "Size of: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), +- "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pio as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), +- "::", +- stringify!(pio) +- ) +- ); +-} +-impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_zone() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone), +- "::", +- stringify!(addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone), +- "::", +- stringify!(size) +- ) +- ); +-} +-impl Default for kvm_coalesced_mmio_zone { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_coalesced_mmio { +- pub phys_addr: __u64, +- pub len: __u32, +- pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1, +- pub data: [__u8; 8usize], +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_coalesced_mmio__bindgen_ty_1 { +- pub pad: __u32, +- pub pio: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1), +- "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pio as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1), +- "::", +- stringify!(pio) +- ) +- ); +-} +-impl Default for kvm_coalesced_mmio__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio() { +- assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).phys_addr as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio), +- "::", +- stringify!(phys_addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio), +- "::", +- stringify!(len) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio), +- "::", +- stringify!(data) +- ) +- ); +-} +-impl Default for kvm_coalesced_mmio { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-pub struct kvm_coalesced_mmio_ring { +- pub first: __u32, +- pub last: __u32, +- pub coalesced_mmio: __IncompleteArrayField, +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_ring() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).first as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), +- "::", +- stringify!(first) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), +- "::", +- stringify!(last) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).coalesced_mmio as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), +- "::", +- stringify!(coalesced_mmio) +- ) +- ); +-} +-impl Default for kvm_coalesced_mmio_ring { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_translation { +- pub linear_address: __u64, +- pub physical_address: __u64, +- pub valid: __u8, +- pub writeable: __u8, +- pub usermode: __u8, +- pub pad: [__u8; 5usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_translation() { +- assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_translation)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_translation)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).linear_address as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(linear_address) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).physical_address as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(physical_address) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).valid as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(valid) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).writeable as *const _ as usize }, +- 17usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(writeable) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).usermode as *const _ as usize }, +- 18usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(usermode) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 19usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(pad) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_mem_op { +- pub gaddr: __u64, +- pub flags: __u64, +- pub size: __u32, +- pub op: __u32, +- pub buf: __u64, +- pub __bindgen_anon_1: kvm_s390_mem_op__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_mem_op__bindgen_ty_1 { +- pub ar: __u8, +- pub sida_offset: __u32, +- pub reserved: [__u8; 32usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_mem_op__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_s390_mem_op__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_mem_op__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ar as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), +- "::", +- stringify!(ar) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).sida_offset as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), +- "::", +- stringify!(sida_offset) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), +- "::", +- stringify!(reserved) +- ) +- ); +-} +-impl Default for kvm_s390_mem_op__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_mem_op() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_s390_mem_op)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_mem_op)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gaddr as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(gaddr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(size) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).op as *const _ as usize }, +- 20usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(op) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf as *const _ as usize }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(buf) +- ) +- ); +-} +-impl Default for kvm_s390_mem_op { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_interrupt { +- pub irq: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_interrupt() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_interrupt)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_interrupt)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irq as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_interrupt), +- "::", +- stringify!(irq) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_dirty_log { +- pub slot: __u32, +- pub padding1: __u32, +- pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_dirty_log__bindgen_ty_1 { +- pub dirty_bitmap: *mut ::std::os::raw::c_void, +- pub padding2: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dirty_bitmap as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_dirty_log__bindgen_ty_1), +- "::", +- stringify!(dirty_bitmap) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).padding2 as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_dirty_log__bindgen_ty_1), +- "::", +- stringify!(padding2) +- ) +- ); +-} +-impl Default for kvm_dirty_log__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_dirty_log() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_log)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_log)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_dirty_log), +- "::", +- stringify!(slot) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding1 as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_dirty_log), +- "::", +- stringify!(padding1) +- ) +- ); +-} +-impl Default for kvm_dirty_log { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_clear_dirty_log { +- pub slot: __u32, +- pub num_pages: __u32, +- pub first_page: __u64, +- pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_clear_dirty_log__bindgen_ty_1 { +- pub dirty_bitmap: *mut ::std::os::raw::c_void, +- pub padding2: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_clear_dirty_log__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dirty_bitmap as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1), +- "::", +- stringify!(dirty_bitmap) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).padding2 as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1), +- "::", +- stringify!(padding2) +- ) +- ); +-} +-impl Default for kvm_clear_dirty_log__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_clear_dirty_log() { +- assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_clear_dirty_log)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_clear_dirty_log)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log), +- "::", +- stringify!(slot) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).num_pages as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log), +- "::", +- stringify!(num_pages) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).first_page as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log), +- "::", +- stringify!(first_page) +- ) +- ); +-} +-impl Default for kvm_clear_dirty_log { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default)] +-pub struct kvm_signal_mask { +- pub len: __u32, +- pub sigset: __IncompleteArrayField<__u8>, +-} +-#[test] +-fn bindgen_test_layout_kvm_signal_mask() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_signal_mask)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_signal_mask)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_signal_mask), +- "::", +- stringify!(len) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sigset as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_signal_mask), +- "::", +- stringify!(sigset) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_tpr_access_ctl { +- pub enabled: __u32, +- pub flags: __u32, +- pub reserved: [__u32; 8usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_tpr_access_ctl() { +- assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_tpr_access_ctl)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_tpr_access_ctl)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), +- "::", +- stringify!(enabled) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), +- "::", +- stringify!(reserved) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_vapic_addr { +- pub vapic_addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_vapic_addr() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_vapic_addr)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_vapic_addr)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vapic_addr as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_vapic_addr), +- "::", +- stringify!(vapic_addr) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_mp_state { +- pub mp_state: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_mp_state() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_mp_state)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_mp_state)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mp_state as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_mp_state), +- "::", +- stringify!(mp_state) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_psw { +- pub mask: __u64, +- pub addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_psw() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_psw)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_psw)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mask as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_psw), +- "::", +- stringify!(mask) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_psw), +- "::", +- stringify!(addr) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_interrupt { +- pub type_: __u32, +- pub parm: __u32, +- pub parm64: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_interrupt() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_interrupt)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_interrupt)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_interrupt), +- "::", +- stringify!(type_) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).parm as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_interrupt), +- "::", +- stringify!(parm) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).parm64 as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_interrupt), +- "::", +- stringify!(parm64) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_io_info { +- pub subchannel_id: __u16, +- pub subchannel_nr: __u16, +- pub io_int_parm: __u32, +- pub io_int_word: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_io_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 12usize, +- concat!("Size of: ", stringify!(kvm_s390_io_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_io_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).subchannel_id as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_io_info), +- "::", +- stringify!(subchannel_id) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).subchannel_nr as *const _ as usize }, +- 2usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_io_info), +- "::", +- stringify!(subchannel_nr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io_int_parm as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_io_info), +- "::", +- stringify!(io_int_parm) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io_int_word as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_io_info), +- "::", +- stringify!(io_int_word) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_ext_info { +- pub ext_params: __u32, +- pub pad: __u32, +- pub ext_params2: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_ext_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_ext_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_ext_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext_params as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_ext_info), +- "::", +- stringify!(ext_params) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_ext_info), +- "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext_params2 as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_ext_info), +- "::", +- stringify!(ext_params2) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pgm_info { +- pub trans_exc_code: __u64, +- pub mon_code: __u64, +- pub per_address: __u64, +- pub data_exc_code: __u32, +- pub code: __u16, +- pub mon_class_nr: __u16, +- pub per_code: __u8, +- pub per_atmid: __u8, +- pub exc_access_id: __u8, +- pub per_access_id: __u8, +- pub op_access_id: __u8, +- pub flags: __u8, +- pub pad: [__u8; 2usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_pgm_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_s390_pgm_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pgm_info)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_exc_code as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(trans_exc_code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mon_code as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(mon_code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_address as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(per_address) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data_exc_code as *const _ as usize }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(data_exc_code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 28usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mon_class_nr as *const _ as usize }, +- 30usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(mon_class_nr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_code as *const _ as usize }, +- 32usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(per_code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_atmid as *const _ as usize }, +- 33usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(per_atmid) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exc_access_id as *const _ as usize }, +- 34usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(exc_access_id) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_access_id as *const _ as usize }, +- 35usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(per_access_id) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).op_access_id as *const _ as usize }, +- 36usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(op_access_id) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 37usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 38usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(pad) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_prefix_info { +- pub address: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_prefix_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_s390_prefix_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_prefix_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_prefix_info), +- "::", +- stringify!(address) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_extcall_info { +- pub code: __u16, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_extcall_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 2usize, +- concat!("Size of: ", stringify!(kvm_s390_extcall_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 2usize, +- concat!("Alignment of ", stringify!(kvm_s390_extcall_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_extcall_info), +- "::", +- stringify!(code) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_emerg_info { +- pub code: __u16, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_emerg_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 2usize, +- concat!("Size of: ", stringify!(kvm_s390_emerg_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 2usize, +- concat!("Alignment of ", stringify!(kvm_s390_emerg_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_emerg_info), +- "::", +- stringify!(code) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_stop_info { +- pub flags: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_stop_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_s390_stop_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_stop_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_stop_info), +- "::", +- stringify!(flags) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_mchk_info { +- pub cr14: __u64, +- pub mcic: __u64, +- pub failing_storage_address: __u64, +- pub ext_damage_code: __u32, +- pub pad: __u32, +- pub fixed_logout: [__u8; 16usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_mchk_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_s390_mchk_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_mchk_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr14 as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(cr14) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mcic as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(mcic) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).failing_storage_address as *const _ +- as usize +- }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(failing_storage_address) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ext_damage_code as *const _ as usize +- }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(ext_damage_code) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 28usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fixed_logout as *const _ as usize }, +- 32usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(fixed_logout) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_irq { +- pub type_: __u64, +- pub u: kvm_s390_irq__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_irq__bindgen_ty_1 { +- pub io: kvm_s390_io_info, +- pub ext: kvm_s390_ext_info, +- pub pgm: kvm_s390_pgm_info, +- pub emerg: kvm_s390_emerg_info, +- pub extcall: kvm_s390_extcall_info, +- pub prefix: kvm_s390_prefix_info, +- pub stop: kvm_s390_stop_info, +- pub mchk: kvm_s390_mchk_info, +- pub reserved: [::std::os::raw::c_char; 64usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_irq__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_s390_irq__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(io) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(ext) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pgm as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(pgm) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).emerg as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(emerg) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).extcall as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(extcall) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).prefix as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(prefix) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).stop as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(stop) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mchk as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(mchk) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(reserved) +- ) +- ); +-} +-impl Default for kvm_s390_irq__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_irq() { +- assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_s390_irq)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq), +- "::", +- stringify!(type_) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq), +- "::", +- stringify!(u) +- ) +- ); +-} +-impl Default for kvm_s390_irq { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_irq_state { +- pub buf: __u64, +- pub flags: __u32, +- pub len: __u32, +- pub reserved: [__u32; 4usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_irq_state() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_s390_irq_state)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq_state)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(buf) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(len) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(reserved) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_guest_debug { +- pub control: __u32, +- pub pad: __u32, +- pub arch: kvm_guest_debug_arch, +-} +-#[test] +-fn bindgen_test_layout_kvm_guest_debug() { +- assert_eq!( +- ::std::mem::size_of::(), +- 520usize, +- concat!("Size of: ", stringify!(kvm_guest_debug)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_guest_debug)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).control as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_guest_debug), +- "::", +- stringify!(control) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_guest_debug), +- "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).arch as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_guest_debug), +- "::", +- stringify!(arch) +- ) +- ); +-} +-pub const kvm_ioeventfd_flag_nr_datamatch: ::std::os::raw::c_uint = 0; +-pub const kvm_ioeventfd_flag_nr_pio: ::std::os::raw::c_uint = 1; +-pub const kvm_ioeventfd_flag_nr_deassign: ::std::os::raw::c_uint = 2; +-pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: ::std::os::raw::c_uint = 3; +-pub const kvm_ioeventfd_flag_nr_fast_mmio: ::std::os::raw::c_uint = 4; +-pub const kvm_ioeventfd_flag_nr_max: ::std::os::raw::c_uint = 5; +-pub type _bindgen_ty_1 = ::std::os::raw::c_uint; +-#[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_ioeventfd { +- pub datamatch: __u64, +- pub addr: __u64, +- pub len: __u32, +- pub fd: __s32, +- pub flags: __u32, +- pub pad: [__u8; 36usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_ioeventfd() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_ioeventfd)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_ioeventfd)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).datamatch as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(datamatch) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(len) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 20usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(fd) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 28usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ioeventfd), +- "::", +- stringify!(pad) +- ) +- ); +-} +-impl Default for kvm_ioeventfd { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_enable_cap { +- pub cap: __u32, +- pub flags: __u32, +- pub args: [__u64; 4usize], +- pub pad: [__u8; 64usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_enable_cap() { +- assert_eq!( +- ::std::mem::size_of::(), +- 104usize, +- concat!("Size of: ", stringify!(kvm_enable_cap)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_enable_cap)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cap as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enable_cap), +- "::", +- stringify!(cap) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enable_cap), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).args as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enable_cap), +- "::", +- stringify!(args) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 40usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enable_cap), +- "::", +- stringify!(pad) +- ) +- ); +-} +-impl Default for kvm_enable_cap { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_pvinfo { +- pub flags: __u32, +- pub hcall: [__u32; 4usize], +- pub pad: [__u8; 108usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_pvinfo() { +- assert_eq!( +- ::std::mem::size_of::(), +- 128usize, +- concat!("Size of: ", stringify!(kvm_ppc_pvinfo)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_pvinfo)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hcall as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), +- "::", +- stringify!(hcall) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 20usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), +- "::", +- stringify!(pad) +- ) +- ); +-} +-impl Default for kvm_ppc_pvinfo { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_one_page_size { +- pub page_shift: __u32, +- pub pte_enc: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_one_page_size() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_ppc_one_page_size)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_one_page_size)) +- ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).page_shift as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hypercall) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_page_size), +- "::", +- stringify!(page_shift) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pte_enc as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_ppc_one_page_size), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pte_enc) ++ stringify!(hypercall) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_one_seg_page_size { +- pub page_shift: __u32, +- pub slb_enc: __u32, +- pub enc: [kvm_ppc_one_page_size; 8usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_one_seg_page_size() { +- assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_ppc_one_seg_page_size)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_one_seg_page_size)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).page_shift as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).tpr_access) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(page_shift) ++ stringify!(tpr_access) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).slb_enc as *const _ as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_sieic) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(slb_enc) ++ stringify!(s390_sieic) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enc as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_reset_flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(enc) ++ stringify!(s390_reset_flags) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_smmu_info { +- pub flags: __u64, +- pub slb_size: __u32, +- pub data_keys: __u16, +- pub instr_keys: __u16, +- pub sps: [kvm_ppc_one_seg_page_size; 8usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_smmu_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 592usize, +- concat!("Size of: ", stringify!(kvm_ppc_smmu_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_ppc_smmu_info)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_ucontrol) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(s390_ucontrol) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slb_size as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dcr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(slb_size) ++ stringify!(dcr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data_keys as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).internal) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(data_keys) ++ stringify!(internal) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).instr_keys as *const _ as usize }, +- 14usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).emulation_failure) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(instr_keys) ++ stringify!(emulation_failure) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sps as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).osi) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(sps) ++ stringify!(osi) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_resize_hpt { +- pub flags: __u64, +- pub shift: __u32, +- pub pad: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_resize_hpt() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_ppc_resize_hpt)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_ppc_resize_hpt)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).papr_hcall) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(papr_hcall) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).shift as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_tsch) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(shift) ++ stringify!(s390_tsch) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(epr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_irqchip { +- pub irqchip: __u32, +- pub pin: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_irqchip() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_irqchip)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irqchip as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).system_event) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_irqchip), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(irqchip) ++ stringify!(system_event) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pin as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_stsi) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_irqchip), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pin) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_irq_routing_msi { +- pub address_lo: __u32, +- pub address_hi: __u32, +- pub data: __u32, +- pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_irq_routing_msi__bindgen_ty_1 { +- pub pad: __u32, +- pub devid: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1) ++ stringify!(s390_stsi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).eoi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(eoi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).devid as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hyperv) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(devid) ++ stringify!(hyperv) + ) + ); +-} +-impl Default for kvm_irq_routing_msi__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_msi() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_msi)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_msi)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_lo as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).arm_nisv) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(address_lo) ++ stringify!(arm_nisv) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_hi as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(address_hi) ++ stringify!(msr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).xen) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(data) ++ stringify!(xen) + ) + ); +-} +-impl Default for kvm_irq_routing_msi { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_s390_adapter { +- pub ind_addr: __u64, +- pub summary_addr: __u64, +- pub ind_offset: __u64, +- pub summary_offset: __u32, +- pub adapter_id: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_s390_adapter() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter)) +- ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ind_addr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_sbi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(ind_addr) ++ stringify!(riscv_sbi) + ) + ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).summary_addr as *const _ +- as usize +- }, +- 8usize, ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_csr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(summary_addr) ++ stringify!(riscv_csr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ind_offset as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).notify) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(ind_offset) ++ stringify!(notify) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).summary_offset as *const _ +- as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_fault) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(summary_offset) ++ stringify!(memory_fault) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).adapter_id as *const _ as usize +- }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(adapter_id) ++ stringify!(padding) + ) + ); + } ++impl Default for kvm_run__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_1 {{ union }}") ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_hv_sint { +- pub vcpu: __u32, +- pub sint: __u32, ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_2 { ++ pub regs: kvm_sync_regs, ++ pub padding: [::std::os::raw::c_char; 2048usize], + } + #[test] +-fn bindgen_test_layout_kvm_irq_routing_hv_sint() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint)) ++ ::std::mem::size_of::(), ++ 2048usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vcpu as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_hv_sint), ++ stringify!(kvm_run__bindgen_ty_2), + "::", +- stringify!(vcpu) ++ stringify!(regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sint as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_hv_sint), ++ stringify!(kvm_run__bindgen_ty_2), + "::", +- stringify!(sint) ++ stringify!(padding) + ) + ); + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_irq_routing_entry { +- pub gsi: __u32, +- pub type_: __u32, +- pub flags: __u32, +- pub pad: __u32, +- pub u: kvm_irq_routing_entry__bindgen_ty_1, ++impl Default for kvm_run__bindgen_ty_2 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_irq_routing_entry__bindgen_ty_1 { +- pub irqchip: kvm_irq_routing_irqchip, +- pub msi: kvm_irq_routing_msi, +- pub adapter: kvm_irq_routing_s390_adapter, +- pub hv_sint: kvm_irq_routing_hv_sint, +- pub pad: [__u32; 8usize], ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_2 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_2 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_run() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 2352usize, ++ concat!("Size of: ", stringify!(kvm_run)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1) +- ) ++ concat!("Alignment of ", stringify!(kvm_run)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).irqchip as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).request_interrupt_window) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run), + "::", +- stringify!(irqchip) ++ stringify!(request_interrupt_window) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msi as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).immediate_exit) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run), + "::", +- stringify!(msi) ++ stringify!(immediate_exit) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).adapter as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run), + "::", +- stringify!(adapter) ++ stringify!(padding1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hv_sint as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).exit_reason) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run), + "::", +- stringify!(hv_sint) ++ stringify!(exit_reason) + ) + ); + assert_eq!( + unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize ++ ::std::ptr::addr_of!((*ptr).ready_for_interrupt_injection) as usize - ptr as usize + }, +- 0usize, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run), + "::", +- stringify!(pad) ++ stringify!(ready_for_interrupt_injection) + ) + ); +-} +-impl Default for kvm_irq_routing_entry__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_entry() { + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_entry)) ++ unsafe { ::std::ptr::addr_of!((*ptr).if_flag) as usize - ptr as usize }, ++ 13usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(if_flag) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_entry)) ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 14usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(flags) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr8) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run), + "::", +- stringify!(gsi) ++ stringify!(cr8) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).apic_base) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run), + "::", +- stringify!(type_) ++ stringify!(apic_base) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_valid_regs) as usize - ptr as usize }, ++ 288usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run), + "::", +- stringify!(flags) ++ stringify!(kvm_valid_regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_dirty_regs) as usize - ptr as usize }, ++ 296usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run), + "::", +- stringify!(pad) ++ stringify!(kvm_dirty_regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s) as usize - ptr as usize }, ++ 304usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run), + "::", +- stringify!(u) ++ stringify!(s) + ) + ); + } +-impl Default for kvm_irq_routing_entry { ++impl Default for kvm_run { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7544,56 +5596,67 @@ impl Default for kvm_irq_routing_entry { + } + } + } ++impl ::std::fmt::Debug for kvm_run { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run {{ request_interrupt_window: {:?}, immediate_exit: {:?}, padding1: {:?}, exit_reason: {:?}, ready_for_interrupt_injection: {:?}, if_flag: {:?}, flags: {:?}, cr8: {:?}, apic_base: {:?}, __bindgen_anon_1: {:?}, kvm_valid_regs: {:?}, kvm_dirty_regs: {:?}, s: {:?} }}" , self . request_interrupt_window , self . immediate_exit , self . padding1 , self . exit_reason , self . ready_for_interrupt_injection , self . if_flag , self . flags , self . cr8 , self . apic_base , self . __bindgen_anon_1 , self . kvm_valid_regs , self . kvm_dirty_regs , self . s) ++ } ++} + #[repr(C)] +-pub struct kvm_irq_routing { +- pub nr: __u32, +- pub flags: __u32, +- pub entries: __IncompleteArrayField, ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio_zone { ++ pub addr: __u64, ++ pub size: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_irq_routing() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing)) +- ); ++fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nr as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_irq_routing), +- "::", +- stringify!(nr) ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing), ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entries as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing), ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), + "::", +- stringify!(entries) ++ stringify!(pio) + ) + ); + } +-impl Default for kvm_irq_routing { ++impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7602,975 +5665,1096 @@ impl Default for kvm_irq_routing { + } + } + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irqfd { +- pub fd: __u32, +- pub gsi: __u32, +- pub flags: __u32, +- pub resamplefd: __u32, +- pub pad: [__u8; 16usize], ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio_zone__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_irqfd() { ++fn bindgen_test_layout_kvm_coalesced_mmio_zone() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irqfd)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irqfd)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), +- "::", +- stringify!(fd) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio_zone), + "::", +- stringify!(gsi) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).resamplefd as *const _ as usize }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio_zone), + "::", +- stringify!(resamplefd) ++ stringify!(size) + ) + ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_irqfd), +- "::", +- stringify!(pad) ++} ++impl Default for kvm_coalesced_mmio_zone { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_zone {{ addr: {:?}, size: {:?}, __bindgen_anon_1: {:?} }}", ++ self.addr, self.size, self.__bindgen_anon_1 + ) +- ); ++ } + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_clock_data { +- pub clock: __u64, +- pub flags: __u32, +- pub pad: [__u32; 9usize], ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio { ++ pub phys_addr: __u64, ++ pub len: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1, ++ pub data: [__u8; 8usize], ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_clock_data() { +- assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_clock_data)) +- ); ++fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_clock_data)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).clock as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_clock_data), +- "::", +- stringify!(clock) ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clock_data), ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clock_data), ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(pio) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_config_tlb { +- pub params: __u64, +- pub array: __u64, +- pub mmu_type: __u32, +- pub array_len: __u32, ++impl Default for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_config_tlb() { ++fn bindgen_test_layout_kvm_coalesced_mmio() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_config_tlb)) ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_config_tlb)) ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).params as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(params) ++ stringify!(phys_addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).array as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(array) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mmu_type as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), +- "::", +- stringify!(mmu_type) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).array_len as *const _ as usize }, +- 20usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(array_len) ++ stringify!(data) + ) + ); + } ++impl Default for kvm_coalesced_mmio { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_coalesced_mmio {{ phys_addr: {:?}, len: {:?}, __bindgen_anon_1: {:?}, data: {:?} }}" , self . phys_addr , self . len , self . __bindgen_anon_1 , self . data) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_dirty_tlb { +- pub bitmap: __u64, +- pub num_dirty: __u32, ++pub struct kvm_coalesced_mmio_ring { ++ pub first: __u32, ++ pub last: __u32, ++ pub coalesced_mmio: __IncompleteArrayField, + } + #[test] +-fn bindgen_test_layout_kvm_dirty_tlb() { ++fn bindgen_test_layout_kvm_coalesced_mmio_ring() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_tlb)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_tlb)) ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).bitmap as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_tlb), ++ stringify!(kvm_coalesced_mmio_ring), + "::", +- stringify!(bitmap) ++ stringify!(first) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).last) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_ring), ++ "::", ++ stringify!(last) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).num_dirty as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).coalesced_mmio) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_tlb), ++ stringify!(kvm_coalesced_mmio_ring), + "::", +- stringify!(num_dirty) ++ stringify!(coalesced_mmio) + ) + ); + } ++impl Default for kvm_coalesced_mmio_ring { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_ring { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_ring {{ first: {:?}, last: {:?}, coalesced_mmio: {:?} }}", ++ self.first, self.last, self.coalesced_mmio ++ ) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default)] +-pub struct kvm_reg_list { +- pub n: __u64, +- pub reg: __IncompleteArrayField<__u64>, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_translation { ++ pub linear_address: __u64, ++ pub physical_address: __u64, ++ pub valid: __u8, ++ pub writeable: __u8, ++ pub usermode: __u8, ++ pub pad: [__u8; 5usize], + } + #[test] +-fn bindgen_test_layout_kvm_reg_list() { ++fn bindgen_test_layout_kvm_translation() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_reg_list)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_translation)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_reg_list)) ++ concat!("Alignment of ", stringify!(kvm_translation)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).n as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).linear_address) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_reg_list), ++ stringify!(kvm_translation), + "::", +- stringify!(n) ++ stringify!(linear_address) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reg as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).physical_address) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_reg_list), ++ stringify!(kvm_translation), + "::", +- stringify!(reg) ++ stringify!(physical_address) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_one_reg { +- pub id: __u64, +- pub addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_one_reg() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).valid) as usize - ptr as usize }, + 16usize, +- concat!("Size of: ", stringify!(kvm_one_reg)) ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(valid) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_one_reg)) ++ unsafe { ::std::ptr::addr_of!((*ptr).writeable) as usize - ptr as usize }, ++ 17usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(writeable) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).usermode) as usize - ptr as usize }, ++ 18usize, + concat!( + "Offset of field: ", +- stringify!(kvm_one_reg), ++ stringify!(kvm_translation), + "::", +- stringify!(id) ++ stringify!(usermode) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 19usize, + concat!( + "Offset of field: ", +- stringify!(kvm_one_reg), ++ stringify!(kvm_translation), + "::", +- stringify!(addr) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_msi { +- pub address_lo: __u32, +- pub address_hi: __u32, +- pub data: __u32, +- pub flags: __u32, +- pub devid: __u32, +- pub pad: [__u8; 12usize], ++pub struct kvm_interrupt { ++ pub irq: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_msi() { ++fn bindgen_test_layout_kvm_interrupt() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_msi)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_interrupt)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_msi)) ++ concat!("Alignment of ", stringify!(kvm_interrupt)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_lo as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(address_lo) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_hi as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_interrupt), + "::", +- stringify!(address_hi) ++ stringify!(irq) + ) + ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_dirty_log { ++ pub slot: __u32, ++ pub padding1: __u32, ++ pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, ++ ::std::mem::size_of::(), + 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(data) +- ) ++ concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(flags) +- ) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).devid as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_dirty_log__bindgen_ty_1), + "::", +- stringify!(devid) ++ stringify!(dirty_bitmap) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_dirty_log__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(padding2) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_arm_device_addr { +- pub id: __u64, +- pub addr: __u64, ++impl Default for kvm_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_dirty_log__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_arm_device_addr() { ++fn bindgen_test_layout_kvm_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_arm_device_addr)) ++ concat!("Size of: ", stringify!(kvm_dirty_log)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_arm_device_addr)) ++ concat!("Alignment of ", stringify!(kvm_dirty_log)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_arm_device_addr), ++ stringify!(kvm_dirty_log), + "::", +- stringify!(id) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_arm_device_addr), ++ stringify!(kvm_dirty_log), + "::", +- stringify!(addr) ++ stringify!(padding1) + ) + ); + } ++impl Default for kvm_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_dirty_log {{ slot: {:?}, padding1: {:?}, __bindgen_anon_1: {:?} }}", ++ self.slot, self.padding1, self.__bindgen_anon_1 ++ ) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_create_device { +- pub type_: __u32, +- pub fd: __u32, +- pub flags: __u32, ++#[derive(Copy, Clone)] ++pub struct kvm_clear_dirty_log { ++ pub slot: __u32, ++ pub num_pages: __u32, ++ pub first_page: __u64, ++ pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_clear_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_create_device() { +- assert_eq!( +- ::std::mem::size_of::(), +- 12usize, +- concat!("Size of: ", stringify!(kvm_create_device)) +- ); ++fn bindgen_test_layout_kvm_clear_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_create_device)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_create_device), +- "::", +- stringify!(type_) ++ "Alignment of ", ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_create_device), ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), + "::", +- stringify!(fd) ++ stringify!(dirty_bitmap) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_create_device), ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(padding2) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_device_attr { +- pub flags: __u32, +- pub group: __u32, +- pub attr: __u64, +- pub addr: __u64, ++impl Default for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_clear_dirty_log__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_device_attr() { ++fn bindgen_test_layout_kvm_clear_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_device_attr)) ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_device_attr)) ++ concat!("Alignment of ", stringify!(kvm_clear_dirty_log)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(flags) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).group as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_pages) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(group) ++ stringify!(num_pages) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).attr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).first_page) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), +- "::", +- stringify!(attr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(addr) ++ stringify!(first_page) + ) + ); + } +-pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1; +-pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2; +-pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3; +-pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5; +-pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8; +-pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_PV_TIME: kvm_device_type = 10; +-pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 11; +-pub type kvm_device_type = ::std::os::raw::c_uint; ++impl Default for kvm_clear_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_clear_dirty_log {{ slot: {:?}, num_pages: {:?}, first_page: {:?}, __bindgen_anon_1: {:?} }}" , self . slot , self . num_pages , self . first_page , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_vfio_spapr_tce { +- pub groupfd: __s32, +- pub tablefd: __s32, ++#[derive(Debug, Default)] ++pub struct kvm_signal_mask { ++ pub len: __u32, ++ pub sigset: __IncompleteArrayField<__u8>, + } + #[test] +-fn bindgen_test_layout_kvm_vfio_spapr_tce() { ++fn bindgen_test_layout_kvm_signal_mask() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_vfio_spapr_tce)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_signal_mask)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce)) ++ concat!("Alignment of ", stringify!(kvm_signal_mask)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).groupfd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_vfio_spapr_tce), ++ stringify!(kvm_signal_mask), + "::", +- stringify!(groupfd) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).tablefd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sigset) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_vfio_spapr_tce), ++ stringify!(kvm_signal_mask), + "::", +- stringify!(tablefd) ++ stringify!(sigset) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_ucas_mapping { +- pub user_addr: __u64, +- pub vcpu_addr: __u64, +- pub length: __u64, ++pub struct kvm_tpr_access_ctl { ++ pub enabled: __u32, ++ pub flags: __u32, ++ pub reserved: [__u32; 8usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_ucas_mapping() { ++fn bindgen_test_layout_kvm_tpr_access_ctl() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_s390_ucas_mapping)) ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(kvm_tpr_access_ctl)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_ucas_mapping)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_tpr_access_ctl)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).user_addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(user_addr) ++ stringify!(enabled) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vcpu_addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(vcpu_addr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).length as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(length) ++ stringify!(reserved) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_enc_region { +- pub addr: __u64, +- pub size: __u64, ++pub struct kvm_vapic_addr { ++ pub vapic_addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_enc_region() { ++fn bindgen_test_layout_kvm_vapic_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_enc_region)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vapic_addr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_enc_region)) ++ concat!("Alignment of ", stringify!(kvm_vapic_addr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vapic_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_enc_region), +- "::", +- stringify!(addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enc_region), ++ stringify!(kvm_vapic_addr), + "::", +- stringify!(size) ++ stringify!(vapic_addr) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pv_sec_parm { +- pub origin: __u64, +- pub length: __u64, ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_mp_state { ++ pub mp_state: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_pv_sec_parm() { ++fn bindgen_test_layout_kvm_mp_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_pv_sec_parm)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_mp_state)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pv_sec_parm)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_mp_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).origin as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mp_state) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_sec_parm), +- "::", +- stringify!(origin) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).length as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pv_sec_parm), ++ stringify!(kvm_mp_state), + "::", +- stringify!(length) ++ stringify!(mp_state) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pv_unp { +- pub addr: __u64, +- pub size: __u64, +- pub tweak: __u64, ++pub struct kvm_guest_debug { ++ pub control: __u32, ++ pub pad: __u32, ++ pub arch: kvm_guest_debug_arch, + } + #[test] +-fn bindgen_test_layout_kvm_s390_pv_unp() { ++fn bindgen_test_layout_kvm_guest_debug() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_s390_pv_unp)) ++ ::std::mem::size_of::(), ++ 520usize, ++ concat!("Size of: ", stringify!(kvm_guest_debug)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pv_unp)) ++ concat!("Alignment of ", stringify!(kvm_guest_debug)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(addr) ++ stringify!(control) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(size) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).tweak as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(tweak) ++ stringify!(arch) + ) + ); + } +-pub const pv_cmd_id_KVM_PV_ENABLE: pv_cmd_id = 0; +-pub const pv_cmd_id_KVM_PV_DISABLE: pv_cmd_id = 1; +-pub const pv_cmd_id_KVM_PV_SET_SEC_PARMS: pv_cmd_id = 2; +-pub const pv_cmd_id_KVM_PV_UNPACK: pv_cmd_id = 3; +-pub const pv_cmd_id_KVM_PV_VERIFY: pv_cmd_id = 4; +-pub const pv_cmd_id_KVM_PV_PREP_RESET: pv_cmd_id = 5; +-pub const pv_cmd_id_KVM_PV_UNSHARE_ALL: pv_cmd_id = 6; +-pub type pv_cmd_id = ::std::os::raw::c_uint; ++pub const kvm_ioeventfd_flag_nr_datamatch: _bindgen_ty_4 = 0; ++pub const kvm_ioeventfd_flag_nr_pio: _bindgen_ty_4 = 1; ++pub const kvm_ioeventfd_flag_nr_deassign: _bindgen_ty_4 = 2; ++pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: _bindgen_ty_4 = 3; ++pub const kvm_ioeventfd_flag_nr_fast_mmio: _bindgen_ty_4 = 4; ++pub const kvm_ioeventfd_flag_nr_max: _bindgen_ty_4 = 5; ++pub type _bindgen_ty_4 = ::std::os::raw::c_uint; + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_pv_cmd { +- pub cmd: __u32, +- pub rc: __u16, +- pub rrc: __u16, +- pub data: __u64, ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_ioeventfd { ++ pub datamatch: __u64, ++ pub addr: __u64, ++ pub len: __u32, ++ pub fd: __s32, + pub flags: __u32, +- pub reserved: [__u32; 3usize], ++ pub pad: [__u8; 36usize], + } + #[test] +-fn bindgen_test_layout_kvm_pv_cmd() { ++fn bindgen_test_layout_kvm_ioeventfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_pv_cmd)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_ioeventfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_pv_cmd)) ++ concat!("Alignment of ", stringify!(kvm_ioeventfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cmd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).datamatch) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(cmd) ++ stringify!(datamatch) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rc as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(rc) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rrc as *const _ as usize }, +- 6usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(rrc) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(data) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", + stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 28usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(reserved) ++ stringify!(pad) + ) + ); + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_xen_hvm_attr { +- pub type_: __u16, +- pub pad: [__u16; 3usize], +- pub u: kvm_xen_hvm_attr__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_xen_hvm_attr__bindgen_ty_1 { +- pub long_mode: __u8, +- pub vector: __u8, +- pub shared_info: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1, +- pub pad: [__u64; 8usize], ++impl Default for kvm_ioeventfd { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 { +- pub gfn: __u64, ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_enable_cap { ++ pub cap: __u32, ++ pub flags: __u32, ++ pub args: [__u64; 4usize], ++ pub pad: [__u8; 64usize], + } + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_enable_cap() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 104usize, ++ concat!("Size of: ", stringify!(kvm_enable_cap)) ++ ); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::align_of::(), + 8usize, ++ concat!("Alignment of ", stringify!(kvm_enable_cap)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cap) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Size of: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(cap) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(flags) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, + 8usize, + concat!( +- "Alignment of ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(args) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gfn as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_enable_cap), + "::", +- stringify!(gfn) ++ stringify!(pad) + ) + ); + } ++impl Default for kvm_enable_cap { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_irqchip { ++ pub irqchip: __u32, ++ pub pin: __u32, ++} + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_irq_routing_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_irqchip)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).long_mode as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_irqchip), + "::", +- stringify!(long_mode) ++ stringify!(irqchip) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vector as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pin) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_irqchip), + "::", +- stringify!(vector) ++ stringify!(pin) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_msi__bindgen_ty_1 { ++ pub pad: __u32, ++ pub devid: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).shared_info as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), + "::", +- stringify!(shared_info) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(devid) + ) + ); + } +-impl Default for kvm_xen_hvm_attr__bindgen_ty_1 { ++impl Default for kvm_irq_routing_msi__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -8579,50 +6763,57 @@ impl Default for kvm_xen_hvm_attr__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_irq_routing_msi__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_msi__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr() { ++fn bindgen_test_layout_kvm_irq_routing_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_xen_hvm_attr)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_hvm_attr)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_msi)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(type_) ++ stringify!(address_lo) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(pad) ++ stringify!(address_hi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(u) ++ stringify!(data) + ) + ); + } +-impl Default for kvm_xen_hvm_attr { ++impl Default for kvm_irq_routing_msi { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -8631,1598 +6822,1469 @@ impl Default for kvm_xen_hvm_attr { + } + } + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_xen_vcpu_attr { +- pub type_: __u16, +- pub pad: [__u16; 3usize], +- pub u: kvm_xen_vcpu_attr__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_xen_vcpu_attr__bindgen_ty_1 { +- pub gpa: __u64, +- pub pad: [__u64; 8usize], +- pub runstate: kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1, ++impl ::std::fmt::Debug for kvm_irq_routing_msi { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_irq_routing_msi {{ address_lo: {:?}, address_hi: {:?}, data: {:?}, __bindgen_anon_1: {:?} }}" , self . address_lo , self . address_hi , self . data , self . __bindgen_anon_1) ++ } + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1 { +- pub state: __u64, +- pub state_entry_time: __u64, +- pub time_running: __u64, +- pub time_runnable: __u64, +- pub time_blocked: __u64, +- pub time_offline: __u64, ++pub struct kvm_irq_routing_s390_adapter { ++ pub ind_addr: __u64, ++ pub summary_addr: __u64, ++ pub ind_offset: __u64, ++ pub summary_offset: __u32, ++ pub adapter_id: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_irq_routing_s390_adapter() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!( +- "Size of: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) +- ) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) +- ) ++ concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).state +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(state) ++ stringify!(ind_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())) +- .state_entry_time as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(state_entry_time) ++ stringify!(summary_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_running +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_offset) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(time_running) ++ stringify!(ind_offset) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_runnable +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_offset) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(time_runnable) ++ stringify!(summary_offset) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_blocked +- as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter_id) as usize - ptr as usize }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(adapter_id) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_hv_sint { ++ pub vcpu: __u32, ++ pub sint: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_hv_sint() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_hv_sint), + "::", +- stringify!(time_blocked) ++ stringify!(vcpu) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_offline +- as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sint) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_hv_sint), + "::", +- stringify!(time_offline) ++ stringify!(sint) + ) + ); + } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_xen_evtchn { ++ pub port: __u32, ++ pub vcpu: __u32, ++ pub priority: __u32, ++} + #[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_irq_routing_xen_evtchn() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_xen_evtchn)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_xen_evtchn)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gpa as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(gpa) ++ stringify!(port) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(pad) ++ stringify!(vcpu) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).runstate as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(runstate) ++ stringify!(priority) + ) + ); + } +-impl Default for kvm_xen_vcpu_attr__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_entry { ++ pub gsi: __u32, ++ pub type_: __u32, ++ pub flags: __u32, ++ pub pad: __u32, ++ pub u: kvm_irq_routing_entry__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_entry__bindgen_ty_1 { ++ pub irqchip: kvm_irq_routing_irqchip, ++ pub msi: kvm_irq_routing_msi, ++ pub adapter: kvm_irq_routing_s390_adapter, ++ pub hv_sint: kvm_irq_routing_hv_sint, ++ pub xen_evtchn: kvm_irq_routing_xen_evtchn, ++ pub pad: [__u32; 8usize], + } + #[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr() { ++fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_xen_vcpu_attr)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), +- "::", +- stringify!(type_) ++ "Alignment of ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(irqchip) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msi) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(u) ++ stringify!(msi) + ) + ); +-} +-impl Default for kvm_xen_vcpu_attr { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-pub const sev_cmd_id_KVM_SEV_INIT: sev_cmd_id = 0; +-pub const sev_cmd_id_KVM_SEV_ES_INIT: sev_cmd_id = 1; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_START: sev_cmd_id = 2; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_DATA: sev_cmd_id = 3; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_VMSA: sev_cmd_id = 4; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_SECRET: sev_cmd_id = 5; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_MEASURE: sev_cmd_id = 6; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_FINISH: sev_cmd_id = 7; +-pub const sev_cmd_id_KVM_SEV_SEND_START: sev_cmd_id = 8; +-pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_DATA: sev_cmd_id = 9; +-pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_VMSA: sev_cmd_id = 10; +-pub const sev_cmd_id_KVM_SEV_SEND_FINISH: sev_cmd_id = 11; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_START: sev_cmd_id = 12; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_DATA: sev_cmd_id = 13; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_VMSA: sev_cmd_id = 14; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_FINISH: sev_cmd_id = 15; +-pub const sev_cmd_id_KVM_SEV_GUEST_STATUS: sev_cmd_id = 16; +-pub const sev_cmd_id_KVM_SEV_DBG_DECRYPT: sev_cmd_id = 17; +-pub const sev_cmd_id_KVM_SEV_DBG_ENCRYPT: sev_cmd_id = 18; +-pub const sev_cmd_id_KVM_SEV_CERT_EXPORT: sev_cmd_id = 19; +-pub const sev_cmd_id_KVM_SEV_GET_ATTESTATION_REPORT: sev_cmd_id = 20; +-pub const sev_cmd_id_KVM_SEV_SEND_CANCEL: sev_cmd_id = 21; +-pub const sev_cmd_id_KVM_SEV_NR_MAX: sev_cmd_id = 22; +-pub type sev_cmd_id = ::std::os::raw::c_uint; +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_cmd { +- pub id: __u32, +- pub data: __u64, +- pub error: __u32, +- pub sev_fd: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_cmd() { +- assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_sev_cmd)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_cmd)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(id) ++ stringify!(adapter) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).hv_sint) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(data) ++ stringify!(hv_sint) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).error as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).xen_evtchn) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(error) ++ stringify!(xen_evtchn) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sev_fd as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(sev_fd) ++ stringify!(pad) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_start { +- pub handle: __u32, +- pub policy: __u32, +- pub dh_uaddr: __u64, +- pub dh_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++impl Default for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_entry__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_start() { ++fn bindgen_test_layout_kvm_irq_routing_entry() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_start)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_start)) ++ concat!("Alignment of ", stringify!(kvm_irq_routing_entry)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(handle) ++ stringify!(gsi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(policy) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dh_uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(dh_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dh_len as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(dh_len) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(session_uaddr) ++ stringify!(u) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_irq_routing_entry { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).session_len as *const _ as usize +- }, +- 32usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_launch_start), +- "::", +- stringify!(session_len) ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing_entry {{ gsi: {:?}, type: {:?}, flags: {:?}, pad: {:?}, u: {:?} }}", ++ self.gsi, self.type_, self.flags, self.pad, self.u + ) +- ); ++ } + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_update_data { +- pub uaddr: __u64, +- pub len: __u32, ++pub struct kvm_irq_routing { ++ pub nr: __u32, ++ pub flags: __u32, ++ pub entries: __IncompleteArrayField, + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_update_data() { ++fn bindgen_test_layout_kvm_irq_routing() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_update_data)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_update_data)) ++ concat!("Alignment of ", stringify!(kvm_irq_routing)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_update_data), ++ stringify!(kvm_irq_routing), ++ "::", ++ stringify!(nr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing), + "::", +- stringify!(uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_update_data), ++ stringify!(kvm_irq_routing), + "::", +- stringify!(len) ++ stringify!(entries) + ) + ); + } ++impl Default for kvm_irq_routing { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing {{ nr: {:?}, flags: {:?}, entries: {:?} }}", ++ self.nr, self.flags, self.entries ++ ) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_secret { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, ++pub struct kvm_irqfd { ++ pub fd: __u32, ++ pub gsi: __u32, ++ pub flags: __u32, ++ pub resamplefd: __u32, ++ pub pad: [__u8; 16usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_secret() { ++fn bindgen_test_layout_kvm_irqfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_secret)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irqfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_secret)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irqfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), +- "::", +- stringify!(hdr_uaddr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hdr_len as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irqfd), + "::", +- stringify!(hdr_len) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irqfd), + "::", +- stringify!(guest_uaddr) ++ stringify!(gsi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).guest_len as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irqfd), + "::", +- stringify!(guest_len) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).resamplefd) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irqfd), + "::", +- stringify!(trans_uaddr) ++ stringify!(resamplefd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).trans_len as *const _ as usize }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irqfd), + "::", +- stringify!(trans_len) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_measure { +- pub uaddr: __u64, +- pub len: __u32, ++pub struct kvm_clock_data { ++ pub clock: __u64, ++ pub flags: __u32, ++ pub pad0: __u32, ++ pub realtime: __u64, ++ pub host_tsc: __u64, ++ pub pad: [__u32; 4usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_measure() { ++fn bindgen_test_layout_kvm_clock_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_measure)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_clock_data)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_measure)) ++ concat!("Alignment of ", stringify!(kvm_clock_data)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).clock) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_measure), ++ stringify!(kvm_clock_data), + "::", +- stringify!(uaddr) ++ stringify!(clock) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_measure), ++ stringify!(kvm_clock_data), + "::", +- stringify!(len) ++ stringify!(flags) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_guest_status { +- pub handle: __u32, +- pub policy: __u32, +- pub state: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_guest_status() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, + 12usize, +- concat!("Size of: ", stringify!(kvm_sev_guest_status)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_sev_guest_status)) ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(pad0) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).realtime) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_clock_data), + "::", +- stringify!(handle) ++ stringify!(realtime) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).host_tsc) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_clock_data), + "::", +- stringify!(policy) ++ stringify!(host_tsc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).state as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_clock_data), + "::", +- stringify!(state) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_dbg { +- pub src_uaddr: __u64, +- pub dst_uaddr: __u64, +- pub len: __u32, ++pub struct kvm_config_tlb { ++ pub params: __u64, ++ pub array: __u64, ++ pub mmu_type: __u32, ++ pub array_len: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_sev_dbg() { ++fn bindgen_test_layout_kvm_config_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_sev_dbg)) ++ concat!("Size of: ", stringify!(kvm_config_tlb)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_dbg)) ++ concat!("Alignment of ", stringify!(kvm_config_tlb)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).src_uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_dbg), +- "::", +- stringify!(src_uaddr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dst_uaddr as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_dbg), +- "::", +- stringify!(dst_uaddr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_dbg), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(len) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_attestation_report { +- pub mnonce: [__u8; 16usize], +- pub uaddr: __u64, +- pub len: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_attestation_report() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_sev_attestation_report)) ++ stringify!(params) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).array) as usize - ptr as usize }, + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_attestation_report)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).mnonce as *const _ as usize +- }, +- 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(mnonce) ++ stringify!(array) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mmu_type) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(uaddr) ++ stringify!(mmu_type) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).array_len) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(len) ++ stringify!(array_len) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_send_start { +- pub policy: __u32, +- pub pdh_cert_uaddr: __u64, +- pub pdh_cert_len: __u32, +- pub plat_certs_uaddr: __u64, +- pub plat_certs_len: __u32, +- pub amd_certs_uaddr: __u64, +- pub amd_certs_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++pub struct kvm_dirty_tlb { ++ pub bitmap: __u64, ++ pub num_dirty: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_sev_send_start() { ++fn bindgen_test_layout_kvm_dirty_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_sev_send_start)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_tlb)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_send_start)) ++ concat!("Alignment of ", stringify!(kvm_dirty_tlb)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).bitmap) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_dirty_tlb), + "::", +- stringify!(policy) ++ stringify!(bitmap) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pdh_cert_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_dirty) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_dirty_tlb), + "::", +- stringify!(pdh_cert_uaddr) ++ stringify!(num_dirty) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_reg_list { ++ pub n: __u64, ++ pub reg: __IncompleteArrayField<__u64>, ++} ++#[test] ++fn bindgen_test_layout_kvm_reg_list() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_cert_len as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_send_start), +- "::", +- stringify!(pdh_cert_len) +- ) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_reg_list)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).plat_certs_uaddr as *const _ as usize +- }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_send_start), +- "::", +- stringify!(plat_certs_uaddr) +- ) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_reg_list)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).plat_certs_len as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).n) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_reg_list), + "::", +- stringify!(plat_certs_len) ++ stringify!(n) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).amd_certs_uaddr as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reg) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_reg_list), + "::", +- stringify!(amd_certs_uaddr) ++ stringify!(reg) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_one_reg { ++ pub id: __u64, ++ pub addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_one_reg() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).amd_certs_len as *const _ as usize +- }, +- 48usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_send_start), +- "::", +- stringify!(amd_certs_len) +- ) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_one_reg)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 56usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_one_reg)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_one_reg), + "::", +- stringify!(session_uaddr) ++ stringify!(id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).session_len as *const _ as usize }, +- 64usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_one_reg), + "::", +- stringify!(session_len) ++ stringify!(addr) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_send_update_data { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, ++pub struct kvm_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub flags: __u32, ++ pub devid: __u32, ++ pub pad: [__u8; 12usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_send_update_data() { ++fn bindgen_test_layout_kvm_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_send_update_data)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_msi)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_send_update_data)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_msi)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(hdr_uaddr) ++ stringify!(address_lo) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_len as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(hdr_len) ++ stringify!(address_hi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(guest_uaddr) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_len as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(guest_len) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(trans_uaddr) ++ stringify!(devid) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_len as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(trans_len) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_receive_start { +- pub handle: __u32, +- pub policy: __u32, +- pub pdh_uaddr: __u64, +- pub pdh_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++pub struct kvm_arm_device_addr { ++ pub id: __u64, ++ pub addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_sev_receive_start() { ++fn bindgen_test_layout_kvm_arm_device_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_sev_receive_start)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_arm_device_addr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_receive_start)) ++ concat!("Alignment of ", stringify!(kvm_arm_device_addr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_arm_device_addr), + "::", +- stringify!(handle) ++ stringify!(id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_arm_device_addr), + "::", +- stringify!(policy) ++ stringify!(addr) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_create_device { ++ pub type_: __u32, ++ pub fd: __u32, ++ pub flags: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_create_device() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_uaddr as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_receive_start), +- "::", +- stringify!(pdh_uaddr) +- ) ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_create_device)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_len as *const _ as usize }, +- 16usize, ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_create_device)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(pdh_len) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(session_uaddr) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_len as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(session_len) ++ stringify!(flags) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_receive_update_data { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, ++pub struct kvm_device_attr { ++ pub flags: __u32, ++ pub group: __u32, ++ pub attr: __u64, ++ pub addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_sev_receive_update_data() { ++fn bindgen_test_layout_kvm_device_attr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_receive_update_data)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_device_attr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_receive_update_data)) ++ concat!("Alignment of ", stringify!(kvm_device_attr)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), +- "::", +- stringify!(hdr_uaddr) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_len as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), +- "::", +- stringify!(hdr_len) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(guest_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_len as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).group) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(guest_len) ++ stringify!(group) + ) + ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).attr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(trans_uaddr) ++ stringify!(attr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_len as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(trans_len) ++ stringify!(addr) + ) + ); + } ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1; ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2; ++pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3; ++pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5; ++pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8; ++pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_PV_TIME: kvm_device_type = 10; ++pub const kvm_device_type_KVM_DEV_TYPE_RISCV_AIA: kvm_device_type = 11; ++pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 12; ++pub type kvm_device_type = ::std::os::raw::c_uint; + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_assigned_pci_dev { +- pub assigned_dev_id: __u32, +- pub busnr: __u32, +- pub devfn: __u32, +- pub flags: __u32, +- pub segnr: __u32, +- pub __bindgen_anon_1: kvm_assigned_pci_dev__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_assigned_pci_dev__bindgen_ty_1 { +- pub reserved: [__u32; 11usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_vfio_spapr_tce { ++ pub groupfd: __s32, ++ pub tablefd: __s32, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_pci_dev__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_vfio_spapr_tce() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 44usize, +- concat!("Size of: ", stringify!(kvm_assigned_pci_dev__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vfio_spapr_tce)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, ++ concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).groupfd) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Alignment of ", +- stringify!(kvm_assigned_pci_dev__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_vfio_spapr_tce), ++ "::", ++ stringify!(groupfd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).tablefd) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev__bindgen_ty_1), ++ stringify!(kvm_vfio_spapr_tce), + "::", +- stringify!(reserved) ++ stringify!(tablefd) + ) + ); + } +-impl Default for kvm_assigned_pci_dev__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_enc_region { ++ pub addr: __u64, ++ pub size: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_pci_dev() { ++fn bindgen_test_layout_kvm_enc_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_assigned_pci_dev)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_enc_region)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_pci_dev)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_enc_region)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_enc_region), + "::", +- stringify!(assigned_dev_id) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).busnr as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_enc_region), + "::", +- stringify!(busnr) ++ stringify!(size) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_dirty_gfn { ++ pub flags: __u32, ++ pub slot: __u32, ++ pub offset: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_gfn() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_gfn)) ++ ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).devfn as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_gfn)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(devfn) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(flags) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).segnr as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(segnr) ++ stringify!(offset) + ) + ); + } +-impl Default for kvm_assigned_pci_dev { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} ++#[doc = " struct kvm_stats_header - Header of per vm/vcpu binary statistics data.\n @flags: Some extra information for header, always 0 for now.\n @name_size: The size in bytes of the memory which contains statistics\n name string including trailing '\\0'. The memory is allocated\n at the send of statistics descriptor.\n @num_desc: The number of statistics the vm or vcpu has.\n @id_offset: The offset of the vm/vcpu stats' id string in the file pointed\n by vm/vcpu stats fd.\n @desc_offset: The offset of the vm/vcpu stats' descriptor block in the file\n pointd by vm/vcpu stats fd.\n @data_offset: The offset of the vm/vcpu stats' data block in the file\n pointed by vm/vcpu stats fd.\n\n This is the header userspace needs to read from stats fd before any other\n readings. It is used by userspace to discover all the information about the\n vm/vcpu's binary statistics.\n Userspace reads this header from the start of the vm/vcpu's stats fd."] + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_assigned_irq { +- pub assigned_dev_id: __u32, +- pub host_irq: __u32, +- pub guest_irq: __u32, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_stats_header { + pub flags: __u32, +- pub __bindgen_anon_1: kvm_assigned_irq__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_assigned_irq__bindgen_ty_1 { +- pub reserved: [__u32; 12usize], ++ pub name_size: __u32, ++ pub num_desc: __u32, ++ pub id_offset: __u32, ++ pub desc_offset: __u32, ++ pub data_offset: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_irq__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_stats_header() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_assigned_irq__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_stats_header)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_irq__bindgen_ty_1)) ++ concat!("Alignment of ", stringify!(kvm_stats_header)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq__bindgen_ty_1), ++ stringify!(kvm_stats_header), + "::", +- stringify!(reserved) ++ stringify!(flags) + ) + ); +-} +-impl Default for kvm_assigned_irq__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_assigned_irq() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_assigned_irq)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).name_size) as usize - ptr as usize }, + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_irq)) ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(name_size) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_desc) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(assigned_dev_id) ++ stringify!(num_desc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).host_irq as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).id_offset) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(host_irq) ++ stringify!(id_offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).guest_irq as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).desc_offset) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(guest_irq) ++ stringify!(desc_offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(flags) ++ stringify!(data_offset) + ) + ); + } +-impl Default for kvm_assigned_irq { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} ++#[doc = " struct kvm_stats_desc - Descriptor of a KVM statistics.\n @flags: Annotations of the stats, like type, unit, etc.\n @exponent: Used together with @flags to determine the unit.\n @size: The number of data items for this stats.\n Every data item is of type __u64.\n @offset: The offset of the stats to the start of stat structure in\n structure kvm or kvm_vcpu.\n @bucket_size: A parameter value used for histogram stats. It is only used\n\t\tfor linear histogram stats, specifying the size of the bucket;\n @name: The name string for the stats. Its size is indicated by the\n &kvm_stats_header->name_size."] + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_assigned_msix_nr { +- pub assigned_dev_id: __u32, +- pub entry_nr: __u16, +- pub padding: __u16, ++#[derive(Debug, Default)] ++pub struct kvm_stats_desc { ++ pub flags: __u32, ++ pub exponent: __s16, ++ pub size: __u16, ++ pub offset: __u32, ++ pub bucket_size: __u32, ++ pub name: __IncompleteArrayField<::std::os::raw::c_char>, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_msix_nr() { ++fn bindgen_test_layout_kvm_stats_desc() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_assigned_msix_nr)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_stats_desc)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_msix_nr)) ++ concat!("Alignment of ", stringify!(kvm_stats_desc)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(assigned_dev_id) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entry_nr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exponent) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(entry_nr) ++ stringify!(exponent) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), +- "::", +- stringify!(padding) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_assigned_msix_entry { +- pub assigned_dev_id: __u32, +- pub gsi: __u32, +- pub entry: __u16, +- pub padding: [__u16; 3usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_assigned_msix_entry() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_assigned_msix_entry)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_msix_entry)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(assigned_dev_id) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(gsi) ++ stringify!(offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entry as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).bucket_size) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(entry) ++ stringify!(bucket_size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 10usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(padding) ++ stringify!(name) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_eventfd { +- pub conn_id: __u32, +- pub fd: __s32, +- pub flags: __u32, +- pub padding: [__u32; 3usize], ++pub struct kvm_memory_attributes { ++ pub address: __u64, ++ pub size: __u64, ++ pub attributes: __u64, ++ pub flags: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_hyperv_eventfd() { ++fn bindgen_test_layout_kvm_memory_attributes() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_hyperv_eventfd)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_memory_attributes)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_hyperv_eventfd)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_memory_attributes)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).conn_id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(conn_id) ++ stringify!(address) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(fd) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(flags) ++ stringify!(attributes) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(padding) ++ stringify!(flags) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_dirty_gfn { +- pub flags: __u32, +- pub slot: __u32, +- pub offset: __u64, ++pub struct kvm_create_guest_memfd { ++ pub size: __u64, ++ pub flags: __u64, ++ pub reserved: [__u64; 6usize], + } + #[test] +-fn bindgen_test_layout_kvm_dirty_gfn() { ++fn bindgen_test_layout_kvm_create_guest_memfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_gfn)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_create_guest_memfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_gfn)) ++ concat!("Alignment of ", stringify!(kvm_create_guest_memfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(flags) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(slot) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).offset as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(offset) ++ stringify!(reserved) + ) + ); + } +diff --git a/vendor/kvm-bindings/src/arm64/mod.rs b/vendor/kvm-bindings/src/arm64/mod.rs +index 75f9cce..50f4703 100644 +--- a/vendor/kvm-bindings/src/arm64/mod.rs ++++ b/vendor/kvm-bindings/src/arm64/mod.rs +@@ -3,12 +3,13 @@ + + #[allow(clippy::all)] + #[allow(clippy::undocumented_unsafe_blocks)] +-// Keep this until https://github.com/rust-lang/rust-bindgen/issues/1651 is fixed. +-#[cfg_attr(test, allow(deref_nullptr))] + pub mod bindings; + #[cfg(feature = "fam-wrappers")] + pub mod fam_wrappers; + ++#[cfg(feature = "serde")] ++mod serialize; ++ + pub use self::bindings::*; + #[cfg(feature = "fam-wrappers")] + pub use self::fam_wrappers::*; +diff --git a/vendor/kvm-bindings/src/arm64/serialize.rs b/vendor/kvm-bindings/src/arm64/serialize.rs +new file mode 100644 +index 0000000..9d30201 +--- /dev/null ++++ b/vendor/kvm-bindings/src/arm64/serialize.rs +@@ -0,0 +1,79 @@ ++use bindings::{ ++ kvm_mp_state, kvm_one_reg, kvm_regs, kvm_vcpu_init, user_fpsimd_state, user_pt_regs, ++}; ++use serde::{Deserialize, Deserializer, Serialize, Serializer}; ++use zerocopy::{transmute, AsBytes}; ++ ++serde_impls! { ++ user_pt_regs, ++ user_fpsimd_state, ++ kvm_regs, ++ kvm_vcpu_init, ++ kvm_mp_state, ++ kvm_one_reg ++} ++ ++#[cfg(test)] ++mod tests { ++ use bindings::*; ++ use serde::{Deserialize, Serialize}; ++ ++ fn is_serde Deserialize<'de> + Default>() { ++ let serialized = bincode::serialize(&T::default()).unwrap(); ++ let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); ++ let serialized_again = bincode::serialize(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn static_assert_serde_implementations() { ++ // This test statically (= at compile-time) asserts that various bindgen generated ++ // structures implement serde's `Serialize` and `Deserialize` traits. ++ // This is to make sure that we do not accidentally remove those implementations ++ // when regenerating bindings. If this test fails to compile, please add ++ // ++ // #[cfg_attr( ++ // feature = "serde", ++ // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++ // )] ++ // ++ // to all structures causing compilation errors (we need the zerocopy traits, as the ++ // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro ++ // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` ++ // traits that it expects to be derived). ++ // ++ // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types ++ // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across ++ // bindgen versions. If after re-adding the derives to all the below items you can compile ++ // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add ++ // the derives to all anonymous types references in the definitions of the below items. ++ ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ } ++ ++ fn is_serde_json Deserialize<'de> + Default>() { ++ let serialized = serde_json::to_string(&T::default()).unwrap(); ++ let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); ++ let serialized_again = serde_json::to_string(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn test_json_serde() { ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ } ++} +diff --git a/vendor/kvm-bindings/src/lib.rs b/vendor/kvm-bindings/src/lib.rs +index 005808b..c44c98e 100644 +--- a/vendor/kvm-bindings/src/lib.rs ++++ b/vendor/kvm-bindings/src/lib.rs +@@ -6,17 +6,33 @@ + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] ++#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +-#[macro_use] + #[cfg(feature = "fam-wrappers")] ++#[macro_use] + extern crate vmm_sys_util; + +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +-mod x86; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +-pub use self::x86::*; ++#[cfg(feature = "serde")] ++extern crate serde; + +-#[cfg(any(target_arch = "aarch", target_arch = "aarch64"))] ++#[cfg(feature = "serde")] ++extern crate zerocopy; ++ ++#[cfg(feature = "serde")] ++#[macro_use] ++mod serialize; ++ ++#[cfg(target_arch = "x86_64")] ++mod x86_64; ++#[cfg(target_arch = "x86_64")] ++pub use self::x86_64::*; ++ ++#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + mod arm64; +-#[cfg(any(target_arch = "aarch", target_arch = "aarch64"))] ++#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + pub use self::arm64::*; ++ ++#[cfg(target_arch = "riscv64")] ++mod riscv64; ++#[cfg(target_arch = "riscv64")] ++pub use self::riscv64::*; +diff --git a/vendor/kvm-bindings/src/riscv64/bindings.rs b/vendor/kvm-bindings/src/riscv64/bindings.rs +new file mode 100644 +index 0000000..4bb65fb +--- /dev/null ++++ b/vendor/kvm-bindings/src/riscv64/bindings.rs +@@ -0,0 +1,8307 @@ ++/* automatically generated by rust-bindgen 0.64.0 */ ++ ++#[repr(C)] ++#[derive(Default)] ++pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); ++impl __IncompleteArrayField { ++ #[inline] ++ pub const fn new() -> Self { ++ __IncompleteArrayField(::std::marker::PhantomData, []) ++ } ++ #[inline] ++ pub fn as_ptr(&self) -> *const T { ++ self as *const _ as *const T ++ } ++ #[inline] ++ pub fn as_mut_ptr(&mut self) -> *mut T { ++ self as *mut _ as *mut T ++ } ++ #[inline] ++ pub unsafe fn as_slice(&self, len: usize) -> &[T] { ++ ::std::slice::from_raw_parts(self.as_ptr(), len) ++ } ++ #[inline] ++ pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { ++ ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) ++ } ++} ++impl ::std::fmt::Debug for __IncompleteArrayField { ++ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ fmt.write_str("__IncompleteArrayField") ++ } ++} ++pub const __BITS_PER_LONG_LONG: u32 = 64; ++pub const __FD_SETSIZE: u32 = 1024; ++pub const _IOC_NRBITS: u32 = 8; ++pub const _IOC_TYPEBITS: u32 = 8; ++pub const _IOC_SIZEBITS: u32 = 14; ++pub const _IOC_DIRBITS: u32 = 2; ++pub const _IOC_NRMASK: u32 = 255; ++pub const _IOC_TYPEMASK: u32 = 255; ++pub const _IOC_SIZEMASK: u32 = 16383; ++pub const _IOC_DIRMASK: u32 = 3; ++pub const _IOC_NRSHIFT: u32 = 0; ++pub const _IOC_TYPESHIFT: u32 = 8; ++pub const _IOC_SIZESHIFT: u32 = 16; ++pub const _IOC_DIRSHIFT: u32 = 30; ++pub const _IOC_NONE: u32 = 0; ++pub const _IOC_WRITE: u32 = 1; ++pub const _IOC_READ: u32 = 2; ++pub const IOC_IN: u32 = 1073741824; ++pub const IOC_OUT: u32 = 2147483648; ++pub const IOC_INOUT: u32 = 3221225472; ++pub const IOCSIZE_MASK: u32 = 1073676288; ++pub const IOCSIZE_SHIFT: u32 = 16; ++pub const PTRACE_GETFDPIC: u32 = 33; ++pub const PTRACE_GETFDPIC_EXEC: u32 = 0; ++pub const PTRACE_GETFDPIC_INTERP: u32 = 1; ++pub const RISCV_MAX_VLENB: u32 = 8192; ++pub const KVM_COALESCED_MMIO_PAGE_OFFSET: u32 = 1; ++pub const KVM_INTERRUPT_SET: i32 = -1; ++pub const KVM_INTERRUPT_UNSET: i32 = -2; ++pub const KVM_RISCV_MODE_S: u32 = 1; ++pub const KVM_RISCV_MODE_U: u32 = 0; ++pub const KVM_RISCV_TIMER_STATE_OFF: u32 = 0; ++pub const KVM_RISCV_TIMER_STATE_ON: u32 = 1; ++pub const KVM_REG_RISCV_TYPE_MASK: u32 = 4278190080; ++pub const KVM_REG_RISCV_TYPE_SHIFT: u32 = 24; ++pub const KVM_REG_RISCV_SUBTYPE_MASK: u32 = 16711680; ++pub const KVM_REG_RISCV_SUBTYPE_SHIFT: u32 = 16; ++pub const KVM_REG_RISCV_CONFIG: u32 = 16777216; ++pub const KVM_REG_RISCV_CORE: u32 = 33554432; ++pub const KVM_REG_RISCV_CSR: u32 = 50331648; ++pub const KVM_REG_RISCV_CSR_GENERAL: u32 = 0; ++pub const KVM_REG_RISCV_CSR_AIA: u32 = 65536; ++pub const KVM_REG_RISCV_CSR_SMSTATEEN: u32 = 131072; ++pub const KVM_REG_RISCV_TIMER: u32 = 67108864; ++pub const KVM_REG_RISCV_FP_F: u32 = 83886080; ++pub const KVM_REG_RISCV_FP_D: u32 = 100663296; ++pub const KVM_REG_RISCV_ISA_EXT: u32 = 117440512; ++pub const KVM_REG_RISCV_ISA_SINGLE: u32 = 0; ++pub const KVM_REG_RISCV_ISA_MULTI_EN: u32 = 65536; ++pub const KVM_REG_RISCV_ISA_MULTI_DIS: u32 = 131072; ++pub const KVM_REG_RISCV_SBI_EXT: u32 = 134217728; ++pub const KVM_REG_RISCV_SBI_SINGLE: u32 = 0; ++pub const KVM_REG_RISCV_SBI_MULTI_EN: u32 = 65536; ++pub const KVM_REG_RISCV_SBI_MULTI_DIS: u32 = 131072; ++pub const KVM_REG_RISCV_VECTOR: u32 = 150994944; ++pub const KVM_REG_RISCV_SBI_STATE: u32 = 167772160; ++pub const KVM_REG_RISCV_SBI_STA: u32 = 0; ++pub const KVM_DEV_RISCV_APLIC_ALIGN: u32 = 4096; ++pub const KVM_DEV_RISCV_APLIC_SIZE: u32 = 16384; ++pub const KVM_DEV_RISCV_APLIC_MAX_HARTS: u32 = 16384; ++pub const KVM_DEV_RISCV_IMSIC_ALIGN: u32 = 4096; ++pub const KVM_DEV_RISCV_IMSIC_SIZE: u32 = 4096; ++pub const KVM_DEV_RISCV_AIA_GRP_CONFIG: u32 = 0; ++pub const KVM_DEV_RISCV_AIA_CONFIG_MODE: u32 = 0; ++pub const KVM_DEV_RISCV_AIA_CONFIG_IDS: u32 = 1; ++pub const KVM_DEV_RISCV_AIA_CONFIG_SRCS: u32 = 2; ++pub const KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS: u32 = 3; ++pub const KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT: u32 = 4; ++pub const KVM_DEV_RISCV_AIA_CONFIG_HART_BITS: u32 = 5; ++pub const KVM_DEV_RISCV_AIA_CONFIG_GUEST_BITS: u32 = 6; ++pub const KVM_DEV_RISCV_AIA_MODE_EMUL: u32 = 0; ++pub const KVM_DEV_RISCV_AIA_MODE_HWACCEL: u32 = 1; ++pub const KVM_DEV_RISCV_AIA_MODE_AUTO: u32 = 2; ++pub const KVM_DEV_RISCV_AIA_IDS_MIN: u32 = 63; ++pub const KVM_DEV_RISCV_AIA_IDS_MAX: u32 = 2048; ++pub const KVM_DEV_RISCV_AIA_SRCS_MAX: u32 = 1024; ++pub const KVM_DEV_RISCV_AIA_GROUP_BITS_MAX: u32 = 8; ++pub const KVM_DEV_RISCV_AIA_GROUP_SHIFT_MIN: u32 = 24; ++pub const KVM_DEV_RISCV_AIA_GROUP_SHIFT_MAX: u32 = 56; ++pub const KVM_DEV_RISCV_AIA_HART_BITS_MAX: u32 = 16; ++pub const KVM_DEV_RISCV_AIA_GUEST_BITS_MAX: u32 = 8; ++pub const KVM_DEV_RISCV_AIA_GRP_ADDR: u32 = 1; ++pub const KVM_DEV_RISCV_AIA_ADDR_APLIC: u32 = 0; ++pub const KVM_DEV_RISCV_AIA_ADDR_MAX: u32 = 16385; ++pub const KVM_DEV_RISCV_AIA_GRP_CTRL: u32 = 2; ++pub const KVM_DEV_RISCV_AIA_CTRL_INIT: u32 = 0; ++pub const KVM_DEV_RISCV_AIA_GRP_APLIC: u32 = 3; ++pub const KVM_DEV_RISCV_AIA_GRP_IMSIC: u32 = 4; ++pub const KVM_DEV_RISCV_AIA_IMSIC_ISEL_BITS: u32 = 12; ++pub const KVM_DEV_RISCV_AIA_IMSIC_ISEL_MASK: u32 = 4095; ++pub const KVM_NR_IRQCHIPS: u32 = 1; ++pub const KVM_API_VERSION: u32 = 12; ++pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1; ++pub const KVM_MEM_READONLY: u32 = 2; ++pub const KVM_MEM_GUEST_MEMFD: u32 = 4; ++pub const KVM_PIT_SPEAKER_DUMMY: u32 = 1; ++pub const KVM_EXIT_HYPERV_SYNIC: u32 = 1; ++pub const KVM_EXIT_HYPERV_HCALL: u32 = 2; ++pub const KVM_EXIT_HYPERV_SYNDBG: u32 = 3; ++pub const KVM_EXIT_XEN_HCALL: u32 = 1; ++pub const KVM_S390_GET_SKEYS_NONE: u32 = 1; ++pub const KVM_S390_SKEYS_MAX: u32 = 1048576; ++pub const KVM_EXIT_UNKNOWN: u32 = 0; ++pub const KVM_EXIT_EXCEPTION: u32 = 1; ++pub const KVM_EXIT_IO: u32 = 2; ++pub const KVM_EXIT_HYPERCALL: u32 = 3; ++pub const KVM_EXIT_DEBUG: u32 = 4; ++pub const KVM_EXIT_HLT: u32 = 5; ++pub const KVM_EXIT_MMIO: u32 = 6; ++pub const KVM_EXIT_IRQ_WINDOW_OPEN: u32 = 7; ++pub const KVM_EXIT_SHUTDOWN: u32 = 8; ++pub const KVM_EXIT_FAIL_ENTRY: u32 = 9; ++pub const KVM_EXIT_INTR: u32 = 10; ++pub const KVM_EXIT_SET_TPR: u32 = 11; ++pub const KVM_EXIT_TPR_ACCESS: u32 = 12; ++pub const KVM_EXIT_S390_SIEIC: u32 = 13; ++pub const KVM_EXIT_S390_RESET: u32 = 14; ++pub const KVM_EXIT_DCR: u32 = 15; ++pub const KVM_EXIT_NMI: u32 = 16; ++pub const KVM_EXIT_INTERNAL_ERROR: u32 = 17; ++pub const KVM_EXIT_OSI: u32 = 18; ++pub const KVM_EXIT_PAPR_HCALL: u32 = 19; ++pub const KVM_EXIT_S390_UCONTROL: u32 = 20; ++pub const KVM_EXIT_WATCHDOG: u32 = 21; ++pub const KVM_EXIT_S390_TSCH: u32 = 22; ++pub const KVM_EXIT_EPR: u32 = 23; ++pub const KVM_EXIT_SYSTEM_EVENT: u32 = 24; ++pub const KVM_EXIT_S390_STSI: u32 = 25; ++pub const KVM_EXIT_IOAPIC_EOI: u32 = 26; ++pub const KVM_EXIT_HYPERV: u32 = 27; ++pub const KVM_EXIT_ARM_NISV: u32 = 28; ++pub const KVM_EXIT_X86_RDMSR: u32 = 29; ++pub const KVM_EXIT_X86_WRMSR: u32 = 30; ++pub const KVM_EXIT_DIRTY_RING_FULL: u32 = 31; ++pub const KVM_EXIT_AP_RESET_HOLD: u32 = 32; ++pub const KVM_EXIT_X86_BUS_LOCK: u32 = 33; ++pub const KVM_EXIT_XEN: u32 = 34; ++pub const KVM_EXIT_RISCV_SBI: u32 = 35; ++pub const KVM_EXIT_RISCV_CSR: u32 = 36; ++pub const KVM_EXIT_NOTIFY: u32 = 37; ++pub const KVM_EXIT_LOONGARCH_IOCSR: u32 = 38; ++pub const KVM_EXIT_MEMORY_FAULT: u32 = 39; ++pub const KVM_INTERNAL_ERROR_EMULATION: u32 = 1; ++pub const KVM_INTERNAL_ERROR_SIMUL_EX: u32 = 2; ++pub const KVM_INTERNAL_ERROR_DELIVERY_EV: u32 = 3; ++pub const KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON: u32 = 4; ++pub const KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES: u32 = 1; ++pub const KVM_EXIT_IO_IN: u32 = 0; ++pub const KVM_EXIT_IO_OUT: u32 = 1; ++pub const KVM_SYSTEM_EVENT_SHUTDOWN: u32 = 1; ++pub const KVM_SYSTEM_EVENT_RESET: u32 = 2; ++pub const KVM_SYSTEM_EVENT_CRASH: u32 = 3; ++pub const KVM_SYSTEM_EVENT_WAKEUP: u32 = 4; ++pub const KVM_SYSTEM_EVENT_SUSPEND: u32 = 5; ++pub const KVM_SYSTEM_EVENT_SEV_TERM: u32 = 6; ++pub const KVM_MSR_EXIT_REASON_INVAL: u32 = 1; ++pub const KVM_MSR_EXIT_REASON_UNKNOWN: u32 = 2; ++pub const KVM_MSR_EXIT_REASON_FILTER: u32 = 4; ++pub const KVM_MSR_EXIT_REASON_VALID_MASK: u32 = 7; ++pub const KVM_NOTIFY_CONTEXT_INVALID: u32 = 1; ++pub const KVM_MEMORY_EXIT_FLAG_PRIVATE: u32 = 8; ++pub const SYNC_REGS_SIZE_BYTES: u32 = 2048; ++pub const KVM_MP_STATE_RUNNABLE: u32 = 0; ++pub const KVM_MP_STATE_UNINITIALIZED: u32 = 1; ++pub const KVM_MP_STATE_INIT_RECEIVED: u32 = 2; ++pub const KVM_MP_STATE_HALTED: u32 = 3; ++pub const KVM_MP_STATE_SIPI_RECEIVED: u32 = 4; ++pub const KVM_MP_STATE_STOPPED: u32 = 5; ++pub const KVM_MP_STATE_CHECK_STOP: u32 = 6; ++pub const KVM_MP_STATE_OPERATING: u32 = 7; ++pub const KVM_MP_STATE_LOAD: u32 = 8; ++pub const KVM_MP_STATE_AP_RESET_HOLD: u32 = 9; ++pub const KVM_MP_STATE_SUSPENDED: u32 = 10; ++pub const KVM_GUESTDBG_ENABLE: u32 = 1; ++pub const KVM_GUESTDBG_SINGLESTEP: u32 = 2; ++pub const KVM_X86_DISABLE_EXITS_MWAIT: u32 = 1; ++pub const KVM_X86_DISABLE_EXITS_HLT: u32 = 2; ++pub const KVM_X86_DISABLE_EXITS_PAUSE: u32 = 4; ++pub const KVM_X86_DISABLE_EXITS_CSTATE: u32 = 8; ++pub const KVM_X86_DISABLE_VALID_EXITS: u32 = 15; ++pub const KVMIO: u32 = 174; ++pub const KVM_VM_S390_UCONTROL: u32 = 1; ++pub const KVM_VM_PPC_HV: u32 = 1; ++pub const KVM_VM_PPC_PR: u32 = 2; ++pub const KVM_VM_MIPS_AUTO: u32 = 0; ++pub const KVM_VM_MIPS_VZ: u32 = 1; ++pub const KVM_VM_MIPS_TE: u32 = 2; ++pub const KVM_S390_SIE_PAGE_OFFSET: u32 = 1; ++pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 255; ++pub const KVM_CAP_IRQCHIP: u32 = 0; ++pub const KVM_CAP_HLT: u32 = 1; ++pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: u32 = 2; ++pub const KVM_CAP_USER_MEMORY: u32 = 3; ++pub const KVM_CAP_SET_TSS_ADDR: u32 = 4; ++pub const KVM_CAP_VAPIC: u32 = 6; ++pub const KVM_CAP_EXT_CPUID: u32 = 7; ++pub const KVM_CAP_CLOCKSOURCE: u32 = 8; ++pub const KVM_CAP_NR_VCPUS: u32 = 9; ++pub const KVM_CAP_NR_MEMSLOTS: u32 = 10; ++pub const KVM_CAP_PIT: u32 = 11; ++pub const KVM_CAP_NOP_IO_DELAY: u32 = 12; ++pub const KVM_CAP_PV_MMU: u32 = 13; ++pub const KVM_CAP_MP_STATE: u32 = 14; ++pub const KVM_CAP_COALESCED_MMIO: u32 = 15; ++pub const KVM_CAP_SYNC_MMU: u32 = 16; ++pub const KVM_CAP_IOMMU: u32 = 18; ++pub const KVM_CAP_DESTROY_MEMORY_REGION_WORKS: u32 = 21; ++pub const KVM_CAP_USER_NMI: u32 = 22; ++pub const KVM_CAP_SET_GUEST_DEBUG: u32 = 23; ++pub const KVM_CAP_IRQ_ROUTING: u32 = 25; ++pub const KVM_CAP_IRQ_INJECT_STATUS: u32 = 26; ++pub const KVM_CAP_ASSIGN_DEV_IRQ: u32 = 29; ++pub const KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: u32 = 30; ++pub const KVM_CAP_IRQFD: u32 = 32; ++pub const KVM_CAP_SET_BOOT_CPU_ID: u32 = 34; ++pub const KVM_CAP_IOEVENTFD: u32 = 36; ++pub const KVM_CAP_SET_IDENTITY_MAP_ADDR: u32 = 37; ++pub const KVM_CAP_ADJUST_CLOCK: u32 = 39; ++pub const KVM_CAP_INTERNAL_ERROR_DATA: u32 = 40; ++pub const KVM_CAP_S390_PSW: u32 = 42; ++pub const KVM_CAP_PPC_SEGSTATE: u32 = 43; ++pub const KVM_CAP_HYPERV: u32 = 44; ++pub const KVM_CAP_HYPERV_VAPIC: u32 = 45; ++pub const KVM_CAP_HYPERV_SPIN: u32 = 46; ++pub const KVM_CAP_PCI_SEGMENT: u32 = 47; ++pub const KVM_CAP_PPC_PAIRED_SINGLES: u32 = 48; ++pub const KVM_CAP_INTR_SHADOW: u32 = 49; ++pub const KVM_CAP_X86_ROBUST_SINGLESTEP: u32 = 51; ++pub const KVM_CAP_PPC_OSI: u32 = 52; ++pub const KVM_CAP_PPC_UNSET_IRQ: u32 = 53; ++pub const KVM_CAP_ENABLE_CAP: u32 = 54; ++pub const KVM_CAP_PPC_GET_PVINFO: u32 = 57; ++pub const KVM_CAP_PPC_IRQ_LEVEL: u32 = 58; ++pub const KVM_CAP_ASYNC_PF: u32 = 59; ++pub const KVM_CAP_TSC_CONTROL: u32 = 60; ++pub const KVM_CAP_GET_TSC_KHZ: u32 = 61; ++pub const KVM_CAP_PPC_BOOKE_SREGS: u32 = 62; ++pub const KVM_CAP_SPAPR_TCE: u32 = 63; ++pub const KVM_CAP_PPC_SMT: u32 = 64; ++pub const KVM_CAP_PPC_RMA: u32 = 65; ++pub const KVM_CAP_MAX_VCPUS: u32 = 66; ++pub const KVM_CAP_PPC_HIOR: u32 = 67; ++pub const KVM_CAP_PPC_PAPR: u32 = 68; ++pub const KVM_CAP_SW_TLB: u32 = 69; ++pub const KVM_CAP_ONE_REG: u32 = 70; ++pub const KVM_CAP_S390_GMAP: u32 = 71; ++pub const KVM_CAP_TSC_DEADLINE_TIMER: u32 = 72; ++pub const KVM_CAP_S390_UCONTROL: u32 = 73; ++pub const KVM_CAP_SYNC_REGS: u32 = 74; ++pub const KVM_CAP_PCI_2_3: u32 = 75; ++pub const KVM_CAP_KVMCLOCK_CTRL: u32 = 76; ++pub const KVM_CAP_SIGNAL_MSI: u32 = 77; ++pub const KVM_CAP_PPC_GET_SMMU_INFO: u32 = 78; ++pub const KVM_CAP_S390_COW: u32 = 79; ++pub const KVM_CAP_PPC_ALLOC_HTAB: u32 = 80; ++pub const KVM_CAP_READONLY_MEM: u32 = 81; ++pub const KVM_CAP_IRQFD_RESAMPLE: u32 = 82; ++pub const KVM_CAP_PPC_BOOKE_WATCHDOG: u32 = 83; ++pub const KVM_CAP_PPC_HTAB_FD: u32 = 84; ++pub const KVM_CAP_S390_CSS_SUPPORT: u32 = 85; ++pub const KVM_CAP_PPC_EPR: u32 = 86; ++pub const KVM_CAP_ARM_PSCI: u32 = 87; ++pub const KVM_CAP_ARM_SET_DEVICE_ADDR: u32 = 88; ++pub const KVM_CAP_DEVICE_CTRL: u32 = 89; ++pub const KVM_CAP_IRQ_MPIC: u32 = 90; ++pub const KVM_CAP_PPC_RTAS: u32 = 91; ++pub const KVM_CAP_IRQ_XICS: u32 = 92; ++pub const KVM_CAP_ARM_EL1_32BIT: u32 = 93; ++pub const KVM_CAP_SPAPR_MULTITCE: u32 = 94; ++pub const KVM_CAP_EXT_EMUL_CPUID: u32 = 95; ++pub const KVM_CAP_HYPERV_TIME: u32 = 96; ++pub const KVM_CAP_IOAPIC_POLARITY_IGNORED: u32 = 97; ++pub const KVM_CAP_ENABLE_CAP_VM: u32 = 98; ++pub const KVM_CAP_S390_IRQCHIP: u32 = 99; ++pub const KVM_CAP_IOEVENTFD_NO_LENGTH: u32 = 100; ++pub const KVM_CAP_VM_ATTRIBUTES: u32 = 101; ++pub const KVM_CAP_ARM_PSCI_0_2: u32 = 102; ++pub const KVM_CAP_PPC_FIXUP_HCALL: u32 = 103; ++pub const KVM_CAP_PPC_ENABLE_HCALL: u32 = 104; ++pub const KVM_CAP_CHECK_EXTENSION_VM: u32 = 105; ++pub const KVM_CAP_S390_USER_SIGP: u32 = 106; ++pub const KVM_CAP_S390_VECTOR_REGISTERS: u32 = 107; ++pub const KVM_CAP_S390_MEM_OP: u32 = 108; ++pub const KVM_CAP_S390_USER_STSI: u32 = 109; ++pub const KVM_CAP_S390_SKEYS: u32 = 110; ++pub const KVM_CAP_MIPS_FPU: u32 = 111; ++pub const KVM_CAP_MIPS_MSA: u32 = 112; ++pub const KVM_CAP_S390_INJECT_IRQ: u32 = 113; ++pub const KVM_CAP_S390_IRQ_STATE: u32 = 114; ++pub const KVM_CAP_PPC_HWRNG: u32 = 115; ++pub const KVM_CAP_DISABLE_QUIRKS: u32 = 116; ++pub const KVM_CAP_X86_SMM: u32 = 117; ++pub const KVM_CAP_MULTI_ADDRESS_SPACE: u32 = 118; ++pub const KVM_CAP_GUEST_DEBUG_HW_BPS: u32 = 119; ++pub const KVM_CAP_GUEST_DEBUG_HW_WPS: u32 = 120; ++pub const KVM_CAP_SPLIT_IRQCHIP: u32 = 121; ++pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: u32 = 122; ++pub const KVM_CAP_HYPERV_SYNIC: u32 = 123; ++pub const KVM_CAP_S390_RI: u32 = 124; ++pub const KVM_CAP_SPAPR_TCE_64: u32 = 125; ++pub const KVM_CAP_ARM_PMU_V3: u32 = 126; ++pub const KVM_CAP_VCPU_ATTRIBUTES: u32 = 127; ++pub const KVM_CAP_MAX_VCPU_ID: u32 = 128; ++pub const KVM_CAP_X2APIC_API: u32 = 129; ++pub const KVM_CAP_S390_USER_INSTR0: u32 = 130; ++pub const KVM_CAP_MSI_DEVID: u32 = 131; ++pub const KVM_CAP_PPC_HTM: u32 = 132; ++pub const KVM_CAP_SPAPR_RESIZE_HPT: u32 = 133; ++pub const KVM_CAP_PPC_MMU_RADIX: u32 = 134; ++pub const KVM_CAP_PPC_MMU_HASH_V3: u32 = 135; ++pub const KVM_CAP_IMMEDIATE_EXIT: u32 = 136; ++pub const KVM_CAP_MIPS_VZ: u32 = 137; ++pub const KVM_CAP_MIPS_TE: u32 = 138; ++pub const KVM_CAP_MIPS_64BIT: u32 = 139; ++pub const KVM_CAP_S390_GS: u32 = 140; ++pub const KVM_CAP_S390_AIS: u32 = 141; ++pub const KVM_CAP_SPAPR_TCE_VFIO: u32 = 142; ++pub const KVM_CAP_X86_DISABLE_EXITS: u32 = 143; ++pub const KVM_CAP_ARM_USER_IRQ: u32 = 144; ++pub const KVM_CAP_S390_CMMA_MIGRATION: u32 = 145; ++pub const KVM_CAP_PPC_FWNMI: u32 = 146; ++pub const KVM_CAP_PPC_SMT_POSSIBLE: u32 = 147; ++pub const KVM_CAP_HYPERV_SYNIC2: u32 = 148; ++pub const KVM_CAP_HYPERV_VP_INDEX: u32 = 149; ++pub const KVM_CAP_S390_AIS_MIGRATION: u32 = 150; ++pub const KVM_CAP_PPC_GET_CPU_CHAR: u32 = 151; ++pub const KVM_CAP_S390_BPB: u32 = 152; ++pub const KVM_CAP_GET_MSR_FEATURES: u32 = 153; ++pub const KVM_CAP_HYPERV_EVENTFD: u32 = 154; ++pub const KVM_CAP_HYPERV_TLBFLUSH: u32 = 155; ++pub const KVM_CAP_S390_HPAGE_1M: u32 = 156; ++pub const KVM_CAP_NESTED_STATE: u32 = 157; ++pub const KVM_CAP_ARM_INJECT_SERROR_ESR: u32 = 158; ++pub const KVM_CAP_MSR_PLATFORM_INFO: u32 = 159; ++pub const KVM_CAP_PPC_NESTED_HV: u32 = 160; ++pub const KVM_CAP_HYPERV_SEND_IPI: u32 = 161; ++pub const KVM_CAP_COALESCED_PIO: u32 = 162; ++pub const KVM_CAP_HYPERV_ENLIGHTENED_VMCS: u32 = 163; ++pub const KVM_CAP_EXCEPTION_PAYLOAD: u32 = 164; ++pub const KVM_CAP_ARM_VM_IPA_SIZE: u32 = 165; ++pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT: u32 = 166; ++pub const KVM_CAP_HYPERV_CPUID: u32 = 167; ++pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2: u32 = 168; ++pub const KVM_CAP_PPC_IRQ_XIVE: u32 = 169; ++pub const KVM_CAP_ARM_SVE: u32 = 170; ++pub const KVM_CAP_ARM_PTRAUTH_ADDRESS: u32 = 171; ++pub const KVM_CAP_ARM_PTRAUTH_GENERIC: u32 = 172; ++pub const KVM_CAP_PMU_EVENT_FILTER: u32 = 173; ++pub const KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: u32 = 174; ++pub const KVM_CAP_HYPERV_DIRECT_TLBFLUSH: u32 = 175; ++pub const KVM_CAP_PPC_GUEST_DEBUG_SSTEP: u32 = 176; ++pub const KVM_CAP_ARM_NISV_TO_USER: u32 = 177; ++pub const KVM_CAP_ARM_INJECT_EXT_DABT: u32 = 178; ++pub const KVM_CAP_S390_VCPU_RESETS: u32 = 179; ++pub const KVM_CAP_S390_PROTECTED: u32 = 180; ++pub const KVM_CAP_PPC_SECURE_GUEST: u32 = 181; ++pub const KVM_CAP_HALT_POLL: u32 = 182; ++pub const KVM_CAP_ASYNC_PF_INT: u32 = 183; ++pub const KVM_CAP_LAST_CPU: u32 = 184; ++pub const KVM_CAP_SMALLER_MAXPHYADDR: u32 = 185; ++pub const KVM_CAP_S390_DIAG318: u32 = 186; ++pub const KVM_CAP_STEAL_TIME: u32 = 187; ++pub const KVM_CAP_X86_USER_SPACE_MSR: u32 = 188; ++pub const KVM_CAP_X86_MSR_FILTER: u32 = 189; ++pub const KVM_CAP_ENFORCE_PV_FEATURE_CPUID: u32 = 190; ++pub const KVM_CAP_SYS_HYPERV_CPUID: u32 = 191; ++pub const KVM_CAP_DIRTY_LOG_RING: u32 = 192; ++pub const KVM_CAP_X86_BUS_LOCK_EXIT: u32 = 193; ++pub const KVM_CAP_PPC_DAWR1: u32 = 194; ++pub const KVM_CAP_SET_GUEST_DEBUG2: u32 = 195; ++pub const KVM_CAP_SGX_ATTRIBUTE: u32 = 196; ++pub const KVM_CAP_VM_COPY_ENC_CONTEXT_FROM: u32 = 197; ++pub const KVM_CAP_PTP_KVM: u32 = 198; ++pub const KVM_CAP_HYPERV_ENFORCE_CPUID: u32 = 199; ++pub const KVM_CAP_SREGS2: u32 = 200; ++pub const KVM_CAP_EXIT_HYPERCALL: u32 = 201; ++pub const KVM_CAP_PPC_RPT_INVALIDATE: u32 = 202; ++pub const KVM_CAP_BINARY_STATS_FD: u32 = 203; ++pub const KVM_CAP_EXIT_ON_EMULATION_FAILURE: u32 = 204; ++pub const KVM_CAP_ARM_MTE: u32 = 205; ++pub const KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM: u32 = 206; ++pub const KVM_CAP_VM_GPA_BITS: u32 = 207; ++pub const KVM_CAP_XSAVE2: u32 = 208; ++pub const KVM_CAP_SYS_ATTRIBUTES: u32 = 209; ++pub const KVM_CAP_PPC_AIL_MODE_3: u32 = 210; ++pub const KVM_CAP_S390_MEM_OP_EXTENSION: u32 = 211; ++pub const KVM_CAP_PMU_CAPABILITY: u32 = 212; ++pub const KVM_CAP_DISABLE_QUIRKS2: u32 = 213; ++pub const KVM_CAP_VM_TSC_CONTROL: u32 = 214; ++pub const KVM_CAP_SYSTEM_EVENT_DATA: u32 = 215; ++pub const KVM_CAP_ARM_SYSTEM_SUSPEND: u32 = 216; ++pub const KVM_CAP_S390_PROTECTED_DUMP: u32 = 217; ++pub const KVM_CAP_X86_TRIPLE_FAULT_EVENT: u32 = 218; ++pub const KVM_CAP_X86_NOTIFY_VMEXIT: u32 = 219; ++pub const KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: u32 = 220; ++pub const KVM_CAP_S390_ZPCI_OP: u32 = 221; ++pub const KVM_CAP_S390_CPU_TOPOLOGY: u32 = 222; ++pub const KVM_CAP_DIRTY_LOG_RING_ACQ_REL: u32 = 223; ++pub const KVM_CAP_S390_PROTECTED_ASYNC_DISABLE: u32 = 224; ++pub const KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP: u32 = 225; ++pub const KVM_CAP_PMU_EVENT_MASKED_EVENTS: u32 = 226; ++pub const KVM_CAP_COUNTER_OFFSET: u32 = 227; ++pub const KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE: u32 = 228; ++pub const KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES: u32 = 229; ++pub const KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES: u32 = 230; ++pub const KVM_CAP_USER_MEMORY2: u32 = 231; ++pub const KVM_CAP_MEMORY_FAULT_INFO: u32 = 232; ++pub const KVM_CAP_MEMORY_ATTRIBUTES: u32 = 233; ++pub const KVM_CAP_GUEST_MEMFD: u32 = 234; ++pub const KVM_CAP_VM_TYPES: u32 = 235; ++pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1; ++pub const KVM_IRQ_ROUTING_MSI: u32 = 2; ++pub const KVM_IRQ_ROUTING_S390_ADAPTER: u32 = 3; ++pub const KVM_IRQ_ROUTING_HV_SINT: u32 = 4; ++pub const KVM_IRQ_ROUTING_XEN_EVTCHN: u32 = 5; ++pub const KVM_IRQFD_FLAG_DEASSIGN: u32 = 1; ++pub const KVM_IRQFD_FLAG_RESAMPLE: u32 = 2; ++pub const KVM_CLOCK_TSC_STABLE: u32 = 2; ++pub const KVM_CLOCK_REALTIME: u32 = 4; ++pub const KVM_CLOCK_HOST_TSC: u32 = 8; ++pub const KVM_MMU_FSL_BOOKE_NOHV: u32 = 0; ++pub const KVM_MMU_FSL_BOOKE_HV: u32 = 1; ++pub const KVM_REG_ARCH_MASK: i64 = -72057594037927936; ++pub const KVM_REG_GENERIC: u32 = 0; ++pub const KVM_REG_PPC: u64 = 1152921504606846976; ++pub const KVM_REG_X86: u64 = 2305843009213693952; ++pub const KVM_REG_IA64: u64 = 3458764513820540928; ++pub const KVM_REG_ARM: u64 = 4611686018427387904; ++pub const KVM_REG_S390: u64 = 5764607523034234880; ++pub const KVM_REG_ARM64: u64 = 6917529027641081856; ++pub const KVM_REG_MIPS: u64 = 8070450532247928832; ++pub const KVM_REG_RISCV: i64 = -9223372036854775808; ++pub const KVM_REG_LOONGARCH: i64 = -8070450532247928832; ++pub const KVM_REG_SIZE_SHIFT: u32 = 52; ++pub const KVM_REG_SIZE_MASK: u64 = 67553994410557440; ++pub const KVM_REG_SIZE_U8: u32 = 0; ++pub const KVM_REG_SIZE_U16: u64 = 4503599627370496; ++pub const KVM_REG_SIZE_U32: u64 = 9007199254740992; ++pub const KVM_REG_SIZE_U64: u64 = 13510798882111488; ++pub const KVM_REG_SIZE_U128: u64 = 18014398509481984; ++pub const KVM_REG_SIZE_U256: u64 = 22517998136852480; ++pub const KVM_REG_SIZE_U512: u64 = 27021597764222976; ++pub const KVM_REG_SIZE_U1024: u64 = 31525197391593472; ++pub const KVM_REG_SIZE_U2048: u64 = 36028797018963968; ++pub const KVM_MSI_VALID_DEVID: u32 = 1; ++pub const KVM_CREATE_DEVICE_TEST: u32 = 1; ++pub const KVM_DEV_VFIO_FILE: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_ADD: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_DEL: u32 = 2; ++pub const KVM_DEV_VFIO_GROUP: u32 = 1; ++pub const KVM_DEV_VFIO_GROUP_ADD: u32 = 1; ++pub const KVM_DEV_VFIO_GROUP_DEL: u32 = 2; ++pub const KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: u32 = 3; ++pub const KVM_S390_STORE_STATUS_NOADDR: i32 = -1; ++pub const KVM_S390_STORE_STATUS_PREFIXED: i32 = -2; ++pub const KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE: u32 = 1; ++pub const KVM_DIRTY_LOG_INITIALLY_SET: u32 = 2; ++pub const KVM_DIRTY_LOG_PAGE_OFFSET: u32 = 0; ++pub const KVM_DIRTY_GFN_F_MASK: u32 = 3; ++pub const KVM_BUS_LOCK_DETECTION_OFF: u32 = 1; ++pub const KVM_BUS_LOCK_DETECTION_EXIT: u32 = 2; ++pub const KVM_PMU_CAP_DISABLE: u32 = 1; ++pub const KVM_STATS_TYPE_SHIFT: u32 = 0; ++pub const KVM_STATS_TYPE_MASK: u32 = 15; ++pub const KVM_STATS_TYPE_CUMULATIVE: u32 = 0; ++pub const KVM_STATS_TYPE_INSTANT: u32 = 1; ++pub const KVM_STATS_TYPE_PEAK: u32 = 2; ++pub const KVM_STATS_TYPE_LINEAR_HIST: u32 = 3; ++pub const KVM_STATS_TYPE_LOG_HIST: u32 = 4; ++pub const KVM_STATS_TYPE_MAX: u32 = 4; ++pub const KVM_STATS_UNIT_SHIFT: u32 = 4; ++pub const KVM_STATS_UNIT_MASK: u32 = 240; ++pub const KVM_STATS_UNIT_NONE: u32 = 0; ++pub const KVM_STATS_UNIT_BYTES: u32 = 16; ++pub const KVM_STATS_UNIT_SECONDS: u32 = 32; ++pub const KVM_STATS_UNIT_CYCLES: u32 = 48; ++pub const KVM_STATS_UNIT_BOOLEAN: u32 = 64; ++pub const KVM_STATS_UNIT_MAX: u32 = 64; ++pub const KVM_STATS_BASE_SHIFT: u32 = 8; ++pub const KVM_STATS_BASE_MASK: u32 = 3840; ++pub const KVM_STATS_BASE_POW10: u32 = 0; ++pub const KVM_STATS_BASE_POW2: u32 = 256; ++pub const KVM_STATS_BASE_MAX: u32 = 256; ++pub const KVM_X86_NOTIFY_VMEXIT_ENABLED: u32 = 1; ++pub const KVM_X86_NOTIFY_VMEXIT_USER: u32 = 2; ++pub const KVM_MEMORY_ATTRIBUTE_PRIVATE: u32 = 8; ++pub type __s8 = ::std::os::raw::c_schar; ++pub type __u8 = ::std::os::raw::c_uchar; ++pub type __s16 = ::std::os::raw::c_short; ++pub type __u16 = ::std::os::raw::c_ushort; ++pub type __s32 = ::std::os::raw::c_int; ++pub type __u32 = ::std::os::raw::c_uint; ++pub type __s64 = ::std::os::raw::c_longlong; ++pub type __u64 = ::std::os::raw::c_ulonglong; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct __kernel_fd_set { ++ pub fds_bits: [::std::os::raw::c_ulong; 16usize], ++} ++#[test] ++fn bindgen_test_layout___kernel_fd_set() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fd_set> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__kernel_fd_set>(), ++ 128usize, ++ concat!("Size of: ", stringify!(__kernel_fd_set)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__kernel_fd_set>(), ++ 8usize, ++ concat!("Alignment of ", stringify!(__kernel_fd_set)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__kernel_fd_set), ++ "::", ++ stringify!(fds_bits) ++ ) ++ ); ++} ++pub type __kernel_sighandler_t = ++ ::std::option::Option; ++pub type __kernel_key_t = ::std::os::raw::c_int; ++pub type __kernel_mqd_t = ::std::os::raw::c_int; ++pub type __kernel_long_t = ::std::os::raw::c_long; ++pub type __kernel_ulong_t = ::std::os::raw::c_ulong; ++pub type __kernel_ino_t = __kernel_ulong_t; ++pub type __kernel_mode_t = ::std::os::raw::c_uint; ++pub type __kernel_pid_t = ::std::os::raw::c_int; ++pub type __kernel_ipc_pid_t = ::std::os::raw::c_int; ++pub type __kernel_uid_t = ::std::os::raw::c_uint; ++pub type __kernel_gid_t = ::std::os::raw::c_uint; ++pub type __kernel_suseconds_t = __kernel_long_t; ++pub type __kernel_daddr_t = ::std::os::raw::c_int; ++pub type __kernel_uid32_t = ::std::os::raw::c_uint; ++pub type __kernel_gid32_t = ::std::os::raw::c_uint; ++pub type __kernel_old_uid_t = __kernel_uid_t; ++pub type __kernel_old_gid_t = __kernel_gid_t; ++pub type __kernel_old_dev_t = ::std::os::raw::c_uint; ++pub type __kernel_size_t = __kernel_ulong_t; ++pub type __kernel_ssize_t = __kernel_long_t; ++pub type __kernel_ptrdiff_t = __kernel_long_t; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct __kernel_fsid_t { ++ pub val: [::std::os::raw::c_int; 2usize], ++} ++#[test] ++fn bindgen_test_layout___kernel_fsid_t() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fsid_t> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__kernel_fsid_t>(), ++ 8usize, ++ concat!("Size of: ", stringify!(__kernel_fsid_t)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__kernel_fsid_t>(), ++ 4usize, ++ concat!("Alignment of ", stringify!(__kernel_fsid_t)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__kernel_fsid_t), ++ "::", ++ stringify!(val) ++ ) ++ ); ++} ++pub type __kernel_off_t = __kernel_long_t; ++pub type __kernel_loff_t = ::std::os::raw::c_longlong; ++pub type __kernel_old_time_t = __kernel_long_t; ++pub type __kernel_time_t = __kernel_long_t; ++pub type __kernel_time64_t = ::std::os::raw::c_longlong; ++pub type __kernel_clock_t = __kernel_long_t; ++pub type __kernel_timer_t = ::std::os::raw::c_int; ++pub type __kernel_clockid_t = ::std::os::raw::c_int; ++pub type __kernel_caddr_t = *mut ::std::os::raw::c_char; ++pub type __kernel_uid16_t = ::std::os::raw::c_ushort; ++pub type __kernel_gid16_t = ::std::os::raw::c_ushort; ++pub type __s128 = i128; ++pub type __u128 = u128; ++pub type __le16 = __u16; ++pub type __be16 = __u16; ++pub type __le32 = __u32; ++pub type __be32 = __u32; ++pub type __le64 = __u64; ++pub type __be64 = __u64; ++pub type __sum16 = __u16; ++pub type __wsum = __u32; ++pub type __poll_t = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct user_regs_struct { ++ pub pc: ::std::os::raw::c_ulong, ++ pub ra: ::std::os::raw::c_ulong, ++ pub sp: ::std::os::raw::c_ulong, ++ pub gp: ::std::os::raw::c_ulong, ++ pub tp: ::std::os::raw::c_ulong, ++ pub t0: ::std::os::raw::c_ulong, ++ pub t1: ::std::os::raw::c_ulong, ++ pub t2: ::std::os::raw::c_ulong, ++ pub s0: ::std::os::raw::c_ulong, ++ pub s1: ::std::os::raw::c_ulong, ++ pub a0: ::std::os::raw::c_ulong, ++ pub a1: ::std::os::raw::c_ulong, ++ pub a2: ::std::os::raw::c_ulong, ++ pub a3: ::std::os::raw::c_ulong, ++ pub a4: ::std::os::raw::c_ulong, ++ pub a5: ::std::os::raw::c_ulong, ++ pub a6: ::std::os::raw::c_ulong, ++ pub a7: ::std::os::raw::c_ulong, ++ pub s2: ::std::os::raw::c_ulong, ++ pub s3: ::std::os::raw::c_ulong, ++ pub s4: ::std::os::raw::c_ulong, ++ pub s5: ::std::os::raw::c_ulong, ++ pub s6: ::std::os::raw::c_ulong, ++ pub s7: ::std::os::raw::c_ulong, ++ pub s8: ::std::os::raw::c_ulong, ++ pub s9: ::std::os::raw::c_ulong, ++ pub s10: ::std::os::raw::c_ulong, ++ pub s11: ::std::os::raw::c_ulong, ++ pub t3: ::std::os::raw::c_ulong, ++ pub t4: ::std::os::raw::c_ulong, ++ pub t5: ::std::os::raw::c_ulong, ++ pub t6: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_user_regs_struct() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!("Size of: ", stringify!(user_regs_struct)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(user_regs_struct)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pc) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(pc) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ra) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(ra) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sp) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(sp) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).gp) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(gp) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).tp) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(tp) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t0) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t0) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t1) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t2) as usize - ptr as usize }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s0) as usize - ptr as usize }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s0) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s1) as usize - ptr as usize }, ++ 72usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a0) as usize - ptr as usize }, ++ 80usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a0) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a1) as usize - ptr as usize }, ++ 88usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a2) as usize - ptr as usize }, ++ 96usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a3) as usize - ptr as usize }, ++ 104usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a3) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a4) as usize - ptr as usize }, ++ 112usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a4) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a5) as usize - ptr as usize }, ++ 120usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a5) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a6) as usize - ptr as usize }, ++ 128usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a6) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).a7) as usize - ptr as usize }, ++ 136usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(a7) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s2) as usize - ptr as usize }, ++ 144usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s3) as usize - ptr as usize }, ++ 152usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s3) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s4) as usize - ptr as usize }, ++ 160usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s4) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s5) as usize - ptr as usize }, ++ 168usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s5) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s6) as usize - ptr as usize }, ++ 176usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s6) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s7) as usize - ptr as usize }, ++ 184usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s7) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s8) as usize - ptr as usize }, ++ 192usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s8) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s9) as usize - ptr as usize }, ++ 200usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s9) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s10) as usize - ptr as usize }, ++ 208usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s10) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s11) as usize - ptr as usize }, ++ 216usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(s11) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t3) as usize - ptr as usize }, ++ 224usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t3) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t4) as usize - ptr as usize }, ++ 232usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t4) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t5) as usize - ptr as usize }, ++ 240usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t5) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).t6) as usize - ptr as usize }, ++ 248usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(user_regs_struct), ++ "::", ++ stringify!(t6) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct __riscv_f_ext_state { ++ pub f: [__u32; 32usize], ++ pub fcsr: __u32, ++} ++#[test] ++fn bindgen_test_layout___riscv_f_ext_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_f_ext_state> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_f_ext_state>(), ++ 132usize, ++ concat!("Size of: ", stringify!(__riscv_f_ext_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_f_ext_state>(), ++ 4usize, ++ concat!("Alignment of ", stringify!(__riscv_f_ext_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_f_ext_state), ++ "::", ++ stringify!(f) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fcsr) as usize - ptr as usize }, ++ 128usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_f_ext_state), ++ "::", ++ stringify!(fcsr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct __riscv_d_ext_state { ++ pub f: [__u64; 32usize], ++ pub fcsr: __u32, ++} ++#[test] ++fn bindgen_test_layout___riscv_d_ext_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_d_ext_state> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_d_ext_state>(), ++ 264usize, ++ concat!("Size of: ", stringify!(__riscv_d_ext_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_d_ext_state>(), ++ 8usize, ++ concat!("Alignment of ", stringify!(__riscv_d_ext_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_d_ext_state), ++ "::", ++ stringify!(f) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fcsr) as usize - ptr as usize }, ++ 256usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_d_ext_state), ++ "::", ++ stringify!(fcsr) ++ ) ++ ); ++} ++#[repr(C)] ++#[repr(align(16))] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct __riscv_q_ext_state { ++ pub f: [__u64; 64usize], ++ pub fcsr: __u32, ++ pub reserved: [__u32; 3usize], ++} ++#[test] ++fn bindgen_test_layout___riscv_q_ext_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_q_ext_state> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_q_ext_state>(), ++ 528usize, ++ concat!("Size of: ", stringify!(__riscv_q_ext_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_q_ext_state>(), ++ 16usize, ++ concat!("Alignment of ", stringify!(__riscv_q_ext_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_q_ext_state), ++ "::", ++ stringify!(f) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fcsr) as usize - ptr as usize }, ++ 512usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_q_ext_state), ++ "::", ++ stringify!(fcsr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 516usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_q_ext_state), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++} ++impl Default for __riscv_q_ext_state { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct __riscv_ctx_hdr { ++ pub magic: __u32, ++ pub size: __u32, ++} ++#[test] ++fn bindgen_test_layout___riscv_ctx_hdr() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_ctx_hdr> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_ctx_hdr>(), ++ 8usize, ++ concat!("Size of: ", stringify!(__riscv_ctx_hdr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_ctx_hdr>(), ++ 4usize, ++ concat!("Alignment of ", stringify!(__riscv_ctx_hdr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).magic) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_ctx_hdr), ++ "::", ++ stringify!(magic) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_ctx_hdr), ++ "::", ++ stringify!(size) ++ ) ++ ); ++} ++#[repr(C)] ++#[repr(align(16))] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct __riscv_extra_ext_header { ++ pub __padding: [__u32; 129usize], ++ pub reserved: __u32, ++ pub hdr: __riscv_ctx_hdr, ++} ++#[test] ++fn bindgen_test_layout___riscv_extra_ext_header() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_extra_ext_header> = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_extra_ext_header>(), ++ 528usize, ++ concat!("Size of: ", stringify!(__riscv_extra_ext_header)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_extra_ext_header>(), ++ 16usize, ++ concat!("Alignment of ", stringify!(__riscv_extra_ext_header)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__padding) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_extra_ext_header), ++ "::", ++ stringify!(__padding) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 516usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_extra_ext_header), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize }, ++ 520usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_extra_ext_header), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++} ++impl Default for __riscv_extra_ext_header { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[repr(align(16))] ++#[derive(Copy, Clone)] ++pub union __riscv_fp_state { ++ pub f: __riscv_f_ext_state, ++ pub d: __riscv_d_ext_state, ++ pub q: __riscv_q_ext_state, ++} ++#[test] ++fn bindgen_test_layout___riscv_fp_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_fp_state> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_fp_state>(), ++ 528usize, ++ concat!("Size of: ", stringify!(__riscv_fp_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_fp_state>(), ++ 16usize, ++ concat!("Alignment of ", stringify!(__riscv_fp_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_fp_state), ++ "::", ++ stringify!(f) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).d) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_fp_state), ++ "::", ++ stringify!(d) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).q) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_fp_state), ++ "::", ++ stringify!(q) ++ ) ++ ); ++} ++impl Default for __riscv_fp_state { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for __riscv_fp_state { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "__riscv_fp_state {{ union }}") ++ } ++} ++#[repr(C)] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct __riscv_v_ext_state { ++ pub vstart: ::std::os::raw::c_ulong, ++ pub vl: ::std::os::raw::c_ulong, ++ pub vtype: ::std::os::raw::c_ulong, ++ pub vcsr: ::std::os::raw::c_ulong, ++ pub vlenb: ::std::os::raw::c_ulong, ++ pub datap: *mut ::std::os::raw::c_void, ++} ++#[test] ++fn bindgen_test_layout___riscv_v_ext_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_v_ext_state> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_v_ext_state>(), ++ 48usize, ++ concat!("Size of: ", stringify!(__riscv_v_ext_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_v_ext_state>(), ++ 8usize, ++ concat!("Alignment of ", stringify!(__riscv_v_ext_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vstart) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(vstart) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vl) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(vl) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vtype) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(vtype) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vcsr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(vcsr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vlenb) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(vlenb) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).datap) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_ext_state), ++ "::", ++ stringify!(datap) ++ ) ++ ); ++} ++impl Default for __riscv_v_ext_state { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct __riscv_v_regset_state { ++ pub vstart: ::std::os::raw::c_ulong, ++ pub vl: ::std::os::raw::c_ulong, ++ pub vtype: ::std::os::raw::c_ulong, ++ pub vcsr: ::std::os::raw::c_ulong, ++ pub vlenb: ::std::os::raw::c_ulong, ++ pub vreg: __IncompleteArrayField<::std::os::raw::c_char>, ++} ++#[test] ++fn bindgen_test_layout___riscv_v_regset_state() { ++ const UNINIT: ::std::mem::MaybeUninit<__riscv_v_regset_state> = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::<__riscv_v_regset_state>(), ++ 40usize, ++ concat!("Size of: ", stringify!(__riscv_v_regset_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::<__riscv_v_regset_state>(), ++ 8usize, ++ concat!("Alignment of ", stringify!(__riscv_v_regset_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vstart) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vstart) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vl) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vl) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vtype) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vtype) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vcsr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vcsr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vlenb) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vlenb) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vreg) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(__riscv_v_regset_state), ++ "::", ++ stringify!(vreg) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_regs {} ++#[test] ++fn bindgen_test_layout_kvm_regs() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_regs)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_regs)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_fpu {} ++#[test] ++fn bindgen_test_layout_kvm_fpu() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_fpu)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_fpu)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_debug_exit_arch {} ++#[test] ++fn bindgen_test_layout_kvm_debug_exit_arch() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_debug_exit_arch)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_debug_exit_arch)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_guest_debug_arch {} ++#[test] ++fn bindgen_test_layout_kvm_guest_debug_arch() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_guest_debug_arch)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_guest_debug_arch)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sync_regs {} ++#[test] ++fn bindgen_test_layout_kvm_sync_regs() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_sync_regs)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_sync_regs)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sregs {} ++#[test] ++fn bindgen_test_layout_kvm_sregs() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_sregs)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_sregs)) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_config { ++ pub isa: ::std::os::raw::c_ulong, ++ pub zicbom_block_size: ::std::os::raw::c_ulong, ++ pub mvendorid: ::std::os::raw::c_ulong, ++ pub marchid: ::std::os::raw::c_ulong, ++ pub mimpid: ::std::os::raw::c_ulong, ++ pub zicboz_block_size: ::std::os::raw::c_ulong, ++ pub satp_mode: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_config() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(kvm_riscv_config)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_config)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).isa) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(isa) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).zicbom_block_size) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(zicbom_block_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mvendorid) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(mvendorid) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).marchid) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(marchid) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mimpid) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(mimpid) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).zicboz_block_size) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(zicboz_block_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).satp_mode) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_config), ++ "::", ++ stringify!(satp_mode) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_core { ++ pub regs: user_regs_struct, ++ pub mode: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_core() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 264usize, ++ concat!("Size of: ", stringify!(kvm_riscv_core)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_core)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_core), ++ "::", ++ stringify!(regs) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mode) as usize - ptr as usize }, ++ 256usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_core), ++ "::", ++ stringify!(mode) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_csr { ++ pub sstatus: ::std::os::raw::c_ulong, ++ pub sie: ::std::os::raw::c_ulong, ++ pub stvec: ::std::os::raw::c_ulong, ++ pub sscratch: ::std::os::raw::c_ulong, ++ pub sepc: ::std::os::raw::c_ulong, ++ pub scause: ::std::os::raw::c_ulong, ++ pub stval: ::std::os::raw::c_ulong, ++ pub sip: ::std::os::raw::c_ulong, ++ pub satp: ::std::os::raw::c_ulong, ++ pub scounteren: ::std::os::raw::c_ulong, ++ pub senvcfg: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_csr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 88usize, ++ concat!("Size of: ", stringify!(kvm_riscv_csr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_csr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sstatus) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(sstatus) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sie) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(sie) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).stvec) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(stvec) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sscratch) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(sscratch) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sepc) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(sepc) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).scause) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(scause) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).stval) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(stval) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sip) as usize - ptr as usize }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(sip) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).satp) as usize - ptr as usize }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(satp) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).scounteren) as usize - ptr as usize }, ++ 72usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(scounteren) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).senvcfg) as usize - ptr as usize }, ++ 80usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_csr), ++ "::", ++ stringify!(senvcfg) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_aia_csr { ++ pub siselect: ::std::os::raw::c_ulong, ++ pub iprio1: ::std::os::raw::c_ulong, ++ pub iprio2: ::std::os::raw::c_ulong, ++ pub sieh: ::std::os::raw::c_ulong, ++ pub siph: ::std::os::raw::c_ulong, ++ pub iprio1h: ::std::os::raw::c_ulong, ++ pub iprio2h: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_aia_csr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(kvm_riscv_aia_csr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_aia_csr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).siselect) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(siselect) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).iprio1) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(iprio1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).iprio2) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(iprio2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sieh) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(sieh) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).siph) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(siph) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).iprio1h) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(iprio1h) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).iprio2h) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_aia_csr), ++ "::", ++ stringify!(iprio2h) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_smstateen_csr { ++ pub sstateen0: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_smstateen_csr() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_riscv_smstateen_csr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_smstateen_csr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sstateen0) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_smstateen_csr), ++ "::", ++ stringify!(sstateen0) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_timer { ++ pub frequency: __u64, ++ pub time: __u64, ++ pub compare: __u64, ++ pub state: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_timer() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_riscv_timer)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_timer)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).frequency) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_timer), ++ "::", ++ stringify!(frequency) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).time) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_timer), ++ "::", ++ stringify!(time) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).compare) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_timer), ++ "::", ++ stringify!(compare) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).state) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_timer), ++ "::", ++ stringify!(state) ++ ) ++ ); ++} ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_A: KVM_RISCV_ISA_EXT_ID = 0; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_C: KVM_RISCV_ISA_EXT_ID = 1; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_D: KVM_RISCV_ISA_EXT_ID = 2; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_F: KVM_RISCV_ISA_EXT_ID = 3; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_H: KVM_RISCV_ISA_EXT_ID = 4; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_I: KVM_RISCV_ISA_EXT_ID = 5; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_M: KVM_RISCV_ISA_EXT_ID = 6; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SVPBMT: KVM_RISCV_ISA_EXT_ID = 7; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SSTC: KVM_RISCV_ISA_EXT_ID = 8; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SVINVAL: KVM_RISCV_ISA_EXT_ID = 9; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZIHINTPAUSE: KVM_RISCV_ISA_EXT_ID = 10; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZICBOM: KVM_RISCV_ISA_EXT_ID = 11; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZICBOZ: KVM_RISCV_ISA_EXT_ID = 12; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBB: KVM_RISCV_ISA_EXT_ID = 13; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SSAIA: KVM_RISCV_ISA_EXT_ID = 14; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_V: KVM_RISCV_ISA_EXT_ID = 15; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SVNAPOT: KVM_RISCV_ISA_EXT_ID = 16; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBA: KVM_RISCV_ISA_EXT_ID = 17; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBS: KVM_RISCV_ISA_EXT_ID = 18; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZICNTR: KVM_RISCV_ISA_EXT_ID = 19; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZICSR: KVM_RISCV_ISA_EXT_ID = 20; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZIFENCEI: KVM_RISCV_ISA_EXT_ID = 21; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZIHPM: KVM_RISCV_ISA_EXT_ID = 22; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_SMSTATEEN: KVM_RISCV_ISA_EXT_ID = 23; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZICOND: KVM_RISCV_ISA_EXT_ID = 24; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBC: KVM_RISCV_ISA_EXT_ID = 25; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBKB: KVM_RISCV_ISA_EXT_ID = 26; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBKC: KVM_RISCV_ISA_EXT_ID = 27; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZBKX: KVM_RISCV_ISA_EXT_ID = 28; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKND: KVM_RISCV_ISA_EXT_ID = 29; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKNE: KVM_RISCV_ISA_EXT_ID = 30; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKNH: KVM_RISCV_ISA_EXT_ID = 31; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKR: KVM_RISCV_ISA_EXT_ID = 32; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKSED: KVM_RISCV_ISA_EXT_ID = 33; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKSH: KVM_RISCV_ISA_EXT_ID = 34; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZKT: KVM_RISCV_ISA_EXT_ID = 35; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVBB: KVM_RISCV_ISA_EXT_ID = 36; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVBC: KVM_RISCV_ISA_EXT_ID = 37; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKB: KVM_RISCV_ISA_EXT_ID = 38; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKG: KVM_RISCV_ISA_EXT_ID = 39; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKNED: KVM_RISCV_ISA_EXT_ID = 40; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKNHA: KVM_RISCV_ISA_EXT_ID = 41; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKNHB: KVM_RISCV_ISA_EXT_ID = 42; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKSED: KVM_RISCV_ISA_EXT_ID = 43; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKSH: KVM_RISCV_ISA_EXT_ID = 44; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVKT: KVM_RISCV_ISA_EXT_ID = 45; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZFH: KVM_RISCV_ISA_EXT_ID = 46; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZFHMIN: KVM_RISCV_ISA_EXT_ID = 47; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZIHINTNTL: KVM_RISCV_ISA_EXT_ID = 48; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVFH: KVM_RISCV_ISA_EXT_ID = 49; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZVFHMIN: KVM_RISCV_ISA_EXT_ID = 50; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZFA: KVM_RISCV_ISA_EXT_ID = 51; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZTSO: KVM_RISCV_ISA_EXT_ID = 52; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_ZACAS: KVM_RISCV_ISA_EXT_ID = 53; ++pub const KVM_RISCV_ISA_EXT_ID_KVM_RISCV_ISA_EXT_MAX: KVM_RISCV_ISA_EXT_ID = 54; ++pub type KVM_RISCV_ISA_EXT_ID = ::std::os::raw::c_uint; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_V01: KVM_RISCV_SBI_EXT_ID = 0; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_TIME: KVM_RISCV_SBI_EXT_ID = 1; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_IPI: KVM_RISCV_SBI_EXT_ID = 2; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_RFENCE: KVM_RISCV_SBI_EXT_ID = 3; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_SRST: KVM_RISCV_SBI_EXT_ID = 4; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_HSM: KVM_RISCV_SBI_EXT_ID = 5; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_PMU: KVM_RISCV_SBI_EXT_ID = 6; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_EXPERIMENTAL: KVM_RISCV_SBI_EXT_ID = 7; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_VENDOR: KVM_RISCV_SBI_EXT_ID = 8; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_DBCN: KVM_RISCV_SBI_EXT_ID = 9; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_STA: KVM_RISCV_SBI_EXT_ID = 10; ++pub const KVM_RISCV_SBI_EXT_ID_KVM_RISCV_SBI_EXT_MAX: KVM_RISCV_SBI_EXT_ID = 11; ++pub type KVM_RISCV_SBI_EXT_ID = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_riscv_sbi_sta { ++ pub shmem_lo: ::std::os::raw::c_ulong, ++ pub shmem_hi: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_riscv_sbi_sta() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_riscv_sbi_sta)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_riscv_sbi_sta)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).shmem_lo) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_sbi_sta), ++ "::", ++ stringify!(shmem_lo) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).shmem_hi) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_riscv_sbi_sta), ++ "::", ++ stringify!(shmem_hi) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_userspace_memory_region { ++ pub slot: __u32, ++ pub flags: __u32, ++ pub guest_phys_addr: __u64, ++ pub memory_size: __u64, ++ pub userspace_addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_userspace_memory_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_userspace_memory_region)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_userspace_memory_region)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(slot) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(guest_phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(memory_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(userspace_addr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_userspace_memory_region2 { ++ pub slot: __u32, ++ pub flags: __u32, ++ pub guest_phys_addr: __u64, ++ pub memory_size: __u64, ++ pub userspace_addr: __u64, ++ pub guest_memfd_offset: __u64, ++ pub guest_memfd: __u32, ++ pub pad1: __u32, ++ pub pad2: [__u64; 14usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_userspace_memory_region2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 160usize, ++ concat!("Size of: ", stringify!(kvm_userspace_memory_region2)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_userspace_memory_region2)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(slot) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(memory_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(userspace_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd_offset) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_memfd_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(guest_memfd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(pad1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region2), ++ "::", ++ stringify!(pad2) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_level { ++ pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1, ++ pub level: __u32, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_level__bindgen_ty_1 { ++ pub irq: __u32, ++ pub status: __s32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_level__bindgen_ty_1), ++ "::", ++ stringify!(irq) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_level__bindgen_ty_1), ++ "::", ++ stringify!(status) ++ ) ++ ); ++} ++impl Default for kvm_irq_level__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_level__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_level__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_level)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).level) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_level), ++ "::", ++ stringify!(level) ++ ) ++ ); ++} ++impl Default for kvm_irq_level { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_level { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_level {{ __bindgen_anon_1: {:?}, level: {:?} }}", ++ self.__bindgen_anon_1, self.level ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irqchip { ++ pub chip_id: __u32, ++ pub pad: __u32, ++ pub chip: kvm_irqchip__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irqchip__bindgen_ty_1 { ++ pub dummy: [::std::os::raw::c_char; 512usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 512usize, ++ concat!("Size of: ", stringify!(kvm_irqchip__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dummy) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqchip__bindgen_ty_1), ++ "::", ++ stringify!(dummy) ++ ) ++ ); ++} ++impl Default for kvm_irqchip__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irqchip__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irqchip__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 520usize, ++ concat!("Size of: ", stringify!(kvm_irqchip)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irqchip)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).chip_id) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqchip), ++ "::", ++ stringify!(chip_id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqchip), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).chip) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqchip), ++ "::", ++ stringify!(chip) ++ ) ++ ); ++} ++impl Default for kvm_irqchip { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irqchip { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irqchip {{ chip_id: {:?}, pad: {:?}, chip: {:?} }}", ++ self.chip_id, self.pad, self.chip ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_pit_config { ++ pub flags: __u32, ++ pub pad: [__u32; 15usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_pit_config() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_pit_config)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_pit_config)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_pit_config), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_pit_config), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_hyperv_exit { ++ pub type_: __u32, ++ pub pad1: __u32, ++ pub u: kvm_hyperv_exit__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_hyperv_exit__bindgen_ty_1 { ++ pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1, ++ pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2, ++ pub syndbg: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 { ++ pub msr: __u32, ++ pub pad2: __u32, ++ pub control: __u64, ++ pub evt_page: __u64, ++ pub msg_page: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(msr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(pad2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(control) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).evt_page) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(evt_page) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).msg_page) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(msg_page) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 { ++ pub input: __u64, ++ pub result: __u64, ++ pub params: [__u64; 2usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(input) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(result) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(params) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3 { ++ pub msr: __u32, ++ pub pad2: __u32, ++ pub control: __u64, ++ pub status: __u64, ++ pub send_page: __u64, ++ pub recv_page: __u64, ++ pub pending_page: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(msr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(pad2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(control) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(status) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).send_page) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(send_page) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).recv_page) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(recv_page) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pending_page) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(pending_page) ++ ) ++ ); ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).synic) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ "::", ++ stringify!(synic) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ "::", ++ stringify!(hcall) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).syndbg) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ "::", ++ stringify!(syndbg) ++ ) ++ ); ++} ++impl Default for kvm_hyperv_exit__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_hyperv_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_hyperv_exit__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(kvm_hyperv_exit)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_hyperv_exit)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit), ++ "::", ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit), ++ "::", ++ stringify!(pad1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit), ++ "::", ++ stringify!(u) ++ ) ++ ); ++} ++impl Default for kvm_hyperv_exit { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_hyperv_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_hyperv_exit {{ type: {:?}, pad1: {:?}, u: {:?} }}", ++ self.type_, self.pad1, self.u ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_xen_exit { ++ pub type_: __u32, ++ pub u: kvm_xen_exit__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_xen_exit__bindgen_ty_1 { ++ pub hcall: kvm_xen_exit__bindgen_ty_1__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_xen_exit__bindgen_ty_1__bindgen_ty_1 { ++ pub longmode: __u32, ++ pub cpl: __u32, ++ pub input: __u64, ++ pub result: __u64, ++ pub params: [__u64; 6usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(longmode) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cpl) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(cpl) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(input) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(result) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(params) ++ ) ++ ); ++} ++#[test] ++fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_xen_exit__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_xen_exit__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1), ++ "::", ++ stringify!(hcall) ++ ) ++ ); ++} ++impl Default for kvm_xen_exit__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_xen_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_xen_exit__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_xen_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 80usize, ++ concat!("Size of: ", stringify!(kvm_xen_exit)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_xen_exit)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit), ++ "::", ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_exit), ++ "::", ++ stringify!(u) ++ ) ++ ); ++} ++impl Default for kvm_xen_exit { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_xen_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_exit {{ type: {:?}, u: {:?} }}", ++ self.type_, self.u ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run { ++ pub request_interrupt_window: __u8, ++ pub immediate_exit: __u8, ++ pub padding1: [__u8; 6usize], ++ pub exit_reason: __u32, ++ pub ready_for_interrupt_injection: __u8, ++ pub if_flag: __u8, ++ pub flags: __u16, ++ pub cr8: __u64, ++ pub apic_base: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1, ++ pub kvm_valid_regs: __u64, ++ pub kvm_dirty_regs: __u64, ++ pub s: kvm_run__bindgen_ty_2, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1 { ++ pub hw: kvm_run__bindgen_ty_1__bindgen_ty_1, ++ pub fail_entry: kvm_run__bindgen_ty_1__bindgen_ty_2, ++ pub ex: kvm_run__bindgen_ty_1__bindgen_ty_3, ++ pub io: kvm_run__bindgen_ty_1__bindgen_ty_4, ++ pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5, ++ pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6, ++ pub iocsr_io: kvm_run__bindgen_ty_1__bindgen_ty_7, ++ pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_8, ++ pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_9, ++ pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_10, ++ pub s390_reset_flags: __u64, ++ pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_11, ++ pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_12, ++ pub internal: kvm_run__bindgen_ty_1__bindgen_ty_13, ++ pub emulation_failure: kvm_run__bindgen_ty_1__bindgen_ty_14, ++ pub osi: kvm_run__bindgen_ty_1__bindgen_ty_15, ++ pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_16, ++ pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_17, ++ pub epr: kvm_run__bindgen_ty_1__bindgen_ty_18, ++ pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_19, ++ pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_20, ++ pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_21, ++ pub hyperv: kvm_hyperv_exit, ++ pub arm_nisv: kvm_run__bindgen_ty_1__bindgen_ty_22, ++ pub msr: kvm_run__bindgen_ty_1__bindgen_ty_23, ++ pub xen: kvm_xen_exit, ++ pub riscv_sbi: kvm_run__bindgen_ty_1__bindgen_ty_24, ++ pub riscv_csr: kvm_run__bindgen_ty_1__bindgen_ty_25, ++ pub notify: kvm_run__bindgen_ty_1__bindgen_ty_26, ++ pub memory_fault: kvm_run__bindgen_ty_1__bindgen_ty_27, ++ pub padding: [::std::os::raw::c_char; 256usize], ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 { ++ pub hardware_exit_reason: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hardware_exit_reason) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(hardware_exit_reason) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 { ++ pub hardware_entry_failure_reason: __u64, ++ pub cpu: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ++ ::std::ptr::addr_of!((*ptr).hardware_entry_failure_reason) as usize - ptr as usize ++ }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(hardware_entry_failure_reason) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cpu) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(cpu) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 { ++ pub exception: __u32, ++ pub error_code: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(exception) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).error_code) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(error_code) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 { ++ pub direction: __u8, ++ pub size: __u8, ++ pub port: __u16, ++ pub count: __u32, ++ pub data_offset: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).direction) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(direction) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 1usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 2usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(port) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(count) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(data_offset) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 { ++ pub arch: kvm_debug_exit_arch, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5), ++ "::", ++ stringify!(arch) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 { ++ pub phys_addr: __u64, ++ pub data: [__u8; 8usize], ++ pub len: __u32, ++ pub is_write: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ "::", ++ stringify!(phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ "::", ++ stringify!(data) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ "::", ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ "::", ++ stringify!(is_write) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 { ++ pub phys_addr: __u64, ++ pub data: [__u8; 8usize], ++ pub len: __u32, ++ pub is_write: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ "::", ++ stringify!(phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ "::", ++ stringify!(data) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ "::", ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ "::", ++ stringify!(is_write) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ pub nr: __u64, ++ pub args: [__u64; 6usize], ++ pub ret: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ pub longmode: __u32, ++ pub flags: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), ++ "::", ++ stringify!(longmode) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 {{ union }}" ++ ) ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ "::", ++ stringify!(nr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ "::", ++ stringify!(args) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ "::", ++ stringify!(ret) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_8 {{ nr: {:?}, args: {:?}, ret: {:?}, __bindgen_anon_1: {:?} }}" , self . nr , self . args , self . ret , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 { ++ pub rip: __u64, ++ pub is_write: __u32, ++ pub pad: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).rip) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ "::", ++ stringify!(rip) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ "::", ++ stringify!(is_write) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 { ++ pub icptcode: __u8, ++ pub ipa: __u16, ++ pub ipb: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).icptcode) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ "::", ++ stringify!(icptcode) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ipa) as usize - ptr as usize }, ++ 2usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ "::", ++ stringify!(ipa) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ "::", ++ stringify!(ipb) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 { ++ pub trans_exc_code: __u64, ++ pub pgm_code: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_exc_code) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), ++ "::", ++ stringify!(trans_exc_code) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pgm_code) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), ++ "::", ++ stringify!(pgm_code) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 { ++ pub dcrn: __u32, ++ pub data: __u32, ++ pub is_write: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dcrn) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ "::", ++ stringify!(dcrn) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ "::", ++ stringify!(data) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ "::", ++ stringify!(is_write) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 { ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub data: [__u64; 16usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 136usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ "::", ++ stringify!(suberror) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ "::", ++ stringify!(ndata) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub flags: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1 { ++ pub insn_size: __u8, ++ pub insn_bytes: [__u8; 15usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_size) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(insn_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_bytes) as usize - ptr as usize }, ++ 1usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(insn_bytes) ++ ) ++ ); ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 {{ union }}" ++ ) ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ "::", ++ stringify!(suberror) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ "::", ++ stringify!(ndata) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_14 {{ suberror: {:?}, ndata: {:?}, flags: {:?}, __bindgen_anon_1: {:?} }}" , self . suberror , self . ndata , self . flags , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 { ++ pub gprs: [__u64; 32usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).gprs) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ "::", ++ stringify!(gprs) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 { ++ pub nr: __u64, ++ pub ret: __u64, ++ pub args: [__u64; 9usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 88usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), ++ "::", ++ stringify!(nr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), ++ "::", ++ stringify!(ret) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), ++ "::", ++ stringify!(args) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 { ++ pub subchannel_id: __u16, ++ pub subchannel_nr: __u16, ++ pub io_int_parm: __u32, ++ pub io_int_word: __u32, ++ pub ipb: __u32, ++ pub dequeued: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 20usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_id) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(subchannel_id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_nr) as usize - ptr as usize }, ++ 2usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(subchannel_nr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_parm) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(io_int_parm) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_word) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(io_int_word) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(ipb) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dequeued) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), ++ "::", ++ stringify!(dequeued) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 { ++ pub epr: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ "::", ++ stringify!(epr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ pub type_: __u32, ++ pub ndata: __u32, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ pub flags: __u64, ++ pub data: [__u64; 16usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 128usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 {{ union }}" ++ ) ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 136usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), ++ "::", ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), ++ "::", ++ stringify!(ndata) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_19 {{ type: {:?}, ndata: {:?}, __bindgen_anon_1: {:?} }}" , self . type_ , self . ndata , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_20 { ++ pub addr: __u64, ++ pub ar: __u8, ++ pub reserved: __u8, ++ pub fc: __u8, ++ pub sel1: __u8, ++ pub sel2: __u16, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_20() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ar) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(ar) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 9usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fc) as usize - ptr as usize }, ++ 10usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(fc) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sel1) as usize - ptr as usize }, ++ 11usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(sel1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sel2) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ "::", ++ stringify!(sel2) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_21 { ++ pub vector: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_21() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 1usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ "::", ++ stringify!(vector) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_22 { ++ pub esr_iss: __u64, ++ pub fault_ipa: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_22() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).esr_iss) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), ++ "::", ++ stringify!(esr_iss) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fault_ipa) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), ++ "::", ++ stringify!(fault_ipa) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_23 { ++ pub error: __u8, ++ pub pad: [__u8; 7usize], ++ pub reason: __u32, ++ pub index: __u32, ++ pub data: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_23() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).error) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(error) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 1usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reason) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(reason) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).index) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(index) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_24 { ++ pub extension_id: ::std::os::raw::c_ulong, ++ pub function_id: ::std::os::raw::c_ulong, ++ pub args: [::std::os::raw::c_ulong; 6usize], ++ pub ret: [::std::os::raw::c_ulong; 2usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_24() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 80usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).extension_id) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), ++ "::", ++ stringify!(extension_id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).function_id) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), ++ "::", ++ stringify!(function_id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), ++ "::", ++ stringify!(args) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), ++ "::", ++ stringify!(ret) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_25 { ++ pub csr_num: ::std::os::raw::c_ulong, ++ pub new_value: ::std::os::raw::c_ulong, ++ pub write_mask: ::std::os::raw::c_ulong, ++ pub ret_value: ::std::os::raw::c_ulong, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_25() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).csr_num) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(csr_num) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).new_value) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(new_value) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).write_mask) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(write_mask) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret_value) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), ++ "::", ++ stringify!(ret_value) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_26 { ++ pub flags: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_26() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_27 { ++ pub flags: __u64, ++ pub gpa: __u64, ++ pub size: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_27() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).gpa) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), ++ "::", ++ stringify!(gpa) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), ++ "::", ++ stringify!(size) ++ ) ++ ); ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hw) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(hw) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fail_entry) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(fail_entry) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ex) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(ex) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).io) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(io) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).debug) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(debug) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mmio) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(mmio) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).iocsr_io) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(iocsr_io) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hypercall) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(hypercall) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).tpr_access) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(tpr_access) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_sieic) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_sieic) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_reset_flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_reset_flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_ucontrol) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_ucontrol) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dcr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(dcr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).internal) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(internal) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).emulation_failure) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(emulation_failure) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).osi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(osi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).papr_hcall) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(papr_hcall) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_tsch) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_tsch) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(epr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).system_event) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(system_event) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_stsi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_stsi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).eoi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(eoi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hyperv) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(hyperv) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).arm_nisv) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(arm_nisv) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(msr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).xen) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(xen) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_sbi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(riscv_sbi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_csr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(riscv_csr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).notify) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(notify) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_fault) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(memory_fault) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_1 {{ union }}") ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_2 { ++ pub regs: kvm_sync_regs, ++ pub padding: [::std::os::raw::c_char; 2048usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 2048usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_2), ++ "::", ++ stringify!(regs) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_2), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++} ++impl Default for kvm_run__bindgen_ty_2 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_2 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_2 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_run() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 2352usize, ++ concat!("Size of: ", stringify!(kvm_run)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_run)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).request_interrupt_window) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(request_interrupt_window) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).immediate_exit) as usize - ptr as usize }, ++ 1usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(immediate_exit) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 2usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(padding1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).exit_reason) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(exit_reason) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ++ ::std::ptr::addr_of!((*ptr).ready_for_interrupt_injection) as usize - ptr as usize ++ }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(ready_for_interrupt_injection) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).if_flag) as usize - ptr as usize }, ++ 13usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(if_flag) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 14usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cr8) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(cr8) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).apic_base) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(apic_base) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_valid_regs) as usize - ptr as usize }, ++ 288usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(kvm_valid_regs) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_dirty_regs) as usize - ptr as usize }, ++ 296usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(kvm_dirty_regs) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).s) as usize - ptr as usize }, ++ 304usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(s) ++ ) ++ ); ++} ++impl Default for kvm_run { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run {{ request_interrupt_window: {:?}, immediate_exit: {:?}, padding1: {:?}, exit_reason: {:?}, ready_for_interrupt_injection: {:?}, if_flag: {:?}, flags: {:?}, cr8: {:?}, apic_base: {:?}, __bindgen_anon_1: {:?}, kvm_valid_regs: {:?}, kvm_dirty_regs: {:?}, s: {:?} }}" , self . request_interrupt_window , self . immediate_exit , self . padding1 , self . exit_reason , self . ready_for_interrupt_injection , self . if_flag , self . flags , self . cr8 , self . apic_base , self . __bindgen_anon_1 , self . kvm_valid_regs , self . kvm_dirty_regs , self . s) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio_zone { ++ pub addr: __u64, ++ pub size: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), ++ "::", ++ stringify!(pio) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio_zone__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio_zone() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_zone), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_zone), ++ "::", ++ stringify!(size) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio_zone { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_zone {{ addr: {:?}, size: {:?}, __bindgen_anon_1: {:?} }}", ++ self.addr, self.size, self.__bindgen_anon_1 ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio { ++ pub phys_addr: __u64, ++ pub len: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1, ++ pub data: [__u8; 8usize], ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), ++ "::", ++ stringify!(pio) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio), ++ "::", ++ stringify!(phys_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio), ++ "::", ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_coalesced_mmio {{ phys_addr: {:?}, len: {:?}, __bindgen_anon_1: {:?}, data: {:?} }}" , self . phys_addr , self . len , self . __bindgen_anon_1 , self . data) ++ } ++} ++#[repr(C)] ++pub struct kvm_coalesced_mmio_ring { ++ pub first: __u32, ++ pub last: __u32, ++ pub coalesced_mmio: __IncompleteArrayField, ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio_ring() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).first) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_ring), ++ "::", ++ stringify!(first) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).last) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_ring), ++ "::", ++ stringify!(last) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).coalesced_mmio) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_coalesced_mmio_ring), ++ "::", ++ stringify!(coalesced_mmio) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio_ring { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_ring { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_ring {{ first: {:?}, last: {:?}, coalesced_mmio: {:?} }}", ++ self.first, self.last, self.coalesced_mmio ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_translation { ++ pub linear_address: __u64, ++ pub physical_address: __u64, ++ pub valid: __u8, ++ pub writeable: __u8, ++ pub usermode: __u8, ++ pub pad: [__u8; 5usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_translation() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_translation)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_translation)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).linear_address) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(linear_address) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).physical_address) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(physical_address) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).valid) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(valid) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).writeable) as usize - ptr as usize }, ++ 17usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(writeable) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).usermode) as usize - ptr as usize }, ++ 18usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(usermode) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 19usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_translation), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_interrupt { ++ pub irq: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_interrupt() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_interrupt)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_interrupt)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_interrupt), ++ "::", ++ stringify!(irq) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_dirty_log { ++ pub slot: __u32, ++ pub padding1: __u32, ++ pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_log__bindgen_ty_1), ++ "::", ++ stringify!(dirty_bitmap) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_log__bindgen_ty_1), ++ "::", ++ stringify!(padding2) ++ ) ++ ); ++} ++impl Default for kvm_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_dirty_log__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_log)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_log)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_log), ++ "::", ++ stringify!(slot) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_log), ++ "::", ++ stringify!(padding1) ++ ) ++ ); ++} ++impl Default for kvm_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_dirty_log {{ slot: {:?}, padding1: {:?}, __bindgen_anon_1: {:?} }}", ++ self.slot, self.padding1, self.__bindgen_anon_1 ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_clear_dirty_log { ++ pub slot: __u32, ++ pub num_pages: __u32, ++ pub first_page: __u64, ++ pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_clear_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_clear_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), ++ "::", ++ stringify!(dirty_bitmap) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), ++ "::", ++ stringify!(padding2) ++ ) ++ ); ++} ++impl Default for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_clear_dirty_log__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_clear_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_clear_dirty_log)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clear_dirty_log), ++ "::", ++ stringify!(slot) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).num_pages) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clear_dirty_log), ++ "::", ++ stringify!(num_pages) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).first_page) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clear_dirty_log), ++ "::", ++ stringify!(first_page) ++ ) ++ ); ++} ++impl Default for kvm_clear_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_clear_dirty_log {{ slot: {:?}, num_pages: {:?}, first_page: {:?}, __bindgen_anon_1: {:?} }}" , self . slot , self . num_pages , self . first_page , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_signal_mask { ++ pub len: __u32, ++ pub sigset: __IncompleteArrayField<__u8>, ++} ++#[test] ++fn bindgen_test_layout_kvm_signal_mask() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_signal_mask)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_signal_mask)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_signal_mask), ++ "::", ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sigset) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_signal_mask), ++ "::", ++ stringify!(sigset) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_tpr_access_ctl { ++ pub enabled: __u32, ++ pub flags: __u32, ++ pub reserved: [__u32; 8usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_tpr_access_ctl() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(kvm_tpr_access_ctl)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_tpr_access_ctl)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_tpr_access_ctl), ++ "::", ++ stringify!(enabled) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_tpr_access_ctl), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_tpr_access_ctl), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_vapic_addr { ++ pub vapic_addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_vapic_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vapic_addr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_vapic_addr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vapic_addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_vapic_addr), ++ "::", ++ stringify!(vapic_addr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_mp_state { ++ pub mp_state: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_mp_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_mp_state)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_mp_state)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mp_state) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_mp_state), ++ "::", ++ stringify!(mp_state) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_guest_debug { ++ pub control: __u32, ++ pub pad: __u32, ++ pub arch: kvm_guest_debug_arch, ++} ++#[test] ++fn bindgen_test_layout_kvm_guest_debug() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_guest_debug)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_guest_debug)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_guest_debug), ++ "::", ++ stringify!(control) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_guest_debug), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_guest_debug), ++ "::", ++ stringify!(arch) ++ ) ++ ); ++} ++pub const kvm_ioeventfd_flag_nr_datamatch: _bindgen_ty_1 = 0; ++pub const kvm_ioeventfd_flag_nr_pio: _bindgen_ty_1 = 1; ++pub const kvm_ioeventfd_flag_nr_deassign: _bindgen_ty_1 = 2; ++pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: _bindgen_ty_1 = 3; ++pub const kvm_ioeventfd_flag_nr_fast_mmio: _bindgen_ty_1 = 4; ++pub const kvm_ioeventfd_flag_nr_max: _bindgen_ty_1 = 5; ++pub type _bindgen_ty_1 = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_ioeventfd { ++ pub datamatch: __u64, ++ pub addr: __u64, ++ pub len: __u32, ++ pub fd: __s32, ++ pub flags: __u32, ++ pub pad: [__u8; 36usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_ioeventfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_ioeventfd)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_ioeventfd)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).datamatch) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(datamatch) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(fd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_ioeventfd), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++impl Default for kvm_ioeventfd { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_enable_cap { ++ pub cap: __u32, ++ pub flags: __u32, ++ pub args: [__u64; 4usize], ++ pub pad: [__u8; 64usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_enable_cap() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 104usize, ++ concat!("Size of: ", stringify!(kvm_enable_cap)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_enable_cap)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cap) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(cap) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(args) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++impl Default for kvm_enable_cap { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_irqchip { ++ pub irqchip: __u32, ++ pub pin: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_irqchip)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_irqchip), ++ "::", ++ stringify!(irqchip) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pin) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_irqchip), ++ "::", ++ stringify!(pin) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_msi__bindgen_ty_1 { ++ pub pad: __u32, ++ pub devid: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ "::", ++ stringify!(devid) ++ ) ++ ); ++} ++impl Default for kvm_irq_routing_msi__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_msi__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_msi__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_msi)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_msi), ++ "::", ++ stringify!(address_lo) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_msi), ++ "::", ++ stringify!(address_hi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_msi), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++impl Default for kvm_irq_routing_msi { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_msi { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_irq_routing_msi {{ address_lo: {:?}, address_hi: {:?}, data: {:?}, __bindgen_anon_1: {:?} }}" , self . address_lo , self . address_hi , self . data , self . __bindgen_anon_1) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_s390_adapter { ++ pub ind_addr: __u64, ++ pub summary_addr: __u64, ++ pub ind_offset: __u64, ++ pub summary_offset: __u32, ++ pub adapter_id: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_s390_adapter() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(ind_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(summary_addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_offset) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(ind_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_offset) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(summary_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter_id) as usize - ptr as usize }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_s390_adapter), ++ "::", ++ stringify!(adapter_id) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_hv_sint { ++ pub vcpu: __u32, ++ pub sint: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_hv_sint() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_hv_sint), ++ "::", ++ stringify!(vcpu) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sint) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_hv_sint), ++ "::", ++ stringify!(sint) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_xen_evtchn { ++ pub port: __u32, ++ pub vcpu: __u32, ++ pub priority: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_xen_evtchn() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_xen_evtchn)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_xen_evtchn)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_xen_evtchn), ++ "::", ++ stringify!(port) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_xen_evtchn), ++ "::", ++ stringify!(vcpu) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_xen_evtchn), ++ "::", ++ stringify!(priority) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_entry { ++ pub gsi: __u32, ++ pub type_: __u32, ++ pub flags: __u32, ++ pub pad: __u32, ++ pub u: kvm_irq_routing_entry__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_entry__bindgen_ty_1 { ++ pub irqchip: kvm_irq_routing_irqchip, ++ pub msi: kvm_irq_routing_msi, ++ pub adapter: kvm_irq_routing_s390_adapter, ++ pub hv_sint: kvm_irq_routing_hv_sint, ++ pub xen_evtchn: kvm_irq_routing_xen_evtchn, ++ pub pad: [__u32; 8usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(irqchip) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).msi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(msi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(adapter) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hv_sint) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(hv_sint) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).xen_evtchn) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(xen_evtchn) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++impl Default for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_entry__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_entry() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_entry)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry), ++ "::", ++ stringify!(gsi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry), ++ "::", ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing_entry), ++ "::", ++ stringify!(u) ++ ) ++ ); ++} ++impl Default for kvm_irq_routing_entry { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing_entry {{ gsi: {:?}, type: {:?}, flags: {:?}, pad: {:?}, u: {:?} }}", ++ self.gsi, self.type_, self.flags, self.pad, self.u ++ ) ++ } ++} ++#[repr(C)] ++pub struct kvm_irq_routing { ++ pub nr: __u32, ++ pub flags: __u32, ++ pub entries: __IncompleteArrayField, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing), ++ "::", ++ stringify!(nr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irq_routing), ++ "::", ++ stringify!(entries) ++ ) ++ ); ++} ++impl Default for kvm_irq_routing { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing {{ nr: {:?}, flags: {:?}, entries: {:?} }}", ++ self.nr, self.flags, self.entries ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irqfd { ++ pub fd: __u32, ++ pub gsi: __u32, ++ pub flags: __u32, ++ pub resamplefd: __u32, ++ pub pad: [__u8; 16usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_irqfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irqfd)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irqfd)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqfd), ++ "::", ++ stringify!(fd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqfd), ++ "::", ++ stringify!(gsi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqfd), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).resamplefd) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqfd), ++ "::", ++ stringify!(resamplefd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqfd), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_clock_data { ++ pub clock: __u64, ++ pub flags: __u32, ++ pub pad0: __u32, ++ pub realtime: __u64, ++ pub host_tsc: __u64, ++ pub pad: [__u32; 4usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_clock_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_clock_data)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_clock_data)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).clock) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(clock) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(pad0) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).realtime) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(realtime) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).host_tsc) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(host_tsc) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_clock_data), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_config_tlb { ++ pub params: __u64, ++ pub array: __u64, ++ pub mmu_type: __u32, ++ pub array_len: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_config_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_config_tlb)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_config_tlb)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_config_tlb), ++ "::", ++ stringify!(params) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).array) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_config_tlb), ++ "::", ++ stringify!(array) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mmu_type) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_config_tlb), ++ "::", ++ stringify!(mmu_type) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).array_len) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_config_tlb), ++ "::", ++ stringify!(array_len) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_dirty_tlb { ++ pub bitmap: __u64, ++ pub num_dirty: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_tlb)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_tlb)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).bitmap) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_tlb), ++ "::", ++ stringify!(bitmap) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).num_dirty) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_tlb), ++ "::", ++ stringify!(num_dirty) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_reg_list { ++ pub n: __u64, ++ pub reg: __IncompleteArrayField<__u64>, ++} ++#[test] ++fn bindgen_test_layout_kvm_reg_list() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_reg_list)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_reg_list)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).n) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_reg_list), ++ "::", ++ stringify!(n) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reg) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_reg_list), ++ "::", ++ stringify!(reg) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_one_reg { ++ pub id: __u64, ++ pub addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_one_reg() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_one_reg)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_one_reg)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_one_reg), ++ "::", ++ stringify!(id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_one_reg), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub flags: __u32, ++ pub devid: __u32, ++ pub pad: [__u8; 12usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_msi)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_msi)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(address_lo) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(address_hi) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(data) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(devid) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msi), ++ "::", ++ stringify!(pad) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_arm_device_addr { ++ pub id: __u64, ++ pub addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_arm_device_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_arm_device_addr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_arm_device_addr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_arm_device_addr), ++ "::", ++ stringify!(id) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_arm_device_addr), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_create_device { ++ pub type_: __u32, ++ pub fd: __u32, ++ pub flags: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_create_device() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_create_device)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_create_device)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_device), ++ "::", ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_device), ++ "::", ++ stringify!(fd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_device), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_device_attr { ++ pub flags: __u32, ++ pub group: __u32, ++ pub attr: __u64, ++ pub addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_device_attr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_device_attr)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_device_attr)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_device_attr), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).group) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_device_attr), ++ "::", ++ stringify!(group) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).attr) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_device_attr), ++ "::", ++ stringify!(attr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_device_attr), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++} ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1; ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2; ++pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3; ++pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5; ++pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8; ++pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_PV_TIME: kvm_device_type = 10; ++pub const kvm_device_type_KVM_DEV_TYPE_RISCV_AIA: kvm_device_type = 11; ++pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 12; ++pub type kvm_device_type = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_vfio_spapr_tce { ++ pub groupfd: __s32, ++ pub tablefd: __s32, ++} ++#[test] ++fn bindgen_test_layout_kvm_vfio_spapr_tce() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vfio_spapr_tce)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).groupfd) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_vfio_spapr_tce), ++ "::", ++ stringify!(groupfd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).tablefd) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_vfio_spapr_tce), ++ "::", ++ stringify!(tablefd) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_enc_region { ++ pub addr: __u64, ++ pub size: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_enc_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_enc_region)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_enc_region)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enc_region), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enc_region), ++ "::", ++ stringify!(size) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_dirty_gfn { ++ pub flags: __u32, ++ pub slot: __u32, ++ pub offset: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_gfn() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_gfn)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_gfn)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_gfn), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_gfn), ++ "::", ++ stringify!(slot) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_dirty_gfn), ++ "::", ++ stringify!(offset) ++ ) ++ ); ++} ++#[doc = " struct kvm_stats_header - Header of per vm/vcpu binary statistics data.\n @flags: Some extra information for header, always 0 for now.\n @name_size: The size in bytes of the memory which contains statistics\n name string including trailing '\\0'. The memory is allocated\n at the send of statistics descriptor.\n @num_desc: The number of statistics the vm or vcpu has.\n @id_offset: The offset of the vm/vcpu stats' id string in the file pointed\n by vm/vcpu stats fd.\n @desc_offset: The offset of the vm/vcpu stats' descriptor block in the file\n pointd by vm/vcpu stats fd.\n @data_offset: The offset of the vm/vcpu stats' data block in the file\n pointed by vm/vcpu stats fd.\n\n This is the header userspace needs to read from stats fd before any other\n readings. It is used by userspace to discover all the information about the\n vm/vcpu's binary statistics.\n Userspace reads this header from the start of the vm/vcpu's stats fd."] ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_stats_header { ++ pub flags: __u32, ++ pub name_size: __u32, ++ pub num_desc: __u32, ++ pub id_offset: __u32, ++ pub desc_offset: __u32, ++ pub data_offset: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_stats_header() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_stats_header)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_stats_header)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).name_size) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(name_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).num_desc) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(num_desc) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).id_offset) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(id_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).desc_offset) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(desc_offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(data_offset) ++ ) ++ ); ++} ++#[doc = " struct kvm_stats_desc - Descriptor of a KVM statistics.\n @flags: Annotations of the stats, like type, unit, etc.\n @exponent: Used together with @flags to determine the unit.\n @size: The number of data items for this stats.\n Every data item is of type __u64.\n @offset: The offset of the stats to the start of stat structure in\n structure kvm or kvm_vcpu.\n @bucket_size: A parameter value used for histogram stats. It is only used\n\t\tfor linear histogram stats, specifying the size of the bucket;\n @name: The name string for the stats. Its size is indicated by the\n &kvm_stats_header->name_size."] ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_stats_desc { ++ pub flags: __u32, ++ pub exponent: __s16, ++ pub size: __u16, ++ pub offset: __u32, ++ pub bucket_size: __u32, ++ pub name: __IncompleteArrayField<::std::os::raw::c_char>, ++} ++#[test] ++fn bindgen_test_layout_kvm_stats_desc() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_stats_desc)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_stats_desc)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).exponent) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(exponent) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 6usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(offset) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).bucket_size) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(bucket_size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_desc), ++ "::", ++ stringify!(name) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_memory_attributes { ++ pub address: __u64, ++ pub size: __u64, ++ pub attributes: __u64, ++ pub flags: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_memory_attributes() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_memory_attributes)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_memory_attributes)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).address) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_memory_attributes), ++ "::", ++ stringify!(address) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_memory_attributes), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_memory_attributes), ++ "::", ++ stringify!(attributes) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_memory_attributes), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_create_guest_memfd { ++ pub size: __u64, ++ pub flags: __u64, ++ pub reserved: [__u64; 6usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_create_guest_memfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_create_guest_memfd)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_create_guest_memfd)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_guest_memfd), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_guest_memfd), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_create_guest_memfd), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++} +diff --git a/vendor/kvm-bindings/src/riscv64/fam_wrappers.rs b/vendor/kvm-bindings/src/riscv64/fam_wrappers.rs +new file mode 100644 +index 0000000..f433172 +--- /dev/null ++++ b/vendor/kvm-bindings/src/riscv64/fam_wrappers.rs +@@ -0,0 +1,49 @@ ++// Copyright 2024 © Institute of Software, CAS. All rights reserved. ++// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. ++// SPDX-License-Identifier: Apache-2.0 ++ ++use vmm_sys_util::fam::{FamStruct, FamStructWrapper}; ++ ++use riscv64::bindings::*; ++ ++// There is no constant in the kernel as far as the maximum number ++// of registers on RISC-V, but KVM_GET_REG_LIST usually returns around 160. ++const RISCV64_REGS_MAX: usize = 200; ++ ++// Implement the FamStruct trait for kvm_reg_list. ++generate_fam_struct_impl!(kvm_reg_list, u64, reg, u64, n, RISCV64_REGS_MAX); ++ ++// Implement the PartialEq trait for kvm_reg_list. ++impl PartialEq for kvm_reg_list { ++ fn eq(&self, other: &kvm_reg_list) -> bool { ++ // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you ++ self.n == other.n ++ } ++} ++ ++/// Wrapper over the `kvm_reg_list` structure. ++/// ++/// The `kvm_reg_list` structure contains a flexible array member. For details check the ++/// [KVM API KVM_GET_REG_LIST](https://docs.kernel.org/virt/kvm/api.html#kvm-get-reg-list) ++/// documentation. To provide safe access to the array elements, this type is ++/// implemented using [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). ++pub type RegList = FamStructWrapper; ++ ++#[cfg(test)] ++mod tests { ++ use super::RegList; ++ ++ #[test] ++ fn test_reg_list_eq() { ++ let mut wrapper = RegList::new(1).unwrap(); ++ assert_eq!(wrapper.as_slice().len(), 1); ++ ++ let mut wrapper2 = wrapper.clone(); ++ assert!(wrapper == wrapper2); ++ ++ wrapper.as_mut_slice()[0] = 1; ++ assert!(wrapper != wrapper2); ++ wrapper2.as_mut_slice()[0] = 1; ++ assert!(wrapper == wrapper2); ++ } ++} +diff --git a/vendor/kvm-bindings/src/x86/mod.rs b/vendor/kvm-bindings/src/riscv64/mod.rs +similarity index 73% +rename from vendor/kvm-bindings/src/x86/mod.rs +rename to vendor/kvm-bindings/src/riscv64/mod.rs +index 0a71400..bef3baf 100644 +--- a/vendor/kvm-bindings/src/x86/mod.rs ++++ b/vendor/kvm-bindings/src/riscv64/mod.rs +@@ -1,13 +1,16 @@ ++// Copyright 2024 © Institute of Software, CAS. All rights reserved. + // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + // SPDX-License-Identifier: Apache-2.0 +-#[allow(clippy::undocumented_unsafe_blocks)] ++ + #[allow(clippy::all)] +-// Keep this until https://github.com/rust-lang/rust-bindgen/issues/1651 is fixed. +-#[cfg_attr(test, allow(deref_nullptr))] ++#[allow(clippy::undocumented_unsafe_blocks)] + pub mod bindings; + #[cfg(feature = "fam-wrappers")] + pub mod fam_wrappers; + ++#[cfg(feature = "serde")] ++mod serialize; ++ + pub use self::bindings::*; + #[cfg(feature = "fam-wrappers")] + pub use self::fam_wrappers::*; +diff --git a/vendor/kvm-bindings/src/riscv64/serialize.rs b/vendor/kvm-bindings/src/riscv64/serialize.rs +new file mode 100644 +index 0000000..791d24b +--- /dev/null ++++ b/vendor/kvm-bindings/src/riscv64/serialize.rs +@@ -0,0 +1,96 @@ ++// Copyright 2024 © Institute of Software, CAS. All rights reserved. ++// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. ++// SPDX-License-Identifier: Apache-2.0 ++ ++use bindings::{ ++ kvm_mp_state, kvm_one_reg, kvm_riscv_aia_csr, kvm_riscv_config, kvm_riscv_core, kvm_riscv_csr, ++ kvm_riscv_sbi_sta, kvm_riscv_smstateen_csr, kvm_riscv_timer, user_regs_struct, ++}; ++use serde::{Deserialize, Deserializer, Serialize, Serializer}; ++use zerocopy::{transmute, AsBytes}; ++ ++serde_impls! { ++ kvm_mp_state, ++ kvm_one_reg, ++ kvm_riscv_config, ++ kvm_riscv_core, ++ user_regs_struct, ++ kvm_riscv_csr, ++ kvm_riscv_aia_csr, ++ kvm_riscv_smstateen_csr, ++ kvm_riscv_timer, ++ kvm_riscv_sbi_sta ++} ++ ++#[cfg(test)] ++mod tests { ++ use bindings::*; ++ use serde::{Deserialize, Serialize}; ++ ++ fn is_serde Deserialize<'de> + Default>() { ++ let serialized = bincode::serialize(&T::default()).unwrap(); ++ let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); ++ let serialized_again = bincode::serialize(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn static_assert_serde_implementations() { ++ // This test statically (= at compile-time) asserts that various bindgen generated ++ // structures implement serde's `Serialize` and `Deserialize` traits. ++ // This is to make sure that we do not accidentally remove those implementations ++ // when regenerating bindings. If this test fails to compile, please add ++ // ++ // #[cfg_attr( ++ // feature = "serde", ++ // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++ // )] ++ // ++ // to all structures causing compilation errors (we need the zerocopy traits, as the ++ // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro ++ // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` ++ // traits that it expects to be derived). ++ // ++ // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types ++ // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across ++ // bindgen versions. If after re-adding the derives to all the below items you can compile ++ // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add ++ // the derives to all anonymous types references in the definitions of the below items. ++ ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ } ++ ++ fn is_serde_json Deserialize<'de> + Default>() { ++ let serialized = serde_json::to_string(&T::default()).unwrap(); ++ let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); ++ let serialized_again = serde_json::to_string(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn test_json_serde() { ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ } ++} +diff --git a/vendor/kvm-bindings/src/serialize.rs b/vendor/kvm-bindings/src/serialize.rs +new file mode 100644 +index 0000000..75c6851 +--- /dev/null ++++ b/vendor/kvm-bindings/src/serialize.rs +@@ -0,0 +1,66 @@ ++// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. ++// SPDX-License-Identifier: Apache-2.0 ++//! Module containing serialization utilities ++ ++/// Macro that generates serde::Serialize and serde::Deserialize implementations for the given types. ++/// This macro assumes that the types implement zerocopy::FromBytes and zerocopy::AsBytes, and uses ++/// these implementations to serialize as opaque byte arrays. During deserialization, it will ++/// try to deserialize as a `Vec`. If this deserialized `Vec` has a length that equals `size_of::`, ++/// it will transmute to `T` (using zerocopy), otherwise the `Vec` will either be zero-padded, or truncated. ++/// This will hopefully allow live update of bindings across kernel versions even if the kernel adds ++/// new fields to the end of some struct (we heavily rely on the kernel not making ABI breaking changes here). ++macro_rules! serde_impls { ++ ($($typ: ty),*) => { ++ $( ++ impl Serialize for $typ { ++ fn serialize(&self, serializer: S) -> Result ++ where ++ S: Serializer ++ { ++ let bytes = self.as_bytes(); ++ serializer.serialize_bytes(bytes) ++ } ++ } ++ ++ impl<'de> Deserialize<'de> for $typ { ++ fn deserialize(deserializer: D) -> Result ++ where ++ D: Deserializer<'de> ++ { ++ struct BytesVisitor; ++ ++ impl<'a> serde::de::Visitor<'a> for BytesVisitor { ++ type Value = [u8; std::mem::size_of::<$typ>()]; ++ ++ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { ++ formatter.write_str("a byte array") ++ } ++ ++ fn visit_bytes(self, bytes: &[u8]) -> Result { ++ let mut backing = [0u8; std::mem::size_of::<$typ>()]; ++ let limit = bytes.len().min(backing.len()); ++ backing[..limit].copy_from_slice(&bytes[..limit]); ++ Ok(backing) ++ } ++ ++ fn visit_seq>(self, mut seq: A) -> Result { ++ let mut backing = [0u8; std::mem::size_of::<$typ>()]; ++ ++ for backing_byte in &mut backing { ++ let Some(byte) = seq.next_element()? else { break }; ++ ++ *backing_byte = byte; ++ } ++ ++ Ok(backing) ++ } ++ } ++ ++ let backing = deserializer.deserialize_bytes(BytesVisitor)?; ++ ++ Ok(transmute!(backing)) ++ } ++ } ++ )* ++ } ++} +diff --git a/vendor/kvm-bindings/src/x86/bindings.rs b/vendor/kvm-bindings/src/x86_64/bindings.rs +similarity index 66% +rename from vendor/kvm-bindings/src/x86/bindings.rs +rename to vendor/kvm-bindings/src/x86_64/bindings.rs +index 2c0d210..c36cd40 100644 +--- a/vendor/kvm-bindings/src/x86/bindings.rs ++++ b/vendor/kvm-bindings/src/x86_64/bindings.rs +@@ -1,7 +1,11 @@ +-/* automatically generated by rust-bindgen 0.59.1 */ ++/* automatically generated by rust-bindgen 0.64.0 */ + +-#[repr(C)] ++#[repr(transparent)] + #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct __BindgenBitfieldUnit { + storage: Storage, + } +@@ -80,8 +84,12 @@ where + } + } + } +-#[repr(C)] ++#[repr(transparent)] + #[derive(Default)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); + impl __IncompleteArrayField { + #[inline] +@@ -154,6 +162,7 @@ impl ::std::cmp::PartialEq for __BindgenUnionField { + } + impl ::std::cmp::Eq for __BindgenUnionField {} + pub const __BITS_PER_LONG: u32 = 64; ++pub const __BITS_PER_LONG_LONG: u32 = 64; + pub const __FD_SETSIZE: u32 = 1024; + pub const _IOC_NRBITS: u32 = 8; + pub const _IOC_TYPEBITS: u32 = 8; +@@ -205,12 +214,15 @@ pub const KVM_NR_IRQCHIPS: u32 = 3; + pub const KVM_RUN_X86_SMM: u32 = 1; + pub const KVM_RUN_X86_BUS_LOCK: u32 = 2; + pub const KVM_APIC_REG_SIZE: u32 = 1024; ++pub const KVM_SREGS2_FLAGS_PDPTRS_VALID: u32 = 1; + pub const KVM_MSR_FILTER_MAX_BITMAP_SIZE: u32 = 1536; + pub const KVM_MSR_FILTER_READ: u32 = 1; + pub const KVM_MSR_FILTER_WRITE: u32 = 2; ++pub const KVM_MSR_FILTER_RANGE_VALID_MASK: u32 = 3; + pub const KVM_MSR_FILTER_MAX_RANGES: u32 = 16; + pub const KVM_MSR_FILTER_DEFAULT_ALLOW: u32 = 0; + pub const KVM_MSR_FILTER_DEFAULT_DENY: u32 = 1; ++pub const KVM_MSR_FILTER_VALID_MASK: u32 = 1; + pub const KVM_CPUID_FLAG_SIGNIFCANT_INDEX: u32 = 1; + pub const KVM_CPUID_FLAG_STATEFUL_FUNC: u32 = 2; + pub const KVM_CPUID_FLAG_STATE_READ_NEXT: u32 = 4; +@@ -218,12 +230,15 @@ pub const KVM_GUESTDBG_USE_SW_BP: u32 = 65536; + pub const KVM_GUESTDBG_USE_HW_BP: u32 = 131072; + pub const KVM_GUESTDBG_INJECT_DB: u32 = 262144; + pub const KVM_GUESTDBG_INJECT_BP: u32 = 524288; ++pub const KVM_GUESTDBG_BLOCKIRQ: u32 = 1048576; + pub const KVM_PIT_FLAGS_HPET_LEGACY: u32 = 1; ++pub const KVM_PIT_FLAGS_SPEAKER_DATA_ON: u32 = 2; + pub const KVM_VCPUEVENT_VALID_NMI_PENDING: u32 = 1; + pub const KVM_VCPUEVENT_VALID_SIPI_VECTOR: u32 = 2; + pub const KVM_VCPUEVENT_VALID_SHADOW: u32 = 4; + pub const KVM_VCPUEVENT_VALID_SMM: u32 = 8; + pub const KVM_VCPUEVENT_VALID_PAYLOAD: u32 = 16; ++pub const KVM_VCPUEVENT_VALID_TRIPLE_FAULT: u32 = 32; + pub const KVM_X86_SHADOW_INT_MOV_SS: u32 = 1; + pub const KVM_X86_SHADOW_INT_STI: u32 = 2; + pub const KVM_MAX_XCRS: u32 = 16; +@@ -236,6 +251,8 @@ pub const KVM_X86_QUIRK_CD_NW_CLEARED: u32 = 2; + pub const KVM_X86_QUIRK_LAPIC_MMIO_HOLE: u32 = 4; + pub const KVM_X86_QUIRK_OUT_7E_INC_RIP: u32 = 8; + pub const KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT: u32 = 16; ++pub const KVM_X86_QUIRK_FIX_HYPERCALL_INSN: u32 = 32; ++pub const KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS: u32 = 64; + pub const KVM_STATE_NESTED_FORMAT_VMX: u32 = 0; + pub const KVM_STATE_NESTED_FORMAT_SVM: u32 = 1; + pub const KVM_STATE_NESTED_GUEST_MODE: u32 = 1; +@@ -248,46 +265,52 @@ pub const KVM_STATE_NESTED_SMM_VMXON: u32 = 2; + pub const KVM_STATE_NESTED_VMX_VMCS_SIZE: u32 = 4096; + pub const KVM_STATE_NESTED_SVM_VMCB_SIZE: u32 = 4096; + pub const KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE: u32 = 1; ++pub const KVM_X86_XCOMP_GUEST_SUPP: u32 = 0; + pub const KVM_PMU_EVENT_ALLOW: u32 = 0; + pub const KVM_PMU_EVENT_DENY: u32 = 1; ++pub const KVM_XEN_HVM_CONFIG_HYPERCALL_MSR: u32 = 1; ++pub const KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL: u32 = 2; ++pub const KVM_XEN_HVM_CONFIG_SHARED_INFO: u32 = 4; ++pub const KVM_XEN_HVM_CONFIG_RUNSTATE: u32 = 8; ++pub const KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL: u32 = 16; ++pub const KVM_XEN_HVM_CONFIG_EVTCHN_SEND: u32 = 32; ++pub const KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG: u32 = 64; ++pub const KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE: u32 = 128; ++pub const KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA: u32 = 256; ++pub const KVM_XEN_EVTCHN_DEASSIGN: u32 = 1; ++pub const KVM_XEN_EVTCHN_UPDATE: u32 = 2; ++pub const KVM_XEN_EVTCHN_RESET: u32 = 4; ++pub const KVM_XEN_ATTR_TYPE_LONG_MODE: u32 = 0; ++pub const KVM_XEN_ATTR_TYPE_SHARED_INFO: u32 = 1; ++pub const KVM_XEN_ATTR_TYPE_UPCALL_VECTOR: u32 = 2; ++pub const KVM_XEN_ATTR_TYPE_EVTCHN: u32 = 3; ++pub const KVM_XEN_ATTR_TYPE_XEN_VERSION: u32 = 4; ++pub const KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG: u32 = 5; ++pub const KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA: u32 = 6; ++pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO: u32 = 0; ++pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: u32 = 1; ++pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR: u32 = 2; ++pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: u32 = 3; ++pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA: u32 = 4; ++pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST: u32 = 5; ++pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID: u32 = 6; ++pub const KVM_XEN_VCPU_ATTR_TYPE_TIMER: u32 = 7; ++pub const KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR: u32 = 8; ++pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA: u32 = 9; ++pub const KVM_X2APIC_API_USE_32BIT_IDS: u32 = 1; ++pub const KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK: u32 = 2; ++pub const KVM_HYPERV_CONN_ID_MASK: u32 = 16777215; ++pub const KVM_HYPERV_EVENTFD_DEASSIGN: u32 = 1; ++pub const KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT: u32 = 56; ++pub const KVM_VCPU_TSC_CTRL: u32 = 0; ++pub const KVM_VCPU_TSC_OFFSET: u32 = 0; ++pub const KVM_X86_DEFAULT_VM: u32 = 0; ++pub const KVM_X86_SW_PROTECTED_VM: u32 = 1; + pub const KVM_API_VERSION: u32 = 12; +-pub const KVM_TRC_SHIFT: u32 = 16; +-pub const KVM_TRC_ENTRYEXIT: u32 = 65536; +-pub const KVM_TRC_HANDLER: u32 = 131072; +-pub const KVM_TRC_VMENTRY: u32 = 65537; +-pub const KVM_TRC_VMEXIT: u32 = 65538; +-pub const KVM_TRC_PAGE_FAULT: u32 = 131073; +-pub const KVM_TRC_HEAD_SIZE: u32 = 12; +-pub const KVM_TRC_CYCLE_SIZE: u32 = 8; +-pub const KVM_TRC_EXTRA_MAX: u32 = 7; +-pub const KVM_TRC_INJ_VIRQ: u32 = 131074; +-pub const KVM_TRC_REDELIVER_EVT: u32 = 131075; +-pub const KVM_TRC_PEND_INTR: u32 = 131076; +-pub const KVM_TRC_IO_READ: u32 = 131077; +-pub const KVM_TRC_IO_WRITE: u32 = 131078; +-pub const KVM_TRC_CR_READ: u32 = 131079; +-pub const KVM_TRC_CR_WRITE: u32 = 131080; +-pub const KVM_TRC_DR_READ: u32 = 131081; +-pub const KVM_TRC_DR_WRITE: u32 = 131082; +-pub const KVM_TRC_MSR_READ: u32 = 131083; +-pub const KVM_TRC_MSR_WRITE: u32 = 131084; +-pub const KVM_TRC_CPUID: u32 = 131085; +-pub const KVM_TRC_INTR: u32 = 131086; +-pub const KVM_TRC_NMI: u32 = 131087; +-pub const KVM_TRC_VMMCALL: u32 = 131088; +-pub const KVM_TRC_HLT: u32 = 131089; +-pub const KVM_TRC_CLTS: u32 = 131090; +-pub const KVM_TRC_LMSW: u32 = 131091; +-pub const KVM_TRC_APIC_ACCESS: u32 = 131092; +-pub const KVM_TRC_TDP_FAULT: u32 = 131093; +-pub const KVM_TRC_GTLB_WRITE: u32 = 131094; +-pub const KVM_TRC_STLB_WRITE: u32 = 131095; +-pub const KVM_TRC_STLB_INVAL: u32 = 131096; +-pub const KVM_TRC_PPC_INSTR: u32 = 131097; + pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1; + pub const KVM_MEM_READONLY: u32 = 2; ++pub const KVM_MEM_GUEST_MEMFD: u32 = 4; + pub const KVM_PIT_SPEAKER_DUMMY: u32 = 1; +-pub const KVM_S390_CMMA_PEEK: u32 = 1; + pub const KVM_EXIT_HYPERV_SYNIC: u32 = 1; + pub const KVM_EXIT_HYPERV_HCALL: u32 = 2; + pub const KVM_EXIT_HYPERV_SYNDBG: u32 = 3; +@@ -329,30 +352,31 @@ pub const KVM_EXIT_DIRTY_RING_FULL: u32 = 31; + pub const KVM_EXIT_AP_RESET_HOLD: u32 = 32; + pub const KVM_EXIT_X86_BUS_LOCK: u32 = 33; + pub const KVM_EXIT_XEN: u32 = 34; ++pub const KVM_EXIT_RISCV_SBI: u32 = 35; ++pub const KVM_EXIT_RISCV_CSR: u32 = 36; ++pub const KVM_EXIT_NOTIFY: u32 = 37; ++pub const KVM_EXIT_LOONGARCH_IOCSR: u32 = 38; ++pub const KVM_EXIT_MEMORY_FAULT: u32 = 39; + pub const KVM_INTERNAL_ERROR_EMULATION: u32 = 1; + pub const KVM_INTERNAL_ERROR_SIMUL_EX: u32 = 2; + pub const KVM_INTERNAL_ERROR_DELIVERY_EV: u32 = 3; + pub const KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON: u32 = 4; ++pub const KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES: u32 = 1; + pub const KVM_EXIT_IO_IN: u32 = 0; + pub const KVM_EXIT_IO_OUT: u32 = 1; +-pub const KVM_S390_RESET_POR: u32 = 1; +-pub const KVM_S390_RESET_CLEAR: u32 = 2; +-pub const KVM_S390_RESET_SUBSYSTEM: u32 = 4; +-pub const KVM_S390_RESET_CPU_INIT: u32 = 8; +-pub const KVM_S390_RESET_IPL: u32 = 16; + pub const KVM_SYSTEM_EVENT_SHUTDOWN: u32 = 1; + pub const KVM_SYSTEM_EVENT_RESET: u32 = 2; + pub const KVM_SYSTEM_EVENT_CRASH: u32 = 3; ++pub const KVM_SYSTEM_EVENT_WAKEUP: u32 = 4; ++pub const KVM_SYSTEM_EVENT_SUSPEND: u32 = 5; ++pub const KVM_SYSTEM_EVENT_SEV_TERM: u32 = 6; + pub const KVM_MSR_EXIT_REASON_INVAL: u32 = 1; + pub const KVM_MSR_EXIT_REASON_UNKNOWN: u32 = 2; + pub const KVM_MSR_EXIT_REASON_FILTER: u32 = 4; ++pub const KVM_MSR_EXIT_REASON_VALID_MASK: u32 = 7; ++pub const KVM_NOTIFY_CONTEXT_INVALID: u32 = 1; ++pub const KVM_MEMORY_EXIT_FLAG_PRIVATE: u32 = 8; + pub const SYNC_REGS_SIZE_BYTES: u32 = 2048; +-pub const KVM_S390_MEMOP_LOGICAL_READ: u32 = 0; +-pub const KVM_S390_MEMOP_LOGICAL_WRITE: u32 = 1; +-pub const KVM_S390_MEMOP_SIDA_READ: u32 = 2; +-pub const KVM_S390_MEMOP_SIDA_WRITE: u32 = 3; +-pub const KVM_S390_MEMOP_F_CHECK_ONLY: u32 = 1; +-pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: u32 = 2; + pub const KVM_MP_STATE_RUNNABLE: u32 = 0; + pub const KVM_MP_STATE_UNINITIALIZED: u32 = 1; + pub const KVM_MP_STATE_INIT_RECEIVED: u32 = 2; +@@ -363,28 +387,7 @@ pub const KVM_MP_STATE_CHECK_STOP: u32 = 6; + pub const KVM_MP_STATE_OPERATING: u32 = 7; + pub const KVM_MP_STATE_LOAD: u32 = 8; + pub const KVM_MP_STATE_AP_RESET_HOLD: u32 = 9; +-pub const KVM_S390_SIGP_STOP: u32 = 4294836224; +-pub const KVM_S390_PROGRAM_INT: u32 = 4294836225; +-pub const KVM_S390_SIGP_SET_PREFIX: u32 = 4294836226; +-pub const KVM_S390_RESTART: u32 = 4294836227; +-pub const KVM_S390_INT_PFAULT_INIT: u32 = 4294836228; +-pub const KVM_S390_INT_PFAULT_DONE: u32 = 4294836229; +-pub const KVM_S390_MCHK: u32 = 4294840320; +-pub const KVM_S390_INT_CLOCK_COMP: u32 = 4294905860; +-pub const KVM_S390_INT_CPU_TIMER: u32 = 4294905861; +-pub const KVM_S390_INT_VIRTIO: u32 = 4294911491; +-pub const KVM_S390_INT_SERVICE: u32 = 4294910977; +-pub const KVM_S390_INT_EMERGENCY: u32 = 4294906369; +-pub const KVM_S390_INT_EXTERNAL_CALL: u32 = 4294906370; +-pub const KVM_S390_INT_IO_MIN: u32 = 0; +-pub const KVM_S390_INT_IO_MAX: u32 = 4294836223; +-pub const KVM_S390_INT_IO_AI_MASK: u32 = 67108864; +-pub const KVM_S390_PGM_FLAGS_ILC_VALID: u32 = 1; +-pub const KVM_S390_PGM_FLAGS_ILC_0: u32 = 2; +-pub const KVM_S390_PGM_FLAGS_ILC_1: u32 = 4; +-pub const KVM_S390_PGM_FLAGS_ILC_MASK: u32 = 6; +-pub const KVM_S390_PGM_FLAGS_NO_REWIND: u32 = 8; +-pub const KVM_S390_STOP_FLAG_STORE_STATUS: u32 = 1; ++pub const KVM_MP_STATE_SUSPENDED: u32 = 10; + pub const KVM_GUESTDBG_ENABLE: u32 = 1; + pub const KVM_GUESTDBG_SINGLESTEP: u32 = 2; + pub const KVM_X86_DISABLE_EXITS_MWAIT: u32 = 1; +@@ -392,11 +395,6 @@ pub const KVM_X86_DISABLE_EXITS_HLT: u32 = 2; + pub const KVM_X86_DISABLE_EXITS_PAUSE: u32 = 4; + pub const KVM_X86_DISABLE_EXITS_CSTATE: u32 = 8; + pub const KVM_X86_DISABLE_VALID_EXITS: u32 = 15; +-pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: u32 = 1; +-pub const KVM_PPC_PAGE_SIZES_MAX_SZ: u32 = 8; +-pub const KVM_PPC_PAGE_SIZES_REAL: u32 = 1; +-pub const KVM_PPC_1T_SEGMENTS: u32 = 2; +-pub const KVM_PPC_NO_HASH: u32 = 4; + pub const KVMIO: u32 = 174; + pub const KVM_VM_S390_UCONTROL: u32 = 1; + pub const KVM_VM_PPC_HV: u32 = 1; +@@ -599,17 +597,53 @@ pub const KVM_CAP_SET_GUEST_DEBUG2: u32 = 195; + pub const KVM_CAP_SGX_ATTRIBUTE: u32 = 196; + pub const KVM_CAP_VM_COPY_ENC_CONTEXT_FROM: u32 = 197; + pub const KVM_CAP_PTP_KVM: u32 = 198; ++pub const KVM_CAP_HYPERV_ENFORCE_CPUID: u32 = 199; ++pub const KVM_CAP_SREGS2: u32 = 200; ++pub const KVM_CAP_EXIT_HYPERCALL: u32 = 201; ++pub const KVM_CAP_PPC_RPT_INVALIDATE: u32 = 202; ++pub const KVM_CAP_BINARY_STATS_FD: u32 = 203; ++pub const KVM_CAP_EXIT_ON_EMULATION_FAILURE: u32 = 204; ++pub const KVM_CAP_ARM_MTE: u32 = 205; ++pub const KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM: u32 = 206; ++pub const KVM_CAP_VM_GPA_BITS: u32 = 207; ++pub const KVM_CAP_XSAVE2: u32 = 208; ++pub const KVM_CAP_SYS_ATTRIBUTES: u32 = 209; ++pub const KVM_CAP_PPC_AIL_MODE_3: u32 = 210; ++pub const KVM_CAP_S390_MEM_OP_EXTENSION: u32 = 211; ++pub const KVM_CAP_PMU_CAPABILITY: u32 = 212; ++pub const KVM_CAP_DISABLE_QUIRKS2: u32 = 213; ++pub const KVM_CAP_VM_TSC_CONTROL: u32 = 214; ++pub const KVM_CAP_SYSTEM_EVENT_DATA: u32 = 215; ++pub const KVM_CAP_ARM_SYSTEM_SUSPEND: u32 = 216; ++pub const KVM_CAP_S390_PROTECTED_DUMP: u32 = 217; ++pub const KVM_CAP_X86_TRIPLE_FAULT_EVENT: u32 = 218; ++pub const KVM_CAP_X86_NOTIFY_VMEXIT: u32 = 219; ++pub const KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: u32 = 220; ++pub const KVM_CAP_S390_ZPCI_OP: u32 = 221; ++pub const KVM_CAP_S390_CPU_TOPOLOGY: u32 = 222; ++pub const KVM_CAP_DIRTY_LOG_RING_ACQ_REL: u32 = 223; ++pub const KVM_CAP_S390_PROTECTED_ASYNC_DISABLE: u32 = 224; ++pub const KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP: u32 = 225; ++pub const KVM_CAP_PMU_EVENT_MASKED_EVENTS: u32 = 226; ++pub const KVM_CAP_COUNTER_OFFSET: u32 = 227; ++pub const KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE: u32 = 228; ++pub const KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES: u32 = 229; ++pub const KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES: u32 = 230; ++pub const KVM_CAP_USER_MEMORY2: u32 = 231; ++pub const KVM_CAP_MEMORY_FAULT_INFO: u32 = 232; ++pub const KVM_CAP_MEMORY_ATTRIBUTES: u32 = 233; ++pub const KVM_CAP_GUEST_MEMFD: u32 = 234; ++pub const KVM_CAP_VM_TYPES: u32 = 235; + pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1; + pub const KVM_IRQ_ROUTING_MSI: u32 = 2; + pub const KVM_IRQ_ROUTING_S390_ADAPTER: u32 = 3; + pub const KVM_IRQ_ROUTING_HV_SINT: u32 = 4; +-pub const KVM_XEN_HVM_CONFIG_HYPERCALL_MSR: u32 = 1; +-pub const KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL: u32 = 2; +-pub const KVM_XEN_HVM_CONFIG_SHARED_INFO: u32 = 4; +-pub const KVM_XEN_HVM_CONFIG_RUNSTATE: u32 = 8; ++pub const KVM_IRQ_ROUTING_XEN_EVTCHN: u32 = 5; + pub const KVM_IRQFD_FLAG_DEASSIGN: u32 = 1; + pub const KVM_IRQFD_FLAG_RESAMPLE: u32 = 2; + pub const KVM_CLOCK_TSC_STABLE: u32 = 2; ++pub const KVM_CLOCK_REALTIME: u32 = 4; ++pub const KVM_CLOCK_HOST_TSC: u32 = 8; + pub const KVM_MMU_FSL_BOOKE_NOHV: u32 = 0; + pub const KVM_MMU_FSL_BOOKE_HV: u32 = 1; + pub const KVM_REG_ARCH_MASK: i64 = -72057594037927936; +@@ -622,6 +656,7 @@ pub const KVM_REG_S390: u64 = 5764607523034234880; + pub const KVM_REG_ARM64: u64 = 6917529027641081856; + pub const KVM_REG_MIPS: u64 = 8070450532247928832; + pub const KVM_REG_RISCV: i64 = -9223372036854775808; ++pub const KVM_REG_LOONGARCH: i64 = -8070450532247928832; + pub const KVM_REG_SIZE_SHIFT: u32 = 52; + pub const KVM_REG_SIZE_MASK: u64 = 67553994410557440; + pub const KVM_REG_SIZE_U8: u32 = 0; +@@ -635,45 +670,45 @@ pub const KVM_REG_SIZE_U1024: u64 = 31525197391593472; + pub const KVM_REG_SIZE_U2048: u64 = 36028797018963968; + pub const KVM_MSI_VALID_DEVID: u32 = 1; + pub const KVM_CREATE_DEVICE_TEST: u32 = 1; ++pub const KVM_DEV_VFIO_FILE: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_ADD: u32 = 1; ++pub const KVM_DEV_VFIO_FILE_DEL: u32 = 2; + pub const KVM_DEV_VFIO_GROUP: u32 = 1; + pub const KVM_DEV_VFIO_GROUP_ADD: u32 = 1; + pub const KVM_DEV_VFIO_GROUP_DEL: u32 = 2; + pub const KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: u32 = 3; + pub const KVM_S390_STORE_STATUS_NOADDR: i32 = -1; + pub const KVM_S390_STORE_STATUS_PREFIXED: i32 = -2; +-pub const KVM_XEN_ATTR_TYPE_LONG_MODE: u32 = 0; +-pub const KVM_XEN_ATTR_TYPE_SHARED_INFO: u32 = 1; +-pub const KVM_XEN_ATTR_TYPE_UPCALL_VECTOR: u32 = 2; +-pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO: u32 = 0; +-pub const KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: u32 = 1; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR: u32 = 2; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: u32 = 3; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA: u32 = 4; +-pub const KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST: u32 = 5; +-pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: u32 = 1; +-pub const KVM_DEV_ASSIGN_PCI_2_3: u32 = 2; +-pub const KVM_DEV_ASSIGN_MASK_INTX: u32 = 4; +-pub const KVM_DEV_IRQ_HOST_INTX: u32 = 1; +-pub const KVM_DEV_IRQ_HOST_MSI: u32 = 2; +-pub const KVM_DEV_IRQ_HOST_MSIX: u32 = 4; +-pub const KVM_DEV_IRQ_GUEST_INTX: u32 = 256; +-pub const KVM_DEV_IRQ_GUEST_MSI: u32 = 512; +-pub const KVM_DEV_IRQ_GUEST_MSIX: u32 = 1024; +-pub const KVM_DEV_IRQ_HOST_MASK: u32 = 255; +-pub const KVM_DEV_IRQ_GUEST_MASK: u32 = 65280; +-pub const KVM_MAX_MSIX_PER_DEV: u32 = 256; +-pub const KVM_X2APIC_API_USE_32BIT_IDS: u32 = 1; +-pub const KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK: u32 = 2; +-pub const KVM_ARM_DEV_EL1_VTIMER: u32 = 1; +-pub const KVM_ARM_DEV_EL1_PTIMER: u32 = 2; +-pub const KVM_ARM_DEV_PMU: u32 = 4; +-pub const KVM_HYPERV_CONN_ID_MASK: u32 = 16777215; +-pub const KVM_HYPERV_EVENTFD_DEASSIGN: u32 = 1; + pub const KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE: u32 = 1; + pub const KVM_DIRTY_LOG_INITIALLY_SET: u32 = 2; + pub const KVM_DIRTY_GFN_F_MASK: u32 = 3; + pub const KVM_BUS_LOCK_DETECTION_OFF: u32 = 1; + pub const KVM_BUS_LOCK_DETECTION_EXIT: u32 = 2; ++pub const KVM_PMU_CAP_DISABLE: u32 = 1; ++pub const KVM_STATS_TYPE_SHIFT: u32 = 0; ++pub const KVM_STATS_TYPE_MASK: u32 = 15; ++pub const KVM_STATS_TYPE_CUMULATIVE: u32 = 0; ++pub const KVM_STATS_TYPE_INSTANT: u32 = 1; ++pub const KVM_STATS_TYPE_PEAK: u32 = 2; ++pub const KVM_STATS_TYPE_LINEAR_HIST: u32 = 3; ++pub const KVM_STATS_TYPE_LOG_HIST: u32 = 4; ++pub const KVM_STATS_TYPE_MAX: u32 = 4; ++pub const KVM_STATS_UNIT_SHIFT: u32 = 4; ++pub const KVM_STATS_UNIT_MASK: u32 = 240; ++pub const KVM_STATS_UNIT_NONE: u32 = 0; ++pub const KVM_STATS_UNIT_BYTES: u32 = 16; ++pub const KVM_STATS_UNIT_SECONDS: u32 = 32; ++pub const KVM_STATS_UNIT_CYCLES: u32 = 48; ++pub const KVM_STATS_UNIT_BOOLEAN: u32 = 64; ++pub const KVM_STATS_UNIT_MAX: u32 = 64; ++pub const KVM_STATS_BASE_SHIFT: u32 = 8; ++pub const KVM_STATS_BASE_MASK: u32 = 3840; ++pub const KVM_STATS_BASE_POW10: u32 = 0; ++pub const KVM_STATS_BASE_POW2: u32 = 256; ++pub const KVM_STATS_BASE_MAX: u32 = 256; ++pub const KVM_X86_NOTIFY_VMEXIT_ENABLED: u32 = 1; ++pub const KVM_X86_NOTIFY_VMEXIT_USER: u32 = 2; ++pub const KVM_MEMORY_ATTRIBUTE_PRIVATE: u32 = 8; + pub type __s8 = ::std::os::raw::c_schar; + pub type __u8 = ::std::os::raw::c_uchar; + pub type __s16 = ::std::os::raw::c_short; +@@ -689,6 +724,8 @@ pub struct __kernel_fd_set { + } + #[test] + fn bindgen_test_layout___kernel_fd_set() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fd_set> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__kernel_fd_set>(), + 128usize, +@@ -700,7 +737,7 @@ fn bindgen_test_layout___kernel_fd_set() { + concat!("Alignment of ", stringify!(__kernel_fd_set)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -739,6 +776,8 @@ pub struct __kernel_fsid_t { + } + #[test] + fn bindgen_test_layout___kernel_fsid_t() { ++ const UNINIT: ::std::mem::MaybeUninit<__kernel_fsid_t> = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__kernel_fsid_t>(), + 8usize, +@@ -750,7 +789,7 @@ fn bindgen_test_layout___kernel_fsid_t() { + concat!("Alignment of ", stringify!(__kernel_fsid_t)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -771,6 +810,8 @@ pub type __kernel_clockid_t = ::std::os::raw::c_int; + pub type __kernel_caddr_t = *mut ::std::os::raw::c_char; + pub type __kernel_uid16_t = ::std::os::raw::c_ushort; + pub type __kernel_gid16_t = ::std::os::raw::c_ushort; ++pub type __s128 = i128; ++pub type __u128 = u128; + pub type __le16 = __u16; + pub type __be16 = __u16; + pub type __le32 = __u32; +@@ -782,82 +823,10 @@ pub type __wsum = __u32; + pub type __poll_t = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_memory_alias { +- pub slot: __u32, +- pub flags: __u32, +- pub guest_phys_addr: __u64, +- pub memory_size: __u64, +- pub target_phys_addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_memory_alias() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_memory_alias)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_memory_alias)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_alias), +- "::", +- stringify!(slot) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_alias), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_phys_addr as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_alias), +- "::", +- stringify!(guest_phys_addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).memory_size as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_alias), +- "::", +- stringify!(memory_size) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).target_phys_addr as *const _ as usize +- }, +- 24usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_memory_alias), +- "::", +- stringify!(target_phys_addr) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_pic_state { + pub last_irr: __u8, + pub irr: __u8, +@@ -878,6 +847,8 @@ pub struct kvm_pic_state { + } + #[test] + fn bindgen_test_layout_kvm_pic_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -889,7 +860,7 @@ fn bindgen_test_layout_kvm_pic_state() { + concat!("Alignment of ", stringify!(kvm_pic_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last_irr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).last_irr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -899,7 +870,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irr) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -909,7 +880,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).imr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).imr) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -919,7 +890,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).isr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).isr) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -929,7 +900,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).priority_add as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).priority_add) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -939,7 +910,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irq_base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irq_base) as usize - ptr as usize }, + 5usize, + concat!( + "Offset of field: ", +@@ -949,7 +920,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).read_reg_select as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).read_reg_select) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", +@@ -959,7 +930,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).poll as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).poll) as usize - ptr as usize }, + 7usize, + concat!( + "Offset of field: ", +@@ -969,7 +940,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).special_mask as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).special_mask) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -979,7 +950,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).init_state as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).init_state) as usize - ptr as usize }, + 9usize, + concat!( + "Offset of field: ", +@@ -989,7 +960,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).auto_eoi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).auto_eoi) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", +@@ -999,9 +970,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).rotate_on_auto_eoi as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rotate_on_auto_eoi) as usize - ptr as usize }, + 11usize, + concat!( + "Offset of field: ", +@@ -1011,9 +980,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).special_fully_nested_mode as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).special_fully_nested_mode) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -1023,7 +990,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).init4 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).init4) as usize - ptr as usize }, + 13usize, + concat!( + "Offset of field: ", +@@ -1033,7 +1000,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).elcr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).elcr) as usize - ptr as usize }, + 14usize, + concat!( + "Offset of field: ", +@@ -1043,7 +1010,7 @@ fn bindgen_test_layout_kvm_pic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).elcr_mask as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).elcr_mask) as usize - ptr as usize }, + 15usize, + concat!( + "Offset of field: ", +@@ -1055,6 +1022,10 @@ fn bindgen_test_layout_kvm_pic_state() { + } + #[repr(C)] + #[derive(Copy, Clone)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_ioapic_state { + pub base_address: __u64, + pub ioregsel: __u32, +@@ -1065,12 +1036,20 @@ pub struct kvm_ioapic_state { + } + #[repr(C)] + #[derive(Copy, Clone)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub union kvm_ioapic_state__bindgen_ty_1 { + pub bits: __u64, + pub fields: kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1 { + pub vector: __u8, + pub _bitfield_align_1: [u8; 0], +@@ -1080,6 +1059,9 @@ pub struct kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -1097,10 +1079,7 @@ fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vector +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1110,10 +1089,7 @@ fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -1123,10 +1099,7 @@ fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dest_id +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dest_id) as usize - ptr as usize }, + 7usize, + concat!( + "Offset of field: ", +@@ -1274,6 +1247,9 @@ impl kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -1285,9 +1261,7 @@ fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_ioapic_state__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).bits as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).bits) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1297,9 +1271,7 @@ fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fields as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fields) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1318,8 +1290,15 @@ impl Default for kvm_ioapic_state__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_ioapic_state__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_ioapic_state__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] + fn bindgen_test_layout_kvm_ioapic_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 216usize, +@@ -1331,7 +1310,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + concat!("Alignment of ", stringify!(kvm_ioapic_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).base_address as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base_address) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1341,7 +1320,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ioregsel as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ioregsel) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1351,7 +1330,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -1361,7 +1340,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irr) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -1371,7 +1350,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -1381,7 +1360,7 @@ fn bindgen_test_layout_kvm_ioapic_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).redirtbl as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).redirtbl) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -1400,8 +1379,17 @@ impl Default for kvm_ioapic_state { + } + } + } ++impl ::std::fmt::Debug for kvm_ioapic_state { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_ioapic_state {{ base_address: {:?}, ioregsel: {:?}, id: {:?}, irr: {:?}, pad: {:?}, redirtbl: {:?} }}" , self . base_address , self . ioregsel , self . id , self . irr , self . pad , self . redirtbl) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_regs { + pub rax: __u64, + pub rbx: __u64, +@@ -1424,6 +1412,8 @@ pub struct kvm_regs { + } + #[test] + fn bindgen_test_layout_kvm_regs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 144usize, +@@ -1435,7 +1425,7 @@ fn bindgen_test_layout_kvm_regs() { + concat!("Alignment of ", stringify!(kvm_regs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rax as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rax) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1445,7 +1435,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rbx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rbx) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1455,7 +1445,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rcx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rcx) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -1465,7 +1455,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rdx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rdx) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -1475,7 +1465,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rsi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rsi) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", +@@ -1485,7 +1475,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rdi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rdi) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", +@@ -1495,7 +1485,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rsp as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rsp) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", +@@ -1505,7 +1495,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rbp as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rbp) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", +@@ -1515,7 +1505,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r8 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r8) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", +@@ -1525,7 +1515,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r9 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r9) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", +@@ -1535,7 +1525,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r10 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r10) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", +@@ -1545,7 +1535,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r11 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r11) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", +@@ -1555,7 +1545,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r12 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r12) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", +@@ -1565,7 +1555,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r13 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r13) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", +@@ -1575,7 +1565,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r14 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r14) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", +@@ -1585,7 +1575,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).r15 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).r15) as usize - ptr as usize }, + 120usize, + concat!( + "Offset of field: ", +@@ -1595,7 +1585,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rip as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rip) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", +@@ -1605,7 +1595,7 @@ fn bindgen_test_layout_kvm_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rflags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rflags) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", +@@ -1617,11 +1607,17 @@ fn bindgen_test_layout_kvm_regs() { + } + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_lapic_state { + pub regs: [::std::os::raw::c_char; 1024usize], + } + #[test] + fn bindgen_test_layout_kvm_lapic_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 1024usize, +@@ -1633,7 +1629,7 @@ fn bindgen_test_layout_kvm_lapic_state() { + concat!("Alignment of ", stringify!(kvm_lapic_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1654,6 +1650,10 @@ impl Default for kvm_lapic_state { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_segment { + pub base: __u64, + pub limit: __u32, +@@ -1671,6 +1671,8 @@ pub struct kvm_segment { + } + #[test] + fn bindgen_test_layout_kvm_segment() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, +@@ -1682,7 +1684,7 @@ fn bindgen_test_layout_kvm_segment() { + concat!("Alignment of ", stringify!(kvm_segment)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1692,7 +1694,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).limit as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).limit) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1702,7 +1704,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).selector as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).selector) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -1712,7 +1714,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 14usize, + concat!( + "Offset of field: ", +@@ -1722,7 +1724,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).present as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).present) as usize - ptr as usize }, + 15usize, + concat!( + "Offset of field: ", +@@ -1732,7 +1734,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dpl as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dpl) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -1742,7 +1744,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).db as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).db) as usize - ptr as usize }, + 17usize, + concat!( + "Offset of field: ", +@@ -1752,7 +1754,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).s) as usize - ptr as usize }, + 18usize, + concat!( + "Offset of field: ", +@@ -1762,7 +1764,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).l as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).l) as usize - ptr as usize }, + 19usize, + concat!( + "Offset of field: ", +@@ -1772,7 +1774,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).g as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).g) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -1782,7 +1784,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).avl as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).avl) as usize - ptr as usize }, + 21usize, + concat!( + "Offset of field: ", +@@ -1792,7 +1794,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).unusable as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).unusable) as usize - ptr as usize }, + 22usize, + concat!( + "Offset of field: ", +@@ -1802,7 +1804,7 @@ fn bindgen_test_layout_kvm_segment() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 23usize, + concat!( + "Offset of field: ", +@@ -1814,6 +1816,10 @@ fn bindgen_test_layout_kvm_segment() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_dtable { + pub base: __u64, + pub limit: __u16, +@@ -1821,6 +1827,8 @@ pub struct kvm_dtable { + } + #[test] + fn bindgen_test_layout_kvm_dtable() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -1832,7 +1840,7 @@ fn bindgen_test_layout_kvm_dtable() { + concat!("Alignment of ", stringify!(kvm_dtable)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1842,7 +1850,7 @@ fn bindgen_test_layout_kvm_dtable() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).limit as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).limit) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -1852,7 +1860,7 @@ fn bindgen_test_layout_kvm_dtable() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", +@@ -1864,6 +1872,10 @@ fn bindgen_test_layout_kvm_dtable() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_sregs { + pub cs: kvm_segment, + pub ds: kvm_segment, +@@ -1886,6 +1898,8 @@ pub struct kvm_sregs { + } + #[test] + fn bindgen_test_layout_kvm_sregs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 312usize, +@@ -1897,7 +1911,7 @@ fn bindgen_test_layout_kvm_sregs() { + concat!("Alignment of ", stringify!(kvm_sregs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -1907,7 +1921,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ds as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ds) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -1917,7 +1931,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).es as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).es) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", +@@ -1927,7 +1941,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fs) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", +@@ -1937,7 +1951,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gs) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", +@@ -1947,7 +1961,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ss as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ss) as usize - ptr as usize }, + 120usize, + concat!( + "Offset of field: ", +@@ -1957,7 +1971,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).tr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).tr) as usize - ptr as usize }, + 144usize, + concat!( + "Offset of field: ", +@@ -1967,7 +1981,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ldt as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ldt) as usize - ptr as usize }, + 168usize, + concat!( + "Offset of field: ", +@@ -1977,7 +1991,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gdt as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gdt) as usize - ptr as usize }, + 192usize, + concat!( + "Offset of field: ", +@@ -1987,7 +2001,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).idt as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).idt) as usize - ptr as usize }, + 208usize, + concat!( + "Offset of field: ", +@@ -1997,7 +2011,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr0 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr0) as usize - ptr as usize }, + 224usize, + concat!( + "Offset of field: ", +@@ -2007,7 +2021,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr2 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr2) as usize - ptr as usize }, + 232usize, + concat!( + "Offset of field: ", +@@ -2017,7 +2031,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr3 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr3) as usize - ptr as usize }, + 240usize, + concat!( + "Offset of field: ", +@@ -2027,7 +2041,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr4 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr4) as usize - ptr as usize }, + 248usize, + concat!( + "Offset of field: ", +@@ -2037,7 +2051,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr8 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr8) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", +@@ -2047,7 +2061,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).efer as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).efer) as usize - ptr as usize }, + 264usize, + concat!( + "Offset of field: ", +@@ -2057,7 +2071,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apic_base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).apic_base) as usize - ptr as usize }, + 272usize, + concat!( + "Offset of field: ", +@@ -2067,7 +2081,7 @@ fn bindgen_test_layout_kvm_sregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).interrupt_bitmap as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).interrupt_bitmap) as usize - ptr as usize }, + 280usize, + concat!( + "Offset of field: ", +@@ -2079,204 +2093,446 @@ fn bindgen_test_layout_kvm_sregs() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_fpu { +- pub fpr: [[__u8; 16usize]; 8usize], +- pub fcw: __u16, +- pub fsw: __u16, +- pub ftwx: __u8, +- pub pad1: __u8, +- pub last_opcode: __u16, +- pub last_ip: __u64, +- pub last_dp: __u64, +- pub xmm: [[__u8; 16usize]; 16usize], +- pub mxcsr: __u32, +- pub pad2: __u32, ++pub struct kvm_sregs2 { ++ pub cs: kvm_segment, ++ pub ds: kvm_segment, ++ pub es: kvm_segment, ++ pub fs: kvm_segment, ++ pub gs: kvm_segment, ++ pub ss: kvm_segment, ++ pub tr: kvm_segment, ++ pub ldt: kvm_segment, ++ pub gdt: kvm_dtable, ++ pub idt: kvm_dtable, ++ pub cr0: __u64, ++ pub cr2: __u64, ++ pub cr3: __u64, ++ pub cr4: __u64, ++ pub cr8: __u64, ++ pub efer: __u64, ++ pub apic_base: __u64, ++ pub flags: __u64, ++ pub pdptrs: [__u64; 4usize], + } + #[test] +-fn bindgen_test_layout_kvm_fpu() { ++fn bindgen_test_layout_kvm_sregs2() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 416usize, +- concat!("Size of: ", stringify!(kvm_fpu)) ++ ::std::mem::size_of::(), ++ 320usize, ++ concat!("Size of: ", stringify!(kvm_sregs2)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_fpu)) ++ concat!("Alignment of ", stringify!(kvm_sregs2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fpr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).cs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(fpr) ++ stringify!(cs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fcw as *const _ as usize }, +- 128usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ds) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(fcw) ++ stringify!(ds) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fsw as *const _ as usize }, +- 130usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).es) as usize - ptr as usize }, ++ 48usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(fsw) ++ stringify!(es) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ftwx as *const _ as usize }, +- 132usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fs) as usize - ptr as usize }, ++ 72usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(ftwx) ++ stringify!(fs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad1 as *const _ as usize }, +- 133usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).gs) as usize - ptr as usize }, ++ 96usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(pad1) ++ stringify!(gs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last_opcode as *const _ as usize }, +- 134usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ss) as usize - ptr as usize }, ++ 120usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(last_opcode) ++ stringify!(ss) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last_ip as *const _ as usize }, +- 136usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).tr) as usize - ptr as usize }, ++ 144usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(last_ip) ++ stringify!(tr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last_dp as *const _ as usize }, +- 144usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ldt) as usize - ptr as usize }, ++ 168usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(last_dp) ++ stringify!(ldt) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).xmm as *const _ as usize }, +- 152usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).gdt) as usize - ptr as usize }, ++ 192usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(xmm) ++ stringify!(gdt) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mxcsr as *const _ as usize }, +- 408usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).idt) as usize - ptr as usize }, ++ 208usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(mxcsr) ++ stringify!(idt) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad2 as *const _ as usize }, +- 412usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr0) as usize - ptr as usize }, ++ 224usize, + concat!( + "Offset of field: ", +- stringify!(kvm_fpu), ++ stringify!(kvm_sregs2), + "::", +- stringify!(pad2) ++ stringify!(cr0) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_msr_entry { +- pub index: __u32, +- pub reserved: __u32, +- pub data: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_msr_entry() { + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_msr_entry)) ++ unsafe { ::std::ptr::addr_of!((*ptr).cr2) as usize - ptr as usize }, ++ 232usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sregs2), ++ "::", ++ stringify!(cr2) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_msr_entry)) ++ unsafe { ::std::ptr::addr_of!((*ptr).cr3) as usize - ptr as usize }, ++ 240usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sregs2), ++ "::", ++ stringify!(cr3) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).index as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr4) as usize - ptr as usize }, ++ 248usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msr_entry), ++ stringify!(kvm_sregs2), + "::", +- stringify!(index) ++ stringify!(cr4) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr8) as usize - ptr as usize }, ++ 256usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msr_entry), ++ stringify!(kvm_sregs2), + "::", +- stringify!(reserved) ++ stringify!(cr8) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).efer) as usize - ptr as usize }, ++ 264usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msr_entry), ++ stringify!(kvm_sregs2), + "::", +- stringify!(data) ++ stringify!(efer) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default)] +-pub struct kvm_msrs { +- pub nmsrs: __u32, +- pub pad: __u32, +- pub entries: __IncompleteArrayField, +-} +-#[test] +-fn bindgen_test_layout_kvm_msrs() { + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).apic_base) as usize - ptr as usize }, ++ 272usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sregs2), ++ "::", ++ stringify!(apic_base) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 280usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sregs2), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pdptrs) as usize - ptr as usize }, ++ 288usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sregs2), ++ "::", ++ stringify!(pdptrs) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_fpu { ++ pub fpr: [[__u8; 16usize]; 8usize], ++ pub fcw: __u16, ++ pub fsw: __u16, ++ pub ftwx: __u8, ++ pub pad1: __u8, ++ pub last_opcode: __u16, ++ pub last_ip: __u64, ++ pub last_dp: __u64, ++ pub xmm: [[__u8; 16usize]; 16usize], ++ pub mxcsr: __u32, ++ pub pad2: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_fpu() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 416usize, ++ concat!("Size of: ", stringify!(kvm_fpu)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_fpu)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fpr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(fpr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fcw) as usize - ptr as usize }, ++ 128usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(fcw) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fsw) as usize - ptr as usize }, ++ 130usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(fsw) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ftwx) as usize - ptr as usize }, ++ 132usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(ftwx) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 133usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(pad1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).last_opcode) as usize - ptr as usize }, ++ 134usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(last_opcode) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).last_ip) as usize - ptr as usize }, ++ 136usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(last_ip) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).last_dp) as usize - ptr as usize }, ++ 144usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(last_dp) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).xmm) as usize - ptr as usize }, ++ 152usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(xmm) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).mxcsr) as usize - ptr as usize }, ++ 408usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(mxcsr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 412usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_fpu), ++ "::", ++ stringify!(pad2) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_msr_entry { ++ pub index: __u32, ++ pub reserved: __u32, ++ pub data: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_msr_entry() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_msr_entry)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_msr_entry)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).index) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msr_entry), ++ "::", ++ stringify!(index) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msr_entry), ++ "::", ++ stringify!(reserved) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_msr_entry), ++ "::", ++ stringify!(data) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_msrs { ++ pub nmsrs: __u32, ++ pub pad: __u32, ++ pub entries: __IncompleteArrayField, ++} ++#[test] ++fn bindgen_test_layout_kvm_msrs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, + concat!("Size of: ", stringify!(kvm_msrs)) + ); + assert_eq!( +@@ -2285,7 +2541,7 @@ fn bindgen_test_layout_kvm_msrs() { + concat!("Alignment of ", stringify!(kvm_msrs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nmsrs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nmsrs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2295,7 +2551,7 @@ fn bindgen_test_layout_kvm_msrs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2305,7 +2561,7 @@ fn bindgen_test_layout_kvm_msrs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entries as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2323,6 +2579,8 @@ pub struct kvm_msr_list { + } + #[test] + fn bindgen_test_layout_kvm_msr_list() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, +@@ -2334,7 +2592,7 @@ fn bindgen_test_layout_kvm_msr_list() { + concat!("Alignment of ", stringify!(kvm_msr_list)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nmsrs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nmsrs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2344,7 +2602,7 @@ fn bindgen_test_layout_kvm_msr_list() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).indices as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).indices) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2364,6 +2622,8 @@ pub struct kvm_msr_filter_range { + } + #[test] + fn bindgen_test_layout_kvm_msr_filter_range() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, +@@ -2375,7 +2635,7 @@ fn bindgen_test_layout_kvm_msr_filter_range() { + concat!("Alignment of ", stringify!(kvm_msr_filter_range)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2385,7 +2645,7 @@ fn bindgen_test_layout_kvm_msr_filter_range() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nmsrs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nmsrs) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2395,7 +2655,7 @@ fn bindgen_test_layout_kvm_msr_filter_range() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).base) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2405,7 +2665,7 @@ fn bindgen_test_layout_kvm_msr_filter_range() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).bitmap as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).bitmap) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2432,6 +2692,8 @@ pub struct kvm_msr_filter { + } + #[test] + fn bindgen_test_layout_kvm_msr_filter() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 392usize, +@@ -2443,7 +2705,7 @@ fn bindgen_test_layout_kvm_msr_filter() { + concat!("Alignment of ", stringify!(kvm_msr_filter)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2453,7 +2715,7 @@ fn bindgen_test_layout_kvm_msr_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ranges as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ranges) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2484,6 +2746,8 @@ pub struct kvm_cpuid_entry { + } + #[test] + fn bindgen_test_layout_kvm_cpuid_entry() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, +@@ -2495,7 +2759,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + concat!("Alignment of ", stringify!(kvm_cpuid_entry)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).function as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).function) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2505,7 +2769,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).eax as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).eax) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2515,7 +2779,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ebx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ebx) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2525,7 +2789,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ecx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ecx) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -2535,7 +2799,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).edx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).edx) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2545,7 +2809,7 @@ fn bindgen_test_layout_kvm_cpuid_entry() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -2564,6 +2828,8 @@ pub struct kvm_cpuid { + } + #[test] + fn bindgen_test_layout_kvm_cpuid() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -2575,7 +2841,7 @@ fn bindgen_test_layout_kvm_cpuid() { + concat!("Alignment of ", stringify!(kvm_cpuid)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nent as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nent) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2585,7 +2851,7 @@ fn bindgen_test_layout_kvm_cpuid() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2595,7 +2861,7 @@ fn bindgen_test_layout_kvm_cpuid() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entries as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2607,6 +2873,10 @@ fn bindgen_test_layout_kvm_cpuid() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_cpuid_entry2 { + pub function: __u32, + pub index: __u32, +@@ -2619,6 +2889,8 @@ pub struct kvm_cpuid_entry2 { + } + #[test] + fn bindgen_test_layout_kvm_cpuid_entry2() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 40usize, +@@ -2630,7 +2902,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + concat!("Alignment of ", stringify!(kvm_cpuid_entry2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).function as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).function) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2640,7 +2912,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).index as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).index) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2650,7 +2922,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2660,7 +2932,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).eax as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).eax) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -2670,7 +2942,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ebx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ebx) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2680,7 +2952,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ecx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ecx) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -2690,7 +2962,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).edx as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).edx) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -2700,7 +2972,7 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", +@@ -2712,6 +2984,10 @@ fn bindgen_test_layout_kvm_cpuid_entry2() { + } + #[repr(C)] + #[derive(Debug, Default)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_cpuid2 { + pub nent: __u32, + pub padding: __u32, +@@ -2719,6 +2995,8 @@ pub struct kvm_cpuid2 { + } + #[test] + fn bindgen_test_layout_kvm_cpuid2() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -2730,7 +3008,7 @@ fn bindgen_test_layout_kvm_cpuid2() { + concat!("Alignment of ", stringify!(kvm_cpuid2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nent as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nent) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2740,7 +3018,7 @@ fn bindgen_test_layout_kvm_cpuid2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2750,7 +3028,7 @@ fn bindgen_test_layout_kvm_cpuid2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entries as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2762,6 +3040,10 @@ fn bindgen_test_layout_kvm_cpuid2() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_pit_channel_state { + pub count: __u32, + pub latched_count: __u16, +@@ -2779,6 +3061,9 @@ pub struct kvm_pit_channel_state { + } + #[test] + fn bindgen_test_layout_kvm_pit_channel_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, +@@ -2790,7 +3075,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + concat!("Alignment of ", stringify!(kvm_pit_channel_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).count as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2800,9 +3085,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).latched_count as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).latched_count) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2812,9 +3095,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).count_latched as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).count_latched) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", +@@ -2824,9 +3105,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).status_latched as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).status_latched) as usize - ptr as usize }, + 7usize, + concat!( + "Offset of field: ", +@@ -2836,7 +3115,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).status as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2846,9 +3125,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).read_state as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).read_state) as usize - ptr as usize }, + 9usize, + concat!( + "Offset of field: ", +@@ -2858,9 +3135,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).write_state as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).write_state) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", +@@ -2870,9 +3145,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).write_latch as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).write_latch) as usize - ptr as usize }, + 11usize, + concat!( + "Offset of field: ", +@@ -2882,7 +3155,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rw_mode as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rw_mode) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -2892,7 +3165,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mode as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mode) as usize - ptr as usize }, + 13usize, + concat!( + "Offset of field: ", +@@ -2902,7 +3175,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).bcd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).bcd) as usize - ptr as usize }, + 14usize, + concat!( + "Offset of field: ", +@@ -2912,7 +3185,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gate as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gate) as usize - ptr as usize }, + 15usize, + concat!( + "Offset of field: ", +@@ -2922,9 +3195,7 @@ fn bindgen_test_layout_kvm_pit_channel_state() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).count_load_time as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).count_load_time) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2945,6 +3216,8 @@ pub struct kvm_debug_exit_arch { + } + #[test] + fn bindgen_test_layout_kvm_debug_exit_arch() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -2956,7 +3229,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + concat!("Alignment of ", stringify!(kvm_debug_exit_arch)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exception as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -2966,7 +3239,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -2976,7 +3249,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pc as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pc) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -2986,7 +3259,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dr6 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dr6) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -2996,7 +3269,7 @@ fn bindgen_test_layout_kvm_debug_exit_arch() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dr7 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dr7) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -3013,6 +3286,8 @@ pub struct kvm_guest_debug_arch { + } + #[test] + fn bindgen_test_layout_kvm_guest_debug_arch() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, +@@ -3024,7 +3299,7 @@ fn bindgen_test_layout_kvm_guest_debug_arch() { + concat!("Alignment of ", stringify!(kvm_guest_debug_arch)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).debugreg as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).debugreg) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3041,6 +3316,8 @@ pub struct kvm_pit_state { + } + #[test] + fn bindgen_test_layout_kvm_pit_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 72usize, +@@ -3052,7 +3329,7 @@ fn bindgen_test_layout_kvm_pit_state() { + concat!("Alignment of ", stringify!(kvm_pit_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).channels as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).channels) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3064,6 +3341,10 @@ fn bindgen_test_layout_kvm_pit_state() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_pit_state2 { + pub channels: [kvm_pit_channel_state; 3usize], + pub flags: __u32, +@@ -3071,6 +3352,8 @@ pub struct kvm_pit_state2 { + } + #[test] + fn bindgen_test_layout_kvm_pit_state2() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 112usize, +@@ -3082,7 +3365,7 @@ fn bindgen_test_layout_kvm_pit_state2() { + concat!("Alignment of ", stringify!(kvm_pit_state2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).channels as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).channels) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3092,7 +3375,7 @@ fn bindgen_test_layout_kvm_pit_state2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", +@@ -3102,7 +3385,7 @@ fn bindgen_test_layout_kvm_pit_state2() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 76usize, + concat!( + "Offset of field: ", +@@ -3120,6 +3403,8 @@ pub struct kvm_reinject_control { + } + #[test] + fn bindgen_test_layout_kvm_reinject_control() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -3131,9 +3416,7 @@ fn bindgen_test_layout_kvm_reinject_control() { + concat!("Alignment of ", stringify!(kvm_reinject_control)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pit_reinject as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pit_reinject) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3143,7 +3426,7 @@ fn bindgen_test_layout_kvm_reinject_control() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3155,6 +3438,10 @@ fn bindgen_test_layout_kvm_reinject_control() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_events { + pub exception: kvm_vcpu_events__bindgen_ty_1, + pub interrupt: kvm_vcpu_events__bindgen_ty_2, +@@ -3162,12 +3449,17 @@ pub struct kvm_vcpu_events { + pub sipi_vector: __u32, + pub flags: __u32, + pub smi: kvm_vcpu_events__bindgen_ty_4, +- pub reserved: [__u8; 27usize], ++ pub triple_fault: kvm_vcpu_events__bindgen_ty_5, ++ pub reserved: [__u8; 26usize], + pub exception_has_payload: __u8, + pub exception_payload: __u64, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_events__bindgen_ty_1 { + pub injected: __u8, + pub nr: __u8, +@@ -3177,6 +3469,9 @@ pub struct kvm_vcpu_events__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -3188,9 +3483,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).injected as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).injected) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3200,9 +3493,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3212,10 +3503,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).has_error_code as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).has_error_code) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -3225,9 +3513,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pending as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pending) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -3237,10 +3523,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).error_code as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).error_code) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -3252,6 +3535,10 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_events__bindgen_ty_2 { + pub injected: __u8, + pub nr: __u8, +@@ -3260,6 +3547,9 @@ pub struct kvm_vcpu_events__bindgen_ty_2 { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, +@@ -3271,9 +3561,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { + concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_2)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).injected as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).injected) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3283,9 +3571,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3295,9 +3581,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).soft as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).soft) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -3307,9 +3591,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).shadow as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).shadow) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -3321,6 +3603,10 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_events__bindgen_ty_3 { + pub injected: __u8, + pub pending: __u8, +@@ -3329,6 +3615,9 @@ pub struct kvm_vcpu_events__bindgen_ty_3 { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, +@@ -3340,9 +3629,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { + concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_3)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).injected as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).injected) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3352,9 +3639,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pending as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pending) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3364,9 +3649,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).masked as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).masked) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -3376,9 +3659,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -3390,6 +3671,10 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_vcpu_events__bindgen_ty_4 { + pub smm: __u8, + pub pending: __u8, +@@ -3398,6 +3683,9 @@ pub struct kvm_vcpu_events__bindgen_ty_4 { + } + #[test] + fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, +@@ -3409,9 +3697,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { + concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_4)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).smm as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).smm) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3421,9 +3707,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pending as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pending) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", +@@ -3433,10 +3717,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).smm_inside_nmi as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).smm_inside_nmi) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -3446,10 +3727,7 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).latched_init as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).latched_init) as usize - ptr as usize }, + 3usize, + concat!( + "Offset of field: ", +@@ -3459,8 +3737,45 @@ fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() { + ) + ); + } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_vcpu_events__bindgen_ty_5 { ++ pub pending: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_5() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 1usize, ++ concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_5)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_5)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pending) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_vcpu_events__bindgen_ty_5), ++ "::", ++ stringify!(pending) ++ ) ++ ); ++} + #[test] + fn bindgen_test_layout_kvm_vcpu_events() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, +@@ -3472,7 +3787,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + concat!("Alignment of ", stringify!(kvm_vcpu_events)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exception as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3482,7 +3797,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).interrupt as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).interrupt) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3492,7 +3807,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nmi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nmi) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -3502,7 +3817,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sipi_vector as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sipi_vector) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -3512,7 +3827,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -3522,7 +3837,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).smi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).smi) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -3532,8 +3847,18 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).triple_fault) as usize - ptr as usize }, + 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_vcpu_events), ++ "::", ++ stringify!(triple_fault) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 29usize, + concat!( + "Offset of field: ", + stringify!(kvm_vcpu_events), +@@ -3542,9 +3867,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).exception_has_payload as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception_has_payload) as usize - ptr as usize }, + 55usize, + concat!( + "Offset of field: ", +@@ -3554,9 +3877,7 @@ fn bindgen_test_layout_kvm_vcpu_events() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).exception_payload as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception_payload) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", +@@ -3568,6 +3889,10 @@ fn bindgen_test_layout_kvm_vcpu_events() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_debugregs { + pub db: [__u64; 4usize], + pub dr6: __u64, +@@ -3577,6 +3902,8 @@ pub struct kvm_debugregs { + } + #[test] + fn bindgen_test_layout_kvm_debugregs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 128usize, +@@ -3588,7 +3915,7 @@ fn bindgen_test_layout_kvm_debugregs() { + concat!("Alignment of ", stringify!(kvm_debugregs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).db as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).db) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3598,7 +3925,7 @@ fn bindgen_test_layout_kvm_debugregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dr6 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dr6) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", +@@ -3608,7 +3935,7 @@ fn bindgen_test_layout_kvm_debugregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dr7 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dr7) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", +@@ -3618,7 +3945,7 @@ fn bindgen_test_layout_kvm_debugregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", +@@ -3628,7 +3955,7 @@ fn bindgen_test_layout_kvm_debugregs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", +@@ -3639,12 +3966,19 @@ fn bindgen_test_layout_kvm_debugregs() { + ); + } + #[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] ++#[derive(Debug)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_xsave { + pub region: [__u32; 1024usize], ++ pub extra: __IncompleteArrayField<__u32>, + } + #[test] + fn bindgen_test_layout_kvm_xsave() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4096usize, +@@ -3656,7 +3990,7 @@ fn bindgen_test_layout_kvm_xsave() { + concat!("Alignment of ", stringify!(kvm_xsave)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).region as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).region) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3665,6 +3999,16 @@ fn bindgen_test_layout_kvm_xsave() { + stringify!(region) + ) + ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).extra) as usize - ptr as usize }, ++ 4096usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xsave), ++ "::", ++ stringify!(extra) ++ ) ++ ); + } + impl Default for kvm_xsave { + fn default() -> Self { +@@ -3677,6 +4021,10 @@ impl Default for kvm_xsave { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_xcr { + pub xcr: __u32, + pub reserved: __u32, +@@ -3684,6 +4032,8 @@ pub struct kvm_xcr { + } + #[test] + fn bindgen_test_layout_kvm_xcr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, +@@ -3695,7 +4045,7 @@ fn bindgen_test_layout_kvm_xcr() { + concat!("Alignment of ", stringify!(kvm_xcr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).xcr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).xcr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3705,7 +4055,7 @@ fn bindgen_test_layout_kvm_xcr() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -3715,7 +4065,7 @@ fn bindgen_test_layout_kvm_xcr() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).value as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3727,6 +4077,10 @@ fn bindgen_test_layout_kvm_xcr() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] + pub struct kvm_xcrs { + pub nr_xcrs: __u32, + pub flags: __u32, +@@ -3735,6 +4089,8 @@ pub struct kvm_xcrs { + } + #[test] + fn bindgen_test_layout_kvm_xcrs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 392usize, +@@ -3746,7 +4102,7 @@ fn bindgen_test_layout_kvm_xcrs() { + concat!("Alignment of ", stringify!(kvm_xcrs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nr_xcrs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr_xcrs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3756,7 +4112,7 @@ fn bindgen_test_layout_kvm_xcrs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -3766,7 +4122,7 @@ fn bindgen_test_layout_kvm_xcrs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).xcrs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).xcrs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3776,7 +4132,7 @@ fn bindgen_test_layout_kvm_xcrs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 264usize, + concat!( + "Offset of field: ", +@@ -3795,6 +4151,8 @@ pub struct kvm_sync_regs { + } + #[test] + fn bindgen_test_layout_kvm_sync_regs() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 520usize, +@@ -3806,7 +4164,7 @@ fn bindgen_test_layout_kvm_sync_regs() { + concat!("Alignment of ", stringify!(kvm_sync_regs)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3816,7 +4174,7 @@ fn bindgen_test_layout_kvm_sync_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sregs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sregs) as usize - ptr as usize }, + 144usize, + concat!( + "Offset of field: ", +@@ -3826,7 +4184,7 @@ fn bindgen_test_layout_kvm_sync_regs() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).events as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).events) as usize - ptr as usize }, + 456usize, + concat!( + "Offset of field: ", +@@ -3844,6 +4202,9 @@ pub struct kvm_vmx_nested_state_data { + } + #[test] + fn bindgen_test_layout_kvm_vmx_nested_state_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8192usize, +@@ -3855,9 +4216,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_data() { + concat!("Alignment of ", stringify!(kvm_vmx_nested_state_data)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmcs12 as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmcs12) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3867,9 +4226,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_data() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).shadow_vmcs12 as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).shadow_vmcs12) as usize - ptr as usize }, + 4096usize, + concat!( + "Offset of field: ", +@@ -3905,6 +4262,9 @@ pub struct kvm_vmx_nested_state_hdr__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_vmx_nested_state_hdr__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 2usize, +@@ -3922,10 +4282,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).flags as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3937,6 +4294,9 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr__bindgen_ty_1() { + } + #[test] + fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -3948,9 +4308,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + concat!("Alignment of ", stringify!(kvm_vmx_nested_state_hdr)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmxon_pa as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmxon_pa) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -3960,9 +4318,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmcs12_pa as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmcs12_pa) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -3972,7 +4328,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).smm as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).smm) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -3982,7 +4338,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 18usize, + concat!( + "Offset of field: ", +@@ -3992,7 +4348,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +@@ -4002,10 +4358,7 @@ fn bindgen_test_layout_kvm_vmx_nested_state_hdr() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).preemption_timer_deadline +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).preemption_timer_deadline) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +@@ -4022,6 +4375,9 @@ pub struct kvm_svm_nested_state_data { + } + #[test] + fn bindgen_test_layout_kvm_svm_nested_state_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4096usize, +@@ -4033,9 +4389,7 @@ fn bindgen_test_layout_kvm_svm_nested_state_data() { + concat!("Alignment of ", stringify!(kvm_svm_nested_state_data)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmcb12 as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmcb12) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4061,6 +4415,9 @@ pub struct kvm_svm_nested_state_hdr { + } + #[test] + fn bindgen_test_layout_kvm_svm_nested_state_hdr() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, +@@ -4072,9 +4429,7 @@ fn bindgen_test_layout_kvm_svm_nested_state_hdr() { + concat!("Alignment of ", stringify!(kvm_svm_nested_state_hdr)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmcb_pa as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmcb_pa) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4101,6 +4456,9 @@ pub union kvm_nested_state__bindgen_ty_1 { + } + #[test] + fn bindgen_test_layout_kvm_nested_state__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 120usize, +@@ -4112,9 +4470,7 @@ fn bindgen_test_layout_kvm_nested_state__bindgen_ty_1() { + concat!("Alignment of ", stringify!(kvm_nested_state__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmx as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vmx) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4124,9 +4480,7 @@ fn bindgen_test_layout_kvm_nested_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).svm as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).svm) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4136,9 +4490,7 @@ fn bindgen_test_layout_kvm_nested_state__bindgen_ty_1() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4157,49 +4509,188 @@ impl Default for kvm_nested_state__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_nested_state__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_nested_state__bindgen_ty_1 {{ union }}") ++ } ++} + #[repr(C)] + pub struct kvm_nested_state__bindgen_ty_2 { +- pub vmx: __BindgenUnionField<[kvm_vmx_nested_state_data; 0usize]>, +- pub svm: __BindgenUnionField<[kvm_svm_nested_state_data; 0usize]>, ++ pub __bindgen_anon_1: __BindgenUnionField, ++ pub __bindgen_anon_2: __BindgenUnionField, + pub bindgen_union_field: [u8; 0usize], + } ++#[repr(C)] ++#[derive(Debug)] ++pub struct kvm_nested_state__bindgen_ty_2__bindgen_ty_1 { ++ pub __empty_vmx: kvm_nested_state__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1, ++ pub vmx: __IncompleteArrayField, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_nested_state__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1 {} + #[test] +-fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2() { ++fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1() { + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 0usize, +- concat!("Size of: ", stringify!(kvm_nested_state__bindgen_ty_2)) ++ concat!( ++ "Size of: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 1usize, +- concat!("Alignment of ", stringify!(kvm_nested_state__bindgen_ty_2)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1) ++ ) + ); ++} ++#[test] ++fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vmx as *const _ as usize +- }, ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__empty_vmx) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_nested_state__bindgen_ty_2), ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1), + "::", +- stringify!(vmx) ++ stringify!(__empty_vmx) + ) + ); + assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).vmx) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_1), ++ "::", ++ stringify!(vmx) ++ ) ++ ); ++} ++impl Default for kvm_nested_state__bindgen_ty_2__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).svm as *const _ as usize +- }, ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug)] ++pub struct kvm_nested_state__bindgen_ty_2__bindgen_ty_2 { ++ pub __empty_svm: kvm_nested_state__bindgen_ty_2__bindgen_ty_2__bindgen_ty_1, ++ pub svm: __IncompleteArrayField, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_nested_state__bindgen_ty_2__bindgen_ty_2__bindgen_ty_1 {} ++#[test] ++fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2__bindgen_ty_2__bindgen_ty_1() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++} ++#[test] ++fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__empty_svm) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2), ++ "::", ++ stringify!(__empty_svm) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).svm) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_nested_state__bindgen_ty_2), ++ stringify!(kvm_nested_state__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(svm) + ) + ); + } ++impl Default for kvm_nested_state__bindgen_ty_2__bindgen_ty_2 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 0usize, ++ concat!("Size of: ", stringify!(kvm_nested_state__bindgen_ty_2)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!("Alignment of ", stringify!(kvm_nested_state__bindgen_ty_2)) ++ ); ++} + impl Default for kvm_nested_state__bindgen_ty_2 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); +@@ -4209,8 +4700,15 @@ impl Default for kvm_nested_state__bindgen_ty_2 { + } + } + } ++impl ::std::fmt::Debug for kvm_nested_state__bindgen_ty_2 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_nested_state__bindgen_ty_2 {{ union }}") ++ } ++} + #[test] + fn bindgen_test_layout_kvm_nested_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 128usize, +@@ -4222,7 +4720,7 @@ fn bindgen_test_layout_kvm_nested_state() { + concat!("Alignment of ", stringify!(kvm_nested_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4232,7 +4730,7 @@ fn bindgen_test_layout_kvm_nested_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).format as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +@@ -4242,7 +4740,7 @@ fn bindgen_test_layout_kvm_nested_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -4252,7 +4750,7 @@ fn bindgen_test_layout_kvm_nested_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hdr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -4262,7 +4760,7 @@ fn bindgen_test_layout_kvm_nested_state() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", +@@ -4281,6 +4779,15 @@ impl Default for kvm_nested_state { + } + } + } ++impl ::std::fmt::Debug for kvm_nested_state { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_nested_state {{ flags: {:?}, format: {:?}, size: {:?}, hdr: {:?}, data: {:?} }}", ++ self.flags, self.format, self.size, self.hdr, self.data ++ ) ++ } ++} + #[repr(C)] + #[derive(Debug, Default)] + pub struct kvm_pmu_event_filter { +@@ -4293,6 +4800,8 @@ pub struct kvm_pmu_event_filter { + } + #[test] + fn bindgen_test_layout_kvm_pmu_event_filter() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, +@@ -4304,7 +4813,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + concat!("Alignment of ", stringify!(kvm_pmu_event_filter)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).action as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).action) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +@@ -4314,7 +4823,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nevents as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nevents) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +@@ -4324,10 +4833,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fixed_counter_bitmap as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fixed_counter_bitmap) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +@@ -4337,7 +4843,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +@@ -4347,7 +4853,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +@@ -4357,7 +4863,7 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).events as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).events) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", +@@ -4369,349 +4875,263 @@ fn bindgen_test_layout_kvm_pmu_event_filter() { + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_user_trace_setup { +- pub buf_size: __u32, +- pub buf_nr: __u32, ++pub struct kvm_x86_mce { ++ pub status: __u64, ++ pub addr: __u64, ++ pub misc: __u64, ++ pub mcg_status: __u64, ++ pub bank: __u8, ++ pub pad1: [__u8; 7usize], ++ pub pad2: [__u64; 3usize], + } + #[test] +-fn bindgen_test_layout_kvm_user_trace_setup() { ++fn bindgen_test_layout_kvm_x86_mce() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_user_trace_setup)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_x86_mce)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_user_trace_setup)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_x86_mce)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf_size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_user_trace_setup), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(buf_size) ++ stringify!(status) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf_nr as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_user_trace_setup), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(buf_nr) ++ stringify!(addr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_breakpoint { +- pub enabled: __u32, +- pub padding: __u32, +- pub address: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_breakpoint() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).misc) as usize - ptr as usize }, + 16usize, +- concat!("Size of: ", stringify!(kvm_breakpoint)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_breakpoint)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, +- 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_breakpoint), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(enabled) ++ stringify!(misc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).mcg_status) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_breakpoint), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(padding) ++ stringify!(mcg_status) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).bank) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_breakpoint), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(address) ++ stringify!(bank) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_debug_guest { +- pub enabled: __u32, +- pub pad: __u32, +- pub breakpoints: [kvm_breakpoint; 4usize], +- pub singlestep: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_debug_guest() { +- assert_eq!( +- ::std::mem::size_of::(), +- 80usize, +- concat!("Size of: ", stringify!(kvm_debug_guest)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_debug_guest)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 33usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(enabled) ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_debug_guest), ++ stringify!(kvm_x86_mce), + "::", +- stringify!(pad) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).breakpoints as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_debug_guest), +- "::", +- stringify!(breakpoints) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).singlestep as *const _ as usize }, +- 72usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_debug_guest), +- "::", +- stringify!(singlestep) ++ stringify!(pad2) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_memory_region { +- pub slot: __u32, ++pub struct kvm_xen_hvm_config { + pub flags: __u32, +- pub guest_phys_addr: __u64, +- pub memory_size: __u64, ++ pub msr: __u32, ++ pub blob_addr_32: __u64, ++ pub blob_addr_64: __u64, ++ pub blob_size_32: __u8, ++ pub blob_size_64: __u8, ++ pub pad2: [__u8; 30usize], + } + #[test] +-fn bindgen_test_layout_kvm_memory_region() { ++fn bindgen_test_layout_kvm_xen_hvm_config() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_memory_region)) ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(kvm_xen_hvm_config)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_memory_region)) ++ concat!("Alignment of ", stringify!(kvm_xen_hvm_config)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(slot) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(flags) ++ stringify!(msr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_phys_addr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).blob_addr_32) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(guest_phys_addr) ++ stringify!(blob_addr_32) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).memory_size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).blob_addr_64) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_memory_region), +- "::", +- stringify!(memory_size) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_userspace_memory_region { +- pub slot: __u32, +- pub flags: __u32, +- pub guest_phys_addr: __u64, +- pub memory_size: __u64, +- pub userspace_addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_userspace_memory_region() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_userspace_memory_region)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_userspace_memory_region)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).slot as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_userspace_memory_region), +- "::", +- stringify!(slot) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).flags as *const _ as usize +- }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_userspace_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(flags) ++ stringify!(blob_addr_64) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_phys_addr as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).blob_size_32) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_userspace_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(guest_phys_addr) ++ stringify!(blob_size_32) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).memory_size as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).blob_size_64) as usize - ptr as usize }, ++ 25usize, + concat!( + "Offset of field: ", +- stringify!(kvm_userspace_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(memory_size) ++ stringify!(blob_size_64) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).userspace_addr as *const _ +- as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 26usize, + concat!( + "Offset of field: ", +- stringify!(kvm_userspace_memory_region), ++ stringify!(kvm_xen_hvm_config), + "::", +- stringify!(userspace_addr) ++ stringify!(pad2) + ) + ); + } + #[repr(C)] + #[derive(Copy, Clone)] +-pub struct kvm_irq_level { +- pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1, +- pub level: __u32, ++pub struct kvm_xen_hvm_attr { ++ pub type_: __u16, ++ pub pad: [__u16; 3usize], ++ pub u: kvm_xen_hvm_attr__bindgen_ty_1, + } + #[repr(C)] + #[derive(Copy, Clone)] +-pub union kvm_irq_level__bindgen_ty_1 { +- pub irq: __u32, +- pub status: __s32, ++pub union kvm_xen_hvm_attr__bindgen_ty_1 { ++ pub long_mode: __u8, ++ pub vector: __u8, ++ pub runstate_update_flag: __u8, ++ pub shared_info: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1, ++ pub evtchn: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2, ++ pub xen_version: __u32, ++ pub pad: [__u64; 8usize], ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 { ++ pub gfn: __u64, ++ pub hva: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irq as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gfn) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_level__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(irq) ++ stringify!(gfn) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).status as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hva) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_level__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(status) ++ stringify!(hva) + ) + ); + } +-impl Default for kvm_irq_level__bindgen_ty_1 { ++impl Default for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -4720,150 +5140,200 @@ impl Default for kvm_irq_level__bindgen_ty_1 { + } + } + } +-#[test] +-fn bindgen_test_layout_kvm_irq_level() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_level)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_level)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).level as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_irq_level), +- "::", +- stringify!(level) ++impl ::std::fmt::Debug for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 {{ union }}" + ) +- ); +-} +-impl Default for kvm_irq_level { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } + } + } + #[repr(C)] + #[derive(Copy, Clone)] +-pub struct kvm_irqchip { +- pub chip_id: __u32, +- pub pad: __u32, +- pub chip: kvm_irqchip__bindgen_ty_1, ++pub struct kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2 { ++ pub send_port: __u32, ++ pub type_: __u32, ++ pub flags: __u32, ++ pub deliver: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1, + } + #[repr(C)] + #[derive(Copy, Clone)] +-pub union kvm_irqchip__bindgen_ty_1 { +- pub dummy: [::std::os::raw::c_char; 512usize], +- pub pic: kvm_pic_state, +- pub ioapic: kvm_ioapic_state, ++pub union kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1 { ++ pub port: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1, ++ pub eventfd: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2, ++ pub padding: [__u32; 4usize], ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1 { ++ pub port: __u32, ++ pub vcpu: __u32, ++ pub priority: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 512usize, +- concat!("Size of: ", stringify!(kvm_irqchip__bindgen_ty_1)) ++ ::std::mem::size_of::< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1, ++ >(), ++ 12usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1)) ++ ::std::mem::align_of::< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1, ++ >(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dummy as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(dummy) ++ stringify!(port) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pic as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(pic) ++ stringify!(vcpu) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ioapic as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(ioapic) ++ stringify!(priority) + ) + ); + } +-impl Default for kvm_irqchip__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2 { ++ pub port: __u32, ++ pub fd: __s32, + } + #[test] +-fn bindgen_test_layout_kvm_irqchip() { +- assert_eq!( +- ::std::mem::size_of::(), +- 520usize, +- concat!("Size of: ", stringify!(kvm_irqchip)) +- ); ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::size_of::< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2, ++ >(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_irqchip)) ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).chip_id as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2, ++ >(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(chip_id) ++ stringify!(port) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(pad) ++ stringify!(fd) + ) + ); ++} ++#[test] ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).chip as *const _ as usize }, +- 8usize, ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqchip), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1), + "::", +- stringify!(chip) ++ stringify!(port) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).eventfd) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1), ++ "::", ++ stringify!(eventfd) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1), ++ "::", ++ stringify!(padding) + ) + ); + } +-impl Default for kvm_irqchip { ++impl Default for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -4872,185 +5342,177 @@ impl Default for kvm_irqchip { + } + } + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_pit_config { +- pub flags: __u32, +- pub pad: [__u32; 15usize], ++impl ::std::fmt::Debug for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_pit_config() { ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_pit_config)) ++ ::std::mem::size_of::(), ++ 28usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_pit_config)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).send_port) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pit_config), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(flags) ++ stringify!(send_port) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pit_config), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(pad) ++ stringify!(type_) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).deliver) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(deliver) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_skeys { +- pub start_gfn: __u64, +- pub count: __u64, +- pub skeydata_addr: __u64, +- pub flags: __u32, +- pub reserved: [__u32; 9usize], ++impl Default for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_2 {{ send_port: {:?}, type: {:?}, flags: {:?}, deliver: {:?} }}" , self . send_port , self . type_ , self . flags , self . deliver) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_s390_skeys() { ++fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 64usize, +- concat!("Size of: ", stringify!(kvm_s390_skeys)) ++ concat!("Size of: ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_skeys)) ++ concat!("Alignment of ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).start_gfn as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).long_mode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(start_gfn) ++ stringify!(long_mode) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).count as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(count) ++ stringify!(vector) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).skeydata_addr as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).runstate_update_flag) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(skeydata_addr) ++ stringify!(runstate_update_flag) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).shared_info) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(shared_info) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).evtchn) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_skeys), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(reserved) ++ stringify!(evtchn) + ) + ); +-} +-#[doc = " kvm_s390_cmma_log - Used for CMMA migration."] +-#[doc = ""] +-#[doc = " Used both for input and output."] +-#[doc = ""] +-#[doc = " @start_gfn: Guest page number to start from."] +-#[doc = " @count: Size of the result buffer."] +-#[doc = " @flags: Control operation mode via KVM_S390_CMMA_* flags"] +-#[doc = " @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty"] +-#[doc = " pages are still remaining."] +-#[doc = " @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set"] +-#[doc = " in the PGSTE."] +-#[doc = " @values: Pointer to the values buffer."] +-#[doc = ""] +-#[doc = " Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls."] +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_cmma_log { +- pub start_gfn: __u64, +- pub count: __u32, +- pub flags: __u32, +- pub __bindgen_anon_1: kvm_s390_cmma_log__bindgen_ty_1, +- pub values: __u64, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_cmma_log__bindgen_ty_1 { +- pub remaining: __u64, +- pub mask: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_cmma_log__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_s390_cmma_log__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_cmma_log__bindgen_ty_1)) +- ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).remaining as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).xen_version) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(remaining) ++ stringify!(xen_version) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).mask as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log__bindgen_ty_1), ++ stringify!(kvm_xen_hvm_attr__bindgen_ty_1), + "::", +- stringify!(mask) ++ stringify!(pad) + ) + ); + } +-impl Default for kvm_s390_cmma_log__bindgen_ty_1 { ++impl Default for kvm_xen_hvm_attr__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -5059,60 +5521,57 @@ impl Default for kvm_s390_cmma_log__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_hvm_attr__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_xen_hvm_attr__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] +-fn bindgen_test_layout_kvm_s390_cmma_log() { ++fn bindgen_test_layout_kvm_xen_hvm_attr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_s390_cmma_log)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_xen_hvm_attr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_cmma_log)) ++ concat!("Alignment of ", stringify!(kvm_xen_hvm_attr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).start_gfn as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), +- "::", +- stringify!(start_gfn) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).count as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_xen_hvm_attr), + "::", +- stringify!(count) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_xen_hvm_attr), + "::", +- stringify!(flags) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).values as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_cmma_log), ++ stringify!(kvm_xen_hvm_attr), + "::", +- stringify!(values) ++ stringify!(u) + ) + ); + } +-impl Default for kvm_s390_cmma_log { ++impl Default for kvm_xen_hvm_attr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -5121,349 +5580,330 @@ impl Default for kvm_s390_cmma_log { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_hvm_attr { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_hvm_attr {{ type: {:?}, pad: {:?}, u: {:?} }}", ++ self.type_, self.pad, self.u ++ ) ++ } ++} + #[repr(C)] + #[derive(Copy, Clone)] +-pub struct kvm_hyperv_exit { +- pub type_: __u32, +- pub pad1: __u32, +- pub u: kvm_hyperv_exit__bindgen_ty_1, ++pub struct kvm_xen_vcpu_attr { ++ pub type_: __u16, ++ pub pad: [__u16; 3usize], ++ pub u: kvm_xen_vcpu_attr__bindgen_ty_1, + } + #[repr(C)] + #[derive(Copy, Clone)] +-pub union kvm_hyperv_exit__bindgen_ty_1 { +- pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1, +- pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2, +- pub syndbg: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3, ++pub union kvm_xen_vcpu_attr__bindgen_ty_1 { ++ pub gpa: __u64, ++ pub hva: __u64, ++ pub pad: [__u64; 8usize], ++ pub runstate: kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1, ++ pub vcpu_id: __u32, ++ pub timer: kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2, ++ pub vector: __u8, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 { +- pub msr: __u32, +- pub pad2: __u32, +- pub control: __u64, +- pub evt_page: __u64, +- pub msg_page: __u64, ++pub struct kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1 { ++ pub state: __u64, ++ pub state_entry_time: __u64, ++ pub time_running: __u64, ++ pub time_runnable: __u64, ++ pub time_blocked: __u64, ++ pub time_offline: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, ++ ::std::mem::size_of::(), ++ 48usize, + concat!( + "Size of: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).state) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(msr) ++ stringify!(state) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad2 as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).state_entry_time) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(pad2) ++ stringify!(state_entry_time) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).control +- as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).time_running) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(control) ++ stringify!(time_running) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).evt_page +- as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).time_runnable) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(evt_page) ++ stringify!(time_runnable) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msg_page +- as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).time_blocked) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(msg_page) ++ stringify!(time_blocked) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).time_offline) as usize - ptr as usize }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ "::", ++ stringify!(time_offline) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 { +- pub input: __u64, +- pub result: __u64, +- pub params: [__u64; 2usize], ++pub struct kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2 { ++ pub port: __u32, ++ pub priority: __u32, ++ pub expires_ns: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() { ++fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, ++ ::std::mem::size_of::(), ++ 16usize, + concat!( + "Size of: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).input +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(input) ++ stringify!(port) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).result +- as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(result) ++ stringify!(priority) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).params +- as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).expires_ns) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(params) ++ stringify!(expires_ns) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3 { +- pub msr: __u32, +- pub pad2: __u32, +- pub control: __u64, +- pub status: __u64, +- pub send_page: __u64, +- pub recv_page: __u64, +- pub pending_page: __u64, +-} + #[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { ++fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!( +- "Size of: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) +- ) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) +- ) ++ concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gpa) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(msr) ++ stringify!(gpa) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad2 as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).hva) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(pad2) ++ stringify!(hva) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).control +- as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(control) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).status +- as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).runstate) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(status) ++ stringify!(runstate) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).send_page +- as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu_id) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(send_page) ++ stringify!(vcpu_id) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).recv_page +- as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).timer) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(recv_page) ++ stringify!(timer) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pending_page +- as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), + "::", +- stringify!(pending_page) ++ stringify!(vector) + ) + ); + } ++impl Default for kvm_xen_vcpu_attr__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_xen_vcpu_attr__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_xen_vcpu_attr__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] +-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_xen_vcpu_attr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_xen_vcpu_attr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) ++ concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).synic as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr), + "::", +- stringify!(synic) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hcall as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr), + "::", +- stringify!(hcall) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).syndbg as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit__bindgen_ty_1), ++ stringify!(kvm_xen_vcpu_attr), + "::", +- stringify!(syndbg) ++ stringify!(u) + ) + ); + } +-impl Default for kvm_hyperv_exit__bindgen_ty_1 { ++impl Default for kvm_xen_vcpu_attr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -5472,1860 +5912,1570 @@ impl Default for kvm_hyperv_exit__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_vcpu_attr { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_vcpu_attr {{ type: {:?}, pad: {:?}, u: {:?} }}", ++ self.type_, self.pad, self.u ++ ) ++ } ++} ++pub const sev_cmd_id_KVM_SEV_INIT: sev_cmd_id = 0; ++pub const sev_cmd_id_KVM_SEV_ES_INIT: sev_cmd_id = 1; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_START: sev_cmd_id = 2; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_DATA: sev_cmd_id = 3; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_VMSA: sev_cmd_id = 4; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_SECRET: sev_cmd_id = 5; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_MEASURE: sev_cmd_id = 6; ++pub const sev_cmd_id_KVM_SEV_LAUNCH_FINISH: sev_cmd_id = 7; ++pub const sev_cmd_id_KVM_SEV_SEND_START: sev_cmd_id = 8; ++pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_DATA: sev_cmd_id = 9; ++pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_VMSA: sev_cmd_id = 10; ++pub const sev_cmd_id_KVM_SEV_SEND_FINISH: sev_cmd_id = 11; ++pub const sev_cmd_id_KVM_SEV_RECEIVE_START: sev_cmd_id = 12; ++pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_DATA: sev_cmd_id = 13; ++pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_VMSA: sev_cmd_id = 14; ++pub const sev_cmd_id_KVM_SEV_RECEIVE_FINISH: sev_cmd_id = 15; ++pub const sev_cmd_id_KVM_SEV_GUEST_STATUS: sev_cmd_id = 16; ++pub const sev_cmd_id_KVM_SEV_DBG_DECRYPT: sev_cmd_id = 17; ++pub const sev_cmd_id_KVM_SEV_DBG_ENCRYPT: sev_cmd_id = 18; ++pub const sev_cmd_id_KVM_SEV_CERT_EXPORT: sev_cmd_id = 19; ++pub const sev_cmd_id_KVM_SEV_GET_ATTESTATION_REPORT: sev_cmd_id = 20; ++pub const sev_cmd_id_KVM_SEV_SEND_CANCEL: sev_cmd_id = 21; ++pub const sev_cmd_id_KVM_SEV_NR_MAX: sev_cmd_id = 22; ++pub type sev_cmd_id = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sev_cmd { ++ pub id: __u32, ++ pub pad0: __u32, ++ pub data: __u64, ++ pub error: __u32, ++ pub sev_fd: __u32, ++} + #[test] +-fn bindgen_test_layout_kvm_hyperv_exit() { ++fn bindgen_test_layout_kvm_sev_cmd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 56usize, +- concat!("Size of: ", stringify!(kvm_hyperv_exit)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_sev_cmd)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_hyperv_exit)) ++ concat!("Alignment of ", stringify!(kvm_sev_cmd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit), ++ stringify!(kvm_sev_cmd), + "::", +- stringify!(type_) ++ stringify!(id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad1 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit), ++ stringify!(kvm_sev_cmd), + "::", +- stringify!(pad1) ++ stringify!(pad0) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_exit), ++ stringify!(kvm_sev_cmd), + "::", +- stringify!(u) ++ stringify!(data) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).error) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_cmd), ++ "::", ++ stringify!(error) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).sev_fd) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_cmd), ++ "::", ++ stringify!(sev_fd) + ) + ); +-} +-impl Default for kvm_hyperv_exit { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_xen_exit { +- pub type_: __u32, +- pub u: kvm_xen_exit__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_xen_exit__bindgen_ty_1 { +- pub hcall: kvm_xen_exit__bindgen_ty_1__bindgen_ty_1, + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_exit__bindgen_ty_1__bindgen_ty_1 { +- pub longmode: __u32, +- pub cpl: __u32, +- pub input: __u64, +- pub result: __u64, +- pub params: [__u64; 6usize], ++pub struct kvm_sev_launch_start { ++ pub handle: __u32, ++ pub policy: __u32, ++ pub dh_uaddr: __u64, ++ pub dh_len: __u32, ++ pub pad0: __u32, ++ pub session_uaddr: __u64, ++ pub session_len: __u32, ++ pub pad1: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_sev_launch_start() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!( +- "Size of: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) +- ) ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(kvm_sev_launch_start)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_launch_start)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).longmode +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).handle) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(longmode) ++ stringify!(handle) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).cpl as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).policy) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(cpl) ++ stringify!(policy) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).input as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dh_uaddr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(input) ++ stringify!(dh_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).result as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dh_len) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(result) ++ stringify!(dh_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).params as *const _ +- as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(params) ++ stringify!(pad0) + ) + ); +-} +-#[test] +-fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1() { + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_xen_exit__bindgen_ty_1)) ++ unsafe { ::std::ptr::addr_of!((*ptr).session_uaddr) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_start), ++ "::", ++ stringify!(session_uaddr) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_exit__bindgen_ty_1)) ++ unsafe { ::std::ptr::addr_of!((*ptr).session_len) as usize - ptr as usize }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_start), ++ "::", ++ stringify!(session_len) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hcall as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 36usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit__bindgen_ty_1), ++ stringify!(kvm_sev_launch_start), + "::", +- stringify!(hcall) ++ stringify!(pad1) + ) + ); + } +-impl Default for kvm_xen_exit__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sev_launch_update_data { ++ pub uaddr: __u64, ++ pub len: __u32, ++ pub pad0: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_xen_exit() { ++fn bindgen_test_layout_kvm_sev_launch_update_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 80usize, +- concat!("Size of: ", stringify!(kvm_xen_exit)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_sev_launch_update_data)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_exit)) ++ concat!("Alignment of ", stringify!(kvm_sev_launch_update_data)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).uaddr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit), ++ stringify!(kvm_sev_launch_update_data), + "::", +- stringify!(type_) ++ stringify!(uaddr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_exit), ++ stringify!(kvm_sev_launch_update_data), + "::", +- stringify!(u) ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_update_data), ++ "::", ++ stringify!(pad0) + ) + ); +-} +-impl Default for kvm_xen_exit { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_run { +- pub request_interrupt_window: __u8, +- pub immediate_exit: __u8, +- pub padding1: [__u8; 6usize], +- pub exit_reason: __u32, +- pub ready_for_interrupt_injection: __u8, +- pub if_flag: __u8, +- pub flags: __u16, +- pub cr8: __u64, +- pub apic_base: __u64, +- pub __bindgen_anon_1: kvm_run__bindgen_ty_1, +- pub kvm_valid_regs: __u64, +- pub kvm_dirty_regs: __u64, +- pub s: kvm_run__bindgen_ty_2, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_run__bindgen_ty_1 { +- pub hw: kvm_run__bindgen_ty_1__bindgen_ty_1, +- pub fail_entry: kvm_run__bindgen_ty_1__bindgen_ty_2, +- pub ex: kvm_run__bindgen_ty_1__bindgen_ty_3, +- pub io: kvm_run__bindgen_ty_1__bindgen_ty_4, +- pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5, +- pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6, +- pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_7, +- pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_8, +- pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_9, +- pub s390_reset_flags: __u64, +- pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_10, +- pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_11, +- pub internal: kvm_run__bindgen_ty_1__bindgen_ty_12, +- pub osi: kvm_run__bindgen_ty_1__bindgen_ty_13, +- pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_14, +- pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_15, +- pub epr: kvm_run__bindgen_ty_1__bindgen_ty_16, +- pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_17, +- pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_18, +- pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_19, +- pub hyperv: kvm_hyperv_exit, +- pub arm_nisv: kvm_run__bindgen_ty_1__bindgen_ty_20, +- pub msr: kvm_run__bindgen_ty_1__bindgen_ty_21, +- pub xen: kvm_xen_exit, +- pub padding: [::std::os::raw::c_char; 256usize], + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 { +- pub hardware_exit_reason: __u64, ++pub struct kvm_sev_launch_secret { ++ pub hdr_uaddr: __u64, ++ pub hdr_len: __u32, ++ pub pad0: __u32, ++ pub guest_uaddr: __u64, ++ pub guest_len: __u32, ++ pub pad1: __u32, ++ pub trans_uaddr: __u64, ++ pub trans_len: __u32, ++ pub pad2: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_sev_launch_secret() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_sev_launch_secret)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_launch_secret)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hardware_exit_reason +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_uaddr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_sev_launch_secret), + "::", +- stringify!(hardware_exit_reason) ++ stringify!(hdr_uaddr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 { +- pub hardware_entry_failure_reason: __u64, +- pub cpu: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_len) as usize - ptr as usize }, + 8usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2) ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_secret), ++ "::", ++ stringify!(hdr_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())) +- .hardware_entry_failure_reason as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), ++ stringify!(kvm_sev_launch_secret), + "::", +- stringify!(hardware_entry_failure_reason) ++ stringify!(pad0) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).cpu as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_uaddr) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), ++ stringify!(kvm_sev_launch_secret), + "::", +- stringify!(cpu) ++ stringify!(guest_uaddr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 { +- pub exception: __u32, +- pub error_code: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3)) ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_len) as usize - ptr as usize }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_secret), ++ "::", ++ stringify!(guest_len) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 28usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3) ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_secret), ++ "::", ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).exception as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_uaddr) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_sev_launch_secret), + "::", +- stringify!(exception) ++ stringify!(trans_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).error_code as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_len) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), ++ stringify!(kvm_sev_launch_secret), + "::", +- stringify!(error_code) ++ stringify!(trans_len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_launch_secret), ++ "::", ++ stringify!(pad2) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 { +- pub direction: __u8, +- pub size: __u8, +- pub port: __u16, +- pub count: __u32, +- pub data_offset: __u64, ++pub struct kvm_sev_launch_measure { ++ pub uaddr: __u64, ++ pub len: __u32, ++ pub pad0: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { ++fn bindgen_test_layout_kvm_sev_launch_measure() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4)) ++ concat!("Size of: ", stringify!(kvm_sev_launch_measure)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_launch_measure)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).direction as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).uaddr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ stringify!(kvm_sev_launch_measure), + "::", +- stringify!(direction) ++ stringify!(uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).size as *const _ +- as usize +- }, +- 1usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ stringify!(kvm_sev_launch_measure), + "::", +- stringify!(size) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).port as *const _ +- as usize +- }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ stringify!(kvm_sev_launch_measure), + "::", +- stringify!(port) ++ stringify!(pad0) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sev_guest_status { ++ pub handle: __u32, ++ pub policy: __u32, ++ pub state: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_sev_guest_status() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_sev_guest_status)) ++ ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).count as *const _ +- as usize +- }, ++ ::std::mem::align_of::(), + 4usize, ++ concat!("Alignment of ", stringify!(kvm_sev_guest_status)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).handle) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ stringify!(kvm_sev_guest_status), + "::", +- stringify!(count) ++ stringify!(handle) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data_offset as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).policy) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ stringify!(kvm_sev_guest_status), + "::", +- stringify!(data_offset) ++ stringify!(policy) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 { +- pub arch: kvm_debug_exit_arch, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).state) as usize - ptr as usize }, + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).arch as *const _ +- as usize +- }, +- 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5), ++ stringify!(kvm_sev_guest_status), + "::", +- stringify!(arch) ++ stringify!(state) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 { +- pub phys_addr: __u64, +- pub data: [__u8; 8usize], ++pub struct kvm_sev_dbg { ++ pub src_uaddr: __u64, ++ pub dst_uaddr: __u64, + pub len: __u32, +- pub is_write: __u8, ++ pub pad0: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { ++fn bindgen_test_layout_kvm_sev_dbg() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6)) ++ concat!("Size of: ", stringify!(kvm_sev_dbg)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_dbg)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).phys_addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).src_uaddr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ stringify!(kvm_sev_dbg), + "::", +- stringify!(phys_addr) ++ stringify!(src_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dst_uaddr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ stringify!(kvm_sev_dbg), + "::", +- stringify!(data) ++ stringify!(dst_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).len as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ stringify!(kvm_sev_dbg), + "::", + stringify!(len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), ++ stringify!(kvm_sev_dbg), + "::", +- stringify!(is_write) ++ stringify!(pad0) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 { +- pub nr: __u64, +- pub args: [__u64; 6usize], +- pub ret: __u64, +- pub longmode: __u32, +- pub pad: __u32, ++pub struct kvm_sev_attestation_report { ++ pub mnonce: [__u8; 16usize], ++ pub uaddr: __u64, ++ pub len: __u32, ++ pub pad0: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() { ++fn bindgen_test_layout_kvm_sev_attestation_report() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_sev_attestation_report)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_attestation_report)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mnonce) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ stringify!(kvm_sev_attestation_report), + "::", +- stringify!(nr) ++ stringify!(mnonce) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).args as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).uaddr) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ stringify!(kvm_sev_attestation_report), + "::", +- stringify!(args) ++ stringify!(uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ret as *const _ as usize +- }, +- 56usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ stringify!(kvm_sev_attestation_report), + "::", +- stringify!(ret) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).longmode as *const _ +- as usize +- }, +- 64usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 28usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ stringify!(kvm_sev_attestation_report), + "::", +- stringify!(longmode) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 68usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), +- "::", +- stringify!(pad) ++ stringify!(pad0) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 { +- pub rip: __u64, +- pub is_write: __u32, +- pub pad: __u32, ++pub struct kvm_sev_send_start { ++ pub policy: __u32, ++ pub pad0: __u32, ++ pub pdh_cert_uaddr: __u64, ++ pub pdh_cert_len: __u32, ++ pub pad1: __u32, ++ pub plat_certs_uaddr: __u64, ++ pub plat_certs_len: __u32, ++ pub pad2: __u32, ++ pub amd_certs_uaddr: __u64, ++ pub amd_certs_len: __u32, ++ pub pad3: __u32, ++ pub session_uaddr: __u64, ++ pub session_len: __u32, ++ pub pad4: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() { ++fn bindgen_test_layout_kvm_sev_send_start() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_sev_send_start)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8) +- ) ++ concat!("Alignment of ", stringify!(kvm_sev_send_start)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).rip as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).policy) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(rip) ++ stringify!(policy) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(is_write) ++ stringify!(pad0) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pdh_cert_uaddr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(pad) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 { +- pub icptcode: __u8, +- pub ipa: __u16, +- pub ipb: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9) ++ stringify!(pdh_cert_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).icptcode as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pdh_cert_len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(icptcode) ++ stringify!(pdh_cert_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipa as *const _ as usize +- }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(ipa) ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipb as *const _ as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).plat_certs_uaddr) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(ipb) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 { +- pub trans_exc_code: __u64, +- pub pgm_code: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ stringify!(plat_certs_uaddr) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).plat_certs_len) as usize - ptr as usize }, ++ 32usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_start), ++ "::", ++ stringify!(plat_certs_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_exc_code +- as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 36usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(trans_exc_code) ++ stringify!(pad2) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pgm_code as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).amd_certs_uaddr) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(pgm_code) ++ stringify!(amd_certs_uaddr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 { +- pub dcrn: __u32, +- pub data: __u32, +- pub is_write: __u8, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() { + assert_eq!( +- ::std::mem::size_of::(), +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).amd_certs_len) as usize - ptr as usize }, ++ 48usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_start), ++ "::", ++ stringify!(amd_certs_len) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad3) as usize - ptr as usize }, ++ 52usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_start), ++ "::", ++ stringify!(pad3) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dcrn as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).session_uaddr) as usize - ptr as usize }, ++ 56usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(dcrn) ++ stringify!(session_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).session_len) as usize - ptr as usize }, ++ 64usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(data) ++ stringify!(session_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).is_write as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad4) as usize - ptr as usize }, ++ 68usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), ++ stringify!(kvm_sev_send_start), + "::", +- stringify!(is_write) ++ stringify!(pad4) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 { +- pub suberror: __u32, +- pub ndata: __u32, +- pub data: [__u64; 16usize], ++pub struct kvm_sev_send_update_data { ++ pub hdr_uaddr: __u64, ++ pub hdr_len: __u32, ++ pub pad0: __u32, ++ pub guest_uaddr: __u64, ++ pub guest_len: __u32, ++ pub pad1: __u32, ++ pub trans_uaddr: __u64, ++ pub trans_len: __u32, ++ pub pad2: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() { ++fn bindgen_test_layout_kvm_sev_send_update_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 136usize, ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_sev_send_update_data)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_sev_send_update_data)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_uaddr) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_update_data), ++ "::", ++ stringify!(hdr_uaddr) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_len) as usize - ptr as usize }, + 8usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_update_data), ++ "::", ++ stringify!(hdr_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).suberror as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ stringify!(kvm_sev_send_update_data), + "::", +- stringify!(suberror) ++ stringify!(pad0) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ndata as *const _ +- as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_uaddr) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ stringify!(kvm_sev_send_update_data), + "::", +- stringify!(ndata) ++ stringify!(guest_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_len) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), ++ stringify!(kvm_sev_send_update_data), + "::", +- stringify!(data) ++ stringify!(guest_len) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 { +- pub gprs: [__u64; 32usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() { + assert_eq!( +- ::std::mem::size_of::(), +- 256usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 28usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_update_data), ++ "::", ++ stringify!(pad1) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_uaddr) as usize - ptr as usize }, ++ 32usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) ++ "Offset of field: ", ++ stringify!(kvm_sev_send_update_data), ++ "::", ++ stringify!(trans_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gprs as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_len) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), ++ stringify!(kvm_sev_send_update_data), + "::", +- stringify!(gprs) ++ stringify!(trans_len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_sev_send_update_data), ++ "::", ++ stringify!(pad2) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 { +- pub nr: __u64, +- pub ret: __u64, +- pub args: [__u64; 9usize], ++pub struct kvm_sev_receive_start { ++ pub handle: __u32, ++ pub policy: __u32, ++ pub pdh_uaddr: __u64, ++ pub pdh_len: __u32, ++ pub pad0: __u32, ++ pub session_uaddr: __u64, ++ pub session_len: __u32, ++ pub pad1: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() { ++fn bindgen_test_layout_kvm_sev_receive_start() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 88usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) +- ) ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(kvm_sev_receive_start)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, ++ concat!("Alignment of ", stringify!(kvm_sev_receive_start)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).handle) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_start), ++ "::", ++ stringify!(handle) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).nr as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).policy) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ stringify!(kvm_sev_receive_start), + "::", +- stringify!(nr) ++ stringify!(policy) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ret as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pdh_uaddr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ stringify!(kvm_sev_receive_start), + "::", +- stringify!(ret) ++ stringify!(pdh_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).args as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pdh_len) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), ++ stringify!(kvm_sev_receive_start), + "::", +- stringify!(args) ++ stringify!(pdh_len) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 { +- pub subchannel_id: __u16, +- pub subchannel_nr: __u16, +- pub io_int_parm: __u32, +- pub io_int_word: __u32, +- pub ipb: __u32, +- pub dequeued: __u8, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, + 20usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_start), ++ "::", ++ stringify!(pad0) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).session_uaddr) as usize - ptr as usize }, ++ 24usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_start), ++ "::", ++ stringify!(session_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).subchannel_id +- as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).session_len) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_start), + "::", +- stringify!(subchannel_id) ++ stringify!(session_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).subchannel_nr +- as *const _ as usize +- }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 36usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_start), + "::", +- stringify!(subchannel_nr) ++ stringify!(pad1) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_sev_receive_update_data { ++ pub hdr_uaddr: __u64, ++ pub hdr_len: __u32, ++ pub pad0: __u32, ++ pub guest_uaddr: __u64, ++ pub guest_len: __u32, ++ pub pad1: __u32, ++ pub trans_uaddr: __u64, ++ pub trans_len: __u32, ++ pub pad2: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_sev_receive_update_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).io_int_parm as *const _ +- as usize +- }, +- 4usize, ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_sev_receive_update_data)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_sev_receive_update_data)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_uaddr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_update_data), + "::", +- stringify!(io_int_parm) ++ stringify!(hdr_uaddr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).io_int_word as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hdr_len) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_update_data), + "::", +- stringify!(io_int_word) ++ stringify!(hdr_len) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ipb as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_update_data), + "::", +- stringify!(ipb) ++ stringify!(pad0) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dequeued as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_uaddr) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), ++ stringify!(kvm_sev_receive_update_data), + "::", +- stringify!(dequeued) ++ stringify!(guest_uaddr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 { +- pub epr: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() { + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_len) as usize - ptr as usize }, ++ 24usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_update_data), ++ "::", ++ stringify!(guest_len) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 28usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_update_data), ++ "::", ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).epr as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_uaddr) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), ++ stringify!(kvm_sev_receive_update_data), + "::", +- stringify!(epr) ++ stringify!(trans_uaddr) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 { +- pub type_: __u32, +- pub flags: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() { + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_len) as usize - ptr as usize }, ++ 40usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_update_data), ++ "::", ++ stringify!(trans_len) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 44usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).type_ as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), +- "::", +- stringify!(type_) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).flags as *const _ +- as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), +- "::", +- stringify!(flags) ++ "Offset of field: ", ++ stringify!(kvm_sev_receive_update_data), ++ "::", ++ stringify!(pad2) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 { +- pub addr: __u64, +- pub ar: __u8, +- pub reserved: __u8, +- pub fc: __u8, +- pub sel1: __u8, +- pub sel2: __u16, ++pub struct kvm_hyperv_eventfd { ++ pub conn_id: __u32, ++ pub fd: __s32, ++ pub flags: __u32, ++ pub padding: [__u32; 3usize], + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() { ++fn bindgen_test_layout_kvm_hyperv_eventfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) +- ) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_hyperv_eventfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) +- ) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_hyperv_eventfd)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).addr as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).conn_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), +- "::", +- stringify!(addr) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ar as *const _ as usize +- }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), +- "::", +- stringify!(ar) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ +- as usize +- }, +- 9usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_hyperv_eventfd), + "::", +- stringify!(reserved) ++ stringify!(conn_id) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fc as *const _ as usize +- }, +- 10usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_hyperv_eventfd), + "::", +- stringify!(fc) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).sel1 as *const _ +- as usize +- }, +- 11usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_hyperv_eventfd), + "::", +- stringify!(sel1) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).sel2 as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), ++ stringify!(kvm_hyperv_eventfd), + "::", +- stringify!(sel2) ++ stringify!(padding) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 { +- pub vector: __u8, ++pub struct kvm_userspace_memory_region { ++ pub slot: __u32, ++ pub flags: __u32, ++ pub guest_phys_addr: __u64, ++ pub memory_size: __u64, ++ pub userspace_addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() { ++fn bindgen_test_layout_kvm_userspace_memory_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 1usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) +- ) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_userspace_memory_region)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 1usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) +- ) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_userspace_memory_region)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vector as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), ++ stringify!(kvm_userspace_memory_region), + "::", +- stringify!(vector) ++ stringify!(slot) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_20 { +- pub esr_iss: __u64, +- pub fault_ipa: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_20() { + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(flags) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, + 8usize, + concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ "Offset of field: ", ++ stringify!(kvm_userspace_memory_region), ++ "::", ++ stringify!(guest_phys_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).esr_iss as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ stringify!(kvm_userspace_memory_region), + "::", +- stringify!(esr_iss) ++ stringify!(memory_size) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fault_ipa as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), ++ stringify!(kvm_userspace_memory_region), + "::", +- stringify!(fault_ipa) ++ stringify!(userspace_addr) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_run__bindgen_ty_1__bindgen_ty_21 { +- pub error: __u8, +- pub pad: [__u8; 7usize], +- pub reason: __u32, +- pub index: __u32, +- pub data: __u64, ++pub struct kvm_userspace_memory_region2 { ++ pub slot: __u32, ++ pub flags: __u32, ++ pub guest_phys_addr: __u64, ++ pub memory_size: __u64, ++ pub userspace_addr: __u64, ++ pub guest_memfd_offset: __u64, ++ pub guest_memfd: __u32, ++ pub pad1: __u32, ++ pub pad2: [__u64; 14usize], + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_21() { ++fn bindgen_test_layout_kvm_userspace_memory_region2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!( +- "Size of: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) +- ) ++ ::std::mem::size_of::(), ++ 160usize, ++ concat!("Size of: ", stringify!(kvm_userspace_memory_region2)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) +- ) ++ concat!("Alignment of ", stringify!(kvm_userspace_memory_region2)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).error as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(error) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ +- as usize +- }, +- 1usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(pad) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reason as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_phys_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(reason) ++ stringify!(guest_phys_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).index as *const _ +- as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_size) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(index) ++ stringify!(memory_size) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).data as *const _ +- as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).userspace_addr) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(data) ++ stringify!(userspace_addr) + ) + ); +-} +-#[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 256usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hw as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd_offset) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(hw) ++ stringify!(guest_memfd_offset) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).fail_entry as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).guest_memfd) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(fail_entry) ++ stringify!(guest_memfd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ex as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, ++ 44usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(ex) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(io) ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).debug as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 48usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_userspace_memory_region2), + "::", +- stringify!(debug) ++ stringify!(pad2) + ) + ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_level { ++ pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1, ++ pub level: __u32, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_level__bindgen_ty_1 { ++ pub irq: __u32, ++ pub status: __s32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mmio as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(mmio) +- ) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hypercall as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(hypercall) +- ) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).tpr_access as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(tpr_access) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).s390_sieic as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irq_level__bindgen_ty_1), + "::", +- stringify!(s390_sieic) ++ stringify!(irq) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).s390_reset_flags as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irq_level__bindgen_ty_1), + "::", +- stringify!(s390_reset_flags) ++ stringify!(status) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_irq_level__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).s390_ucontrol as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_ucontrol) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dcr as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(dcr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).internal as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(internal) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).osi as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(osi) +- ) +- ); ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_level__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_level__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_level() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).papr_hcall as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(papr_hcall) +- ) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_level)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s390_tsch as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_tsch) +- ) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_level)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).epr as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).level) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irq_level), + "::", +- stringify!(epr) ++ stringify!(level) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_irq_level { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).system_event as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(system_event) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s390_stsi as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(s390_stsi) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).eoi as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(eoi) ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_level { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_level {{ __bindgen_anon_1: {:?}, level: {:?} }}", ++ self.__bindgen_anon_1, self.level + ) +- ); ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_irqchip { ++ pub chip_id: __u32, ++ pub pad: __u32, ++ pub chip: kvm_irqchip__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irqchip__bindgen_ty_1 { ++ pub dummy: [::std::os::raw::c_char; 512usize], ++ pub pic: kvm_pic_state, ++ pub ioapic: kvm_ioapic_state, ++} ++#[test] ++fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hyperv as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(hyperv) +- ) ++ ::std::mem::size_of::(), ++ 512usize, ++ concat!("Size of: ", stringify!(kvm_irqchip__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).arm_nisv as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), +- "::", +- stringify!(arm_nisv) +- ) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).msr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dummy) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irqchip__bindgen_ty_1), + "::", +- stringify!(msr) ++ stringify!(dummy) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).xen as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pic) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irqchip__bindgen_ty_1), + "::", +- stringify!(xen) ++ stringify!(pic) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ioapic) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_1), ++ stringify!(kvm_irqchip__bindgen_ty_1), + "::", +- stringify!(padding) ++ stringify!(ioapic) + ) + ); + } +-impl Default for kvm_run__bindgen_ty_1 { ++impl Default for kvm_irqchip__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7334,46 +7484,57 @@ impl Default for kvm_run__bindgen_ty_1 { + } + } + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_run__bindgen_ty_2 { +- pub regs: kvm_sync_regs, +- pub padding: [::std::os::raw::c_char; 2048usize], ++impl ::std::fmt::Debug for kvm_irqchip__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irqchip__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_run__bindgen_ty_2() { ++fn bindgen_test_layout_kvm_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 2048usize, +- concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2)) ++ ::std::mem::size_of::(), ++ 520usize, ++ concat!("Size of: ", stringify!(kvm_irqchip)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2)) ++ concat!("Alignment of ", stringify!(kvm_irqchip)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).chip_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_2), ++ stringify!(kvm_irqchip), + "::", +- stringify!(regs) ++ stringify!(chip_id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run__bindgen_ty_2), ++ stringify!(kvm_irqchip), + "::", +- stringify!(padding) ++ stringify!(pad) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).chip) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_irqchip), ++ "::", ++ stringify!(chip) + ) + ); + } +-impl Default for kvm_run__bindgen_ty_2 { ++impl Default for kvm_irqchip { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7382,368 +7543,360 @@ impl Default for kvm_run__bindgen_ty_2 { + } + } + } ++impl ::std::fmt::Debug for kvm_irqchip { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irqchip {{ chip_id: {:?}, pad: {:?}, chip: {:?} }}", ++ self.chip_id, self.pad, self.chip ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_pit_config { ++ pub flags: __u32, ++ pub pad: [__u32; 15usize], ++} + #[test] +-fn bindgen_test_layout_kvm_run() { ++fn bindgen_test_layout_kvm_pit_config() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 2352usize, +- concat!("Size of: ", stringify!(kvm_run)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_pit_config)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_run)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_pit_config)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).request_interrupt_window as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_pit_config), + "::", +- stringify!(request_interrupt_window) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).immediate_exit as *const _ as usize }, +- 1usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_pit_config), + "::", +- stringify!(immediate_exit) ++ stringify!(pad) + ) + ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_hyperv_exit { ++ pub type_: __u32, ++ pub pad1: __u32, ++ pub u: kvm_hyperv_exit__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_hyperv_exit__bindgen_ty_1 { ++ pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1, ++ pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2, ++ pub syndbg: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 { ++ pub msr: __u32, ++ pub pad2: __u32, ++ pub control: __u64, ++ pub evt_page: __u64, ++ pub msg_page: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding1 as *const _ as usize }, +- 2usize, ++ ::std::mem::size_of::(), ++ 32usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(padding1) ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exit_reason as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(exit_reason) ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ready_for_interrupt_injection as *const _ as usize +- }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(ready_for_interrupt_injection) ++ stringify!(msr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).if_flag as *const _ as usize }, +- 13usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(if_flag) ++ stringify!(pad2) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 14usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(control) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr8 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).evt_page) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(cr8) ++ stringify!(evt_page) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).apic_base as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).msg_page) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(apic_base) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).kvm_valid_regs as *const _ as usize }, +- 288usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(kvm_valid_regs) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).kvm_dirty_regs as *const _ as usize }, +- 296usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run), +- "::", +- stringify!(kvm_dirty_regs) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).s as *const _ as usize }, +- 304usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_run), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(s) ++ stringify!(msg_page) + ) + ); + } +-impl Default for kvm_run { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_coalesced_mmio_zone { +- pub addr: __u64, +- pub size: __u32, +- pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1, +-} + #[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_coalesced_mmio_zone__bindgen_ty_1 { +- pub pad: __u32, +- pub pio: __u32, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 { ++ pub input: __u64, ++ pub result: __u64, ++ pub params: [__u64; 2usize], + } + #[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, ++ ::std::mem::size_of::(), ++ 32usize, + concat!( + "Size of: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(pad) ++ stringify!(input) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pio as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(pio) ++ stringify!(result) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2), ++ "::", ++ stringify!(params) + ) + ); + } +-impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3 { ++ pub msr: __u32, ++ pub pad2: __u32, ++ pub control: __u64, ++ pub status: __u64, ++ pub send_page: __u64, ++ pub recv_page: __u64, ++ pub pending_page: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_zone() { ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), + "::", +- stringify!(addr) ++ stringify!(msr) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad2) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(pad2) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_zone), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), + "::", +- stringify!(size) ++ stringify!(control) + ) + ); +-} +-impl Default for kvm_coalesced_mmio_zone { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_coalesced_mmio { +- pub phys_addr: __u64, +- pub len: __u32, +- pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1, +- pub data: [__u8; 8usize], +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_coalesced_mmio__bindgen_ty_1 { +- pub pad: __u32, +- pub pio: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() { + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1)) ++ unsafe { ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(status) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).send_page) as usize - ptr as usize }, ++ 24usize, + concat!( +- "Alignment of ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(send_page) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).recv_page) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), + "::", +- stringify!(pad) ++ stringify!(recv_page) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pio as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pending_page) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio__bindgen_ty_1), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_3), + "::", +- stringify!(pio) ++ stringify!(pending_page) + ) + ); + } +-impl Default for kvm_coalesced_mmio__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[test] +-fn bindgen_test_layout_kvm_coalesced_mmio() { ++fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio)) ++ concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).phys_addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).synic) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), + "::", +- stringify!(phys_addr) ++ stringify!(synic) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), + "::", +- stringify!(len) ++ stringify!(hcall) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).syndbg) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio), ++ stringify!(kvm_hyperv_exit__bindgen_ty_1), + "::", +- stringify!(data) ++ stringify!(syndbg) + ) + ); + } +-impl Default for kvm_coalesced_mmio { ++impl Default for kvm_hyperv_exit__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7752,58 +7905,57 @@ impl Default for kvm_coalesced_mmio { + } + } + } +-#[repr(C)] +-pub struct kvm_coalesced_mmio_ring { +- pub first: __u32, +- pub last: __u32, +- pub coalesced_mmio: __IncompleteArrayField, ++impl ::std::fmt::Debug for kvm_hyperv_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_hyperv_exit__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_coalesced_mmio_ring() { ++fn bindgen_test_layout_kvm_hyperv_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring)) ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(kvm_hyperv_exit)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring)) ++ concat!("Alignment of ", stringify!(kvm_hyperv_exit)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).first as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), ++ stringify!(kvm_hyperv_exit), + "::", +- stringify!(first) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).last as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad1) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), ++ stringify!(kvm_hyperv_exit), + "::", +- stringify!(last) ++ stringify!(pad1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).coalesced_mmio as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_coalesced_mmio_ring), ++ stringify!(kvm_hyperv_exit), + "::", +- stringify!(coalesced_mmio) ++ stringify!(u) + ) + ); + } +-impl Default for kvm_coalesced_mmio_ring { ++impl Default for kvm_hyperv_exit { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7812,159 +7964,183 @@ impl Default for kvm_coalesced_mmio_ring { + } + } + } ++impl ::std::fmt::Debug for kvm_hyperv_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_hyperv_exit {{ type: {:?}, pad1: {:?}, u: {:?} }}", ++ self.type_, self.pad1, self.u ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_xen_exit { ++ pub type_: __u32, ++ pub u: kvm_xen_exit__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_xen_exit__bindgen_ty_1 { ++ pub hcall: kvm_xen_exit__bindgen_ty_1__bindgen_ty_1, ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_translation { +- pub linear_address: __u64, +- pub physical_address: __u64, +- pub valid: __u8, +- pub writeable: __u8, +- pub usermode: __u8, +- pub pad: [__u8; 5usize], ++pub struct kvm_xen_exit__bindgen_ty_1__bindgen_ty_1 { ++ pub longmode: __u32, ++ pub cpl: __u32, ++ pub input: __u64, ++ pub result: __u64, ++ pub params: [__u64; 6usize], + } + #[test] +-fn bindgen_test_layout_kvm_translation() { ++fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_translation)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_translation)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).linear_address as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_translation), +- "::", +- stringify!(linear_address) ++ "Alignment of ", ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).physical_address as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_translation), ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(physical_address) ++ stringify!(longmode) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).valid as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cpl) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_translation), ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(valid) ++ stringify!(cpl) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).writeable as *const _ as usize }, +- 17usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).input) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_translation), ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(writeable) ++ stringify!(input) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).usermode as *const _ as usize }, +- 18usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).result) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_translation), ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(usermode) ++ stringify!(result) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 19usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_translation), ++ stringify!(kvm_xen_exit__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(params) + ) + ); + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_mem_op { +- pub gaddr: __u64, +- pub flags: __u64, +- pub size: __u32, +- pub op: __u32, +- pub buf: __u64, +- pub __bindgen_anon_1: kvm_s390_mem_op__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_mem_op__bindgen_ty_1 { +- pub ar: __u8, +- pub sida_offset: __u32, +- pub reserved: [__u8; 32usize], +-} + #[test] +-fn bindgen_test_layout_kvm_s390_mem_op__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_xen_exit__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_s390_mem_op__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_xen_exit__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_mem_op__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_xen_exit__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ar as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hcall) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), ++ stringify!(kvm_xen_exit__bindgen_ty_1), + "::", +- stringify!(ar) ++ stringify!(hcall) + ) + ); +- assert_eq!( ++} ++impl Default for kvm_xen_exit__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +- &(*(::std::ptr::null::())).sida_offset as *const _ +- as usize +- }, ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_xen_exit__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_xen_exit__bindgen_ty_1 {{ union }}") ++ } ++} ++#[test] ++fn bindgen_test_layout_kvm_xen_exit() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 80usize, ++ concat!("Size of: ", stringify!(kvm_xen_exit)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_xen_exit)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), ++ stringify!(kvm_xen_exit), + "::", +- stringify!(sida_offset) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op__bindgen_ty_1), ++ stringify!(kvm_xen_exit), + "::", +- stringify!(reserved) ++ stringify!(u) + ) + ); + } +-impl Default for kvm_s390_mem_op__bindgen_ty_1 { ++impl Default for kvm_xen_exit { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -7973,2216 +8149,2194 @@ impl Default for kvm_s390_mem_op__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_xen_exit { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_xen_exit {{ type: {:?}, u: {:?} }}", ++ self.type_, self.u ++ ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run { ++ pub request_interrupt_window: __u8, ++ pub immediate_exit: __u8, ++ pub padding1: [__u8; 6usize], ++ pub exit_reason: __u32, ++ pub ready_for_interrupt_injection: __u8, ++ pub if_flag: __u8, ++ pub flags: __u16, ++ pub cr8: __u64, ++ pub apic_base: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1, ++ pub kvm_valid_regs: __u64, ++ pub kvm_dirty_regs: __u64, ++ pub s: kvm_run__bindgen_ty_2, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1 { ++ pub hw: kvm_run__bindgen_ty_1__bindgen_ty_1, ++ pub fail_entry: kvm_run__bindgen_ty_1__bindgen_ty_2, ++ pub ex: kvm_run__bindgen_ty_1__bindgen_ty_3, ++ pub io: kvm_run__bindgen_ty_1__bindgen_ty_4, ++ pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5, ++ pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6, ++ pub iocsr_io: kvm_run__bindgen_ty_1__bindgen_ty_7, ++ pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_8, ++ pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_9, ++ pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_10, ++ pub s390_reset_flags: __u64, ++ pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_11, ++ pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_12, ++ pub internal: kvm_run__bindgen_ty_1__bindgen_ty_13, ++ pub emulation_failure: kvm_run__bindgen_ty_1__bindgen_ty_14, ++ pub osi: kvm_run__bindgen_ty_1__bindgen_ty_15, ++ pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_16, ++ pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_17, ++ pub epr: kvm_run__bindgen_ty_1__bindgen_ty_18, ++ pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_19, ++ pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_20, ++ pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_21, ++ pub hyperv: kvm_hyperv_exit, ++ pub arm_nisv: kvm_run__bindgen_ty_1__bindgen_ty_22, ++ pub msr: kvm_run__bindgen_ty_1__bindgen_ty_23, ++ pub xen: kvm_xen_exit, ++ pub riscv_sbi: kvm_run__bindgen_ty_1__bindgen_ty_24, ++ pub riscv_csr: kvm_run__bindgen_ty_1__bindgen_ty_25, ++ pub notify: kvm_run__bindgen_ty_1__bindgen_ty_26, ++ pub memory_fault: kvm_run__bindgen_ty_1__bindgen_ty_27, ++ pub padding: [::std::os::raw::c_char; 256usize], ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 { ++ pub hardware_exit_reason: __u64, ++} + #[test] +-fn bindgen_test_layout_kvm_s390_mem_op() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_s390_mem_op)) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::size_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_mem_op)) ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gaddr as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(gaddr) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).hardware_exit_reason) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(hardware_exit_reason) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 { ++ pub hardware_entry_failure_reason: __u64, ++ pub cpu: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, ++ ::std::mem::size_of::(), + 16usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mem_op), +- "::", +- stringify!(size) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).op as *const _ as usize }, +- 20usize, ++ unsafe { ++ ::std::ptr::addr_of!((*ptr).hardware_entry_failure_reason) as usize - ptr as usize ++ }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(op) ++ stringify!(hardware_entry_failure_reason) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cpu) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mem_op), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2), + "::", +- stringify!(buf) ++ stringify!(cpu) + ) + ); + } +-impl Default for kvm_s390_mem_op { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_interrupt { +- pub irq: __u32, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 { ++ pub exception: __u32, ++ pub error_code: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_interrupt() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_interrupt)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_interrupt)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irq as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exception) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_interrupt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), + "::", +- stringify!(irq) ++ stringify!(exception) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).error_code) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3), ++ "::", ++ stringify!(error_code) + ) + ); + } + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_dirty_log { +- pub slot: __u32, +- pub padding1: __u32, +- pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_dirty_log__bindgen_ty_1 { +- pub dirty_bitmap: *mut ::std::os::raw::c_void, +- pub padding2: __u64, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 { ++ pub direction: __u8, ++ pub size: __u8, ++ pub port: __u16, ++ pub count: __u32, ++ pub data_offset: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dirty_bitmap as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).direction) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_log__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), + "::", +- stringify!(dirty_bitmap) ++ stringify!(direction) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).padding2 as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_log__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), + "::", +- stringify!(padding2) ++ stringify!(size) + ) + ); +-} +-impl Default for kvm_dirty_log__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_dirty_log() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_log)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_log)) ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 2usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), ++ "::", ++ stringify!(port) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_log), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), + "::", +- stringify!(slot) ++ stringify!(count) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding1 as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_log), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4), + "::", +- stringify!(padding1) ++ stringify!(data_offset) + ) + ); + } +-impl Default for kvm_dirty_log { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_clear_dirty_log { +- pub slot: __u32, +- pub num_pages: __u32, +- pub first_page: __u64, +- pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_clear_dirty_log__bindgen_ty_1 { +- pub dirty_bitmap: *mut ::std::os::raw::c_void, +- pub padding2: __u64, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 { ++ pub arch: kvm_debug_exit_arch, + } + #[test] +-fn bindgen_test_layout_kvm_clear_dirty_log__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).dirty_bitmap as *const _ +- as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1), +- "::", +- stringify!(dirty_bitmap) ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).padding2 as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clear_dirty_log__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5), + "::", +- stringify!(padding2) ++ stringify!(arch) + ) + ); + } +-impl Default for kvm_clear_dirty_log__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 { ++ pub phys_addr: __u64, ++ pub data: [__u8; 8usize], ++ pub len: __u32, ++ pub is_write: __u8, + } + #[test] +-fn bindgen_test_layout_kvm_clear_dirty_log() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_clear_dirty_log)) ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_clear_dirty_log)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_clear_dirty_log), +- "::", +- stringify!(slot) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).num_pages as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clear_dirty_log), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), + "::", +- stringify!(num_pages) ++ stringify!(phys_addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).first_page as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clear_dirty_log), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), + "::", +- stringify!(first_page) ++ stringify!(data) + ) + ); +-} +-impl Default for kvm_clear_dirty_log { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default)] +-pub struct kvm_signal_mask { +- pub len: __u32, +- pub sigset: __IncompleteArrayField<__u8>, +-} +-#[test] +-fn bindgen_test_layout_kvm_signal_mask() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_signal_mask)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_signal_mask)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_signal_mask), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), + "::", + stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sigset as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_signal_mask), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6), + "::", +- stringify!(sigset) ++ stringify!(is_write) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_tpr_access_ctl { +- pub enabled: __u32, +- pub flags: __u32, +- pub reserved: [__u32; 8usize], ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 { ++ pub phys_addr: __u64, ++ pub data: [__u8; 8usize], ++ pub len: __u32, ++ pub is_write: __u8, + } + #[test] +-fn bindgen_test_layout_kvm_tpr_access_ctl() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_tpr_access_ctl)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_tpr_access_ctl)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enabled as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(enabled) ++ stringify!(phys_addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(flags) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_tpr_access_ctl), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), + "::", +- stringify!(reserved) ++ stringify!(len) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7), ++ "::", ++ stringify!(is_write) + ) + ); + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_vapic_addr { +- pub vapic_addr: __u64, ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ pub nr: __u64, ++ pub args: [__u64; 6usize], ++ pub ret: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ pub longmode: __u32, ++ pub flags: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_vapic_addr() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 8usize, +- concat!("Size of: ", stringify!(kvm_vapic_addr)) ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_vapic_addr)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vapic_addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).longmode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_vapic_addr), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), + "::", +- stringify!(vapic_addr) ++ stringify!(longmode) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_mp_state { +- pub mp_state: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_mp_state() { +- assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_mp_state)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_mp_state)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mp_state as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_mp_state), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1), + "::", +- stringify!(mp_state) ++ stringify!(flags) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_psw { +- pub mask: __u64, +- pub addr: __u64, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_8__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_s390_psw() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_psw)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_psw)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mask as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_psw), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), + "::", +- stringify!(mask) ++ stringify!(nr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_psw), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), + "::", +- stringify!(addr) ++ stringify!(args) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8), ++ "::", ++ stringify!(ret) + ) + ); + } ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_8 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_8 {{ nr: {:?}, args: {:?}, ret: {:?}, __bindgen_anon_1: {:?} }}" , self . nr , self . args , self . ret , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_interrupt { +- pub type_: __u32, +- pub parm: __u32, +- pub parm64: __u64, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 { ++ pub rip: __u64, ++ pub is_write: __u32, ++ pub pad: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_interrupt() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_s390_interrupt)) ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_interrupt)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).rip) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_interrupt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(type_) ++ stringify!(rip) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).parm as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_interrupt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(parm) ++ stringify!(is_write) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).parm64 as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_interrupt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9), + "::", +- stringify!(parm64) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_io_info { +- pub subchannel_id: __u16, +- pub subchannel_nr: __u16, +- pub io_int_parm: __u32, +- pub io_int_word: __u32, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 { ++ pub icptcode: __u8, ++ pub ipa: __u16, ++ pub ipb: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_io_info() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 12usize, +- concat!("Size of: ", stringify!(kvm_s390_io_info)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_io_info)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).subchannel_id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).icptcode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_io_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), + "::", +- stringify!(subchannel_id) ++ stringify!(icptcode) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).subchannel_nr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ipa) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_io_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), + "::", +- stringify!(subchannel_nr) ++ stringify!(ipa) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io_int_parm as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_io_info), +- "::", +- stringify!(io_int_parm) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io_int_word as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_io_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10), + "::", +- stringify!(io_int_word) ++ stringify!(ipb) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_ext_info { +- pub ext_params: __u32, +- pub pad: __u32, +- pub ext_params2: __u64, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 { ++ pub trans_exc_code: __u64, ++ pub pgm_code: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_ext_info() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_s390_ext_info)) ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_ext_info)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext_params as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_ext_info), +- "::", +- stringify!(ext_params) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).trans_exc_code) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ext_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), + "::", +- stringify!(pad) ++ stringify!(trans_exc_code) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext_params2 as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).pgm_code) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ext_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11), + "::", +- stringify!(ext_params2) ++ stringify!(pgm_code) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pgm_info { +- pub trans_exc_code: __u64, +- pub mon_code: __u64, +- pub per_address: __u64, +- pub data_exc_code: __u32, +- pub code: __u16, +- pub mon_class_nr: __u16, +- pub per_code: __u8, +- pub per_atmid: __u8, +- pub exc_access_id: __u8, +- pub per_access_id: __u8, +- pub op_access_id: __u8, +- pub flags: __u8, +- pub pad: [__u8; 2usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_pgm_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_s390_pgm_info)) ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 { ++ pub dcrn: __u32, ++ pub data: __u32, ++ pub is_write: __u8, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pgm_info)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_exc_code as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).dcrn) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(trans_exc_code) ++ stringify!(dcrn) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mon_code as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(mon_code) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_address as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).is_write) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12), + "::", +- stringify!(per_address) ++ stringify!(is_write) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 { ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub data: [__u64; 16usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data_exc_code as *const _ as usize }, +- 24usize, ++ ::std::mem::size_of::(), ++ 136usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(data_exc_code) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 28usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(code) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mon_class_nr as *const _ as usize }, +- 30usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), + "::", +- stringify!(mon_class_nr) ++ stringify!(suberror) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_code as *const _ as usize }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), + "::", +- stringify!(per_code) ++ stringify!(ndata) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_atmid as *const _ as usize }, +- 33usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13), + "::", +- stringify!(per_atmid) ++ stringify!(data) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ pub suberror: __u32, ++ pub ndata: __u32, ++ pub flags: __u64, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1 { ++ pub insn_size: __u8, ++ pub insn_bytes: [__u8; 15usize], ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit< ++ kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1, ++ > = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).exc_access_id as *const _ as usize }, +- 34usize, ++ ::std::mem::align_of::(), ++ 1usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(exc_access_id) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).per_access_id as *const _ as usize }, +- 35usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_size) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(per_access_id) ++ stringify!(insn_size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).op_access_id as *const _ as usize }, +- 36usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).insn_bytes) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pgm_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1__bindgen_ty_1), + "::", +- stringify!(op_access_id) ++ stringify!(insn_bytes) + ) + ); ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1() { + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 37usize, ++ ::std::mem::size_of::(), ++ 16usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(flags) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 38usize, ++ ::std::mem::align_of::(), ++ 1usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pgm_info), +- "::", +- stringify!(pad) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_prefix_info { +- pub address: __u32, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_14__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_s390_prefix_info() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_s390_prefix_info)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_prefix_info)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).suberror) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_prefix_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(address) ++ stringify!(suberror) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_extcall_info { +- pub code: __u16, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_extcall_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 2usize, +- concat!("Size of: ", stringify!(kvm_s390_extcall_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 2usize, +- concat!("Alignment of ", stringify!(kvm_s390_extcall_info)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_extcall_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(code) ++ stringify!(ndata) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_emerg_info { +- pub code: __u16, +-} +-#[test] +-fn bindgen_test_layout_kvm_s390_emerg_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 2usize, +- concat!("Size of: ", stringify!(kvm_s390_emerg_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 2usize, +- concat!("Alignment of ", stringify!(kvm_s390_emerg_info)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).code as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_emerg_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14), + "::", +- stringify!(code) ++ stringify!(flags) + ) + ); + } ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_14 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_14 {{ suberror: {:?}, ndata: {:?}, flags: {:?}, __bindgen_anon_1: {:?} }}" , self . suberror , self . ndata , self . flags , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_stop_info { +- pub flags: __u32, ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 { ++ pub gprs: [__u64; 32usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_stop_info() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_s390_stop_info)) ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_s390_stop_info)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gprs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_stop_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15), + "::", +- stringify!(flags) ++ stringify!(gprs) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_mchk_info { +- pub cr14: __u64, +- pub mcic: __u64, +- pub failing_storage_address: __u64, +- pub ext_damage_code: __u32, +- pub pad: __u32, +- pub fixed_logout: [__u8; 16usize], ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 { ++ pub nr: __u64, ++ pub ret: __u64, ++ pub args: [__u64; 9usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_mchk_info() { +- assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_s390_mchk_info)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_mchk_info)) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cr14 as *const _ as usize }, +- 0usize, ++ ::std::mem::size_of::(), ++ 88usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(cr14) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mcic as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(mcic) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).failing_storage_address as *const _ +- as usize +- }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_mchk_info), +- "::", +- stringify!(failing_storage_address) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ext_damage_code as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mchk_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(ext_damage_code) ++ stringify!(nr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mchk_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(pad) ++ stringify!(ret) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fixed_logout as *const _ as usize }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_mchk_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16), + "::", +- stringify!(fixed_logout) ++ stringify!(args) + ) + ); + } + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_s390_irq { +- pub type_: __u64, +- pub u: kvm_s390_irq__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_s390_irq__bindgen_ty_1 { +- pub io: kvm_s390_io_info, +- pub ext: kvm_s390_ext_info, +- pub pgm: kvm_s390_pgm_info, +- pub emerg: kvm_s390_emerg_info, +- pub extcall: kvm_s390_extcall_info, +- pub prefix: kvm_s390_prefix_info, +- pub stop: kvm_s390_stop_info, +- pub mchk: kvm_s390_mchk_info, +- pub reserved: [::std::os::raw::c_char; 64usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 { ++ pub subchannel_id: __u16, ++ pub subchannel_nr: __u16, ++ pub io_int_parm: __u32, ++ pub io_int_word: __u32, ++ pub ipb: __u32, ++ pub dequeued: __u8, + } + #[test] +-fn bindgen_test_layout_kvm_s390_irq__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_s390_irq__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).io as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(io) +- ) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).ext as *const _ as usize }, +- 0usize, ++ ::std::mem::size_of::(), ++ 20usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(ext) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pgm as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), +- "::", +- stringify!(pgm) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).emerg as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(emerg) ++ stringify!(subchannel_id) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).extcall as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).subchannel_nr) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(extcall) ++ stringify!(subchannel_nr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).prefix as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_parm) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(prefix) ++ stringify!(io_int_parm) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).stop as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io_int_word) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(stop) ++ stringify!(io_int_word) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mchk as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ipb) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(mchk) ++ stringify!(ipb) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dequeued) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17), + "::", +- stringify!(reserved) ++ stringify!(dequeued) + ) + ); + } +-impl Default for kvm_s390_irq__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 { ++ pub epr: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_irq() { +- assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_s390_irq)) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq), +- "::", +- stringify!(type_) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18), + "::", +- stringify!(u) ++ stringify!(epr) + ) + ); + } +-impl Default for kvm_s390_irq { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ pub type_: __u32, ++ pub ndata: __u32, ++ pub __bindgen_anon_1: kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1, + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_irq_state { +- pub buf: __u64, +- pub flags: __u32, +- pub len: __u32, +- pub reserved: [__u32; 4usize], ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ pub flags: __u64, ++ pub data: [__u64; 16usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_irq_state() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_s390_irq_state)) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_irq_state)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).buf as *const _ as usize }, +- 0usize, ++ ::std::mem::size_of::(), ++ 128usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(buf) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_s390_irq_state), +- "::", +- stringify!(flags) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq_state), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), + "::", +- stringify!(len) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_irq_state), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1), + "::", +- stringify!(reserved) ++ stringify!(data) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_guest_debug { +- pub control: __u32, +- pub pad: __u32, +- pub arch: kvm_guest_debug_arch, ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_run__bindgen_ty_1__bindgen_ty_19__bindgen_ty_1 {{ union }}" ++ ) ++ } + } + #[test] +-fn bindgen_test_layout_kvm_guest_debug() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_guest_debug)) ++ ::std::mem::size_of::(), ++ 136usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_guest_debug)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).control as *const _ as usize }, +- 0usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_guest_debug), +- "::", +- stringify!(control) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_guest_debug), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), + "::", +- stringify!(pad) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).arch as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ndata) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_guest_debug), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19), + "::", +- stringify!(arch) ++ stringify!(ndata) + ) + ); + } +-pub const kvm_ioeventfd_flag_nr_datamatch: ::std::os::raw::c_uint = 0; +-pub const kvm_ioeventfd_flag_nr_pio: ::std::os::raw::c_uint = 1; +-pub const kvm_ioeventfd_flag_nr_deassign: ::std::os::raw::c_uint = 2; +-pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: ::std::os::raw::c_uint = 3; +-pub const kvm_ioeventfd_flag_nr_fast_mmio: ::std::os::raw::c_uint = 4; +-pub const kvm_ioeventfd_flag_nr_max: ::std::os::raw::c_uint = 5; +-pub type _bindgen_ty_1 = ::std::os::raw::c_uint; ++impl Default for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1__bindgen_ty_19 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run__bindgen_ty_1__bindgen_ty_19 {{ type: {:?}, ndata: {:?}, __bindgen_anon_1: {:?} }}" , self . type_ , self . ndata , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_ioeventfd { +- pub datamatch: __u64, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_20 { + pub addr: __u64, +- pub len: __u32, +- pub fd: __s32, +- pub flags: __u32, +- pub pad: [__u8; 36usize], ++ pub ar: __u8, ++ pub reserved: __u8, ++ pub fc: __u8, ++ pub sel1: __u8, ++ pub sel2: __u16, + } + #[test] +-fn bindgen_test_layout_kvm_ioeventfd() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_20() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_ioeventfd)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_ioeventfd)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).datamatch as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(datamatch) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ar) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(addr) ++ stringify!(ar) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 9usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(len) ++ stringify!(reserved) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fc) as usize - ptr as usize }, ++ 10usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(fd) ++ stringify!(fc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sel1) as usize - ptr as usize }, ++ 11usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(flags) ++ stringify!(sel1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sel2) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ioeventfd), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_20), + "::", +- stringify!(pad) ++ stringify!(sel2) + ) + ); + } +-impl Default for kvm_ioeventfd { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_enable_cap { +- pub cap: __u32, +- pub flags: __u32, +- pub args: [__u64; 4usize], +- pub pad: [__u8; 64usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_21 { ++ pub vector: __u8, + } + #[test] +-fn bindgen_test_layout_kvm_enable_cap() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_21() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 104usize, +- concat!("Size of: ", stringify!(kvm_enable_cap)) ++ ::std::mem::size_of::(), ++ 1usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_enable_cap)) ++ ::std::mem::align_of::(), ++ 1usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cap as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vector) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_enable_cap), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_21), + "::", +- stringify!(cap) ++ stringify!(vector) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_22 { ++ pub esr_iss: __u64, ++ pub fault_ipa: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_22() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, ++ ::std::mem::size_of::(), ++ 16usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_enable_cap), +- "::", +- stringify!(flags) ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).args as *const _ as usize }, ++ ::std::mem::align_of::(), + 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).esr_iss) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_enable_cap), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), + "::", +- stringify!(args) ++ stringify!(esr_iss) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fault_ipa) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_enable_cap), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_22), + "::", +- stringify!(pad) ++ stringify!(fault_ipa) + ) + ); + } +-impl Default for kvm_enable_cap { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} + #[repr(C)] +-#[derive(Debug, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_pvinfo { +- pub flags: __u32, +- pub hcall: [__u32; 4usize], +- pub pad: [__u8; 108usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_23 { ++ pub error: __u8, ++ pub pad: [__u8; 7usize], ++ pub reason: __u32, ++ pub index: __u32, ++ pub data: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_ppc_pvinfo() { +- assert_eq!( +- ::std::mem::size_of::(), +- 128usize, +- concat!("Size of: ", stringify!(kvm_ppc_pvinfo)) +- ); ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_23() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_pvinfo)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), +- "::", +- stringify!(flags) ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hcall as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).error) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(hcall) ++ stringify!(error) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 1usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_pvinfo), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", + stringify!(pad) + ) + ); +-} +-impl Default for kvm_ppc_pvinfo { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_one_page_size { +- pub page_shift: __u32, +- pub pte_enc: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_ppc_one_page_size() { + assert_eq!( +- ::std::mem::size_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).reason) as usize - ptr as usize }, + 8usize, +- concat!("Size of: ", stringify!(kvm_ppc_one_page_size)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_one_page_size)) ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), ++ "::", ++ stringify!(reason) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).page_shift as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).index) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_page_size), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(page_shift) ++ stringify!(index) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pte_enc as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_page_size), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_23), + "::", +- stringify!(pte_enc) ++ stringify!(data) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_one_seg_page_size { +- pub page_shift: __u32, +- pub slb_enc: __u32, +- pub enc: [kvm_ppc_one_page_size; 8usize], ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_24 { ++ pub extension_id: ::std::os::raw::c_ulong, ++ pub function_id: ::std::os::raw::c_ulong, ++ pub args: [::std::os::raw::c_ulong; 6usize], ++ pub ret: [::std::os::raw::c_ulong; 2usize], + } + #[test] +-fn bindgen_test_layout_kvm_ppc_one_seg_page_size() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_24() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_ppc_one_seg_page_size)) ++ ::std::mem::size_of::(), ++ 80usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_ppc_one_seg_page_size)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).page_shift as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).extension_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(page_shift) ++ stringify!(extension_id) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).slb_enc as *const _ as usize +- }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).function_id) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(slb_enc) ++ stringify!(function_id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).enc as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), ++ "::", ++ stringify!(args) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).ret) as usize - ptr as usize }, ++ 64usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_one_seg_page_size), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_24), + "::", +- stringify!(enc) ++ stringify!(ret) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_smmu_info { +- pub flags: __u64, +- pub slb_size: __u32, +- pub data_keys: __u16, +- pub instr_keys: __u16, +- pub sps: [kvm_ppc_one_seg_page_size; 8usize], ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_25 { ++ pub csr_num: ::std::os::raw::c_ulong, ++ pub new_value: ::std::os::raw::c_ulong, ++ pub write_mask: ::std::os::raw::c_ulong, ++ pub ret_value: ::std::os::raw::c_ulong, + } + #[test] +-fn bindgen_test_layout_kvm_ppc_smmu_info() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_25() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 592usize, +- concat!("Size of: ", stringify!(kvm_ppc_smmu_info)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_ppc_smmu_info)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).csr_num) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(flags) ++ stringify!(csr_num) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slb_size as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).new_value) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(slb_size) ++ stringify!(new_value) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data_keys as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).write_mask) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(data_keys) ++ stringify!(write_mask) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).instr_keys as *const _ as usize }, +- 14usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).ret_value) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_25), + "::", +- stringify!(instr_keys) ++ stringify!(ret_value) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_26 { ++ pub flags: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_26() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sps as *const _ as usize }, +- 16usize, ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_smmu_info), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_26), + "::", +- stringify!(sps) ++ stringify!(flags) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_ppc_resize_hpt { ++pub struct kvm_run__bindgen_ty_1__bindgen_ty_27 { + pub flags: __u64, +- pub shift: __u32, +- pub pad: __u32, ++ pub gpa: __u64, ++ pub size: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_ppc_resize_hpt() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_27() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_ppc_resize_hpt)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!( ++ "Size of: ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_ppc_resize_hpt)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", + stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).shift as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gpa) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", +- stringify!(shift) ++ stringify!(gpa) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_ppc_resize_hpt), ++ stringify!(kvm_run__bindgen_ty_1__bindgen_ty_27), + "::", +- stringify!(pad) ++ stringify!(size) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_irqchip { +- pub irqchip: __u32, +- pub pin: __u32, +-} + #[test] +-fn bindgen_test_layout_kvm_irq_routing_irqchip() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_irqchip)) ++ ::std::mem::size_of::(), ++ 256usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).irqchip as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hw) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_irqchip), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(irqchip) ++ stringify!(hw) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pin as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fail_entry) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_irqchip), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pin) ++ stringify!(fail_entry) + ) + ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_irq_routing_msi { +- pub address_lo: __u32, +- pub address_hi: __u32, +- pub data: __u32, +- pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_irq_routing_msi__bindgen_ty_1 { +- pub pad: __u32, +- pub devid: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() { + assert_eq!( +- ::std::mem::size_of::(), +- 4usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1)) ++ unsafe { ::std::ptr::addr_of!((*ptr).ex) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(ex) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).io) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Alignment of ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(io) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).debug) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(debug) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).devid as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mmio) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(devid) ++ stringify!(mmio) + ) + ); +-} +-impl Default for kvm_irq_routing_msi__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_msi() { + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_msi)) ++ unsafe { ::std::ptr::addr_of!((*ptr).iocsr_io) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(iocsr_io) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_msi)) ++ unsafe { ::std::ptr::addr_of!((*ptr).hypercall) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(hypercall) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_lo as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).tpr_access) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(address_lo) ++ stringify!(tpr_access) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_hi as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_sieic) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(address_hi) ++ stringify!(s390_sieic) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_reset_flags) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_msi), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(data) ++ stringify!(s390_reset_flags) + ) + ); +-} +-impl Default for kvm_irq_routing_msi { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_s390_adapter { +- pub ind_addr: __u64, +- pub summary_addr: __u64, +- pub ind_offset: __u64, +- pub summary_offset: __u32, +- pub adapter_id: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_s390_adapter() { + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter)) ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_ucontrol) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_ucontrol) ++ ) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter)) ++ unsafe { ::std::ptr::addr_of!((*ptr).dcr) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(dcr) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ind_addr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).internal) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(ind_addr) ++ stringify!(internal) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).summary_addr as *const _ +- as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).emulation_failure) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(summary_addr) ++ stringify!(emulation_failure) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).ind_offset as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).osi) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(ind_offset) ++ stringify!(osi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).summary_offset as *const _ +- as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).papr_hcall) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(summary_offset) ++ stringify!(papr_hcall) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).adapter_id as *const _ as usize +- }, +- 28usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_tsch) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_s390_adapter), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(adapter_id) ++ stringify!(s390_tsch) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irq_routing_hv_sint { +- pub vcpu: __u32, +- pub sint: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_hv_sint() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vcpu as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).epr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_hv_sint), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(vcpu) ++ stringify!(epr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sint as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).system_event) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_hv_sint), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(sint) ++ stringify!(system_event) + ) + ); +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_irq_routing_entry { +- pub gsi: __u32, +- pub type_: __u32, +- pub flags: __u32, +- pub pad: __u32, +- pub u: kvm_irq_routing_entry__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_irq_routing_entry__bindgen_ty_1 { +- pub irqchip: kvm_irq_routing_irqchip, +- pub msi: kvm_irq_routing_msi, +- pub adapter: kvm_irq_routing_s390_adapter, +- pub hv_sint: kvm_irq_routing_hv_sint, +- pub pad: [__u32; 8usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1)) +- ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s390_stsi) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Alignment of ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_run__bindgen_ty_1), ++ "::", ++ stringify!(s390_stsi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).irqchip as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).eoi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(irqchip) ++ stringify!(eoi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).msi as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).hyperv) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(msi) ++ stringify!(hyperv) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).adapter as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).arm_nisv) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(adapter) ++ stringify!(arm_nisv) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hv_sint as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).msr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(hv_sint) ++ stringify!(msr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).xen) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry__bindgen_ty_1), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(xen) + ) + ); +-} +-impl Default for kvm_irq_routing_entry__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_irq_routing_entry() { +- assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_irq_routing_entry)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing_entry)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_sbi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(gsi) ++ stringify!(riscv_sbi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).riscv_csr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(type_) ++ stringify!(riscv_csr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).notify) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(notify) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).memory_fault) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(memory_fault) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing_entry), ++ stringify!(kvm_run__bindgen_ty_1), + "::", +- stringify!(u) ++ stringify!(padding) + ) + ); + } +-impl Default for kvm_irq_routing_entry { ++impl Default for kvm_run__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -10191,56 +10345,54 @@ impl Default for kvm_irq_routing_entry { + } + } + } ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_1 {{ union }}") ++ } ++} + #[repr(C)] +-pub struct kvm_irq_routing { +- pub nr: __u32, +- pub flags: __u32, +- pub entries: __IncompleteArrayField, ++#[derive(Copy, Clone)] ++pub union kvm_run__bindgen_ty_2 { ++ pub regs: kvm_sync_regs, ++ pub padding: [::std::os::raw::c_char; 2048usize], + } + #[test] +-fn bindgen_test_layout_kvm_irq_routing() { ++fn bindgen_test_layout_kvm_run__bindgen_ty_2() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_irq_routing)) ++ ::std::mem::size_of::(), ++ 2048usize, ++ concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_irq_routing)) ++ concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).nr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).regs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing), +- "::", +- stringify!(nr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_irq_routing), ++ stringify!(kvm_run__bindgen_ty_2), + "::", +- stringify!(flags) ++ stringify!(regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entries as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irq_routing), ++ stringify!(kvm_run__bindgen_ty_2), + "::", +- stringify!(entries) ++ stringify!(padding) + ) + ); + } +-impl Default for kvm_irq_routing { ++impl Default for kvm_run__bindgen_ty_2 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -10249,1163 +10401,1316 @@ impl Default for kvm_irq_routing { + } + } + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_x86_mce { +- pub status: __u64, +- pub addr: __u64, +- pub misc: __u64, +- pub mcg_status: __u64, +- pub bank: __u8, +- pub pad1: [__u8; 7usize], +- pub pad2: [__u64; 3usize], ++impl ::std::fmt::Debug for kvm_run__bindgen_ty_2 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_run__bindgen_ty_2 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_x86_mce() { ++fn bindgen_test_layout_kvm_run() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_x86_mce)) ++ ::std::mem::size_of::(), ++ 2352usize, ++ concat!("Size of: ", stringify!(kvm_run)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_x86_mce)) ++ concat!("Alignment of ", stringify!(kvm_run)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).request_interrupt_window) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(request_interrupt_window) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).immediate_exit) as usize - ptr as usize }, ++ 1usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_run), ++ "::", ++ stringify!(immediate_exit) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).status as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 2usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(status) ++ stringify!(padding1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exit_reason) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(addr) ++ stringify!(exit_reason) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).misc as *const _ as usize }, +- 16usize, ++ unsafe { ++ ::std::ptr::addr_of!((*ptr).ready_for_interrupt_injection) as usize - ptr as usize ++ }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(misc) ++ stringify!(ready_for_interrupt_injection) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mcg_status as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).if_flag) as usize - ptr as usize }, ++ 13usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(mcg_status) ++ stringify!(if_flag) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).bank as *const _ as usize }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 14usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(bank) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad1 as *const _ as usize }, +- 33usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).cr8) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(pad1) ++ stringify!(cr8) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad2 as *const _ as usize }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).apic_base) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_x86_mce), ++ stringify!(kvm_run), + "::", +- stringify!(pad2) ++ stringify!(apic_base) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_hvm_config { +- pub flags: __u32, +- pub msr: __u32, +- pub blob_addr_32: __u64, +- pub blob_addr_64: __u64, +- pub blob_size_32: __u8, +- pub blob_size_64: __u8, +- pub pad2: [__u8; 30usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_xen_hvm_config() { +- assert_eq!( +- ::std::mem::size_of::(), +- 56usize, +- concat!("Size of: ", stringify!(kvm_xen_hvm_config)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_hvm_config)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_valid_regs) as usize - ptr as usize }, ++ 288usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_config), ++ stringify!(kvm_run), + "::", +- stringify!(flags) ++ stringify!(kvm_valid_regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).msr as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).kvm_dirty_regs) as usize - ptr as usize }, ++ 296usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_config), ++ stringify!(kvm_run), + "::", +- stringify!(msr) ++ stringify!(kvm_dirty_regs) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).blob_addr_32 as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).s) as usize - ptr as usize }, ++ 304usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_config), ++ stringify!(kvm_run), + "::", +- stringify!(blob_addr_32) ++ stringify!(s) + ) + ); ++} ++impl Default for kvm_run { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_run { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_run {{ request_interrupt_window: {:?}, immediate_exit: {:?}, padding1: {:?}, exit_reason: {:?}, ready_for_interrupt_injection: {:?}, if_flag: {:?}, flags: {:?}, cr8: {:?}, apic_base: {:?}, __bindgen_anon_1: {:?}, kvm_valid_regs: {:?}, kvm_dirty_regs: {:?}, s: {:?} }}" , self . request_interrupt_window , self . immediate_exit , self . padding1 , self . exit_reason , self . ready_for_interrupt_injection , self . if_flag , self . flags , self . cr8 , self . apic_base , self . __bindgen_anon_1 , self . kvm_valid_regs , self . kvm_dirty_regs , self . s) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio_zone { ++ pub addr: __u64, ++ pub size: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).blob_addr_64 as *const _ as usize }, +- 16usize, ++ ::std::mem::size_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_xen_hvm_config), +- "::", +- stringify!(blob_addr_64) ++ "Size of: ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).blob_size_32 as *const _ as usize }, +- 24usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_xen_hvm_config), +- "::", +- stringify!(blob_size_32) ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).blob_size_64 as *const _ as usize }, +- 25usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_config), ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), + "::", +- stringify!(blob_size_64) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad2 as *const _ as usize }, +- 26usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_config), ++ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1), + "::", +- stringify!(pad2) ++ stringify!(pio) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_irqfd { +- pub fd: __u32, +- pub gsi: __u32, +- pub flags: __u32, +- pub resamplefd: __u32, +- pub pad: [__u8; 16usize], ++impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio_zone__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_irqfd() { ++fn bindgen_test_layout_kvm_coalesced_mmio_zone() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_irqfd)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_irqfd)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio_zone), + "::", +- stringify!(fd) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio_zone), + "::", +- stringify!(gsi) ++ stringify!(size) ++ ) ++ ); ++} ++impl Default for kvm_coalesced_mmio_zone { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_zone { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_zone {{ addr: {:?}, size: {:?}, __bindgen_anon_1: {:?} }}", ++ self.addr, self.size, self.__bindgen_anon_1 + ) ++ } ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_coalesced_mmio { ++ pub phys_addr: __u64, ++ pub len: __u32, ++ pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1, ++ pub data: [__u8; 8usize], ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_coalesced_mmio__bindgen_ty_1 { ++ pub pad: __u32, ++ pub pio: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ ::std::mem::align_of::(), ++ 4usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_irqfd), +- "::", +- stringify!(flags) ++ "Alignment of ", ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).resamplefd as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), + "::", +- stringify!(resamplefd) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pio) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_irqfd), ++ stringify!(kvm_coalesced_mmio__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(pio) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_clock_data { +- pub clock: __u64, +- pub flags: __u32, +- pub pad: [__u32; 9usize], ++impl Default for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_coalesced_mmio__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_clock_data() { ++fn bindgen_test_layout_kvm_coalesced_mmio() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_clock_data)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_clock_data)) ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).clock as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clock_data), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(clock) ++ stringify!(phys_addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clock_data), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(flags) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_clock_data), ++ stringify!(kvm_coalesced_mmio), + "::", +- stringify!(pad) ++ stringify!(data) + ) + ); + } ++impl Default for kvm_coalesced_mmio { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_coalesced_mmio {{ phys_addr: {:?}, len: {:?}, __bindgen_anon_1: {:?}, data: {:?} }}" , self . phys_addr , self . len , self . __bindgen_anon_1 , self . data) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_config_tlb { +- pub params: __u64, +- pub array: __u64, +- pub mmu_type: __u32, +- pub array_len: __u32, ++pub struct kvm_coalesced_mmio_ring { ++ pub first: __u32, ++ pub last: __u32, ++ pub coalesced_mmio: __IncompleteArrayField, + } + #[test] +-fn bindgen_test_layout_kvm_config_tlb() { ++fn bindgen_test_layout_kvm_coalesced_mmio_ring() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_config_tlb)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_config_tlb)) ++ concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).params as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio_ring), + "::", +- stringify!(params) ++ stringify!(first) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).array as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).last) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio_ring), + "::", +- stringify!(array) ++ stringify!(last) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).mmu_type as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).coalesced_mmio) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_config_tlb), ++ stringify!(kvm_coalesced_mmio_ring), + "::", +- stringify!(mmu_type) ++ stringify!(coalesced_mmio) + ) + ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).array_len as *const _ as usize }, +- 20usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_config_tlb), +- "::", +- stringify!(array_len) ++} ++impl Default for kvm_coalesced_mmio_ring { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_coalesced_mmio_ring { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_coalesced_mmio_ring {{ first: {:?}, last: {:?}, coalesced_mmio: {:?} }}", ++ self.first, self.last, self.coalesced_mmio + ) +- ); ++ } + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_dirty_tlb { +- pub bitmap: __u64, +- pub num_dirty: __u32, ++pub struct kvm_translation { ++ pub linear_address: __u64, ++ pub physical_address: __u64, ++ pub valid: __u8, ++ pub writeable: __u8, ++ pub usermode: __u8, ++ pub pad: [__u8; 5usize], + } + #[test] +-fn bindgen_test_layout_kvm_dirty_tlb() { ++fn bindgen_test_layout_kvm_translation() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_tlb)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_translation)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_tlb)) ++ concat!("Alignment of ", stringify!(kvm_translation)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).bitmap as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).linear_address) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_tlb), ++ stringify!(kvm_translation), + "::", +- stringify!(bitmap) ++ stringify!(linear_address) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).num_dirty as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).physical_address) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_tlb), ++ stringify!(kvm_translation), + "::", +- stringify!(num_dirty) ++ stringify!(physical_address) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default)] +-pub struct kvm_reg_list { +- pub n: __u64, +- pub reg: __IncompleteArrayField<__u64>, +-} +-#[test] +-fn bindgen_test_layout_kvm_reg_list() { +- assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_reg_list)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_reg_list)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).n as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).valid) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_reg_list), ++ stringify!(kvm_translation), + "::", +- stringify!(n) ++ stringify!(valid) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reg as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).writeable) as usize - ptr as usize }, ++ 17usize, + concat!( + "Offset of field: ", +- stringify!(kvm_reg_list), ++ stringify!(kvm_translation), + "::", +- stringify!(reg) ++ stringify!(writeable) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_one_reg { +- pub id: __u64, +- pub addr: __u64, +-} +-#[test] +-fn bindgen_test_layout_kvm_one_reg() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_one_reg)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_one_reg)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).usermode) as usize - ptr as usize }, ++ 18usize, + concat!( + "Offset of field: ", +- stringify!(kvm_one_reg), ++ stringify!(kvm_translation), + "::", +- stringify!(id) ++ stringify!(usermode) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 19usize, + concat!( + "Offset of field: ", +- stringify!(kvm_one_reg), ++ stringify!(kvm_translation), + "::", +- stringify!(addr) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_msi { +- pub address_lo: __u32, +- pub address_hi: __u32, +- pub data: __u32, +- pub flags: __u32, +- pub devid: __u32, +- pub pad: [__u8; 12usize], ++pub struct kvm_interrupt { ++ pub irq: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_msi() { ++fn bindgen_test_layout_kvm_interrupt() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_msi)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_interrupt)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_msi)) ++ concat!("Alignment of ", stringify!(kvm_interrupt)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_lo as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irq) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(address_lo) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).address_hi as *const _ as usize }, +- 4usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_interrupt), + "::", +- stringify!(address_hi) ++ stringify!(irq) + ) + ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_dirty_log { ++ pub slot: __u32, ++ pub padding1: __u32, ++ pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, ++ ::std::mem::size_of::(), + 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(data) +- ) ++ concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_msi), +- "::", +- stringify!(flags) +- ) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).devid as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_dirty_log__bindgen_ty_1), + "::", +- stringify!(devid) ++ stringify!(dirty_bitmap) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_msi), ++ stringify!(kvm_dirty_log__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(padding2) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_arm_device_addr { +- pub id: __u64, +- pub addr: __u64, ++impl Default for kvm_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_dirty_log__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_arm_device_addr() { ++fn bindgen_test_layout_kvm_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 16usize, +- concat!("Size of: ", stringify!(kvm_arm_device_addr)) ++ concat!("Size of: ", stringify!(kvm_dirty_log)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_arm_device_addr)) ++ concat!("Alignment of ", stringify!(kvm_dirty_log)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_arm_device_addr), ++ stringify!(kvm_dirty_log), + "::", +- stringify!(id) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding1) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_arm_device_addr), ++ stringify!(kvm_dirty_log), + "::", +- stringify!(addr) ++ stringify!(padding1) + ) + ); + } ++impl Default for kvm_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_dirty_log {{ slot: {:?}, padding1: {:?}, __bindgen_anon_1: {:?} }}", ++ self.slot, self.padding1, self.__bindgen_anon_1 ++ ) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_create_device { +- pub type_: __u32, +- pub fd: __u32, +- pub flags: __u32, ++#[derive(Copy, Clone)] ++pub struct kvm_clear_dirty_log { ++ pub slot: __u32, ++ pub num_pages: __u32, ++ pub first_page: __u64, ++ pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_clear_dirty_log__bindgen_ty_1 { ++ pub dirty_bitmap: *mut ::std::os::raw::c_void, ++ pub padding2: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_create_device() { +- assert_eq!( +- ::std::mem::size_of::(), +- 12usize, +- concat!("Size of: ", stringify!(kvm_create_device)) +- ); ++fn bindgen_test_layout_kvm_clear_dirty_log__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_create_device)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, ++ ::std::mem::align_of::(), ++ 8usize, + concat!( +- "Offset of field: ", +- stringify!(kvm_create_device), +- "::", +- stringify!(type_) ++ "Alignment of ", ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).dirty_bitmap) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_create_device), ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), + "::", +- stringify!(fd) ++ stringify!(dirty_bitmap) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).padding2) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_create_device), ++ stringify!(kvm_clear_dirty_log__bindgen_ty_1), + "::", +- stringify!(flags) ++ stringify!(padding2) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_device_attr { +- pub flags: __u32, +- pub group: __u32, +- pub attr: __u64, +- pub addr: __u64, ++impl Default for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_clear_dirty_log__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_device_attr() { ++fn bindgen_test_layout_kvm_clear_dirty_log() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), + 24usize, +- concat!("Size of: ", stringify!(kvm_device_attr)) ++ concat!("Size of: ", stringify!(kvm_clear_dirty_log)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_device_attr)) ++ concat!("Alignment of ", stringify!(kvm_clear_dirty_log)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(flags) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).group as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_pages) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(group) ++ stringify!(num_pages) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).attr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).first_page) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_device_attr), +- "::", +- stringify!(attr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_device_attr), ++ stringify!(kvm_clear_dirty_log), + "::", +- stringify!(addr) ++ stringify!(first_page) + ) + ); + } +-pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1; +-pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2; +-pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3; +-pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5; +-pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8; +-pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9; +-pub const kvm_device_type_KVM_DEV_TYPE_ARM_PV_TIME: kvm_device_type = 10; +-pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 11; +-pub type kvm_device_type = ::std::os::raw::c_uint; ++impl Default for kvm_clear_dirty_log { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_clear_dirty_log { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_clear_dirty_log {{ slot: {:?}, num_pages: {:?}, first_page: {:?}, __bindgen_anon_1: {:?} }}" , self . slot , self . num_pages , self . first_page , self . __bindgen_anon_1) ++ } ++} + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_vfio_spapr_tce { +- pub groupfd: __s32, +- pub tablefd: __s32, ++#[derive(Debug, Default)] ++pub struct kvm_signal_mask { ++ pub len: __u32, ++ pub sigset: __IncompleteArrayField<__u8>, + } + #[test] +-fn bindgen_test_layout_kvm_vfio_spapr_tce() { ++fn bindgen_test_layout_kvm_signal_mask() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_vfio_spapr_tce)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_signal_mask)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce)) ++ concat!("Alignment of ", stringify!(kvm_signal_mask)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).groupfd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_vfio_spapr_tce), ++ stringify!(kvm_signal_mask), + "::", +- stringify!(groupfd) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).tablefd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).sigset) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_vfio_spapr_tce), ++ stringify!(kvm_signal_mask), + "::", +- stringify!(tablefd) ++ stringify!(sigset) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_ucas_mapping { +- pub user_addr: __u64, +- pub vcpu_addr: __u64, +- pub length: __u64, ++pub struct kvm_tpr_access_ctl { ++ pub enabled: __u32, ++ pub flags: __u32, ++ pub reserved: [__u32; 8usize], + } + #[test] +-fn bindgen_test_layout_kvm_s390_ucas_mapping() { ++fn bindgen_test_layout_kvm_tpr_access_ctl() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_s390_ucas_mapping)) ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(kvm_tpr_access_ctl)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_ucas_mapping)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_tpr_access_ctl)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).user_addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(user_addr) ++ stringify!(enabled) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).vcpu_addr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(vcpu_addr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).length as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_ucas_mapping), ++ stringify!(kvm_tpr_access_ctl), + "::", +- stringify!(length) ++ stringify!(reserved) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_enc_region { +- pub addr: __u64, +- pub size: __u64, ++pub struct kvm_vapic_addr { ++ pub vapic_addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_enc_region() { ++fn bindgen_test_layout_kvm_vapic_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_enc_region)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vapic_addr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_enc_region)) ++ concat!("Alignment of ", stringify!(kvm_vapic_addr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).vapic_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_enc_region), +- "::", +- stringify!(addr) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_enc_region), ++ stringify!(kvm_vapic_addr), + "::", +- stringify!(size) ++ stringify!(vapic_addr) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pv_sec_parm { +- pub origin: __u64, +- pub length: __u64, ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_mp_state { ++ pub mp_state: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_s390_pv_sec_parm() { ++fn bindgen_test_layout_kvm_mp_state() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_s390_pv_sec_parm)) ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_mp_state)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pv_sec_parm)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_mp_state)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).origin as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mp_state) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_sec_parm), +- "::", +- stringify!(origin) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).length as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_s390_pv_sec_parm), ++ stringify!(kvm_mp_state), + "::", +- stringify!(length) ++ stringify!(mp_state) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_s390_pv_unp { +- pub addr: __u64, +- pub size: __u64, +- pub tweak: __u64, ++pub struct kvm_guest_debug { ++ pub control: __u32, ++ pub pad: __u32, ++ pub arch: kvm_guest_debug_arch, + } + #[test] +-fn bindgen_test_layout_kvm_s390_pv_unp() { ++fn bindgen_test_layout_kvm_guest_debug() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_s390_pv_unp)) ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(kvm_guest_debug)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_s390_pv_unp)) ++ concat!("Alignment of ", stringify!(kvm_guest_debug)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).control) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(addr) ++ stringify!(control) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).size as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(size) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).tweak as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).arch) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_s390_pv_unp), ++ stringify!(kvm_guest_debug), + "::", +- stringify!(tweak) ++ stringify!(arch) + ) + ); + } +-pub const pv_cmd_id_KVM_PV_ENABLE: pv_cmd_id = 0; +-pub const pv_cmd_id_KVM_PV_DISABLE: pv_cmd_id = 1; +-pub const pv_cmd_id_KVM_PV_SET_SEC_PARMS: pv_cmd_id = 2; +-pub const pv_cmd_id_KVM_PV_UNPACK: pv_cmd_id = 3; +-pub const pv_cmd_id_KVM_PV_VERIFY: pv_cmd_id = 4; +-pub const pv_cmd_id_KVM_PV_PREP_RESET: pv_cmd_id = 5; +-pub const pv_cmd_id_KVM_PV_UNSHARE_ALL: pv_cmd_id = 6; +-pub type pv_cmd_id = ::std::os::raw::c_uint; ++pub const kvm_ioeventfd_flag_nr_datamatch: _bindgen_ty_1 = 0; ++pub const kvm_ioeventfd_flag_nr_pio: _bindgen_ty_1 = 1; ++pub const kvm_ioeventfd_flag_nr_deassign: _bindgen_ty_1 = 2; ++pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: _bindgen_ty_1 = 3; ++pub const kvm_ioeventfd_flag_nr_fast_mmio: _bindgen_ty_1 = 4; ++pub const kvm_ioeventfd_flag_nr_max: _bindgen_ty_1 = 5; ++pub type _bindgen_ty_1 = ::std::os::raw::c_uint; + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_pv_cmd { +- pub cmd: __u32, +- pub rc: __u16, +- pub rrc: __u16, +- pub data: __u64, ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_ioeventfd { ++ pub datamatch: __u64, ++ pub addr: __u64, ++ pub len: __u32, ++ pub fd: __s32, + pub flags: __u32, +- pub reserved: [__u32; 3usize], ++ pub pad: [__u8; 36usize], + } + #[test] +-fn bindgen_test_layout_kvm_pv_cmd() { ++fn bindgen_test_layout_kvm_ioeventfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_pv_cmd)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_ioeventfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_pv_cmd)) ++ concat!("Alignment of ", stringify!(kvm_ioeventfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).cmd as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).datamatch) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(cmd) ++ stringify!(datamatch) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rc as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(rc) ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).rrc as *const _ as usize }, +- 6usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(rrc) ++ stringify!(len) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(data) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", + stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).reserved as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 28usize, + concat!( + "Offset of field: ", +- stringify!(kvm_pv_cmd), ++ stringify!(kvm_ioeventfd), + "::", +- stringify!(reserved) ++ stringify!(pad) + ) + ); + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_xen_hvm_attr { +- pub type_: __u16, +- pub pad: [__u16; 3usize], +- pub u: kvm_xen_hvm_attr__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_xen_hvm_attr__bindgen_ty_1 { +- pub long_mode: __u8, +- pub vector: __u8, +- pub shared_info: kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1, +- pub pad: [__u64; 8usize], ++impl Default for kvm_ioeventfd { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1 { +- pub gfn: __u64, ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct kvm_enable_cap { ++ pub cap: __u32, ++ pub flags: __u32, ++ pub args: [__u64; 4usize], ++ pub pad: [__u8; 64usize], + } + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_enable_cap() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), ++ ::std::mem::size_of::(), ++ 104usize, ++ concat!("Size of: ", stringify!(kvm_enable_cap)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), + 8usize, ++ concat!("Alignment of ", stringify!(kvm_enable_cap)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).cap) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Size of: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(cap) + ) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).args) as usize - ptr as usize }, + 8usize, + concat!( +- "Alignment of ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_enable_cap), ++ "::", ++ stringify!(args) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gfn as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 40usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_enable_cap), + "::", +- stringify!(gfn) ++ stringify!(pad) + ) + ); + } ++impl Default for kvm_enable_cap { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_irqchip { ++ pub irqchip: __u32, ++ pub pin: __u32, ++} + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_irq_routing_irqchip() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_irqchip)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_hvm_attr__bindgen_ty_1)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).long_mode as *const _ +- as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_irqchip), + "::", +- stringify!(long_mode) ++ stringify!(irqchip) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).vector as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pin) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_irqchip), + "::", +- stringify!(vector) ++ stringify!(pin) + ) + ); ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_msi__bindgen_ty_1 { ++ pub pad: __u32, ++ pub devid: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).shared_info as *const _ +- as usize +- }, ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), + "::", +- stringify!(shared_info) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_msi__bindgen_ty_1), + "::", +- stringify!(pad) ++ stringify!(devid) + ) + ); + } +-impl Default for kvm_xen_hvm_attr__bindgen_ty_1 { ++impl Default for kvm_irq_routing_msi__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -11414,50 +11719,57 @@ impl Default for kvm_xen_hvm_attr__bindgen_ty_1 { + } + } + } ++impl ::std::fmt::Debug for kvm_irq_routing_msi__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_msi__bindgen_ty_1 {{ union }}") ++ } ++} + #[test] +-fn bindgen_test_layout_kvm_xen_hvm_attr() { +- assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_xen_hvm_attr)) ++fn bindgen_test_layout_kvm_irq_routing_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_msi)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_hvm_attr)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_msi)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(type_) ++ stringify!(address_lo) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(pad) ++ stringify!(address_hi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_hvm_attr), ++ stringify!(kvm_irq_routing_msi), + "::", +- stringify!(u) ++ stringify!(data) + ) + ); + } +-impl Default for kvm_xen_hvm_attr { ++impl Default for kvm_irq_routing_msi { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { +@@ -11466,1598 +11778,1469 @@ impl Default for kvm_xen_hvm_attr { + } + } + } +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_xen_vcpu_attr { +- pub type_: __u16, +- pub pad: [__u16; 3usize], +- pub u: kvm_xen_vcpu_attr__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_xen_vcpu_attr__bindgen_ty_1 { +- pub gpa: __u64, +- pub pad: [__u64; 8usize], +- pub runstate: kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1, ++impl ::std::fmt::Debug for kvm_irq_routing_msi { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write ! (f , "kvm_irq_routing_msi {{ address_lo: {:?}, address_hi: {:?}, data: {:?}, __bindgen_anon_1: {:?} }}" , self . address_lo , self . address_hi , self . data , self . __bindgen_anon_1) ++ } + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1 { +- pub state: __u64, +- pub state_entry_time: __u64, +- pub time_running: __u64, +- pub time_runnable: __u64, +- pub time_blocked: __u64, +- pub time_offline: __u64, ++pub struct kvm_irq_routing_s390_adapter { ++ pub ind_addr: __u64, ++ pub summary_addr: __u64, ++ pub ind_offset: __u64, ++ pub summary_offset: __u32, ++ pub adapter_id: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_irq_routing_s390_adapter() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!( +- "Size of: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) +- ) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!( +- "Alignment of ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1) +- ) ++ concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).state +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(state) ++ stringify!(ind_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())) +- .state_entry_time as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(state_entry_time) ++ stringify!(summary_addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_running +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).ind_offset) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(time_running) ++ stringify!(ind_offset) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_runnable +- as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).summary_offset) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(time_runnable) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_blocked +- as *const _ as usize +- }, +- 32usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(time_blocked) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).time_offline +- as *const _ as usize +- }, +- 40usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1__bindgen_ty_1), +- "::", +- stringify!(time_offline) +- ) +- ); +-} +-#[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr__bindgen_ty_1() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr__bindgen_ty_1)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).gpa as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), +- "::", +- stringify!(gpa) +- ) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pad as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(pad) ++ stringify!(summary_offset) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).runstate as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter_id) as usize - ptr as usize }, ++ 28usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr__bindgen_ty_1), ++ stringify!(kvm_irq_routing_s390_adapter), + "::", +- stringify!(runstate) ++ stringify!(adapter_id) + ) + ); + } +-impl Default for kvm_xen_vcpu_attr__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_irq_routing_hv_sint { ++ pub vcpu: __u32, ++ pub sint: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_xen_vcpu_attr() { +- assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_xen_vcpu_attr)) +- ); ++fn bindgen_test_layout_kvm_irq_routing_hv_sint() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::size_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_xen_vcpu_attr)) ++ concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), +- "::", +- stringify!(type_) +- ) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, +- 2usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), ++ stringify!(kvm_irq_routing_hv_sint), + "::", +- stringify!(pad) ++ stringify!(vcpu) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).sint) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_xen_vcpu_attr), ++ stringify!(kvm_irq_routing_hv_sint), + "::", +- stringify!(u) ++ stringify!(sint) + ) + ); + } +-impl Default for kvm_xen_vcpu_attr { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-pub const sev_cmd_id_KVM_SEV_INIT: sev_cmd_id = 0; +-pub const sev_cmd_id_KVM_SEV_ES_INIT: sev_cmd_id = 1; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_START: sev_cmd_id = 2; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_DATA: sev_cmd_id = 3; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_VMSA: sev_cmd_id = 4; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_SECRET: sev_cmd_id = 5; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_MEASURE: sev_cmd_id = 6; +-pub const sev_cmd_id_KVM_SEV_LAUNCH_FINISH: sev_cmd_id = 7; +-pub const sev_cmd_id_KVM_SEV_SEND_START: sev_cmd_id = 8; +-pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_DATA: sev_cmd_id = 9; +-pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_VMSA: sev_cmd_id = 10; +-pub const sev_cmd_id_KVM_SEV_SEND_FINISH: sev_cmd_id = 11; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_START: sev_cmd_id = 12; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_DATA: sev_cmd_id = 13; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_VMSA: sev_cmd_id = 14; +-pub const sev_cmd_id_KVM_SEV_RECEIVE_FINISH: sev_cmd_id = 15; +-pub const sev_cmd_id_KVM_SEV_GUEST_STATUS: sev_cmd_id = 16; +-pub const sev_cmd_id_KVM_SEV_DBG_DECRYPT: sev_cmd_id = 17; +-pub const sev_cmd_id_KVM_SEV_DBG_ENCRYPT: sev_cmd_id = 18; +-pub const sev_cmd_id_KVM_SEV_CERT_EXPORT: sev_cmd_id = 19; +-pub const sev_cmd_id_KVM_SEV_GET_ATTESTATION_REPORT: sev_cmd_id = 20; +-pub const sev_cmd_id_KVM_SEV_SEND_CANCEL: sev_cmd_id = 21; +-pub const sev_cmd_id_KVM_SEV_NR_MAX: sev_cmd_id = 22; +-pub type sev_cmd_id = ::std::os::raw::c_uint; + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_cmd { +- pub id: __u32, +- pub data: __u64, +- pub error: __u32, +- pub sev_fd: __u32, ++pub struct kvm_irq_routing_xen_evtchn { ++ pub port: __u32, ++ pub vcpu: __u32, ++ pub priority: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_sev_cmd() { +- assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_sev_cmd)) +- ); ++fn bindgen_test_layout_kvm_irq_routing_xen_evtchn() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_cmd)) ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_xen_evtchn)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_cmd), +- "::", +- stringify!(id) +- ) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing_xen_evtchn)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).data as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(data) ++ stringify!(port) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).error as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).vcpu) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(error) ++ stringify!(vcpu) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).sev_fd as *const _ as usize }, +- 20usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_cmd), ++ stringify!(kvm_irq_routing_xen_evtchn), + "::", +- stringify!(sev_fd) ++ stringify!(priority) + ) + ); + } + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_start { +- pub handle: __u32, +- pub policy: __u32, +- pub dh_uaddr: __u64, +- pub dh_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++#[derive(Copy, Clone)] ++pub struct kvm_irq_routing_entry { ++ pub gsi: __u32, ++ pub type_: __u32, ++ pub flags: __u32, ++ pub pad: __u32, ++ pub u: kvm_irq_routing_entry__bindgen_ty_1, ++} ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub union kvm_irq_routing_entry__bindgen_ty_1 { ++ pub irqchip: kvm_irq_routing_irqchip, ++ pub msi: kvm_irq_routing_msi, ++ pub adapter: kvm_irq_routing_s390_adapter, ++ pub hv_sint: kvm_irq_routing_hv_sint, ++ pub xen_evtchn: kvm_irq_routing_xen_evtchn, ++ pub pad: [__u32; 8usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_start() { ++fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_start)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_start)) ++ concat!( ++ "Alignment of ", ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1) ++ ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).irqchip) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(handle) ++ stringify!(irqchip) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).msi) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(policy) ++ stringify!(msi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dh_uaddr as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).adapter) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(dh_uaddr) ++ stringify!(adapter) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dh_len as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).hv_sint) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(dh_len) ++ stringify!(hv_sint) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).xen_evtchn) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(session_uaddr) ++ stringify!(xen_evtchn) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_len as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_start), ++ stringify!(kvm_irq_routing_entry__bindgen_ty_1), + "::", +- stringify!(session_len) ++ stringify!(pad) + ) + ); + } +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_update_data { +- pub uaddr: __u64, +- pub len: __u32, ++impl Default for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry__bindgen_ty_1 { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!(f, "kvm_irq_routing_entry__bindgen_ty_1 {{ union }}") ++ } + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_update_data() { ++fn bindgen_test_layout_kvm_irq_routing_entry() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_update_data)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing_entry)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_update_data)) ++ concat!("Alignment of ", stringify!(kvm_irq_routing_entry)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_update_data), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(uaddr) ++ stringify!(gsi) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_update_data), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(len) ++ stringify!(type_) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_secret { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_launch_secret() { +- assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_secret)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_secret)) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize }, +- 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(hdr_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).hdr_len as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(hdr_len) ++ stringify!(pad) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing_entry), + "::", +- stringify!(guest_uaddr) ++ stringify!(u) + ) + ); ++} ++impl Default for kvm_irq_routing_entry { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing_entry { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing_entry {{ gsi: {:?}, type: {:?}, flags: {:?}, pad: {:?}, u: {:?} }}", ++ self.gsi, self.type_, self.flags, self.pad, self.u ++ ) ++ } ++} ++#[repr(C)] ++pub struct kvm_irq_routing { ++ pub nr: __u32, ++ pub flags: __u32, ++ pub entries: __IncompleteArrayField, ++} ++#[test] ++fn bindgen_test_layout_kvm_irq_routing() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_irq_routing)) ++ ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).guest_len as *const _ as usize }, +- 24usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_irq_routing)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).nr) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing), + "::", +- stringify!(guest_len) ++ stringify!(nr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing), + "::", +- stringify!(trans_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).trans_len as *const _ as usize }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_secret), ++ stringify!(kvm_irq_routing), + "::", +- stringify!(trans_len) ++ stringify!(entries) + ) + ); + } ++impl Default for kvm_irq_routing { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++impl ::std::fmt::Debug for kvm_irq_routing { ++ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ++ write!( ++ f, ++ "kvm_irq_routing {{ nr: {:?}, flags: {:?}, entries: {:?} }}", ++ self.nr, self.flags, self.entries ++ ) ++ } ++} + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_launch_measure { +- pub uaddr: __u64, +- pub len: __u32, ++pub struct kvm_irqfd { ++ pub fd: __u32, ++ pub gsi: __u32, ++ pub flags: __u32, ++ pub resamplefd: __u32, ++ pub pad: [__u8; 16usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_launch_measure() { ++fn bindgen_test_layout_kvm_irqfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_sev_launch_measure)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_irqfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_launch_measure)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_irqfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_measure), ++ stringify!(kvm_irqfd), + "::", +- stringify!(uaddr) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).gsi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_launch_measure), ++ stringify!(kvm_irqfd), + "::", +- stringify!(len) ++ stringify!(gsi) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_guest_status { +- pub handle: __u32, +- pub policy: __u32, +- pub state: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_guest_status() { +- assert_eq!( +- ::std::mem::size_of::(), +- 12usize, +- concat!("Size of: ", stringify!(kvm_sev_guest_status)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_sev_guest_status)) +- ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_irqfd), + "::", +- stringify!(handle) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).resamplefd) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_irqfd), + "::", +- stringify!(policy) ++ stringify!(resamplefd) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).state as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_guest_status), ++ stringify!(kvm_irqfd), + "::", +- stringify!(state) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_dbg { +- pub src_uaddr: __u64, +- pub dst_uaddr: __u64, +- pub len: __u32, ++#[cfg_attr( ++ feature = "serde", ++ derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++)] ++pub struct kvm_clock_data { ++ pub clock: __u64, ++ pub flags: __u32, ++ pub pad0: __u32, ++ pub realtime: __u64, ++ pub host_tsc: __u64, ++ pub pad: [__u32; 4usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_dbg() { ++fn bindgen_test_layout_kvm_clock_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_sev_dbg)) ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(kvm_clock_data)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_dbg)) ++ concat!("Alignment of ", stringify!(kvm_clock_data)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).src_uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).clock) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_dbg), ++ stringify!(kvm_clock_data), + "::", +- stringify!(src_uaddr) ++ stringify!(clock) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).dst_uaddr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_dbg), ++ stringify!(kvm_clock_data), + "::", +- stringify!(dst_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad0) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_dbg), ++ stringify!(kvm_clock_data), + "::", +- stringify!(len) ++ stringify!(pad0) + ) + ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_attestation_report { +- pub mnonce: [__u8; 16usize], +- pub uaddr: __u64, +- pub len: __u32, +-} +-#[test] +-fn bindgen_test_layout_kvm_sev_attestation_report() { +- assert_eq!( +- ::std::mem::size_of::(), +- 32usize, +- concat!("Size of: ", stringify!(kvm_sev_attestation_report)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_attestation_report)) +- ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).mnonce as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).realtime) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_clock_data), + "::", +- stringify!(mnonce) ++ stringify!(realtime) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).uaddr as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).host_tsc) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_clock_data), + "::", +- stringify!(uaddr) ++ stringify!(host_tsc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 32usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_attestation_report), ++ stringify!(kvm_clock_data), + "::", +- stringify!(len) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_send_start { +- pub policy: __u32, +- pub pdh_cert_uaddr: __u64, +- pub pdh_cert_len: __u32, +- pub plat_certs_uaddr: __u64, +- pub plat_certs_len: __u32, +- pub amd_certs_uaddr: __u64, +- pub amd_certs_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++pub struct kvm_config_tlb { ++ pub params: __u64, ++ pub array: __u64, ++ pub mmu_type: __u32, ++ pub array_len: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_sev_send_start() { ++fn bindgen_test_layout_kvm_config_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 72usize, +- concat!("Size of: ", stringify!(kvm_sev_send_start)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_config_tlb)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_send_start)) ++ concat!("Alignment of ", stringify!(kvm_config_tlb)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).params) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(policy) ++ stringify!(params) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).pdh_cert_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).array) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(pdh_cert_uaddr) ++ stringify!(array) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_cert_len as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).mmu_type) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(pdh_cert_len) ++ stringify!(mmu_type) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).plat_certs_uaddr as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).array_len) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_config_tlb), + "::", +- stringify!(plat_certs_uaddr) ++ stringify!(array_len) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_dirty_tlb { ++ pub bitmap: __u64, ++ pub num_dirty: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_dirty_tlb() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).plat_certs_len as *const _ as usize +- }, +- 32usize, ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_tlb)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_tlb)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).bitmap) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_dirty_tlb), + "::", +- stringify!(plat_certs_len) ++ stringify!(bitmap) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).amd_certs_uaddr as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_dirty) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_dirty_tlb), + "::", +- stringify!(amd_certs_uaddr) ++ stringify!(num_dirty) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_reg_list { ++ pub n: __u64, ++ pub reg: __IncompleteArrayField<__u64>, ++} ++#[test] ++fn bindgen_test_layout_kvm_reg_list() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).amd_certs_len as *const _ as usize +- }, +- 48usize, ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_reg_list)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_reg_list)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).n) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_reg_list), + "::", +- stringify!(amd_certs_len) ++ stringify!(n) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).reg) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_reg_list), ++ "::", ++ stringify!(reg) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_one_reg { ++ pub id: __u64, ++ pub addr: __u64, ++} ++#[test] ++fn bindgen_test_layout_kvm_one_reg() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_one_reg)) ++ ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 56usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_one_reg)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_one_reg), + "::", +- stringify!(session_uaddr) ++ stringify!(id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).session_len as *const _ as usize }, +- 64usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_start), ++ stringify!(kvm_one_reg), + "::", +- stringify!(session_len) ++ stringify!(addr) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_send_update_data { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, ++pub struct kvm_msi { ++ pub address_lo: __u32, ++ pub address_hi: __u32, ++ pub data: __u32, ++ pub flags: __u32, ++ pub devid: __u32, ++ pub pad: [__u8; 12usize], + } + #[test] +-fn bindgen_test_layout_kvm_sev_send_update_data() { ++fn bindgen_test_layout_kvm_msi() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_send_update_data)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_msi)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_send_update_data)) ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_msi)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_lo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(hdr_uaddr) ++ stringify!(address_lo) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_len as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).address_hi) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(hdr_len) ++ stringify!(address_hi) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(guest_uaddr) ++ stringify!(data) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_len as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(guest_len) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).devid) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(trans_uaddr) ++ stringify!(devid) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_len as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).pad) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_send_update_data), ++ stringify!(kvm_msi), + "::", +- stringify!(trans_len) ++ stringify!(pad) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_receive_start { +- pub handle: __u32, +- pub policy: __u32, +- pub pdh_uaddr: __u64, +- pub pdh_len: __u32, +- pub session_uaddr: __u64, +- pub session_len: __u32, ++pub struct kvm_arm_device_addr { ++ pub id: __u64, ++ pub addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_sev_receive_start() { ++fn bindgen_test_layout_kvm_arm_device_addr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 40usize, +- concat!("Size of: ", stringify!(kvm_sev_receive_start)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_arm_device_addr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_receive_start)) ++ concat!("Alignment of ", stringify!(kvm_arm_device_addr)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).handle as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_arm_device_addr), + "::", +- stringify!(handle) ++ stringify!(id) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).policy as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_arm_device_addr), + "::", +- stringify!(policy) ++ stringify!(addr) + ) + ); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_create_device { ++ pub type_: __u32, ++ pub fd: __u32, ++ pub flags: __u32, ++} ++#[test] ++fn bindgen_test_layout_kvm_create_device() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_uaddr as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_sev_receive_start), +- "::", +- stringify!(pdh_uaddr) +- ) ++ ::std::mem::size_of::(), ++ 12usize, ++ concat!("Size of: ", stringify!(kvm_create_device)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).pdh_len as *const _ as usize }, +- 16usize, ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_create_device)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(pdh_len) ++ stringify!(type_) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_uaddr as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(session_uaddr) ++ stringify!(fd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).session_len as *const _ as usize +- }, +- 32usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_start), ++ stringify!(kvm_create_device), + "::", +- stringify!(session_len) ++ stringify!(flags) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_sev_receive_update_data { +- pub hdr_uaddr: __u64, +- pub hdr_len: __u32, +- pub guest_uaddr: __u64, +- pub guest_len: __u32, +- pub trans_uaddr: __u64, +- pub trans_len: __u32, ++pub struct kvm_device_attr { ++ pub flags: __u32, ++ pub group: __u32, ++ pub attr: __u64, ++ pub addr: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_sev_receive_update_data() { ++fn bindgen_test_layout_kvm_device_attr() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_sev_receive_update_data)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_device_attr)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_sev_receive_update_data)) ++ concat!("Alignment of ", stringify!(kvm_device_attr)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_uaddr as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(hdr_uaddr) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).hdr_len as *const _ as usize +- }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).group) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(hdr_len) ++ stringify!(group) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_uaddr as *const _ as usize +- }, +- 16usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).attr) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(guest_uaddr) ++ stringify!(attr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).guest_len as *const _ as usize +- }, +- 24usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_device_attr), + "::", +- stringify!(guest_len) ++ stringify!(addr) + ) + ); ++} ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1; ++pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2; ++pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3; ++pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5; ++pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8; ++pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9; ++pub const kvm_device_type_KVM_DEV_TYPE_ARM_PV_TIME: kvm_device_type = 10; ++pub const kvm_device_type_KVM_DEV_TYPE_RISCV_AIA: kvm_device_type = 11; ++pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 12; ++pub type kvm_device_type = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_vfio_spapr_tce { ++ pub groupfd: __s32, ++ pub tablefd: __s32, ++} ++#[test] ++fn bindgen_test_layout_kvm_vfio_spapr_tce() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 8usize, ++ concat!("Size of: ", stringify!(kvm_vfio_spapr_tce)) ++ ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_uaddr as *const _ as usize +- }, +- 32usize, ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).groupfd) as usize - ptr as usize }, ++ 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_vfio_spapr_tce), + "::", +- stringify!(trans_uaddr) ++ stringify!(groupfd) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).trans_len as *const _ as usize +- }, +- 40usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).tablefd) as usize - ptr as usize }, ++ 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_sev_receive_update_data), ++ stringify!(kvm_vfio_spapr_tce), + "::", +- stringify!(trans_len) ++ stringify!(tablefd) + ) + ); + } + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_assigned_pci_dev { +- pub assigned_dev_id: __u32, +- pub busnr: __u32, +- pub devfn: __u32, +- pub flags: __u32, +- pub segnr: __u32, +- pub __bindgen_anon_1: kvm_assigned_pci_dev__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_assigned_pci_dev__bindgen_ty_1 { +- pub reserved: [__u32; 11usize], ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_enc_region { ++ pub addr: __u64, ++ pub size: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_pci_dev__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_enc_region() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 44usize, +- concat!("Size of: ", stringify!(kvm_assigned_pci_dev__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_enc_region)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_enc_region)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, ++ 0usize, + concat!( +- "Alignment of ", +- stringify!(kvm_assigned_pci_dev__bindgen_ty_1) ++ "Offset of field: ", ++ stringify!(kvm_enc_region), ++ "::", ++ stringify!(addr) + ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ +- as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev__bindgen_ty_1), ++ stringify!(kvm_enc_region), + "::", +- stringify!(reserved) ++ stringify!(size) + ) + ); + } +-impl Default for kvm_assigned_pci_dev__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_dirty_gfn { ++ pub flags: __u32, ++ pub slot: __u32, ++ pub offset: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_pci_dev() { ++fn bindgen_test_layout_kvm_dirty_gfn() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_assigned_pci_dev)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_dirty_gfn)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_pci_dev)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_dirty_gfn)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(assigned_dev_id) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).busnr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).slot) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(busnr) ++ stringify!(slot) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).devfn as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), +- "::", +- stringify!(devfn) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), +- "::", +- stringify!(flags) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).segnr as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_assigned_pci_dev), ++ stringify!(kvm_dirty_gfn), + "::", +- stringify!(segnr) ++ stringify!(offset) + ) + ); + } +-impl Default for kvm_assigned_pci_dev { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} ++#[doc = " struct kvm_stats_header - Header of per vm/vcpu binary statistics data.\n @flags: Some extra information for header, always 0 for now.\n @name_size: The size in bytes of the memory which contains statistics\n name string including trailing '\\0'. The memory is allocated\n at the send of statistics descriptor.\n @num_desc: The number of statistics the vm or vcpu has.\n @id_offset: The offset of the vm/vcpu stats' id string in the file pointed\n by vm/vcpu stats fd.\n @desc_offset: The offset of the vm/vcpu stats' descriptor block in the file\n pointd by vm/vcpu stats fd.\n @data_offset: The offset of the vm/vcpu stats' data block in the file\n pointed by vm/vcpu stats fd.\n\n This is the header userspace needs to read from stats fd before any other\n readings. It is used by userspace to discover all the information about the\n vm/vcpu's binary statistics.\n Userspace reads this header from the start of the vm/vcpu's stats fd."] + #[repr(C)] +-#[derive(Copy, Clone)] +-pub struct kvm_assigned_irq { +- pub assigned_dev_id: __u32, +- pub host_irq: __u32, +- pub guest_irq: __u32, ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct kvm_stats_header { + pub flags: __u32, +- pub __bindgen_anon_1: kvm_assigned_irq__bindgen_ty_1, +-} +-#[repr(C)] +-#[derive(Copy, Clone)] +-pub union kvm_assigned_irq__bindgen_ty_1 { +- pub reserved: [__u32; 12usize], ++ pub name_size: __u32, ++ pub num_desc: __u32, ++ pub id_offset: __u32, ++ pub desc_offset: __u32, ++ pub data_offset: __u32, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_irq__bindgen_ty_1() { ++fn bindgen_test_layout_kvm_stats_header() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 48usize, +- concat!("Size of: ", stringify!(kvm_assigned_irq__bindgen_ty_1)) ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(kvm_stats_header)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_irq__bindgen_ty_1)) ++ concat!("Alignment of ", stringify!(kvm_stats_header)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).reserved as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq__bindgen_ty_1), ++ stringify!(kvm_stats_header), + "::", +- stringify!(reserved) ++ stringify!(flags) + ) + ); +-} +-impl Default for kvm_assigned_irq__bindgen_ty_1 { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} +-#[test] +-fn bindgen_test_layout_kvm_assigned_irq() { +- assert_eq!( +- ::std::mem::size_of::(), +- 64usize, +- concat!("Size of: ", stringify!(kvm_assigned_irq)) +- ); + assert_eq!( +- ::std::mem::align_of::(), ++ unsafe { ::std::ptr::addr_of!((*ptr).name_size) as usize - ptr as usize }, + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_irq)) ++ concat!( ++ "Offset of field: ", ++ stringify!(kvm_stats_header), ++ "::", ++ stringify!(name_size) ++ ) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, +- 0usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).num_desc) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(assigned_dev_id) ++ stringify!(num_desc) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).host_irq as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).id_offset) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(host_irq) ++ stringify!(id_offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).guest_irq as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).desc_offset) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(guest_irq) ++ stringify!(desc_offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, ++ 20usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_irq), ++ stringify!(kvm_stats_header), + "::", +- stringify!(flags) ++ stringify!(data_offset) + ) + ); + } +-impl Default for kvm_assigned_irq { +- fn default() -> Self { +- let mut s = ::std::mem::MaybeUninit::::uninit(); +- unsafe { +- ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); +- s.assume_init() +- } +- } +-} ++#[doc = " struct kvm_stats_desc - Descriptor of a KVM statistics.\n @flags: Annotations of the stats, like type, unit, etc.\n @exponent: Used together with @flags to determine the unit.\n @size: The number of data items for this stats.\n Every data item is of type __u64.\n @offset: The offset of the stats to the start of stat structure in\n structure kvm or kvm_vcpu.\n @bucket_size: A parameter value used for histogram stats. It is only used\n\t\tfor linear histogram stats, specifying the size of the bucket;\n @name: The name string for the stats. Its size is indicated by the\n &kvm_stats_header->name_size."] + #[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_assigned_msix_nr { +- pub assigned_dev_id: __u32, +- pub entry_nr: __u16, +- pub padding: __u16, ++#[derive(Debug, Default)] ++pub struct kvm_stats_desc { ++ pub flags: __u32, ++ pub exponent: __s16, ++ pub size: __u16, ++ pub offset: __u32, ++ pub bucket_size: __u32, ++ pub name: __IncompleteArrayField<::std::os::raw::c_char>, + } + #[test] +-fn bindgen_test_layout_kvm_assigned_msix_nr() { ++fn bindgen_test_layout_kvm_stats_desc() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 8usize, +- concat!("Size of: ", stringify!(kvm_assigned_msix_nr)) ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(kvm_stats_desc)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_msix_nr)) ++ concat!("Alignment of ", stringify!(kvm_stats_desc)) + ); + assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(assigned_dev_id) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entry_nr as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).exponent) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(entry_nr) ++ stringify!(exponent) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_nr), +- "::", +- stringify!(padding) +- ) +- ); +-} +-#[repr(C)] +-#[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_assigned_msix_entry { +- pub assigned_dev_id: __u32, +- pub gsi: __u32, +- pub entry: __u16, +- pub padding: [__u16; 3usize], +-} +-#[test] +-fn bindgen_test_layout_kvm_assigned_msix_entry() { +- assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_assigned_msix_entry)) +- ); +- assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_assigned_msix_entry)) +- ); +- assert_eq!( +- unsafe { +- &(*(::std::ptr::null::())).assigned_dev_id as *const _ as usize +- }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(assigned_dev_id) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).gsi as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(gsi) ++ stringify!(offset) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).entry as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).bucket_size) as usize - ptr as usize }, ++ 12usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(entry) ++ stringify!(bucket_size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 10usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_assigned_msix_entry), ++ stringify!(kvm_stats_desc), + "::", +- stringify!(padding) ++ stringify!(name) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_hyperv_eventfd { +- pub conn_id: __u32, +- pub fd: __s32, +- pub flags: __u32, +- pub padding: [__u32; 3usize], ++pub struct kvm_memory_attributes { ++ pub address: __u64, ++ pub size: __u64, ++ pub attributes: __u64, ++ pub flags: __u64, + } + #[test] +-fn bindgen_test_layout_kvm_hyperv_eventfd() { ++fn bindgen_test_layout_kvm_memory_attributes() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 24usize, +- concat!("Size of: ", stringify!(kvm_hyperv_eventfd)) ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(kvm_memory_attributes)) + ); + assert_eq!( +- ::std::mem::align_of::(), +- 4usize, +- concat!("Alignment of ", stringify!(kvm_hyperv_eventfd)) ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(kvm_memory_attributes)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).conn_id as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).address) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(conn_id) ++ stringify!(address) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(fd) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(flags) ++ stringify!(attributes) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).padding as *const _ as usize }, +- 12usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 24usize, + concat!( + "Offset of field: ", +- stringify!(kvm_hyperv_eventfd), ++ stringify!(kvm_memory_attributes), + "::", +- stringify!(padding) ++ stringify!(flags) + ) + ); + } + #[repr(C)] + #[derive(Debug, Default, Copy, Clone, PartialEq)] +-pub struct kvm_dirty_gfn { +- pub flags: __u32, +- pub slot: __u32, +- pub offset: __u64, ++pub struct kvm_create_guest_memfd { ++ pub size: __u64, ++ pub flags: __u64, ++ pub reserved: [__u64; 6usize], + } + #[test] +-fn bindgen_test_layout_kvm_dirty_gfn() { ++fn bindgen_test_layout_kvm_create_guest_memfd() { ++ const UNINIT: ::std::mem::MaybeUninit = ++ ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); + assert_eq!( +- ::std::mem::size_of::(), +- 16usize, +- concat!("Size of: ", stringify!(kvm_dirty_gfn)) ++ ::std::mem::size_of::(), ++ 64usize, ++ concat!("Size of: ", stringify!(kvm_create_guest_memfd)) + ); + assert_eq!( +- ::std::mem::align_of::(), ++ ::std::mem::align_of::(), + 8usize, +- concat!("Alignment of ", stringify!(kvm_dirty_gfn)) ++ concat!("Alignment of ", stringify!(kvm_create_guest_memfd)) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(flags) ++ stringify!(size) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).slot as *const _ as usize }, +- 4usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, ++ 8usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(slot) ++ stringify!(flags) + ) + ); + assert_eq!( +- unsafe { &(*(::std::ptr::null::())).offset as *const _ as usize }, +- 8usize, ++ unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, ++ 16usize, + concat!( + "Offset of field: ", +- stringify!(kvm_dirty_gfn), ++ stringify!(kvm_create_guest_memfd), + "::", +- stringify!(offset) ++ stringify!(reserved) + ) + ); + } +diff --git a/vendor/kvm-bindings/src/x86/fam_wrappers.rs b/vendor/kvm-bindings/src/x86_64/fam_wrappers.rs +similarity index 60% +rename from vendor/kvm-bindings/src/x86/fam_wrappers.rs +rename to vendor/kvm-bindings/src/x86_64/fam_wrappers.rs +index 9d397c3..fd4eee4 100644 +--- a/vendor/kvm-bindings/src/x86/fam_wrappers.rs ++++ b/vendor/kvm-bindings/src/x86_64/fam_wrappers.rs +@@ -3,7 +3,7 @@ + + use vmm_sys_util::fam::{FamStruct, FamStructWrapper}; + +-use x86::bindings::*; ++use x86_64::bindings::*; + + /// Maximum number of CPUID entries that can be returned by a call to KVM ioctls. + /// +@@ -94,10 +94,76 @@ impl PartialEq for kvm_msr_list { + /// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). + pub type MsrList = FamStructWrapper; + ++/// Helper structure to treat post-5.17 [`kvm_xsave`] as a FamStruct. ++/// ++/// See also: [`Xsave`]. ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct kvm_xsave2 { ++ /// The length, in bytes, of the FAM in [`kvm_xsave`]. ++ /// ++ /// Note that `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` returns the size of the entire ++ /// `kvm_xsave` structure, e.g. the sum of header and FAM. Thus, this `len` field ++ /// is equal to `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) - 4096`. ++ pub len: usize, ++ pub xsave: kvm_xsave, ++} ++ ++// SAFETY: ++// - `kvm_xsave2` is a POD ++// - `kvm_xsave2` contains a flexible array member as its final field, due to `kvm_xsave` containing ++// one, and being `repr(C)` ++// - `Entry` is a POD ++unsafe impl FamStruct for kvm_xsave2 { ++ type Entry = __u32; ++ ++ fn len(&self) -> usize { ++ self.len ++ } ++ ++ unsafe fn set_len(&mut self, len: usize) { ++ self.len = len; ++ } ++ ++ fn max_len() -> usize { ++ __u32::MAX as usize ++ } ++ ++ fn as_slice(&self) -> &[::Entry] { ++ let len = self.len(); ++ // SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches ++ // the actual in-memory length of the FAM ++ unsafe { self.xsave.extra.as_slice(len) } ++ } ++ ++ fn as_mut_slice(&mut self) -> &mut [::Entry] { ++ let len = self.len(); ++ // SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches ++ // the actual in-memory length of the FAM ++ unsafe { self.xsave.extra.as_mut_slice(len) } ++ } ++} ++ ++/// Wrapper over the post-5.17 [`kvm_xsave`] structure. ++/// ++/// In linux 5.17, kvm_xsave got turned into a FamStruct by adding the flexible "extra" member ++/// to its definition. However, unlike all other such structs, it does not contain a "length" ++/// field. Instead, the length of the flexible array member has to be determined by querying ++/// the [`KVM_CAP_XSAVE2`] capability. This requires access to a VM file descriptor, and thus ++/// cannot happen in the [`FamStruct::len`] trait method. To work around this, we define a wrapper ++/// struct that caches the length of a previous `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` call, ++/// and implement [`FamStruct`] for this wrapper. Then in kvm-ioctls, we can expose a function ++/// that first queries `KVM_CAP_XSAVE2`, then invokes [`KVM_GET_XSAVE2`] to retrives the `kvm_xsave` ++/// structure, and finally combine them into the [`kvm_xsave2`] helper structure to be managed as a ++/// `FamStruct`. ++pub type Xsave = FamStructWrapper; ++ + #[cfg(test)] + mod tests { +- use super::{CpuId, MsrList, Msrs}; +- use x86::bindings::kvm_cpuid_entry2; ++ use super::{CpuId, MsrList, Msrs, Xsave}; ++ use x86_64::bindings::kvm_cpuid_entry2; ++ ++ use vmm_sys_util::fam::FamStruct; + + #[test] + fn test_cpuid_eq() { +@@ -120,10 +186,15 @@ mod tests { + + let mut wrapper2 = wrapper.clone(); + assert!(wrapper == wrapper2); +- +- wrapper.as_mut_fam_struct().pad = 1; ++ // SAFETY: We are not modifying the `nmsrs` field ++ unsafe { ++ wrapper.as_mut_fam_struct().pad = 1; ++ } + assert!(wrapper != wrapper2); +- wrapper2.as_mut_fam_struct().pad = 1; ++ // SAFETY: We are not modifying the `nmsrs` field ++ unsafe { ++ wrapper2.as_mut_fam_struct().pad = 1; ++ } + assert!(wrapper == wrapper2); + + wrapper.as_mut_slice()[1].data = 1; +@@ -146,4 +217,11 @@ mod tests { + wrapper2.as_mut_slice()[0] = 1; + assert!(wrapper == wrapper2); + } ++ #[test] ++ fn test_xsave() { ++ let wrapper = Xsave::new(1).unwrap(); ++ assert_eq!(wrapper.as_slice().len(), 1); ++ assert_eq!(wrapper.as_fam_struct_ref().len(), 1); ++ assert_eq!(wrapper.as_fam_struct_ref().len, 1); ++ } + } +diff --git a/vendor/kvm-bindings/src/x86_64/mod.rs b/vendor/kvm-bindings/src/x86_64/mod.rs +new file mode 100644 +index 0000000..08e1bab +--- /dev/null ++++ b/vendor/kvm-bindings/src/x86_64/mod.rs +@@ -0,0 +1,14 @@ ++// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. ++// SPDX-License-Identifier: Apache-2.0 ++#[allow(clippy::undocumented_unsafe_blocks)] ++#[allow(clippy::all)] ++pub mod bindings; ++#[cfg(feature = "fam-wrappers")] ++pub mod fam_wrappers; ++ ++#[cfg(feature = "serde")] ++mod serialize; ++ ++pub use self::bindings::*; ++#[cfg(feature = "fam-wrappers")] ++pub use self::fam_wrappers::*; +diff --git a/vendor/kvm-bindings/src/x86_64/serialize.rs b/vendor/kvm-bindings/src/x86_64/serialize.rs +new file mode 100644 +index 0000000..4b3fe36 +--- /dev/null ++++ b/vendor/kvm-bindings/src/x86_64/serialize.rs +@@ -0,0 +1,156 @@ ++// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. ++// SPDX-License-Identifier: Apache-2.0 ++ ++use bindings::{ ++ kvm_clock_data, kvm_cpuid2, kvm_cpuid_entry2, kvm_debugregs, kvm_dtable, kvm_irqchip, ++ kvm_irqchip__bindgen_ty_1, kvm_lapic_state, kvm_mp_state, kvm_msr_entry, kvm_msrs, ++ kvm_pit_channel_state, kvm_pit_state2, kvm_regs, kvm_segment, kvm_sregs, kvm_vcpu_events, ++ kvm_xcr, kvm_xcrs, kvm_xsave, ++}; ++use serde::{Deserialize, Deserializer, Serialize, Serializer}; ++use zerocopy::{transmute, AsBytes, FromBytes, FromZeroes}; ++ ++serde_impls!( ++ kvm_regs, ++ kvm_segment, ++ kvm_dtable, ++ kvm_sregs, ++ kvm_msr_entry, ++ kvm_cpuid_entry2, ++ kvm_pit_channel_state, ++ kvm_pit_state2, ++ kvm_vcpu_events, ++ kvm_debugregs, ++ kvm_xcr, ++ kvm_xcrs, ++ kvm_mp_state, ++ kvm_clock_data, ++ kvm_lapic_state, ++ kvm_msrs, ++ kvm_cpuid2, ++ kvm_xsave, ++ kvm_irqchip ++); ++ ++// SAFETY: zerocopy's derives explicitly disallow deriving for unions where ++// the fields have different sizes, due to the smaller fields having padding. ++// Miri however does not complain about these implementations (e.g. about ++// reading the "padding" for one union field as valid data for a bigger one) ++unsafe impl FromZeroes for kvm_irqchip__bindgen_ty_1 { ++ fn only_derive_is_allowed_to_implement_this_trait() ++ where ++ Self: Sized, ++ { ++ } ++} ++ ++// SAFETY: zerocopy's derives explicitly disallow deriving for unions where ++// the fields have different sizes, due to the smaller fields having padding. ++// Miri however does not complain about these implementations (e.g. about ++// reading the "padding" for one union field as valid data for a bigger one) ++unsafe impl FromBytes for kvm_irqchip__bindgen_ty_1 { ++ fn only_derive_is_allowed_to_implement_this_trait() ++ where ++ Self: Sized, ++ { ++ } ++} ++ ++// SAFETY: zerocopy's derives explicitly disallow deriving for unions where ++// the fields have different sizes, due to the smaller fields having padding. ++// Miri however does not complain about these implementations (e.g. about ++// reading the "padding" for one union field as valid data for a bigger one) ++unsafe impl AsBytes for kvm_irqchip__bindgen_ty_1 { ++ fn only_derive_is_allowed_to_implement_this_trait() ++ where ++ Self: Sized, ++ { ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use bindings::*; ++ ++ fn is_serde Deserialize<'de> + Default>() { ++ let serialized = bincode::serialize(&T::default()).unwrap(); ++ let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); ++ let serialized_again = bincode::serialize(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn static_assert_serde_implementations() { ++ // This test statically (= at compile-time) asserts that various bindgen generated ++ // structures implement serde's `Serialize` and `Deserialize` traits. ++ // This is to make sure that we do not accidentally remove those implementations ++ // when regenerating bindings. If this test fails to compile, please add ++ // ++ // #[cfg_attr( ++ // feature = "serde", ++ // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) ++ // )] ++ // ++ // to all structures causing compilation errors (we need the zerocopy traits, as the ++ // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro ++ // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` ++ // traits that it expects to be derived). ++ // ++ // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types ++ // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across ++ // bindgen versions. If after re-adding the derives to all the below items you can compile ++ // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add ++ // the derives to all anonymous types references in the definitions of the below items. ++ ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ is_serde::(); ++ } ++ ++ fn is_serde_json Deserialize<'de> + Default>() { ++ let serialized = serde_json::to_string(&T::default()).unwrap(); ++ let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); ++ let serialized_again = serde_json::to_string(&deserialized).unwrap(); ++ // Compare the serialized state after a roundtrip, to work around issues with ++ // bindings not implementing `PartialEq`. ++ assert_eq!(serialized, serialized_again); ++ } ++ ++ #[test] ++ fn test_json_serde() { ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ is_serde_json::(); ++ } ++} +diff --git a/vendor/kvm-ioctls/.cargo-checksum.json b/vendor/kvm-ioctls/.cargo-checksum.json +index 99c8773..9953ab5 100644 +--- a/vendor/kvm-ioctls/.cargo-checksum.json ++++ b/vendor/kvm-ioctls/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{"CHANGELOG.md":"836f769bf8baab397f24ad3d9daddc0a9570383e0fc262bfd7cc5505ceca2cf8","CODEOWNERS":"3db77159229a7245a1130bfe8636ba8a12806bb4589f23c15f68c6d036394f9b","Cargo.toml":"616f139019b40179d63ef8ac1630857a621e0baf80d1d5b9de306d01def3eece","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"6ae314acf8e015716cdfbed46fdc6ded0a599411b8b98cd61c87f9940f85ffc7","README.md":"fe70ffb039d3e5e7a229643407735558d95aaf6018e80368a607d6bdfabe9fb6","THIRD-PARTY":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","build.rs":"9e07404d93cd2f4179028a061099992e67737558e75f80f3c7d3ca41c733aaed","coverage_config_aarch64.json":"2defd2846ef32131b20cfe4eaa1ec649cb5db59b6343c6bb4ec936780ab20c8d","coverage_config_x86_64.json":"0f48198a737dd4b4eea1d7ea20dbd663205d1ece3f9ad8d41a2e2f1be6b09282","src/cap.rs":"ca1976bdcc9dda968a9575050f1b1f390af0255c5a83167a6c348ea21a04818b","src/ioctls/device.rs":"6f7b10e0e1f20943990f525928b6bf8a19471e0488138993400fa9031d0765a5","src/ioctls/mod.rs":"4646a418c64faf1592539ea2807d72ebfaf76ef93ad4cbd978cc7059a1757726","src/ioctls/system.rs":"6e97a75558dc777198c9de2e8b19ee0a2afe3d7bd94894a4c05a26f11b8eb0a6","src/ioctls/vcpu.rs":"b374bfe01626c27fdffe8a1a8bd168a057edb2ca94f40bc66188aa7164496dac","src/ioctls/vm.rs":"bcd6c4428ac61810dc11f97f475590ec2490287cc18c4ebe292d84254da4c785","src/kvm_ioctls.rs":"bf1007e31224001c54b0173e13e350ac84794a2d2f86f8362062a6f0c42a6119","src/lib.rs":"f7b75bf1694dab48509e2d1034d3447f86270d5dae8706f47c00512d4fed9d86"},"package":"9bdde2b46ee7b6587ef79f751019c4726c4f2d3e4628df5d69f3f9c5cb6c6bd4"} +\ No newline at end of file ++{"files":{"CHANGELOG.md":"919de491099dcbf3ee4ad4f88d31f9357d11bac0c6ecce857268aca42b95a10c","CODEOWNERS":"aac8f130c705d49fae7d10f1852fa3077d94d7f18d0031d381c58a96588fa1ec","Cargo.toml":"2e3c9be524193be18551759becc413707ae5c7218771cc5a29c1232944596612","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"6ae314acf8e015716cdfbed46fdc6ded0a599411b8b98cd61c87f9940f85ffc7","README.md":"7dcd03b99cf6cf67b7aeb4477890ad498c6caaba88ba847bef8c9f7c4606dcdd","THIRD-PARTY":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","build.rs":"b54b20e2cdb6edb0093a526ba6bdb0411ef9fe2b1366cb881d299a7d120936bb","coverage_config_aarch64.json":"2defd2846ef32131b20cfe4eaa1ec649cb5db59b6343c6bb4ec936780ab20c8d","coverage_config_x86_64.json":"d16a82b6a1c483fa0adfbd651f19b5c18fd2f802da63574b084ba7383a470ea0","src/cap.rs":"608dec81f08b946a8fcb81ab41f98fa6e160cb30ec51c1733b8159881fb83d0d","src/ioctls/device.rs":"aa97106ebe39df05a772a0f8dc9f110381451b7991c213e68f194e425b7c0afb","src/ioctls/mod.rs":"1b1fbd036173bf68ec2259afb14682084dec22c119f608cb1030d00dcb86db71","src/ioctls/system.rs":"b01b679ab12bf922d2ab8bd9b68a62c05c3ea707a388e0f995c74eab14688fc0","src/ioctls/vcpu.rs":"457b2d22655b2941818d55e432e5cf9605d52be16fc55faea993e49733a471fa","src/ioctls/vm.rs":"b960389204fc1b437719355f07b5b80f58466d1316cc38e91e8309104588a70c","src/kvm_ioctls.rs":"5446cb404310d99f2b64bcfd06313fdd590e2b2770bd140a7e9537781c273afc","src/lib.rs":"2ae6bbbdcdc6ffdfcaa2ba1e280b72d1044ebaaa79866d62f6edc739164b66c6"},"package":"e013ae7fcd2c6a8f384104d16afe7ea02969301ea2bb2a56e44b011ebc907cab"} +\ No newline at end of file +diff --git a/vendor/kvm-ioctls/CHANGELOG.md b/vendor/kvm-ioctls/CHANGELOG.md +index 752408d..f46e5b6 100644 +--- a/vendor/kvm-ioctls/CHANGELOG.md ++++ b/vendor/kvm-ioctls/CHANGELOG.md +@@ -1,12 +1,73 @@ +-# Upcoming Release ++# Changelog + +-## Added ++## Upcoming Release + +-## Changed ++## v0.19.1 + +-# v0.15.0 ++### Fixed + +-## Added ++- [[#298](https://github.com/rust-vmm/kvm/pull/298)]: Fixed incorrect usage of `ioctl_wit_ref` in the ++ `create_device` method. Replace it with `ioctl_wit_mut_ref` as the passed parameter may be mutated by the ++ ioctl. ++ ++## v0.19.0 ++ ++### Added ++ ++- [[#275](https://github.com/rust-vmm/kvm-ioctls/pull/275)]: Introduce `riscv64` ioctls. ++ ++### Removed ++ ++- [[#289](https://github.com/rust-vmm/kvm-ioctls/pull/289)]: Drop `x86` 32-bit ++ and `arm` 32-bit support. ++ ++### Changed ++ ++- [[#273](https://github.com/rust-vmm/kvm-ioctls/pull/273)]: `DeviceFd::get_device_attr` is now ++ marked as unsafe. ++- [[#277](https://github.com/rust-vmm/kvm-ioctls/pull/277)]: Updated kvm-bindings to 0.9.1. ++ ++## v0.18.0 ++ ++### Added ++ ++- [[#264](https://github.com/rust-vmm/kvm-ioctls/pull/264)]: Added `KVM_SET_USER_MEMORY_REGION2`, ++ `KVM_CREATE_GUEST_MEMFD` and `KVM_SET_MEMORY_ATTRIBUTES` ioctls. ++- [[#267](https://github.com/rust-vmm/kvm-ioctls/pull/267)]: Added `HypercallExit` field to ++ `VcpuExit::Hypercall` and added `ExitHypercall` to `Cap`. ++- [[#270](https://github.com/rust-vmm/kvm-ioctls/pull/270)]: Added `MemoryFaultInfo` to `Cap` and ++ propagated `MemoryFault` exit reason in `KVM_RUN`. ++ ++## v0.17.0 ++ ++### Changed ++ ++- [[#255](https://github.com/rust-vmm/kvm-ioctls/issues/255)]: Fixed a ++ soundness issue when accessing the `kvm_run` struct. `VcpuFd::run()` and ++ `VcpuFd::set_kvm_immediate_exit()` now take `&mut self` as a consequence. ++- [[#260](https://github.com/rust-vmm/kvm-ioctls/pull/260)]: Updated kvm-bindings to 0.8.0. ++ ++## v0.16.0 ++ ++### Added ++- [[#242](https://github.com/rust-vmm/kvm-ioctls/pull/242)] x86: add support ++ for SMI injection via `Vcpu::smi()` (`KVM_SMI` ioctl). ++- [[#241](https://github.com/rust-vmm/kvm-ioctls/pull/241)] Add support for ++ userspace MSR handling. ++- [[#246](https://github.com/rust-vmm/kvm-ioctls/pull/246)] Add support for ++ userspace NMI injection (`KVM_NMI` ioctl). ++- [[#244](https://github.com/rust-vmm/kvm-ioctls/pull/244)] add support for ++ coalesced MMIO (`KVM_CAP_COALESCED_MMIO` / `KVM_CAP_COALESCED_PIO`) ++ ++### Changed ++- [[#234](https://github.com/rust-vmm/kvm-ioctls/issues/234)] vcpu: export ++reg_size as a public method. ++- [[#243](https://github.com/rust-vmm/kvm-ioctls/pull/243)] derived the `Copy` ++ trait for `IoEventAddress` and `NoDatamatch`. ++ ++## v0.15.0 ++ ++### Added + - [[#230](https://github.com/rust-vmm/kvm-ioctls/pull/230)] Added + `check_extension_raw` method to use raw integer values instead + of `Cap` enum. +@@ -15,36 +76,36 @@ support for vCPU SVE feature. + - [[#219](https://github.com/rust-vmm/kvm-ioctls/pull/226)] Add `Cap::ArmPtrAuthAddress` + and `Cap::ArmPtrAuthGeneric` capabilities. + +-# v0.14.0 ++## v0.14.0 + +-## Added ++### Added + + - [[#219](https://github.com/rust-vmm/kvm-ioctls/pull/219)] Support for + `KVM_GET_MSR_FEATURE_INDEX_LIST` and `KVM_GET_MSRS` system ioctls. + - [[#221](https://github.com/rust-vmm/kvm-ioctls/pull/221)] Add + `Cap::ArmPmuV3`. +- +-## Changed ++ ++### Changed + + - [[#223](https://github.com/rust-vmm/kvm-ioctls/pull/223)] aarch64: + Updated `get/set_one_reg` to support different registers sizes through + byte slices. + +-# v0.13.0 ++## v0.13.0 + +-## Added ++### Added + - [[#213](https://github.com/rust-vmm/kvm-ioctls/pull/213)] Add `Kvm::new_with_path()` + and `Kvm::open_with_cloexec_at()` to allow using kvm device files other than + `/dev/kvm`. + +-# v0.12.0 ++## v0.12.0 + +-## Added ++### Added + +-- [[#187](https://github.com/rust-vmm/kvm-ioctls/pull/187)] Support for ++- [[#187](https://github.com/rust-vmm/kvm-ioctls/pull/187)] Support for + `KVM_SET_IDENTITY_MAP_ADDR` + - Derive Debug for all exported structs and enums +-- [[#189](https://github.com/rust-vmm/kvm-ioctls/pull/189)] Expose `KVM_SET_` and ++- [[#189](https://github.com/rust-vmm/kvm-ioctls/pull/189)] Expose `KVM_SET_` and + `KVM_HAS_DEVICE_ATTR` for vcpu + - [[#191](https://github.com/rust-vmm/kvm-ioctls/pull/191)] Add `KVM_TRANSLATE` support and + the `translate_gva` function that translates guest virtual address to the physical address +@@ -59,7 +120,7 @@ support for vCPU SVE feature. + - [[#202](https://github.com/rust-vmm/kvm-ioctls/pull/202)] Added `check_extension_int` + which allows checking the capabilities that return numbers instead of booleans + +-## Changed ++### Changed + + - Updated vmm-sys-util to 0.11.0 + - Updated kvm-bindings to 0.6.0 +@@ -69,14 +130,14 @@ support for vCPU SVE feature. + - [[#195](https://github.com/rust-vmm/kvm-ioctls/pull/195)] Do not panic on unsupported + `KVM_EXIT` reason + - [[#196](https://github.com/rust-vmm/kvm-ioctls/pull/196)] Expose a mutable reference +- to the `kvm_run` structure to allow proper handling of unsupported exit reasons ++ to the `kvm_run` structure to allow proper handling of unsupported exit reasons + - [[#200](https://github.com/rust-vmm/kvm-ioctls/pull/200)] Fix wrong `target_arch` gate + preventing `set_guest_debug` from being exported on ARM + - [[#206](https://github.com/rust-vmm/kvm-ioctls/pull/206)] use `u128` in `get/set_on_reg` + +-# v0.11.0 ++## v0.11.0 + +-## Added ++### Added + - [[#178](https://github.com/rust-vmm/kvm-ioctls/pull/178)] Support for the AMD + Security Encrypted Virtualization (SEV) through the following VM ioctls: + `encrypt_op`, `encrypt_op_sev`, `register_enc_memory_region` and +@@ -84,54 +145,54 @@ support for vCPU SVE feature. + - [[#184](https://github.com/rust-vmm/kvm-ioctls/pull/184)] `DeviceFd` now + derives `Debug`. + +-# v0.10.0 ++## v0.10.0 + +-## Changed ++### Changed + - Now depends on kvm-bindings >=0.5.0 which replaced the v4.20 KVM bindings + with the v5.13 ones. + - Updated `VcpuExit::Debug` to return architecture specific information for the + debug event. + +-# v0.9.0 ++## v0.9.0 + +-## Added ++### Added + - Support for accessing and controlling the Time Stamp Counter on x86 platforms + through the `get_tsc_khz` and `set_tsc_khz` functions. + +-## Changed ++### Changed + - Updated `create_vm` on `aarch64` to create a VM fd from the KVM fd using the + host's maximum IPA size. + +-# v0.8.0 ++## v0.8.0 + +-## Added ++### Added + - Support for specifying VM type (an opaque platform and architecture specific + constant) when creating a VM (`KVM_CREATE_VM` ioctl) via the + `Kvm::create_vm_with_type` function. + +-## Changed ++### Changed + - Now depends on kvm-bindings >=0.4.0 to support use of a newer vmm-sys-utils + dependency. + +-# v0.7.0 ++## v0.7.0 + +-## Added ++### Added + - Support for the system API that returns the maximum allowed vCPU ID + (`KVM_CAP_MAX_VCPU_ID`). + - Support for `KVM_MEMORY_ENCRYPT_OP`. + +-## Fixed ++### Fixed + - [[#119](https://github.com/rust-vmm/kvm-ioctls/issues/119)]: Disallow invalid + number of cpuid entries to be passed to `get_supported_cpuid` and + `get_emulated_cpuid`. + +-## Changed ++### Changed + - [[#123](https://github.com/rust-vmm/kvm-ioctls/issues/123)]: Updated + `create_vcpu` to use `u64` as the parameter for the number of vCPUs. + +-# v0.6.0 ++## v0.6.0 + +-## Added ++### Added + - Support for the vcpu ioctls: `KVM_SET_GUEST_DEBUG`, `KVM_KVMCLOCK_CTRL`, and + `KVM_GET_REG_LIST`. + - Support for the vm ioctl `KVM_GET_DEVICE_ATTR`. +@@ -144,31 +205,31 @@ support for vCPU SVE feature. + - Support for checking the VM capabilities via `Vm::check_extension`. + - Create a VM with flexible IPA size using `Kvm::create_vm_with_ipa_size`. + +-## Removed ++### Removed + - Removed `Kvm::new_with_fd_number`. The same functionality is offered by the + `Kvm` [FromRawFd](https://doc.rust-lang.org/std/os/unix/io/trait.FromRawFd.html) + trait implementation. + +-## Changed ++### Changed + - The VM ioctl `unregister_ioevent` now correctly unregisters the events that + correspond to the data match passed as a parameter. + - The `SystemEvent` Vcpu Exit now also contains the relevant type and flags. + - Updated `get_dirty_log` such that it does not assume the page size is 4K, + but instead reads it using `libc::sysconf`. + +-# v0.5.0 ++## v0.5.0 + +-## Added ++### Added + - Support for the vcpu ioctls `KVM_GET/SET_VCPU_EVENTS` and `KVM_GET_DIRTY_LOG` + on `aarch64`. + - Support for the vcpu ioctl `KVM_IRQ_LINE`. + +-# v0.4.0 ++## v0.4.0 + +-## Added ++### Added + - Support for unregistering ioeventfds through `KVM_IOEVENTFD`. + +-## Changed ++### Changed + - Functions working with event FDs now require + vmm_sys_util::eventfd::EventFd in their interface instead of + RawFd. +@@ -182,15 +243,15 @@ support for vCPU SVE feature. + not have to use kvm_ioctls::Result outside the crate. + - kvm_ioctls::Error now works with errno::Error instead of io::Error. + +-## Removed ++### Removed + - CpuId safe wrapper over FAM struct kvm_cpuid2. The safe wrapper is + now provided by the kvm_bindings crate starting with v0.2.0. + - KVM_MAX_MSR_ENTRIES and MAX_KVM_CPUID_ENTRIES. Equivalent constants + are provided by the kvm_bindings crate starting with v0.2.0. + +-# v0.3.0 ++## v0.3.0 + +-## Added ++### Added + - Support for setting vcpu `kvm_immediate_exit` flag + - Support for the vcpu ioctl `KVM_GET_CPUID2` + - Support for the vcpu ioctl `KVM_GET_MP_STATE` +@@ -211,23 +272,23 @@ support for vCPU SVE feature. + - Support for the vm ioctl `KVM_SET_PIT2` + - Support for the vcpu ioctl `KVM_GET_ONE_REG` + +-## Changed ++### Changed + - Function offering support for `KVM_SET_MSRS` also returns the number + of MSR entries successfully written. + +-# v0.2.0 ++## v0.2.0 + +-## Added ++### Added + - Add support for `KVM_ENABLE_CAP`. + - Add support for `KVM_SIGNAL_MSI`. + +-## Fixed ++### Fixed + - Fix bug in KvmRunWrapper. The memory for kvm_run struct was not unmapped + after the KvmRunWrapper object got out of scope. + - Return proper value when receiving the EOI KVM exit. + - Mark set_user_memory_region as unsafe. + +-# v0.1.0 ++## v0.1.0 + + First release of the kvm-ioctls crate. + +diff --git a/vendor/kvm-ioctls/CODEOWNERS b/vendor/kvm-ioctls/CODEOWNERS +index 9649f2d..064bfa2 100644 +--- a/vendor/kvm-ioctls/CODEOWNERS ++++ b/vendor/kvm-ioctls/CODEOWNERS +@@ -1,3 +1,3 @@ + # These owners will be the default owners for everything in + # the repo. +-* @acatangiu @aghecenco @andreeaflorescu @lauralt @sameo @roypat @JonathanWoollett-Light ++* @acatangiu @aghecenco @andreeaflorescu @lauralt @sameo @roypat @ShadowCurse +diff --git a/vendor/kvm-ioctls/Cargo.toml b/vendor/kvm-ioctls/Cargo.toml +index a60571a..5b858b6 100644 +--- a/vendor/kvm-ioctls/Cargo.toml ++++ b/vendor/kvm-ioctls/Cargo.toml +@@ -12,23 +12,36 @@ + [package] + edition = "2021" + name = "kvm-ioctls" +-version = "0.15.0" ++version = "0.19.1" + authors = ["Amazon Firecracker Team "] ++build = "build.rs" ++autolib = false ++autobins = false ++autoexamples = false ++autotests = false ++autobenches = false + description = "Safe wrappers over KVM ioctls" + readme = "README.md" + keywords = ["kvm"] + license = "Apache-2.0 OR MIT" + repository = "https://github.com/rust-vmm/kvm-ioctls" + ++[lib] ++name = "kvm_ioctls" ++path = "src/lib.rs" ++ ++[dependencies.bitflags] ++version = "2.4.1" ++ + [dependencies.kvm-bindings] +-version = "0.6.0" ++version = "0.10.0" + features = ["fam-wrappers"] + + [dependencies.libc] + version = "0.2.39" + + [dependencies.vmm-sys-util] +-version = "0.11.0" ++version = "0.12.1" + + [dev-dependencies.byteorder] + version = "1.2.1" +diff --git a/vendor/kvm-ioctls/README.md b/vendor/kvm-ioctls/README.md +index faedf93..2b4a5fd 100644 +--- a/vendor/kvm-ioctls/README.md ++++ b/vendor/kvm-ioctls/README.md +@@ -18,10 +18,7 @@ as the code documentation. + + ## Supported Platforms + +-The kvm-ioctls can be used on x86_64 and aarch64. Right now the aarch64 support +-is considered experimental. For a production ready version, please check the +-progress in the corresponding +-[GitHub issue](https://github.com/rust-vmm/kvm-ioctls/issues/8). ++The kvm-ioctls can be used on x86_64, aarch64 and riscv64 (experimental). + + ## Running the tests + +@@ -31,14 +28,16 @@ For the complete list of tests, check our + [CI pipeline](https://buildkite.com/rust-vmm/kvm-ioctls-ci). + + Each individual test runs in a container. To reproduce a test locally, you can +-use the dev-container on both x86 and arm64. ++use the dev-container on x86_64, arm64 and riscv64. + + ```bash ++# For running riscv64 tests, replace v47 with v47-riscv. This provides an ++# emulated riscv64 environment on a x86_64 host. + docker run --device=/dev/kvm \ + -it \ + --security-opt seccomp=unconfined \ + --volume $(pwd)/kvm-ioctls:/kvm-ioctls \ +- rustvmm/dev:v16 ++ rustvmm/dev:v47 + cd kvm-ioctls/ + cargo test + ``` +diff --git a/vendor/kvm-ioctls/build.rs b/vendor/kvm-ioctls/build.rs +index 60b655a..067a65d 100644 +--- a/vendor/kvm-ioctls/build.rs ++++ b/vendor/kvm-ioctls/build.rs +@@ -2,6 +2,8 @@ + // SPDX-License-Identifier: Apache-2.0 OR MIT + + fn main() { ++ // Add `has_sev` to expected attributes. ++ println!("cargo:rustc-check-cfg=cfg(has_sev)"); + // Define a `has_sev` attribute, which is used for conditional + // execution of SEV-specific tests and examples. + if std::path::Path::new("/dev/sev").exists() { +diff --git a/vendor/kvm-ioctls/coverage_config_x86_64.json b/vendor/kvm-ioctls/coverage_config_x86_64.json +index 2ab10dd..08c0327 100644 +--- a/vendor/kvm-ioctls/coverage_config_x86_64.json ++++ b/vendor/kvm-ioctls/coverage_config_x86_64.json +@@ -1,5 +1,5 @@ + { +- "coverage_score": 84.6, ++ "coverage_score": 92.61, + "exclude_path": "", + "crate_features": "" + } +diff --git a/vendor/kvm-ioctls/src/cap.rs b/vendor/kvm-ioctls/src/cap.rs +index 99c5c16..617c2a9 100644 +--- a/vendor/kvm-ioctls/src/cap.rs ++++ b/vendor/kvm-ioctls/src/cap.rs +@@ -41,33 +41,29 @@ pub enum Cap { + Iommu = KVM_CAP_IOMMU, + DestroyMemoryRegionWorks = KVM_CAP_DESTROY_MEMORY_REGION_WORKS, + UserNmi = KVM_CAP_USER_NMI, ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "s390x"))] + SetGuestDebug = KVM_CAP_SET_GUEST_DEBUG, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + ReinjectControl = KVM_CAP_REINJECT_CONTROL, + IrqRouting = KVM_CAP_IRQ_ROUTING, + IrqInjectStatus = KVM_CAP_IRQ_INJECT_STATUS, + AssignDevIrq = KVM_CAP_ASSIGN_DEV_IRQ, + JoinMemoryRegionsWorks = KVM_CAP_JOIN_MEMORY_REGIONS_WORKS, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + Mce = KVM_CAP_MCE, + Irqfd = KVM_CAP_IRQFD, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + Pit2 = KVM_CAP_PIT2, + SetBootCpuId = KVM_CAP_SET_BOOT_CPU_ID, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + PitState2 = KVM_CAP_PIT_STATE2, + Ioeventfd = KVM_CAP_IOEVENTFD, + SetIdentityMapAddr = KVM_CAP_SET_IDENTITY_MAP_ADDR, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + XenHvm = KVM_CAP_XEN_HVM, + AdjustClock = KVM_CAP_ADJUST_CLOCK, + InternalErrorData = KVM_CAP_INTERNAL_ERROR_DATA, +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + VcpuEvents = KVM_CAP_VCPU_EVENTS, + S390Psw = KVM_CAP_S390_PSW, + PpcSegstate = KVM_CAP_PPC_SEGSTATE, +@@ -77,15 +73,15 @@ pub enum Cap { + PciSegment = KVM_CAP_PCI_SEGMENT, + PpcPairedSingles = KVM_CAP_PPC_PAIRED_SINGLES, + IntrShadow = KVM_CAP_INTR_SHADOW, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + Debugregs = KVM_CAP_DEBUGREGS, + X86RobustSinglestep = KVM_CAP_X86_ROBUST_SINGLESTEP, + PpcOsi = KVM_CAP_PPC_OSI, + PpcUnsetIrq = KVM_CAP_PPC_UNSET_IRQ, + EnableCap = KVM_CAP_ENABLE_CAP, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + Xsave = KVM_CAP_XSAVE, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + Xcrs = KVM_CAP_XCRS, + PpcGetPvinfo = KVM_CAP_PPC_GET_PVINFO, + PpcIrqLevel = KVM_CAP_PPC_IRQ_LEVEL, +@@ -138,7 +134,9 @@ pub enum Cap { + PpcEnableHcall = KVM_CAP_PPC_ENABLE_HCALL, + CheckExtensionVm = KVM_CAP_CHECK_EXTENSION_VM, + S390UserSigp = KVM_CAP_S390_USER_SIGP, +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] ++ X86Smm = KVM_CAP_X86_SMM, ++ #[cfg(target_arch = "x86_64")] + SplitIrqchip = KVM_CAP_SPLIT_IRQCHIP, + ArmPmuV3 = KVM_CAP_ARM_PMU_V3, + ImmediateExit = KVM_CAP_IMMEDIATE_EXIT, +@@ -149,10 +147,17 @@ pub enum Cap { + DebugHwBps = KVM_CAP_GUEST_DEBUG_HW_BPS, + DebugHwWps = KVM_CAP_GUEST_DEBUG_HW_WPS, + GetMsrFeatures = KVM_CAP_GET_MSR_FEATURES, ++ CoalescedPio = KVM_CAP_COALESCED_PIO, + #[cfg(target_arch = "aarch64")] + ArmSve = KVM_CAP_ARM_SVE, +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + ArmPtrAuthAddress = KVM_CAP_ARM_PTRAUTH_ADDRESS, +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + ArmPtrAuthGeneric = KVM_CAP_ARM_PTRAUTH_GENERIC, ++ #[cfg(target_arch = "x86_64")] ++ X86UserSpaceMsr = KVM_CAP_X86_USER_SPACE_MSR, ++ #[cfg(target_arch = "x86_64")] ++ ExitHypercall = KVM_CAP_EXIT_HYPERCALL, ++ #[cfg(target_arch = "x86_64")] ++ MemoryFaultInfo = KVM_CAP_MEMORY_FAULT_INFO, + } +diff --git a/vendor/kvm-ioctls/src/ioctls/device.rs b/vendor/kvm-ioctls/src/ioctls/device.rs +index 6669570..fc13104 100644 +--- a/vendor/kvm-ioctls/src/ioctls/device.rs ++++ b/vendor/kvm-ioctls/src/ioctls/device.rs +@@ -1,3 +1,5 @@ ++// Copyright © 2024 Institute of Software, CAS. All rights reserved. ++// + // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + // SPDX-License-Identifier: Apache-2.0 OR MIT + +@@ -41,36 +43,46 @@ impl DeviceFd { + /// + /// # Example + /// ++ /// Configuring a VFIO device using `set_device_attr`. Note that VFIO ++ /// devices are not yet available on RISC-V The patch for QEMU: ++ /// https://lore.kernel.org/all/20240903201633.93182-1-dbarboza@ventanamicro.com/ ++ /// and patch for linux kernel ++ /// https://github.com/ventanamicro/linux/tree/dev-upstream are both not ++ /// upstreamed. Disabling VFIO device test for RISC-V at the time being. ++ /// + /// ```rust + /// # extern crate kvm_ioctls; + /// # extern crate kvm_bindings; + /// # use kvm_ioctls::Kvm; +- /// # use kvm_bindings::{ +- /// kvm_device_type_KVM_DEV_TYPE_VFIO, +- /// KVM_DEV_VFIO_GROUP, KVM_DEV_VFIO_GROUP_ADD, KVM_CREATE_DEVICE_TEST +- /// }; + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// +- /// let mut device = kvm_bindings::kvm_create_device { +- /// type_: kvm_device_type_KVM_DEV_TYPE_VFIO, +- /// fd: 0, +- /// flags: KVM_CREATE_DEVICE_TEST, +- /// }; ++ /// #[cfg(not(target_arch = "riscv64"))] ++ /// { ++ /// # use kvm_bindings::{ ++ /// # kvm_device_type_KVM_DEV_TYPE_VFIO, ++ /// # KVM_DEV_VFIO_GROUP, KVM_DEV_VFIO_GROUP_ADD, KVM_CREATE_DEVICE_TEST ++ /// # }; ++ /// let mut device = kvm_bindings::kvm_create_device { ++ /// type_: kvm_device_type_KVM_DEV_TYPE_VFIO, ++ /// fd: 0, ++ /// flags: KVM_CREATE_DEVICE_TEST, ++ /// }; + /// +- /// let device_fd = vm +- /// .create_device(&mut device) +- /// .expect("Cannot create KVM device"); ++ /// let device_fd = vm ++ /// .create_device(&mut device) ++ /// .expect("Cannot create KVM device"); + /// +- /// let dist_attr = kvm_bindings::kvm_device_attr { +- /// group: KVM_DEV_VFIO_GROUP, +- /// attr: u64::from(KVM_DEV_VFIO_GROUP_ADD), +- /// addr: 0x0, +- /// flags: 0, +- /// }; ++ /// let dist_attr = kvm_bindings::kvm_device_attr { ++ /// group: KVM_DEV_VFIO_GROUP, ++ /// attr: u64::from(KVM_DEV_VFIO_GROUP_ADD), ++ /// addr: 0x0, ++ /// flags: 0, ++ /// }; + /// +- /// if (device_fd.has_device_attr(&dist_attr).is_ok()) { +- /// device_fd.set_device_attr(&dist_attr).unwrap(); ++ /// if (device_fd.has_device_attr(&dist_attr).is_ok()) { ++ /// device_fd.set_device_attr(&dist_attr).unwrap(); ++ /// } + /// } + /// ``` + pub fn set_device_attr(&self, device_attr: &kvm_device_attr) -> Result<()> { +@@ -102,6 +114,11 @@ impl DeviceFd { + /// * `device_attr` - The `addr` field of the `device_attr` structure will point to + /// the device attribute data. + /// ++ /// # Safety ++ /// ++ /// The caller is responsible for the validity of the `device_attr` argument, ++ /// including that it is safe to write to the `addr` member. ++ /// + /// # Examples + /// ```rust + /// # extern crate kvm_ioctls; +@@ -138,14 +155,16 @@ impl DeviceFd { + /// let mut data: u32 = 0; + /// let mut gic_attr = kvm_bindings::kvm_device_attr::default(); + /// gic_attr.group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS; +- /// gic_attr.addr = &mut data as *const u32 as u64; ++ /// gic_attr.addr = &mut data as *mut u32 as u64; + /// +- /// device_fd.get_device_attr(&mut gic_attr).unwrap(); ++ /// // SAFETY: gic_attr.addr is safe to write to. ++ /// unsafe { device_fd.get_device_attr(&mut gic_attr) }.unwrap(); + /// } + /// ``` +- pub fn get_device_attr(&self, device_attr: &mut kvm_device_attr) -> Result<()> { +- // SAFETY: We are calling this function with a Device fd, and we trust the kernel. +- let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_DEVICE_ATTR(), device_attr) }; ++ pub unsafe fn get_device_attr(&self, device_attr: &mut kvm_device_attr) -> Result<()> { ++ // SAFETY: Caller has ensured device_attr.addr is safe to write to. ++ // We are calling this function with a Device fd, we trust the kernel. ++ let ret = ioctl_with_mut_ref(self, KVM_GET_DEVICE_ATTR(), device_attr); + if ret != 0 { + return Err(errno::Error::last()); + } +@@ -183,21 +202,18 @@ mod tests { + #![allow(clippy::undocumented_unsafe_blocks)] + use super::*; + use crate::ioctls::system::Kvm; +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + use kvm_bindings::{ + kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3, kvm_device_type_KVM_DEV_TYPE_VFIO, + KVM_DEV_VFIO_GROUP, KVM_DEV_VFIO_GROUP_ADD, + }; + #[cfg(target_arch = "aarch64")] +- use kvm_bindings::{ +- KVM_DEV_ARM_VGIC_CTRL_INIT, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_VFIO_GROUP, +- KVM_DEV_VFIO_GROUP_ADD, +- }; ++ use kvm_bindings::{KVM_DEV_VFIO_GROUP, KVM_DEV_VFIO_GROUP_ADD}; + + use kvm_bindings::KVM_CREATE_DEVICE_TEST; + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_create_device() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +@@ -208,7 +224,7 @@ mod tests { + flags: KVM_CREATE_DEVICE_TEST, + }; + // This fails on x86_64 because there is no VGIC there. +- assert!(vm.create_device(&mut gic_device).is_err()); ++ vm.create_device(&mut gic_device).unwrap_err(); + + gic_device.type_ = kvm_device_type_KVM_DEV_TYPE_VFIO; + +@@ -233,16 +249,16 @@ mod tests { + + // We are just creating a test device. Creating a real device would make the CI dependent + // on host configuration (like having /dev/vfio). We expect this to fail. +- assert!(device_fd.has_device_attr(&dist_attr).is_err()); +- assert!(device_fd.get_device_attr(&mut dist_attr_mut).is_err()); +- assert!(device_fd.set_device_attr(&dist_attr).is_err()); ++ device_fd.has_device_attr(&dist_attr).unwrap_err(); ++ unsafe { device_fd.get_device_attr(&mut dist_attr_mut) }.unwrap_err(); ++ device_fd.set_device_attr(&dist_attr).unwrap_err(); + assert_eq!(errno::Error::last().errno(), 25); + } + + #[test] + #[cfg(target_arch = "aarch64")] + fn test_create_device() { +- use crate::ioctls::vm::{create_gic_device, set_supported_nr_irqs}; ++ use crate::ioctls::vm::{create_gic_device, request_gic_init, set_supported_nr_irqs}; + use kvm_bindings::{ + kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, + }; +@@ -258,7 +274,7 @@ mod tests { + }; + // This fails on aarch64 as it does not use MPIC (MultiProcessor Interrupt Controller), + // it uses the VGIC. +- assert!(vm.create_device(&mut gic_device).is_err()); ++ vm.create_device(&mut gic_device).unwrap_err(); + + let device_fd = create_gic_device(&vm, 0); + +@@ -279,21 +295,13 @@ mod tests { + addr: 0x0, + flags: 0, + }; +- assert!(device_fd.has_device_attr(&dist_attr).is_err()); ++ device_fd.has_device_attr(&dist_attr).unwrap_err(); + + // Set maximum supported number of IRQs of the vGIC device to 128. + set_supported_nr_irqs(&device_fd, 128); + +- // Following attribute works with VGIC, they should be accepted. +- let dist_attr = kvm_bindings::kvm_device_attr { +- group: KVM_DEV_ARM_VGIC_GRP_CTRL, +- attr: u64::from(KVM_DEV_ARM_VGIC_CTRL_INIT), +- addr: 0x0, +- flags: 0, +- }; +- +- assert!(device_fd.has_device_attr(&dist_attr).is_ok()); +- assert!(device_fd.set_device_attr(&dist_attr).is_ok()); ++ // Initialize valid vGIC device. ++ request_gic_init(&device_fd); + + // Test `get_device_attr`. Here we try to extract the maximum supported number of IRQs. + // This value should be saved in the address provided to the ioctl. +@@ -307,13 +315,98 @@ mod tests { + + // Without properly providing the address to where the + // value will be stored, the ioctl fails with EFAULT. +- let res = device_fd.get_device_attr(&mut gic_attr); ++ let res = unsafe { device_fd.get_device_attr(&mut gic_attr) }; + assert_eq!(res, Err(Error::new(libc::EFAULT))); + +- gic_attr.addr = &mut data as *const u32 as u64; +- assert!(device_fd.get_device_attr(&mut gic_attr).is_ok()); ++ gic_attr.addr = &mut data as *mut u32 as u64; ++ unsafe { device_fd.get_device_attr(&mut gic_attr) }.unwrap(); + // The maximum supported number of IRQs should be 128, same as the value + // when we initialize the GIC. + assert_eq!(data, 128); + } ++ ++ #[test] ++ #[cfg(target_arch = "riscv64")] ++ fn test_create_device() { ++ use crate::ioctls::vm::{create_aia_device, request_aia_init, set_supported_nr_irqs}; ++ use kvm_bindings::{ ++ kvm_device_attr, kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20, ++ KVM_DEV_RISCV_AIA_ADDR_APLIC, KVM_DEV_RISCV_AIA_CONFIG_SRCS, ++ KVM_DEV_RISCV_AIA_GRP_ADDR, KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ }; ++ use vmm_sys_util::errno::Error; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ ++ let mut aia_device = kvm_bindings::kvm_create_device { ++ type_: kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20, ++ fd: 0, ++ flags: KVM_CREATE_DEVICE_TEST, ++ }; ++ // This fails on riscv64 as it does not use MPIC (MultiProcessor Interrupt Controller), ++ // it uses the vAIA. ++ vm.create_device(&mut aia_device).unwrap_err(); ++ ++ let device_fd = create_aia_device(&vm, 0); ++ ++ // AIA on riscv64 requires at least one online vCPU prior to setting ++ // device attributes. Otherwise it would fail when trying to set address ++ // of IMSIC. ++ vm.create_vcpu(0).unwrap(); ++ ++ // Following lines to re-construct device_fd are used to test ++ // DeviceFd::from_raw_fd() and DeviceFd::as_raw_fd(). ++ let raw_fd = unsafe { libc::dup(device_fd.as_raw_fd()) }; ++ assert!(raw_fd >= 0); ++ let device_fd = unsafe { DeviceFd::from_raw_fd(raw_fd) }; ++ ++ // Set maximum supported number of IRQs of the vAIA device to 128. ++ set_supported_nr_irqs(&device_fd, 128); ++ ++ // Before request vAIA device to initialize, APLIC and IMSIC must be set ++ let aplic_addr: u64 = 0x4000; ++ device_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: u64::from(KVM_DEV_RISCV_AIA_ADDR_APLIC), ++ addr: &aplic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ let imsic_addr: u64 = 0x8000; ++ device_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: 1u64, ++ addr: &imsic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ ++ // Initialize valid vAIA device. ++ request_aia_init(&device_fd); ++ ++ // Test `get_device_attr`. Here we try to extract the maximum supported number of IRQs. ++ // This value should be saved in the address provided to the ioctl. ++ let mut data: u32 = 0; ++ ++ let mut aia_attr = kvm_bindings::kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ attr: u64::from(KVM_DEV_RISCV_AIA_CONFIG_SRCS), ++ addr: data as u64, ++ ..Default::default() ++ }; ++ ++ // Without properly providing the address to where the ++ // value will be stored, the ioctl fails with EFAULT. ++ let res = unsafe { device_fd.get_device_attr(&mut aia_attr) }; ++ assert_eq!(res, Err(Error::new(libc::EFAULT))); ++ ++ aia_attr.addr = &mut data as *mut u32 as u64; ++ unsafe { device_fd.get_device_attr(&mut aia_attr) }.unwrap(); ++ // The maximum supported number of IRQs should be 128, same as the value ++ // when we initialize the AIA. ++ assert_eq!(data, 128); ++ } + } +diff --git a/vendor/kvm-ioctls/src/ioctls/mod.rs b/vendor/kvm-ioctls/src/ioctls/mod.rs +index 9079acc..a5f96c1 100644 +--- a/vendor/kvm-ioctls/src/ioctls/mod.rs ++++ b/vendor/kvm-ioctls/src/ioctls/mod.rs +@@ -5,10 +5,13 @@ + // Use of this source code is governed by a BSD-style license that can be + // found in the THIRD-PARTY file. + ++use std::mem::size_of; + use std::os::unix::io::AsRawFd; +-use std::ptr::null_mut; ++use std::ptr::{null_mut, NonNull}; + +-use kvm_bindings::kvm_run; ++use kvm_bindings::{ ++ kvm_coalesced_mmio, kvm_coalesced_mmio_ring, kvm_run, KVM_COALESCED_MMIO_PAGE_OFFSET, ++}; + use vmm_sys_util::errno; + + /// Wrappers over KVM device ioctls. +@@ -26,13 +29,108 @@ pub mod vm; + /// is otherwise a direct mapping to Result. + pub type Result = std::result::Result; + ++/// A wrapper around the coalesced MMIO ring page. ++#[derive(Debug)] ++pub(crate) struct KvmCoalescedIoRing { ++ addr: NonNull, ++ page_size: usize, ++} ++ ++impl KvmCoalescedIoRing { ++ /// Maps the coalesced MMIO ring from the vCPU file descriptor. ++ pub(crate) fn mmap_from_fd(fd: &F) -> Result { ++ // SAFETY: We trust the sysconf libc function and we're calling it ++ // with a correct parameter. ++ let page_size = match unsafe { libc::sysconf(libc::_SC_PAGESIZE) } { ++ -1 => return Err(errno::Error::last()), ++ ps => ps as usize, ++ }; ++ ++ let offset = KVM_COALESCED_MMIO_PAGE_OFFSET * page_size as u32; ++ // SAFETY: KVM guarantees that there is a page at offset ++ // KVM_COALESCED_MMIO_PAGE_OFFSET * PAGE_SIZE if the appropriate ++ // capability is available. If it is not, the call will simply ++ // fail. ++ let addr = unsafe { ++ libc::mmap( ++ null_mut(), ++ page_size, ++ libc::PROT_READ | libc::PROT_WRITE, ++ libc::MAP_SHARED, ++ fd.as_raw_fd(), ++ offset.into(), ++ ) ++ }; ++ let addr = NonNull::new(addr) ++ .filter(|addr| addr.as_ptr() != libc::MAP_FAILED) ++ .ok_or_else(errno::Error::last)?; ++ ++ Ok(Self { ++ addr: addr.cast(), ++ page_size, ++ }) ++ } ++ ++ /// Compute the size of the MMIO ring. ++ /// Taken from [include/uapi/linux/kvm.h](https://elixir.bootlin.com/linux/v6.6/source/include/uapi/linux/kvm.h#L562) ++ const fn ring_max(&self) -> usize { ++ (self.page_size - size_of::()) / size_of::() ++ } ++ ++ /// Gets a mutable reference to the ring ++ fn ring_mut(&mut self) -> &mut kvm_coalesced_mmio_ring { ++ // SAFETY: We have a `&mut self` and the pointer is private, so this ++ // access is exclusive. ++ unsafe { self.addr.as_mut() } ++ } ++ ++ /// Reads a single entry from the MMIO ring. ++ /// ++ /// # Returns ++ /// ++ /// An entry from the MMIO ring buffer, or [`None`] if the ring is empty. ++ pub(crate) fn read_entry(&mut self) -> Option { ++ let ring_max = self.ring_max(); ++ ++ let ring = self.ring_mut(); ++ if ring.first == ring.last { ++ return None; ++ } ++ ++ let entries = ring.coalesced_mmio.as_ptr(); ++ // SAFETY: `ring.first` is an `u32` coming from mapped memory filled ++ // by the kernel, so we trust it. `entries` is a pointer coming from ++ // mmap(), so pointer arithmetic cannot overflow. We have a `&mut self`, ++ // so nobody else has access to the contents of the pointer. ++ let elem = unsafe { entries.add(ring.first as usize).read() }; ++ ring.first = (ring.first + 1) % ring_max as u32; ++ ++ Some(elem) ++ } ++} ++ ++impl Drop for KvmCoalescedIoRing { ++ fn drop(&mut self) { ++ // SAFETY: This is safe because we mmap the page ourselves, and nobody ++ // else is holding a reference to it. ++ unsafe { ++ libc::munmap(self.addr.as_ptr().cast(), self.page_size); ++ } ++ } ++} ++ ++// SAFETY: See safety comments about [`KvmRunWrapper`]. ++unsafe impl Send for KvmCoalescedIoRing {} ++// SAFETY: See safety comments about [`KvmRunWrapper`]. ++unsafe impl Sync for KvmCoalescedIoRing {} ++ + /// Safe wrapper over the `kvm_run` struct. + /// + /// The wrapper is needed for sending the pointer to `kvm_run` between + /// threads as raw pointers do not implement `Send` and `Sync`. + #[derive(Debug)] + pub struct KvmRunWrapper { +- kvm_run_ptr: *mut u8, ++ kvm_run_ptr: NonNull, + // This field is need so we can `munmap` the memory mapped to hold `kvm_run`. + mmap_size: usize, + } +@@ -51,7 +149,7 @@ impl KvmRunWrapper { + /// # Arguments + /// * `fd` - File descriptor to mmap from. + /// * `size` - Size of memory region in bytes. +- pub fn mmap_from_fd(fd: &dyn AsRawFd, size: usize) -> Result { ++ pub fn mmap_from_fd(fd: &F, size: usize) -> Result { + // SAFETY: This is safe because we are creating a mapping in a place not already used by + // any other area in this process. + let addr = unsafe { +@@ -64,25 +162,30 @@ impl KvmRunWrapper { + 0, + ) + }; +- if addr == libc::MAP_FAILED { +- return Err(errno::Error::last()); +- } ++ let addr = NonNull::new(addr) ++ .filter(|addr| addr.as_ptr() != libc::MAP_FAILED) ++ .ok_or_else(errno::Error::last)?; + + Ok(KvmRunWrapper { +- kvm_run_ptr: addr as *mut u8, ++ kvm_run_ptr: addr.cast(), + mmap_size: size, + }) + } + + /// Returns a mutable reference to `kvm_run`. +- #[allow(clippy::mut_from_ref)] +- pub fn as_mut_ref(&self) -> &mut kvm_run { +- #[allow(clippy::cast_ptr_alignment)] ++ pub fn as_mut_ref(&mut self) -> &mut kvm_run { ++ // SAFETY: Safe because we know we mapped enough memory to hold the kvm_run struct because ++ // the kernel told us how large it was. Nobody else has access to this pointer so it cannot ++ // be aliased. ++ unsafe { self.kvm_run_ptr.as_mut() } ++ } ++} ++ ++impl AsRef for KvmRunWrapper { ++ fn as_ref(&self) -> &kvm_run { + // SAFETY: Safe because we know we mapped enough memory to hold the kvm_run struct because + // the kernel told us how large it was. +- unsafe { +- &mut *(self.kvm_run_ptr as *mut kvm_run) +- } ++ unsafe { self.kvm_run_ptr.as_ref() } + } + } + +@@ -91,7 +194,7 @@ impl Drop for KvmRunWrapper { + // SAFETY: This is safe because we mmap the area at kvm_run_ptr ourselves, + // and nobody else is holding a reference to it. + unsafe { +- libc::munmap(self.kvm_run_ptr as *mut libc::c_void, self.mmap_size); ++ libc::munmap(self.kvm_run_ptr.as_ptr().cast(), self.mmap_size); + } + } + } +diff --git a/vendor/kvm-ioctls/src/ioctls/system.rs b/vendor/kvm-ioctls/src/ioctls/system.rs +index 69f48d7..83d41fc 100644 +--- a/vendor/kvm-ioctls/src/ioctls/system.rs ++++ b/vendor/kvm-ioctls/src/ioctls/system.rs +@@ -14,12 +14,12 @@ use crate::cap::Cap; + use crate::ioctls::vm::{new_vmfd, VmFd}; + use crate::ioctls::Result; + use crate::kvm_ioctls::*; +-#[cfg(any(target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + use kvm_bindings::KVM_VM_TYPE_ARM_IPA_SIZE_MASK; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + use kvm_bindings::{CpuId, MsrList, Msrs, KVM_MAX_CPUID_ENTRIES, KVM_MAX_MSR_ENTRIES}; + use vmm_sys_util::errno; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + use vmm_sys_util::ioctl::ioctl_with_mut_ptr; + use vmm_sys_util::ioctl::{ioctl, ioctl_with_val}; + +@@ -96,7 +96,7 @@ impl Kvm { + /// ``` + pub fn open_with_cloexec(close_on_exec: bool) -> Result { + // SAFETY: Safe because we give a constant nul-terminated string. +- let kvm_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"/dev/kvm\0") }; ++ let kvm_path = c"/dev/kvm"; + Self::open_with_cloexec_at(kvm_path, close_on_exec) + } + +@@ -193,7 +193,7 @@ impl Kvm { + /// use kvm_ioctls::Cap; + /// + /// let kvm = Kvm::new().unwrap(); +- /// assert!(kvm.check_extension_raw(Cap::MaxVcpuId as c_ulong) > 0); ++ /// assert!(kvm.check_extension_raw(Cap::MaxVcpus as c_ulong) > 0); + /// ``` + pub fn check_extension_raw(&self, c: c_ulong) -> i32 { + // SAFETY: Safe because we know that our file is a KVM fd. +@@ -217,7 +217,7 @@ impl Kvm { + /// use kvm_ioctls::Cap; + /// + /// let kvm = Kvm::new().unwrap(); +- /// assert!(kvm.check_extension_int(Cap::MaxVcpuId) > 0); ++ /// assert!(kvm.check_extension_int(Cap::MaxVcpus) > 0); + /// ``` + pub fn check_extension_int(&self, c: Cap) -> i32 { + self.check_extension_raw(c as c_ulong) +@@ -352,7 +352,7 @@ impl Kvm { + } + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn get_cpuid(&self, kind: u64, num_entries: usize) -> Result { + if num_entries > KVM_MAX_CPUID_ENTRIES { + // Returns the same error the underlying `ioctl` would have sent. +@@ -395,7 +395,7 @@ impl Kvm { + /// let cpuid_entries = cpuid.as_mut_slice(); + /// assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_emulated_cpuid(&self, num_entries: usize) -> Result { + self.get_cpuid(KVM_GET_EMULATED_CPUID(), num_entries) + } +@@ -424,7 +424,7 @@ impl Kvm { + /// let cpuid_entries = cpuid.as_mut_slice(); + /// assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_supported_cpuid(&self, num_entries: usize) -> Result { + self.get_cpuid(KVM_GET_SUPPORTED_CPUID(), num_entries) + } +@@ -441,7 +441,7 @@ impl Kvm { + /// let kvm = Kvm::new().unwrap(); + /// let msr_index_list = kvm.get_msr_index_list().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_msr_index_list(&self) -> Result { + let mut msr_list = + MsrList::new(KVM_MAX_MSR_ENTRIES).map_err(|_| errno::Error::new(libc::ENOMEM))?; +@@ -477,7 +477,7 @@ impl Kvm { + /// let kvm = Kvm::new().unwrap(); + /// let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_msr_feature_index_list(&self) -> Result { + let mut msr_list = + MsrList::new(KVM_MAX_MSR_ENTRIES).map_err(|_| errno::Error::new(libc::ENOMEM))?; +@@ -531,7 +531,7 @@ impl Kvm { + /// .unwrap(); + /// let ret = kvm.get_msrs(&mut msrs).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_msrs(&self, msrs: &mut Msrs) -> Result { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_msrs struct. + let ret = unsafe { ioctl_with_mut_ptr(self, KVM_GET_MSRS(), msrs.as_mut_fam_struct_ptr()) }; +@@ -576,7 +576,7 @@ impl Kvm { + /// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`. + /// assert!(vm.run_size() == kvm.get_vcpu_mmap_size().unwrap()); + /// ``` +- #[cfg(any(target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + pub fn create_vm(&self) -> Result { + let mut ipa_size = 0; // Create using default VM type + if self.check_extension(Cap::ArmVmIPASize) { +@@ -615,7 +615,7 @@ impl Kvm { + /// assert!(vm.run_size() == kvm.get_vcpu_mmap_size().unwrap()); + /// } + /// ``` +- #[cfg(any(target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + pub fn create_vm_with_ipa_size(&self, ipa_size: u32) -> Result { + self.create_vm_with_type((ipa_size & KVM_VM_TYPE_ARM_IPA_SIZE_MASK).into()) + } +@@ -729,10 +729,9 @@ impl FromRawFd for Kvm { + mod tests { + #![allow(clippy::undocumented_unsafe_blocks)] + use super::*; +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +- use kvm_bindings::KVM_MAX_CPUID_ENTRIES; + use libc::{fcntl, FD_CLOEXEC, F_GETFD}; +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ use std::os::fd::IntoRawFd; ++ #[cfg(target_arch = "x86_64")] + use vmm_sys_util::fam::FamStruct; + + #[test] +@@ -742,7 +741,7 @@ mod tests { + + #[test] + fn test_kvm_new_with_path() { +- let kvm_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"/dev/kvm\0") }; ++ let kvm_path = c"/dev/kvm"; + Kvm::new_with_path(kvm_path).unwrap(); + } + +@@ -848,7 +847,7 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_create_vm_with_ipa_size() { + let kvm = Kvm::new().unwrap(); + if kvm.check_extension(Cap::ArmVmIPASize) { +@@ -858,18 +857,17 @@ mod tests { + kvm.create_vm_with_ipa_size(host_ipa_limit as u32).unwrap(); + // Test invalid input values + // Case 1: IPA size is smaller than 32. +- assert!(kvm.create_vm_with_ipa_size(31).is_err()); ++ kvm.create_vm_with_ipa_size(31).unwrap_err(); + // Case 2: IPA size is bigger than Host_IPA_Limit. +- assert!(kvm +- .create_vm_with_ipa_size((host_ipa_limit + 1) as u32) +- .is_err()); ++ kvm.create_vm_with_ipa_size((host_ipa_limit + 1) as u32) ++ .unwrap_err(); + } else { + // Unsupported, we can't provide an IPA size. Only KVM type=0 works. +- assert!(kvm.create_vm_with_type(0).is_err()); ++ kvm.create_vm_with_type(0).unwrap_err(); + } + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn test_get_supported_cpuid() { + let kvm = Kvm::new().unwrap(); +@@ -880,11 +878,11 @@ mod tests { + + // Test case for more than MAX entries + let cpuid_err = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES + 1_usize); +- assert!(cpuid_err.is_err()); ++ cpuid_err.unwrap_err(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_get_emulated_cpuid() { + let kvm = Kvm::new().unwrap(); + let mut cpuid = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap(); +@@ -894,10 +892,10 @@ mod tests { + + // Test case for more than MAX entries + let cpuid_err = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES + 1_usize); +- assert!(cpuid_err.is_err()); ++ cpuid_err.unwrap_err(); + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn test_cpuid_clone() { + let kvm = Kvm::new().unwrap(); +@@ -912,7 +910,7 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn get_msr_index_list() { + let kvm = Kvm::new().unwrap(); + let msr_list = kvm.get_msr_index_list().unwrap(); +@@ -920,7 +918,7 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn get_msr_feature_index_list() { + let kvm = Kvm::new().unwrap(); + let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap(); +@@ -928,7 +926,7 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn get_msrs() { + use kvm_bindings::kvm_msr_entry; + +@@ -963,7 +961,7 @@ mod tests { + ); + assert_eq!(faulty_kvm.get_nr_vcpus(), 4); + assert_eq!(faulty_kvm.get_nr_memslots(), 32); +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + { + assert_eq!( + faulty_kvm.get_emulated_cpuid(4).err().unwrap().errno(), +@@ -980,5 +978,9 @@ mod tests { + ); + } + assert_eq!(faulty_kvm.create_vm().err().unwrap().errno(), badf_errno); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ let _ = faulty_kvm.kvm.into_raw_fd(); + } + } +diff --git a/vendor/kvm-ioctls/src/ioctls/vcpu.rs b/vendor/kvm-ioctls/src/ioctls/vcpu.rs +index 0da5f12..8b2caa9 100644 +--- a/vendor/kvm-ioctls/src/ioctls/vcpu.rs ++++ b/vendor/kvm-ioctls/src/ioctls/vcpu.rs +@@ -1,3 +1,5 @@ ++// Copyright © 2024 Institute of Software, CAS. All rights reserved. ++// + // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + // SPDX-License-Identifier: Apache-2.0 OR MIT + // +@@ -10,21 +12,81 @@ use libc::EINVAL; + use std::fs::File; + use std::os::unix::io::{AsRawFd, RawFd}; + +-use crate::ioctls::{KvmRunWrapper, Result}; ++use crate::ioctls::{KvmCoalescedIoRing, KvmRunWrapper, Result}; + use crate::kvm_ioctls::*; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +-use kvm_bindings::{CpuId, Msrs, KVM_MAX_CPUID_ENTRIES}; + use vmm_sys_util::errno; + use vmm_sys_util::ioctl::{ioctl, ioctl_with_mut_ref, ioctl_with_ref}; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + use vmm_sys_util::ioctl::{ioctl_with_mut_ptr, ioctl_with_ptr, ioctl_with_val}; + + /// Helper method to obtain the size of the register through its id +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +-fn reg_size(reg_id: u64) -> usize { ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] ++pub fn reg_size(reg_id: u64) -> usize { + 2_usize.pow(((reg_id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT) as u32) + } + ++/// Information about a [`VcpuExit`] triggered by an Hypercall (`KVM_EXIT_HYPERCALL`). ++#[derive(Debug)] ++pub struct HypercallExit<'a> { ++ /// The hypercall number. ++ pub nr: u64, ++ /// The arguments for the hypercall. ++ pub args: [u64; 6], ++ /// The return code to be indicated to the guest. ++ pub ret: &'a mut u64, ++ /// Whether the hypercall was executed in long mode. ++ pub longmode: u32, ++} ++ ++/// Information about a [`VcpuExit`] triggered by an MSR read (`KVM_EXIT_X86_RDMSR`). ++#[derive(Debug)] ++pub struct ReadMsrExit<'a> { ++ /// Must be set to 1 by the the user if the read access should fail. This ++ /// will inject a #GP fault into the guest when the VCPU is executed ++ /// again. ++ pub error: &'a mut u8, ++ /// The reason for this exit. ++ pub reason: MsrExitReason, ++ /// The MSR the guest wants to read. ++ pub index: u32, ++ /// The data to be supplied by the user as the MSR Contents to the guest. ++ pub data: &'a mut u64, ++} ++ ++/// Information about a [`VcpuExit`] triggered by an MSR write (`KVM_EXIT_X86_WRMSR`). ++#[derive(Debug)] ++pub struct WriteMsrExit<'a> { ++ /// Must be set to 1 by the the user if the write access should fail. This ++ /// will inject a #GP fault into the guest when the VCPU is executed ++ /// again. ++ pub error: &'a mut u8, ++ /// The reason for this exit. ++ pub reason: MsrExitReason, ++ /// The MSR the guest wants to write. ++ pub index: u32, ++ /// The data the guest wants to write into the MSR. ++ pub data: u64, ++} ++ ++bitflags::bitflags! { ++ /// The reason for a [`VcpuExit::X86Rdmsr`] or[`VcpuExit::X86Wrmsr`]. This ++ /// is also used when enabling ++ /// [`Cap::X86UserSpaceMsr`](crate::Cap::X86UserSpaceMsr) to specify which ++ /// reasons should be forwarded to the user via those exits. ++ #[derive(Clone, Copy, Debug, PartialEq, Eq)] ++ pub struct MsrExitReason: u32 { ++ /// Corresponds to [`KVM_MSR_EXIT_REASON_UNKNOWN`]. The exit was ++ /// triggered by an access to an MSR that is unknown to KVM. ++ const Unknown = KVM_MSR_EXIT_REASON_UNKNOWN; ++ /// Corresponds to [`KVM_MSR_EXIT_REASON_INVAL`]. The exit was ++ /// triggered by an access to an invalid MSR or to reserved bits. ++ const Inval = KVM_MSR_EXIT_REASON_INVAL; ++ /// Corresponds to [`KVM_MSR_EXIT_REASON_FILTER`]. The exit was ++ /// triggered by an access to a filtered MSR. ++ const Filter = KVM_MSR_EXIT_REASON_FILTER; ++ } ++} ++ + /// Reasons for vCPU exits. + /// + /// The exit reasons are mapped to the `KVM_EXIT_*` defines in the +@@ -50,7 +112,7 @@ pub enum VcpuExit<'a> { + /// Corresponds to KVM_EXIT_EXCEPTION. + Exception, + /// Corresponds to KVM_EXIT_HYPERCALL. +- Hypercall, ++ Hypercall(HypercallExit<'a>), + /// Corresponds to KVM_EXIT_DEBUG. + /// + /// Provides architecture specific information for the debug event. +@@ -95,13 +157,26 @@ pub enum VcpuExit<'a> { + /// Corresponds to KVM_EXIT_EPR. + Epr, + /// Corresponds to KVM_EXIT_SYSTEM_EVENT. +- SystemEvent(u32 /* type */, u64 /* flags */), ++ SystemEvent(u32 /* type */, &'a [u64] /* data */), + /// Corresponds to KVM_EXIT_S390_STSI. + S390Stsi, + /// Corresponds to KVM_EXIT_IOAPIC_EOI. + IoapicEoi(u8 /* vector */), + /// Corresponds to KVM_EXIT_HYPERV. + Hyperv, ++ /// Corresponds to KVM_EXIT_X86_RDMSR. ++ X86Rdmsr(ReadMsrExit<'a>), ++ /// Corresponds to KVM_EXIT_X86_WRMSR. ++ X86Wrmsr(WriteMsrExit<'a>), ++ /// Corresponds to KVM_EXIT_MEMORY_FAULT. ++ MemoryFault { ++ /// flags ++ flags: u64, ++ /// gpa ++ gpa: u64, ++ /// size ++ size: u64, ++ }, + /// Corresponds to an exit reason that is unknown from the current version + /// of the kvm-ioctls crate. Let the consumer decide about what to do with + /// it. +@@ -113,12 +188,14 @@ pub enum VcpuExit<'a> { + pub struct VcpuFd { + vcpu: File, + kvm_run_ptr: KvmRunWrapper, ++ /// A pointer to the coalesced MMIO page ++ coalesced_mmio_ring: Option, + } + + /// KVM Sync Registers used to tell KVM which registers to sync + #[repr(u32)] + #[derive(Debug, Copy, Clone)] +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + pub enum SyncReg { + /// General purpose registers, + Register = KVM_SYNC_X86_REGS, +@@ -145,10 +222,9 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] + /// let regs = vcpu.get_regs().unwrap(); + /// ``` +- #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + pub fn get_regs(&self) -> Result { + let mut regs = kvm_regs::default(); + // SAFETY: Safe because we know that our file is a vCPU fd, we know the kernel will only +@@ -258,16 +334,13 @@ impl VcpuFd { + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// +- /// #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] +- /// { +- /// // Get the current vCPU registers. +- /// let mut regs = vcpu.get_regs().unwrap(); +- /// // Set a new value for the Instruction Pointer. +- /// regs.rip = 0x100; +- /// vcpu.set_regs(®s).unwrap(); +- /// } ++ /// // Get the current vCPU registers. ++ /// let mut regs = vcpu.get_regs().unwrap(); ++ /// // Set a new value for the Instruction Pointer. ++ /// regs.rip = 0x100; ++ /// vcpu.set_regs(®s).unwrap(); + /// ``` +- #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + pub fn set_regs(&self, regs: &kvm_regs) -> Result<()> { + // SAFETY: Safe because we know that our file is a vCPU fd, we know the kernel will only + // read the correct amount of memory from our pointer, and we verify the return result. +@@ -292,10 +365,9 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] + /// let sregs = vcpu.get_sregs().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_sregs(&self) -> Result { + let mut regs = kvm_sregs::default(); + // SAFETY: Safe because we know that our file is a vCPU fd, we know the kernel will only +@@ -322,16 +394,14 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] +- /// { +- /// let mut sregs = vcpu.get_sregs().unwrap(); +- /// // Update the code segment (cs). +- /// sregs.cs.base = 0; +- /// sregs.cs.selector = 0; +- /// vcpu.set_sregs(&sregs).unwrap(); +- /// } ++ /// ++ /// let mut sregs = vcpu.get_sregs().unwrap(); ++ /// // Update the code segment (cs). ++ /// sregs.cs.base = 0; ++ /// sregs.cs.selector = 0; ++ /// vcpu.set_sregs(&sregs).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_sregs(&self, sregs: &kvm_sregs) -> Result<()> { + // SAFETY: Safe because we know that our file is a vCPU fd, we know the kernel will only + // read the correct amount of memory from our pointer, and we verify the return result. +@@ -356,10 +426,10 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// let fpu = vcpu.get_fpu().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_fpu(&self) -> Result { + let mut fpu = kvm_fpu::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_fpu struct. +@@ -387,7 +457,7 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// let KVM_FPU_CWD: u16 = 0x37f; + /// let fpu = kvm_fpu { +@@ -397,7 +467,7 @@ impl VcpuFd { + /// vcpu.set_fpu(&fpu).unwrap(); + /// } + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_fpu(&self, fpu: &kvm_fpu) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_fpu struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_FPU(), fpu) }; +@@ -442,7 +512,7 @@ impl VcpuFd { + /// vcpu.set_cpuid2(&kvm_cpuid).unwrap(); + /// ``` + /// +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_cpuid2(&self, cpuid: &CpuId) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_cpuid2 struct. + let ret = unsafe { ioctl_with_ptr(self, KVM_SET_CPUID2(), cpuid.as_fam_struct_ptr()) }; +@@ -475,7 +545,7 @@ impl VcpuFd { + /// let cpuid = vcpu.get_cpuid2(KVM_MAX_CPUID_ENTRIES).unwrap(); + /// ``` + /// +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_cpuid2(&self, num_entries: usize) -> Result { + if num_entries > KVM_MAX_CPUID_ENTRIES { + // Returns the same error the underlying `ioctl` would have sent. +@@ -511,7 +581,7 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let mut cap: kvm_enable_cap = Default::default(); +- /// if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") { ++ /// if cfg!(target_arch = "x86_64") { + /// // KVM_CAP_HYPERV_SYNIC needs KVM_CAP_SPLIT_IRQCHIP enabled + /// cap.cap = KVM_CAP_SPLIT_IRQCHIP; + /// cap.args[0] = 24; +@@ -526,7 +596,7 @@ impl VcpuFd { + /// } + /// ``` + /// +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn enable_cap(&self, cap: &kvm_enable_cap) -> Result<()> { + // SAFETY: The ioctl is safe because we allocated the struct and we know the + // kernel will write exactly the size of the struct. +@@ -556,7 +626,7 @@ impl VcpuFd { + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// let lapic = vcpu.get_lapic().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_lapic(&self) -> Result { + let mut klapic = kvm_lapic_state::default(); + +@@ -601,7 +671,7 @@ impl VcpuFd { + /// // Update the value of LAPIC. + /// vcpu.set_lapic(&lapic).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_lapic(&self, klapic: &kvm_lapic_state) -> Result<()> { + // SAFETY: The ioctl is safe because the kernel will only read from the klapic struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_LAPIC(), klapic) }; +@@ -647,7 +717,7 @@ impl VcpuFd { + /// let read = vcpu.get_msrs(&mut msrs).unwrap(); + /// assert_eq!(read, 2); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_msrs(&self, msrs: &mut Msrs) -> Result { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_msrs struct. + let ret = unsafe { ioctl_with_mut_ptr(self, KVM_GET_MSRS(), msrs.as_mut_fam_struct_ptr()) }; +@@ -686,7 +756,7 @@ impl VcpuFd { + /// let written = vcpu.set_msrs(&msrs).unwrap(); + /// assert_eq!(written, 1); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_msrs(&self, msrs: &Msrs) -> Result { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_msrs struct. + let ret = unsafe { ioctl_with_ptr(self, KVM_SET_MSRS(), msrs.as_fam_struct_ptr()) }; +@@ -717,11 +787,10 @@ impl VcpuFd { + /// let mp_state = vcpu.get_mp_state().unwrap(); + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + pub fn get_mp_state(&self) -> Result { + let mut mp_state = Default::default(); +@@ -755,11 +824,10 @@ impl VcpuFd { + /// vcpu.set_mp_state(mp_state).unwrap(); + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + pub fn set_mp_state(&self, mp_state: kvm_mp_state) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_mp_state struct. +@@ -789,7 +857,7 @@ impl VcpuFd { + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// let xsave = vcpu.get_xsave().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_xsave(&self) -> Result { + let mut xsave = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_xsave struct. +@@ -821,7 +889,7 @@ impl VcpuFd { + /// // Your `xsave` manipulation here. + /// vcpu.set_xsave(&xsave).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_xsave(&self, xsave: &kvm_xsave) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_xsave struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_XSAVE(), xsave) }; +@@ -850,7 +918,7 @@ impl VcpuFd { + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// let xcrs = vcpu.get_xcrs().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_xcrs(&self) -> Result { + let mut xcrs = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_xcrs struct. +@@ -882,7 +950,7 @@ impl VcpuFd { + /// // Your `xcrs` manipulation here. + /// vcpu.set_xcrs(&xcrs).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_xcrs(&self, xcrs: &kvm_xcrs) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_xcrs struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_XCRS(), xcrs) }; +@@ -911,7 +979,7 @@ impl VcpuFd { + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// let debug_regs = vcpu.get_debug_regs().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_debug_regs(&self) -> Result { + let mut debug_regs = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_debugregs struct. +@@ -943,7 +1011,7 @@ impl VcpuFd { + /// // Your `debug_regs` manipulation here. + /// vcpu.set_debug_regs(&debug_regs).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_debug_regs(&self, debug_regs: &kvm_debugregs) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_debugregs struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_DEBUGREGS(), debug_regs) }; +@@ -975,12 +1043,7 @@ impl VcpuFd { + /// let vcpu_events = vcpu.get_vcpu_events().unwrap(); + /// } + /// ``` +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + pub fn get_vcpu_events(&self) -> Result { + let mut vcpu_events = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_vcpu_events struct. +@@ -1014,13 +1077,7 @@ impl VcpuFd { + /// vcpu.set_vcpu_events(&vcpu_events).unwrap(); + /// } + /// ``` +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] +- ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + pub fn set_vcpu_events(&self, vcpu_events: &kvm_vcpu_events) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_vcpu_events struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_VCPU_EVENTS(), vcpu_events) }; +@@ -1056,7 +1113,7 @@ impl VcpuFd { + /// vm.get_preferred_target(&mut kvi).unwrap(); + /// vcpu.vcpu_init(&kvi).unwrap(); + /// ``` +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + pub fn vcpu_init(&self, kvi: &kvm_vcpu_init) -> Result<()> { + // SAFETY: This is safe because we allocated the struct and we know the kernel will read + // exactly the size of the struct. +@@ -1143,16 +1200,19 @@ impl VcpuFd { + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// +- /// // KVM_GET_REG_LIST demands that the vcpus be initalized. +- /// let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); +- /// vm.get_preferred_target(&mut kvi).unwrap(); +- /// vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu"); ++ /// // KVM_GET_REG_LIST on Aarch64 demands that the vcpus be initialized. ++ /// #[cfg(target_arch = "aarch64")] ++ /// { ++ /// let mut kvi = kvm_bindings::kvm_vcpu_init::default(); ++ /// vm.get_preferred_target(&mut kvi).unwrap(); ++ /// vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu"); + /// +- /// let mut reg_list = RegList::new(500).unwrap(); +- /// vcpu.get_reg_list(&mut reg_list).unwrap(); +- /// assert!(reg_list.as_fam_struct_ref().n > 0); ++ /// let mut reg_list = RegList::new(500).unwrap(); ++ /// vcpu.get_reg_list(&mut reg_list).unwrap(); ++ /// assert!(reg_list.as_fam_struct_ref().n > 0); ++ /// } + /// ``` +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub fn get_reg_list(&self, reg_list: &mut RegList) -> Result<()> { + let ret = + // SAFETY: This is safe because we allocated the struct and we trust the kernel will read +@@ -1186,7 +1246,7 @@ impl VcpuFd { + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); + /// +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] ++ /// #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + /// { + /// let debug_struct = kvm_guest_debug { + /// // Configure the vcpu so that a KVM_DEBUG_EXIT would be generated +@@ -1201,11 +1261,10 @@ impl VcpuFd { + /// } + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", + target_arch = "aarch64", +- target_arch = "s390", +- target_arch = "ppc" ++ target_arch = "s390x", ++ target_arch = "powerpc" + ))] + pub fn set_guest_debug(&self, debug_struct: &kvm_guest_debug) -> Result<()> { + // SAFETY: Safe because we allocated the structure and we trust the kernel. +@@ -1230,7 +1289,7 @@ impl VcpuFd { + /// + /// `data` should be equal or bigger then the register size + /// oterwise function will return EINVAL error +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub fn set_one_reg(&self, reg_id: u64, data: &[u8]) -> Result { + let reg_size = reg_size(reg_id); + if data.len() < reg_size { +@@ -1262,7 +1321,7 @@ impl VcpuFd { + /// + /// `data` should be equal or bigger then the register size + /// oterwise function will return EINVAL error +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub fn get_one_reg(&self, reg_id: u64, data: &mut [u8]) -> Result { + let reg_size = reg_size(reg_id); + if data.len() < reg_size { +@@ -1285,7 +1344,7 @@ impl VcpuFd { + /// + /// See the documentation for `KVM_KVMCLOCK_CTRL` in the + /// [KVM API documentation](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt). +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn kvmclock_ctrl(&self) -> Result<()> { + // SAFETY: Safe because we know that our file is a KVM fd and that the request + // is one of the ones defined by kernel. +@@ -1346,7 +1405,7 @@ impl VcpuFd { + /// slice.write(&x86_code).unwrap(); + /// } + /// +- /// let vcpu_fd = vm.create_vcpu(0).unwrap(); ++ /// let mut vcpu_fd = vm.create_vcpu(0).unwrap(); + /// + /// let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap(); + /// vcpu_sregs.cs.base = 0; +@@ -1371,7 +1430,7 @@ impl VcpuFd { + /// } + /// } + /// ``` +- pub fn run(&self) -> Result { ++ pub fn run(&mut self) -> Result { + // SAFETY: Safe because we know that our file is a vCPU fd and we verify the return result. + let ret = unsafe { ioctl(self, KVM_RUN()) }; + if ret == 0 { +@@ -1391,18 +1450,29 @@ impl VcpuFd { + // SAFETY: The data_offset is defined by the kernel to be some number of bytes + // into the kvm_run stucture, which we have fully mmap'd. + let data_ptr = unsafe { run_start.offset(io.data_offset as isize) }; +- // SAFETY: The slice's lifetime is limited to the lifetime of this vCPU, which is equal +- // to the mmap of the `kvm_run` struct that this is slicing from. +- let data_slice = unsafe { +- std::slice::from_raw_parts_mut::(data_ptr as *mut u8, data_size) +- }; ++ let data_slice = ++ // SAFETY: The slice's lifetime is limited to the lifetime of this vCPU, which is equal ++ // to the mmap of the `kvm_run` struct that this is slicing from. ++ unsafe { std::slice::from_raw_parts_mut::(data_ptr, data_size) }; + match u32::from(io.direction) { + KVM_EXIT_IO_IN => Ok(VcpuExit::IoIn(port, data_slice)), + KVM_EXIT_IO_OUT => Ok(VcpuExit::IoOut(port, data_slice)), + _ => Err(errno::Error::new(EINVAL)), + } + } +- KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall), ++ KVM_EXIT_HYPERCALL => { ++ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us ++ // which union field to use. ++ let hypercall = unsafe { &mut run.__bindgen_anon_1.hypercall }; ++ Ok(VcpuExit::Hypercall(HypercallExit { ++ nr: hypercall.nr, ++ args: hypercall.args, ++ ret: &mut hypercall.ret, ++ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us ++ // which union field to use. ++ longmode: unsafe { hypercall.__bindgen_anon_1.longmode }, ++ })) ++ } + KVM_EXIT_DEBUG => { + // SAFETY: Safe because the exit_reason (which comes from the kernel) told us + // which union field to use. +@@ -1423,6 +1493,30 @@ impl VcpuFd { + Ok(VcpuExit::MmioRead(addr, data_slice)) + } + } ++ KVM_EXIT_X86_RDMSR => { ++ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us ++ // which union field to use. ++ let msr = unsafe { &mut run.__bindgen_anon_1.msr }; ++ let exit = ReadMsrExit { ++ error: &mut msr.error, ++ reason: MsrExitReason::from_bits_truncate(msr.reason), ++ index: msr.index, ++ data: &mut msr.data, ++ }; ++ Ok(VcpuExit::X86Rdmsr(exit)) ++ } ++ KVM_EXIT_X86_WRMSR => { ++ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us ++ // which union field to use. ++ let msr = unsafe { &mut run.__bindgen_anon_1.msr }; ++ let exit = WriteMsrExit { ++ error: &mut msr.error, ++ reason: MsrExitReason::from_bits_truncate(msr.reason), ++ index: msr.index, ++ data: msr.data, ++ }; ++ Ok(VcpuExit::X86Wrmsr(exit)) ++ } + KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen), + KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown), + KVM_EXIT_FAIL_ENTRY => { +@@ -1452,10 +1546,10 @@ impl VcpuFd { + // SAFETY: Safe because the exit_reason (which comes from the kernel) told us + // which union field to use. + let system_event = unsafe { &mut run.__bindgen_anon_1.system_event }; +- Ok(VcpuExit::SystemEvent( +- system_event.type_, +- system_event.flags, +- )) ++ let ndata = system_event.ndata; ++ // SAFETY: Safe because we only populate with valid data (based on ndata) ++ let data = unsafe { &system_event.__bindgen_anon_1.data[0..ndata as usize] }; ++ Ok(VcpuExit::SystemEvent(system_event.type_, data)) + } + KVM_EXIT_S390_STSI => Ok(VcpuExit::S390Stsi), + KVM_EXIT_IOAPIC_EOI => { +@@ -1468,7 +1562,30 @@ impl VcpuFd { + r => Ok(VcpuExit::Unsupported(r)), + } + } else { +- Err(errno::Error::last()) ++ let errno = errno::Error::last(); ++ let run = self.kvm_run_ptr.as_mut_ref(); ++ // From https://docs.kernel.org/virt/kvm/api.html#kvm-run : ++ // ++ // KVM_EXIT_MEMORY_FAULT is unique among all KVM exit reasons in that it accompanies ++ // a return code of ‘-1’, not ‘0’! errno will always be set to EFAULT or EHWPOISON ++ // when KVM exits with KVM_EXIT_MEMORY_FAULT, userspace should assume kvm_run.exit_reason ++ // is stale/undefined for all other error numbers. ++ if ret == -1 ++ && (errno == errno::Error::new(libc::EFAULT) ++ || errno == errno::Error::new(libc::EHWPOISON)) ++ && run.exit_reason == KVM_EXIT_MEMORY_FAULT ++ { ++ // SAFETY: Safe because the exit_reason (which comes from the kernel) told us ++ // which union field to use. ++ let fault = unsafe { &mut run.__bindgen_anon_1.memory_fault }; ++ Ok(VcpuExit::MemoryFault { ++ flags: fault.flags, ++ gpa: fault.gpa, ++ size: fault.size, ++ }) ++ } else { ++ Err(errno) ++ } + } + } + +@@ -1478,7 +1595,7 @@ impl VcpuFd { + } + + /// Sets the `immediate_exit` flag on the `kvm_run` struct associated with this vCPU to `val`. +- pub fn set_kvm_immediate_exit(&self, val: u8) { ++ pub fn set_kvm_immediate_exit(&mut self, val: u8) { + let kvm_run = self.kvm_run_ptr.as_mut_ref(); + kvm_run.immediate_exit = val; + } +@@ -1496,7 +1613,7 @@ impl VcpuFd { + /// let tsc_khz = vcpu.get_tsc_khz().unwrap(); + /// ``` + /// +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_tsc_khz(&self) -> Result { + // SAFETY: Safe because we know that our file is a KVM fd and that the request is one of + // the ones defined by kernel. +@@ -1513,7 +1630,7 @@ impl VcpuFd { + /// # Arguments + /// + /// * `freq` - The frequency unit is KHz as per the KVM API documentation +- /// for `KVM_SET_TSC_KHZ`. ++ /// for `KVM_SET_TSC_KHZ`. + /// + /// # Example + /// +@@ -1528,7 +1645,7 @@ impl VcpuFd { + /// } + /// ``` + /// +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_tsc_khz(&self, freq: u32) -> Result<()> { + // SAFETY: Safe because we know that our file is a KVM fd and that the request is one of + // the ones defined by kernel. +@@ -1558,10 +1675,10 @@ impl VcpuFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let vcpu = vm.create_vcpu(0).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// let tr = vcpu.translate_gva(0x10000).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn translate_gva(&self, gva: u64) -> Result { + let mut tr = kvm_translation { + linear_address: gva, +@@ -1595,9 +1712,9 @@ impl VcpuFd { + /// vcpu.set_sync_valid_reg(SyncReg::SystemRegister); + /// vcpu.set_sync_valid_reg(SyncReg::VcpuEvents); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_sync_valid_reg(&mut self, reg: SyncReg) { +- let mut kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); ++ let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); + kvm_run.kvm_valid_regs |= reg as u64; + } + +@@ -1617,9 +1734,9 @@ impl VcpuFd { + /// let mut vcpu = vm.create_vcpu(0).unwrap(); + /// vcpu.set_sync_dirty_reg(SyncReg::Register); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_sync_dirty_reg(&mut self, reg: SyncReg) { +- let mut kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); ++ let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); + kvm_run.kvm_dirty_regs |= reg as u64; + } + +@@ -1639,9 +1756,9 @@ impl VcpuFd { + /// let mut vcpu = vm.create_vcpu(0).unwrap(); + /// vcpu.clear_sync_valid_reg(SyncReg::Register); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn clear_sync_valid_reg(&mut self, reg: SyncReg) { +- let mut kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); ++ let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); + kvm_run.kvm_valid_regs &= !(reg as u64); + } + +@@ -1661,9 +1778,9 @@ impl VcpuFd { + /// let mut vcpu = vm.create_vcpu(0).unwrap(); + /// vcpu.clear_sync_dirty_reg(SyncReg::Register); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn clear_sync_dirty_reg(&mut self, reg: SyncReg) { +- let mut kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); ++ let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); + kvm_run.kvm_dirty_regs &= !(reg as u64); + } + +@@ -1683,9 +1800,9 @@ impl VcpuFd { + /// let guest_rax = vcpu.sync_regs().regs.rax; + /// } + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn sync_regs(&self) -> kvm_sync_regs { +- let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); ++ let kvm_run = self.kvm_run_ptr.as_ref(); + + // SAFETY: Accessing this union field could be out of bounds if the `kvm_run` + // allocation isn't large enough. The `kvm_run` region is set using +@@ -1712,7 +1829,7 @@ impl VcpuFd { + /// vcpu.run(); + /// } + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn sync_regs_mut(&mut self) -> &mut kvm_sync_regs { + let kvm_run: &mut kvm_run = self.kvm_run_ptr.as_mut_ref(); + +@@ -1721,6 +1838,104 @@ impl VcpuFd { + // `get_vcpu_map_size`, so this region is in bounds + unsafe { &mut kvm_run.s.regs } + } ++ ++ /// Triggers an SMI on the virtual CPU. ++ /// ++ /// See documentation for `KVM_SMI`. ++ /// ++ /// ```rust ++ /// # use kvm_ioctls::{Kvm, Cap}; ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// let vcpu = vm.create_vcpu(0).unwrap(); ++ /// if kvm.check_extension(Cap::X86Smm) { ++ /// vcpu.smi().unwrap(); ++ /// } ++ /// ``` ++ #[cfg(target_arch = "x86_64")] ++ pub fn smi(&self) -> Result<()> { ++ // SAFETY: Safe because we call this with a Vcpu fd and we trust the kernel. ++ let ret = unsafe { ioctl(self, KVM_SMI()) }; ++ match ret { ++ 0 => Ok(()), ++ _ => Err(errno::Error::last()), ++ } ++ } ++ ++ /// Queues an NMI on the thread's vcpu. Only usable if `KVM_CAP_USER_NMI` ++ /// is available. ++ /// ++ /// See the documentation for `KVM_NMI`. ++ /// ++ /// # Example ++ /// ++ /// ```rust ++ /// # use kvm_ioctls::{Kvm, Cap}; ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// let vcpu = vm.create_vcpu(0).unwrap(); ++ /// if kvm.check_extension(Cap::UserNmi) { ++ /// vcpu.nmi().unwrap(); ++ /// } ++ /// ``` ++ #[cfg(target_arch = "x86_64")] ++ pub fn nmi(&self) -> Result<()> { ++ // SAFETY: Safe because we call this with a Vcpu fd and we trust the kernel. ++ let ret = unsafe { ioctl(self, KVM_NMI()) }; ++ match ret { ++ 0 => Ok(()), ++ _ => Err(errno::Error::last()), ++ } ++ } ++ ++ /// Maps the coalesced MMIO ring page. This allows reading entries from ++ /// the ring via [`coalesced_mmio_read()`](VcpuFd::coalesced_mmio_read). ++ /// ++ /// # Returns ++ /// ++ /// Returns an error if the buffer could not be mapped, usually because ++ /// `KVM_CAP_COALESCED_MMIO` ([`Cap::CoalescedMmio`](crate::Cap::CoalescedMmio)) ++ /// is not available. ++ /// ++ /// # Examples ++ /// ++ /// ```rust ++ /// # use kvm_ioctls::{Kvm, Cap}; ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// let mut vcpu = vm.create_vcpu(0).unwrap(); ++ /// if kvm.check_extension(Cap::CoalescedMmio) { ++ /// vcpu.map_coalesced_mmio_ring().unwrap(); ++ /// } ++ /// ``` ++ pub fn map_coalesced_mmio_ring(&mut self) -> Result<()> { ++ if self.coalesced_mmio_ring.is_none() { ++ let ring = KvmCoalescedIoRing::mmap_from_fd(&self.vcpu)?; ++ self.coalesced_mmio_ring = Some(ring); ++ } ++ Ok(()) ++ } ++ ++ /// Read a single entry from the coalesced MMIO ring. ++ /// For entries to be appended to the ring by the kernel, addresses must be registered ++ /// via [`VmFd::register_coalesced_mmio()`](crate::VmFd::register_coalesced_mmio()). ++ /// ++ /// [`map_coalesced_mmio_ring()`](VcpuFd::map_coalesced_mmio_ring) must have been called beforehand. ++ /// ++ /// See the documentation for `KVM_(UN)REGISTER_COALESCED_MMIO`. ++ /// ++ /// # Returns ++ /// ++ /// * An error if [`map_coalesced_mmio_ring()`](VcpuFd::map_coalesced_mmio_ring) ++ /// was not called beforehand. ++ /// * [`Ok`] if the ring is empty. ++ /// * [`Ok>`] if an entry was successfully read. ++ pub fn coalesced_mmio_read(&mut self) -> Result> { ++ self.coalesced_mmio_ring ++ .as_mut() ++ .ok_or(errno::Error::new(libc::EIO)) ++ .map(|ring| ring.read_entry()) ++ } + } + + /// Helper function to create a new `VcpuFd`. +@@ -1729,7 +1944,11 @@ impl VcpuFd { + /// `create_vcpu` from `VmFd`. The function cannot be part of the `VcpuFd` implementation because + /// then it would be exported with the public `VcpuFd` interface. + pub fn new_vcpu(vcpu: File, kvm_run_ptr: KvmRunWrapper) -> VcpuFd { +- VcpuFd { vcpu, kvm_run_ptr } ++ VcpuFd { ++ vcpu, ++ kvm_run_ptr, ++ coalesced_mmio_ring: None, ++ } + } + + impl AsRawFd for VcpuFd { +@@ -1744,18 +1963,14 @@ mod tests { + extern crate byteorder; + + use super::*; +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + use crate::cap::Cap; + use crate::ioctls::system::Kvm; ++ use std::ptr::NonNull; + + // Helper function for memory mapping `size` bytes of anonymous memory. + // Panics if the mmap fails. +- fn mmap_anonymous(size: usize) -> *mut u8 { ++ fn mmap_anonymous(size: usize) -> NonNull { + use std::ptr::null_mut; + + let addr = unsafe { +@@ -1772,7 +1987,7 @@ mod tests { + panic!("mmap failed."); + } + +- addr as *mut u8 ++ NonNull::new(addr).unwrap().cast() + } + + #[test] +@@ -1780,7 +1995,7 @@ mod tests { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + +- assert!(vm.create_vcpu(0).is_ok()); ++ vm.create_vcpu(0).unwrap(); + } + + #[cfg(target_arch = "x86_64")] +@@ -1925,7 +2140,7 @@ mod tests { + assert!(kvm.check_extension(Cap::Irqchip)); + let vm = kvm.create_vm().unwrap(); + // The get_lapic ioctl will fail if there is no irqchip created beforehand. +- assert!(vm.create_irq_chip().is_ok()); ++ vm.create_irq_chip().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + let mut klapic: kvm_lapic_state = vcpu.get_lapic().unwrap(); + +@@ -1994,11 +2209,10 @@ mod tests { + } + + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + #[test] + fn mpstate_test() { +@@ -2011,7 +2225,7 @@ mod tests { + assert_eq!(mp_state, other_mp_state); + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn xsave_test() { + let kvm = Kvm::new().unwrap(); +@@ -2023,7 +2237,7 @@ mod tests { + assert_eq!(&xsave.region[..], &other_xsave.region[..]); + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn xcrs_test() { + let kvm = Kvm::new().unwrap(); +@@ -2035,7 +2249,7 @@ mod tests { + assert_eq!(xcrs, other_xcrs); + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn debugregs_test() { + let kvm = Kvm::new().unwrap(); +@@ -2047,12 +2261,7 @@ mod tests { + assert_eq!(debugregs, other_debugregs); + } + +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + #[test] + fn vcpu_events_test() { + let kvm = Kvm::new().unwrap(); +@@ -2090,7 +2299,7 @@ mod tests { + ]; + + let mem_size = 0x20000; +- let load_addr = mmap_anonymous(mem_size); ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); + let guest_addr: u64 = 0x10000; + let slot: u32 = 0; + let mem_region = kvm_userspace_memory_region { +@@ -2111,8 +2320,8 @@ mod tests { + slice.write_all(&code).unwrap(); + } + +- let vcpu_fd = vm.create_vcpu(0).unwrap(); +- let mut kvi = kvm_bindings::kvm_vcpu_init::default(); ++ let mut vcpu_fd = vm.create_vcpu(0).unwrap(); ++ let mut kvi = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi).unwrap(); + kvi.features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + vcpu_fd.vcpu_init(&kvi).unwrap(); +@@ -2162,9 +2371,101 @@ mod tests { + .sum(); + assert_eq!(dirty_pages, 1); + } +- VcpuExit::SystemEvent(type_, flags) => { ++ VcpuExit::SystemEvent(type_, data) => { + assert_eq!(type_, KVM_SYSTEM_EVENT_SHUTDOWN); +- assert_eq!(flags, 0); ++ assert_eq!(data[0], 0); ++ break; ++ } ++ r => panic!("unexpected exit reason: {:?}", r), ++ } ++ } ++ } ++ ++ #[cfg(target_arch = "riscv64")] ++ #[test] ++ fn test_run_code() { ++ use std::io::Write; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ #[rustfmt::skip] ++ let code = [ ++ 0x13, 0x05, 0x50, 0x40, // li a0, 0x0405; ++ 0x23, 0x20, 0xac, 0x00, // sw a0, 0(s8); test physical memory write ++ 0x03, 0xa5, 0x0c, 0x00, // lw a0, 0(s9); test MMIO read ++ 0x93, 0x05, 0x70, 0x60, // li a1, 0x0607; ++ 0x23, 0xa0, 0xbc, 0x00, // sw a1, 0(s9); test MMIO write ++ 0x6f, 0x00, 0x00, 0x00, // j .; shouldn't get here, but if so loop forever ++ ]; ++ ++ let mem_size = 0x20000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x10000; ++ let slot: u32 = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: KVM_MEM_LOG_DIRTY_PAGES, ++ }; ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ } ++ ++ unsafe { ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let mut vcpu_fd = vm.create_vcpu(0).unwrap(); ++ ++ let core_reg_base: u64 = 0x8030_0000_0200_0000; ++ let mmio_addr: u64 = guest_addr + mem_size as u64; ++ ++ // Set the PC to the guest address where we loaded the code. ++ vcpu_fd ++ .set_one_reg(core_reg_base, &(guest_addr as u128).to_le_bytes()) ++ .unwrap(); ++ ++ // Set s8 and s9 to the addresses the guest test code needs ++ vcpu_fd ++ .set_one_reg( ++ core_reg_base + 24, ++ &(guest_addr as u128 + 0x10000).to_le_bytes(), ++ ) ++ .unwrap(); ++ vcpu_fd ++ .set_one_reg(core_reg_base + 25, &(mmio_addr as u128).to_le_bytes()) ++ .unwrap(); ++ ++ loop { ++ match vcpu_fd.run().expect("run failed") { ++ VcpuExit::MmioRead(addr, data) => { ++ assert_eq!(addr, mmio_addr); ++ assert_eq!(data.len(), 4); ++ data[3] = 0x0; ++ data[2] = 0x0; ++ data[1] = 0x5; ++ data[0] = 0x6; ++ } ++ VcpuExit::MmioWrite(addr, data) => { ++ assert_eq!(addr, mmio_addr); ++ assert_eq!(data.len(), 4); ++ assert_eq!(data[3], 0x0); ++ assert_eq!(data[2], 0x0); ++ assert_eq!(data[1], 0x6); ++ assert_eq!(data[0], 0x7); ++ // The code snippet dirties one page at guest_addr + 0x10000. ++ // The code page should not be dirty, as it's not written by the guest. ++ let dirty_pages_bitmap = vm.get_dirty_log(slot, mem_size).unwrap(); ++ let dirty_pages: u32 = dirty_pages_bitmap ++ .into_iter() ++ .map(|page| page.count_ones()) ++ .sum(); ++ assert_eq!(dirty_pages, 1); + break; + } + r => panic!("unexpected exit reason: {:?}", r), +@@ -2195,7 +2496,7 @@ mod tests { + let expected_rips: [u64; 3] = [0x1003, 0x1005, 0x1007]; + + let mem_size = 0x4000; +- let load_addr = mmap_anonymous(mem_size); ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); + let guest_addr: u64 = 0x1000; + let slot: u32 = 0; + let mem_region = kvm_userspace_memory_region { +@@ -2216,7 +2517,7 @@ mod tests { + slice.write_all(&code).unwrap(); + } + +- let vcpu_fd = vm.create_vcpu(0).unwrap(); ++ let mut vcpu_fd = vm.create_vcpu(0).unwrap(); + + let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap(); + assert_ne!(vcpu_sregs.cs.base, 0); +@@ -2300,91 +2601,132 @@ mod tests { + } + + #[test] +- #[cfg(target_arch = "x86_64")] ++ #[cfg(any( ++ target_arch = "x86_64", ++ target_arch = "aarch64", ++ target_arch = "riscv64" ++ ))] + fn test_faulty_vcpu_fd() { +- use std::os::unix::io::FromRawFd; ++ use std::os::unix::io::{FromRawFd, IntoRawFd}; + + let badf_errno = libc::EBADF; + +- let faulty_vcpu_fd = VcpuFd { ++ let mut faulty_vcpu_fd = VcpuFd { + vcpu: unsafe { File::from_raw_fd(-2) }, + kvm_run_ptr: KvmRunWrapper { +- kvm_run_ptr: mmap_anonymous(10), ++ kvm_run_ptr: mmap_anonymous(10).cast(), + mmap_size: 10, + }, ++ coalesced_mmio_ring: None, + }; + +- assert_eq!(faulty_vcpu_fd.get_regs().unwrap_err().errno(), badf_errno); + assert_eq!( +- faulty_vcpu_fd +- .set_regs(&unsafe { std::mem::zeroed() }) +- .unwrap_err() +- .errno(), ++ faulty_vcpu_fd.get_mp_state().unwrap_err().errno(), + badf_errno + ); +- assert_eq!(faulty_vcpu_fd.get_sregs().unwrap_err().errno(), badf_errno); + assert_eq!( + faulty_vcpu_fd +- .set_sregs(&unsafe { std::mem::zeroed() }) ++ .set_mp_state(kvm_mp_state::default()) + .unwrap_err() + .errno(), + badf_errno + ); +- assert_eq!(faulty_vcpu_fd.get_fpu().unwrap_err().errno(), badf_errno); ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + assert_eq!( +- faulty_vcpu_fd +- .set_fpu(&unsafe { std::mem::zeroed() }) +- .unwrap_err() +- .errno(), ++ faulty_vcpu_fd.get_vcpu_events().unwrap_err().errno(), + badf_errno + ); ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + assert_eq!( + faulty_vcpu_fd +- .set_cpuid2( +- &Kvm::new() +- .unwrap() +- .get_supported_cpuid(KVM_MAX_CPUID_ENTRIES) +- .unwrap() +- ) ++ .set_vcpu_events(&kvm_vcpu_events::default()) + .unwrap_err() + .errno(), + badf_errno + ); +- assert_eq!( +- faulty_vcpu_fd.get_cpuid2(1).err().unwrap().errno(), +- badf_errno +- ); +- // `kvm_lapic_state` does not implement debug by default so we cannot +- // use unwrap_err here. +- assert!(faulty_vcpu_fd.get_lapic().is_err()); +- assert_eq!( +- faulty_vcpu_fd +- .set_lapic(&unsafe { std::mem::zeroed() }) ++ assert_eq!(faulty_vcpu_fd.run().unwrap_err().errno(), badf_errno); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ let _ = faulty_vcpu_fd.vcpu.into_raw_fd(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "x86_64")] ++ fn test_faulty_vcpu_fd_x86_64() { ++ use std::os::unix::io::{FromRawFd, IntoRawFd}; ++ ++ let badf_errno = libc::EBADF; ++ ++ let faulty_vcpu_fd = VcpuFd { ++ vcpu: unsafe { File::from_raw_fd(-2) }, ++ kvm_run_ptr: KvmRunWrapper { ++ kvm_run_ptr: mmap_anonymous(10).cast(), ++ mmap_size: 10, ++ }, ++ coalesced_mmio_ring: None, ++ }; ++ ++ assert_eq!(faulty_vcpu_fd.get_regs().unwrap_err().errno(), badf_errno); ++ assert_eq!( ++ faulty_vcpu_fd ++ .set_regs(&unsafe { std::mem::zeroed() }) + .unwrap_err() + .errno(), + badf_errno + ); ++ assert_eq!(faulty_vcpu_fd.get_sregs().unwrap_err().errno(), badf_errno); + assert_eq!( + faulty_vcpu_fd +- .get_msrs(&mut Msrs::new(1).unwrap()) ++ .set_sregs(&unsafe { std::mem::zeroed() }) + .unwrap_err() + .errno(), + badf_errno + ); ++ assert_eq!(faulty_vcpu_fd.get_fpu().unwrap_err().errno(), badf_errno); + assert_eq!( + faulty_vcpu_fd +- .set_msrs(&Msrs::new(1).unwrap()) ++ .set_fpu(&unsafe { std::mem::zeroed() }) + .unwrap_err() + .errno(), + badf_errno + ); + assert_eq!( +- faulty_vcpu_fd.get_mp_state().unwrap_err().errno(), ++ faulty_vcpu_fd ++ .set_cpuid2( ++ &Kvm::new() ++ .unwrap() ++ .get_supported_cpuid(KVM_MAX_CPUID_ENTRIES) ++ .unwrap() ++ ) ++ .unwrap_err() ++ .errno(), + badf_errno + ); ++ assert_eq!( ++ faulty_vcpu_fd.get_cpuid2(1).err().unwrap().errno(), ++ badf_errno ++ ); ++ // `kvm_lapic_state` does not implement debug by default so we cannot ++ // use unwrap_err here. ++ faulty_vcpu_fd.get_lapic().unwrap_err(); + assert_eq!( + faulty_vcpu_fd +- .set_mp_state(kvm_mp_state::default()) ++ .set_lapic(&unsafe { std::mem::zeroed() }) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .get_msrs(&mut Msrs::new(1).unwrap()) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .set_msrs(&Msrs::new(1).unwrap()) + .unwrap_err() + .errno(), + badf_errno +@@ -2421,56 +2763,191 @@ mod tests { + badf_errno + ); + assert_eq!( +- faulty_vcpu_fd.get_vcpu_events().unwrap_err().errno(), ++ faulty_vcpu_fd.kvmclock_ctrl().unwrap_err().errno(), ++ badf_errno ++ ); ++ faulty_vcpu_fd.get_tsc_khz().unwrap_err(); ++ faulty_vcpu_fd.set_tsc_khz(1000000).unwrap_err(); ++ faulty_vcpu_fd.translate_gva(u64::MAX).unwrap_err(); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ let _ = faulty_vcpu_fd.vcpu.into_raw_fd(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "aarch64")] ++ fn test_faulty_vcpu_target_aarch64() { ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ let vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // KVM defines valid targets as 0 to KVM_ARM_NUM_TARGETS-1, so pick a big raw number ++ // greater than that as target to be invalid ++ let kvi = kvm_vcpu_init { ++ target: 300, ++ ..Default::default() ++ }; ++ ++ vcpu.vcpu_init(&kvi).unwrap_err(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "aarch64")] ++ fn test_faulty_vcpu_fd_aarch64() { ++ use std::os::unix::io::{FromRawFd, IntoRawFd}; ++ ++ let badf_errno = libc::EBADF; ++ ++ let faulty_vcpu_fd = VcpuFd { ++ vcpu: unsafe { File::from_raw_fd(-2) }, ++ kvm_run_ptr: KvmRunWrapper { ++ kvm_run_ptr: mmap_anonymous(10).cast(), ++ mmap_size: 10, ++ }, ++ coalesced_mmio_ring: None, ++ }; ++ ++ let device_attr = kvm_device_attr { ++ group: KVM_ARM_VCPU_PMU_V3_CTRL, ++ attr: u64::from(KVM_ARM_VCPU_PMU_V3_INIT), ++ addr: 0x0, ++ flags: 0, ++ }; ++ ++ let reg_id = 0x6030_0000_0010_0042; ++ let mut reg_data = 0u128.to_le_bytes(); ++ ++ assert_eq!( ++ faulty_vcpu_fd ++ .set_device_attr(&device_attr) ++ .unwrap_err() ++ .errno(), + badf_errno + ); + assert_eq!( + faulty_vcpu_fd +- .set_vcpu_events(&kvm_vcpu_events::default()) ++ .has_device_attr(&device_attr) + .unwrap_err() + .errno(), + badf_errno + ); +- assert_eq!(faulty_vcpu_fd.run().unwrap_err().errno(), badf_errno); + assert_eq!( +- faulty_vcpu_fd.kvmclock_ctrl().unwrap_err().errno(), ++ faulty_vcpu_fd ++ .vcpu_init(&kvm_vcpu_init::default()) ++ .unwrap_err() ++ .errno(), + badf_errno + ); +- assert!(faulty_vcpu_fd.get_tsc_khz().is_err()); +- assert!(faulty_vcpu_fd.set_tsc_khz(1000000).is_err()); +- assert!(faulty_vcpu_fd.translate_gva(u64::MAX).is_err()); ++ assert_eq!( ++ faulty_vcpu_fd ++ .vcpu_finalize(&(KVM_ARM_VCPU_SVE as i32)) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .get_reg_list(&mut RegList::new(500).unwrap()) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .set_one_reg(reg_id, ®_data) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .get_one_reg(reg_id, &mut reg_data) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ faulty_vcpu_fd.vcpu.into_raw_fd(); + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "riscv64")] ++ fn test_faulty_vcpu_fd_riscv64() { ++ use std::os::unix::io::{FromRawFd, IntoRawFd}; ++ ++ let badf_errno = libc::EBADF; ++ ++ let faulty_vcpu_fd = VcpuFd { ++ vcpu: unsafe { File::from_raw_fd(-2) }, ++ kvm_run_ptr: KvmRunWrapper { ++ kvm_run_ptr: mmap_anonymous(10).cast(), ++ mmap_size: 10, ++ }, ++ coalesced_mmio_ring: None, ++ }; ++ ++ let reg_id = 0x8030_0000_0200_000a; ++ let mut reg_data = 0u128.to_le_bytes(); ++ ++ assert_eq!( ++ faulty_vcpu_fd ++ .get_reg_list(&mut RegList::new(200).unwrap()) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .set_one_reg(reg_id, ®_data) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ assert_eq!( ++ faulty_vcpu_fd ++ .get_one_reg(reg_id, &mut reg_data) ++ .unwrap_err() ++ .errno(), ++ badf_errno ++ ); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ faulty_vcpu_fd.vcpu.into_raw_fd(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "aarch64")] + fn test_get_preferred_target() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); +- assert!(vcpu.vcpu_init(&kvi).is_err()); ++ let mut kvi = kvm_vcpu_init::default(); + + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); +- assert!(vcpu.vcpu_init(&kvi).is_ok()); ++ vcpu.vcpu_init(&kvi).unwrap(); + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_set_one_reg() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); ++ let mut kvi = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); + vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu"); + let data: u128 = 0; + let reg_id: u64 = 0; + +- assert!(vcpu.set_one_reg(reg_id, &data.to_le_bytes()).is_err()); ++ vcpu.set_one_reg(reg_id, &data.to_le_bytes()).unwrap_err(); + // Exercising KVM_SET_ONE_REG by trying to alter the data inside the PSTATE register (which is a + // specific aarch64 register). + // This regiseter is 64 bit wide (8 bytes). +@@ -2479,17 +2956,17 @@ mod tests { + .expect("Failed to set pstate register"); + + // Trying to set 8 byte register with 7 bytes must fail. +- assert!(vcpu.set_one_reg(PSTATE_REG_ID, &[0_u8; 7]).is_err()); ++ vcpu.set_one_reg(PSTATE_REG_ID, &[0_u8; 7]).unwrap_err(); + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_get_one_reg() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); ++ let mut kvi = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); + vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu"); +@@ -2515,11 +2992,11 @@ mod tests { + assert_eq!(data, PSTATE_FAULT_BITS_64 as u128); + + // Trying to get 8 byte register with 7 bytes must fail. +- assert!(vcpu.get_one_reg(PSTATE_REG_ID, &mut [0_u8; 7]).is_err()); ++ vcpu.get_one_reg(PSTATE_REG_ID, &mut [0_u8; 7]).unwrap_err(); + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_get_reg_list() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +@@ -2530,7 +3007,7 @@ mod tests { + let err = vcpu.get_reg_list(&mut reg_list).unwrap_err(); + assert!(err.errno() == libc::ENOEXEC); + +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); ++ let mut kvi = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); + vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu"); +@@ -2539,12 +3016,88 @@ mod tests { + // not allocated memory, so the first time it fails. + let err = vcpu.get_reg_list(&mut reg_list).unwrap_err(); + assert!(err.errno() == libc::E2BIG); +- assert!(reg_list.as_mut_fam_struct().n > 0); ++ // SAFETY: This structure is a result from a specific vCPU ioctl ++ assert!(unsafe { reg_list.as_mut_fam_struct() }.n > 0); + + // We make use of the number of registers returned to allocate memory and + // try one more time. +- let mut reg_list = RegList::new(reg_list.as_mut_fam_struct().n as usize).unwrap(); +- assert!(vcpu.get_reg_list(&mut reg_list).is_ok()); ++ // SAFETY: This structure is a result from a specific vCPU ioctl ++ let mut reg_list = ++ RegList::new(unsafe { reg_list.as_mut_fam_struct() }.n as usize).unwrap(); ++ vcpu.get_reg_list(&mut reg_list).unwrap() ++ } ++ ++ #[test] ++ #[cfg(target_arch = "riscv64")] ++ fn test_set_one_reg() { ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ let vcpu = vm.create_vcpu(0).unwrap(); ++ ++ let data: u128 = 0; ++ let reg_id: u64 = 0; ++ ++ vcpu.set_one_reg(reg_id, &data.to_le_bytes()).unwrap_err(); ++ // Exercising KVM_SET_ONE_REG by trying to alter the data inside the A0 ++ // register. ++ // This regiseter is 64 bit wide (8 bytes). ++ const A0_REG_ID: u64 = 0x8030_0000_0200_000a; ++ vcpu.set_one_reg(A0_REG_ID, &data.to_le_bytes()) ++ .expect("Failed to set a0 register"); ++ ++ // Trying to set 8 byte register with 7 bytes must fail. ++ vcpu.set_one_reg(A0_REG_ID, &[0_u8; 7]).unwrap_err(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "riscv64")] ++ fn test_get_one_reg() { ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ let vcpu = vm.create_vcpu(0).unwrap(); ++ ++ const PRESET: u64 = 0x7; ++ let data: u128 = PRESET as u128; ++ const A0_REG_ID: u64 = 0x8030_0000_0200_000a; ++ vcpu.set_one_reg(A0_REG_ID, &data.to_le_bytes()) ++ .expect("Failed to set a0 register"); ++ ++ let mut bytes = [0_u8; 16]; ++ vcpu.get_one_reg(A0_REG_ID, &mut bytes) ++ .expect("Failed to get a0 register"); ++ let data = u128::from_le_bytes(bytes); ++ assert_eq!(data, PRESET as u128); ++ ++ // Trying to get 8 byte register with 7 bytes must fail. ++ vcpu.get_one_reg(A0_REG_ID, &mut [0_u8; 7]).unwrap_err(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "riscv64")] ++ fn test_get_reg_list() { ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ let vcpu = vm.create_vcpu(0).unwrap(); ++ ++ let mut reg_list = RegList::new(1).unwrap(); ++ ++ // KVM_GET_REG_LIST offers us a number of registers for which we have ++ // not allocated memory, so the first time it fails. ++ let err = vcpu.get_reg_list(&mut reg_list).unwrap_err(); ++ assert!(err.errno() == libc::E2BIG); ++ // SAFETY: This structure is a result from a specific vCPU ioctl ++ assert!(unsafe { reg_list.as_mut_fam_struct() }.n > 0); ++ ++ // We make use of the number of registers returned to allocate memory and ++ // try one more time. ++ // SAFETY: This structure is a result from a specific vCPU ioctl ++ let mut reg_list = ++ RegList::new(unsafe { reg_list.as_mut_fam_struct() }.n as usize).unwrap(); ++ vcpu.get_reg_list(&mut reg_list).unwrap(); ++ ++ // Test get a register list contains 200 registers explicitly ++ let mut reg_list = RegList::new(200).unwrap(); ++ vcpu.get_reg_list(&mut reg_list).unwrap(); + } + + #[test] +@@ -2560,10 +3113,10 @@ mod tests { + fn test_set_kvm_immediate_exit() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +- let vcpu = vm.create_vcpu(0).unwrap(); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().immediate_exit, 0); ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().immediate_exit, 0); + vcpu.set_kvm_immediate_exit(1); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().immediate_exit, 1); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().immediate_exit, 1); + } + + #[test] +@@ -2596,7 +3149,7 @@ mod tests { + let vcpu = vm.create_vcpu(0).unwrap(); + + if !kvm.check_extension(Cap::GetTscKhz) { +- assert!(vcpu.get_tsc_khz().is_err()) ++ vcpu.get_tsc_khz().unwrap_err(); + } else { + assert!(vcpu.get_tsc_khz().unwrap() > 0); + } +@@ -2611,11 +3164,11 @@ mod tests { + let freq = vcpu.get_tsc_khz().unwrap(); + + if !(kvm.check_extension(Cap::GetTscKhz) && kvm.check_extension(Cap::TscControl)) { +- assert!(vcpu.set_tsc_khz(0).is_err()); ++ vcpu.set_tsc_khz(0).unwrap_err(); + } else { +- assert!(vcpu.set_tsc_khz(freq - 500000).is_ok()); ++ vcpu.set_tsc_khz(freq - 500000).unwrap(); + assert_eq!(vcpu.get_tsc_khz().unwrap(), freq - 500000); +- assert!(vcpu.set_tsc_khz(freq + 500000).is_ok()); ++ vcpu.set_tsc_khz(freq + 500000).unwrap(); + assert_eq!(vcpu.get_tsc_khz().unwrap(), freq + 500000); + } + } +@@ -2635,9 +3188,9 @@ mod tests { + ]; + for reg in &sync_regs { + vcpu.set_sync_valid_reg(*reg); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().kvm_valid_regs, *reg as u64); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().kvm_valid_regs, *reg as u64); + vcpu.clear_sync_valid_reg(*reg); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().kvm_valid_regs, 0); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().kvm_valid_regs, 0); + } + + // Test that multiple valid SyncRegs can be set at the same time +@@ -2645,7 +3198,7 @@ mod tests { + vcpu.set_sync_valid_reg(SyncReg::SystemRegister); + vcpu.set_sync_valid_reg(SyncReg::VcpuEvents); + assert_eq!( +- vcpu.kvm_run_ptr.as_mut_ref().kvm_valid_regs, ++ vcpu.kvm_run_ptr.as_ref().kvm_valid_regs, + SyncReg::Register as u64 | SyncReg::SystemRegister as u64 | SyncReg::VcpuEvents as u64 + ); + +@@ -2658,9 +3211,9 @@ mod tests { + + for reg in &sync_regs { + vcpu.set_sync_dirty_reg(*reg); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().kvm_dirty_regs, *reg as u64); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().kvm_dirty_regs, *reg as u64); + vcpu.clear_sync_dirty_reg(*reg); +- assert_eq!(vcpu.kvm_run_ptr.as_mut_ref().kvm_dirty_regs, 0); ++ assert_eq!(vcpu.kvm_run_ptr.as_ref().kvm_dirty_regs, 0); + } + + // Test that multiple dirty SyncRegs can be set at the same time +@@ -2668,7 +3221,7 @@ mod tests { + vcpu.set_sync_dirty_reg(SyncReg::SystemRegister); + vcpu.set_sync_dirty_reg(SyncReg::VcpuEvents); + assert_eq!( +- vcpu.kvm_run_ptr.as_mut_ref().kvm_dirty_regs, ++ vcpu.kvm_run_ptr.as_ref().kvm_dirty_regs, + SyncReg::Register as u64 | SyncReg::SystemRegister as u64 | SyncReg::VcpuEvents as u64 + ); + } +@@ -2689,7 +3242,7 @@ mod tests { + ]; + + let mem_size = 0x4000; +- let load_addr = mmap_anonymous(mem_size); ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); + let guest_addr: u64 = 0x1000; + let slot: u32 = 0; + let mem_region = kvm_userspace_memory_region { +@@ -2714,7 +3267,7 @@ mod tests { + + let orig_sregs = vcpu.get_sregs().unwrap(); + +- let mut sync_regs = vcpu.sync_regs_mut(); ++ let sync_regs = vcpu.sync_regs_mut(); + + // Initialize the sregs in sync_regs to be the original sregs + sync_regs.sregs = orig_sregs; +@@ -2751,13 +3304,13 @@ mod tests { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); +- assert!(vcpu.translate_gva(0x10000).is_ok()); ++ vcpu.translate_gva(0x10000).unwrap(); + assert_eq!(vcpu.translate_gva(0x10000).unwrap().valid, 1); + assert_eq!( + vcpu.translate_gva(0x10000).unwrap().physical_address, + 0x10000 + ); +- assert!(vcpu.translate_gva(u64::MAX).is_ok()); ++ vcpu.translate_gva(u64::MAX).unwrap(); + assert_eq!(vcpu.translate_gva(u64::MAX).unwrap().valid, 0); + } + +@@ -2768,22 +3321,22 @@ mod tests { + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + +- let dist_attr = kvm_bindings::kvm_device_attr { ++ let dist_attr = kvm_device_attr { + group: KVM_ARM_VCPU_PMU_V3_CTRL, + attr: u64::from(KVM_ARM_VCPU_PMU_V3_INIT), + addr: 0x0, + flags: 0, + }; + +- assert!(vcpu.has_device_attr(&dist_attr).is_err()); +- assert!(vcpu.set_device_attr(&dist_attr).is_err()); +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); ++ vcpu.has_device_attr(&dist_attr).unwrap_err(); ++ vcpu.set_device_attr(&dist_attr).unwrap_err(); ++ let mut kvi: kvm_vcpu_init = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); +- kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2 | 1 << KVM_ARM_VCPU_PMU_V3; +- assert!(vcpu.vcpu_init(&kvi).is_ok()); +- assert!(vcpu.has_device_attr(&dist_attr).is_ok()); +- assert!(vcpu.set_device_attr(&dist_attr).is_ok()); ++ kvi.features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2 | 1 << KVM_ARM_VCPU_PMU_V3; ++ vcpu.vcpu_init(&kvi).unwrap(); ++ vcpu.has_device_attr(&dist_attr).unwrap(); ++ vcpu.set_device_attr(&dist_attr).unwrap(); + } + + #[test] +@@ -2793,15 +3346,446 @@ mod tests { + let vm = kvm.create_vm().unwrap(); + let vcpu = vm.create_vcpu(0).unwrap(); + +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); ++ let mut kvi = kvm_vcpu_init::default(); + vm.get_preferred_target(&mut kvi) + .expect("Cannot get preferred target"); + if kvm.check_extension(Cap::ArmPtrAuthAddress) { +- kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PTRAUTH_ADDRESS; ++ kvi.features[0] |= 1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS; + } + if kvm.check_extension(Cap::ArmPtrAuthGeneric) { +- kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PTRAUTH_GENERIC; ++ kvi.features[0] |= 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC; + } +- assert!(vcpu.vcpu_init(&kvi).is_ok()); ++ vcpu.vcpu_init(&kvi).unwrap(); ++ } ++ ++ #[cfg(target_arch = "x86_64")] ++ #[test] ++ fn test_userspace_rdmsr_exit() { ++ use std::io::Write; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ #[rustfmt::skip] ++ let code = [ ++ 0x0F, 0x32, /* rdmsr */ ++ 0xF4 /* hlt */ ++ ]; ++ ++ if !vm.check_extension(Cap::X86UserSpaceMsr) { ++ return; ++ } ++ let cap = kvm_enable_cap { ++ cap: Cap::X86UserSpaceMsr as u32, ++ args: [MsrExitReason::Unknown.bits() as u64, 0, 0, 0], ++ ..Default::default() ++ }; ++ vm.enable_cap(&cap).unwrap(); ++ ++ let mem_size = 0x4000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x1000; ++ let slot: u32 = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: 0, ++ }; ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // Set up special registers ++ let mut vcpu_sregs = vcpu.get_sregs().unwrap(); ++ assert_ne!(vcpu_sregs.cs.base, 0); ++ assert_ne!(vcpu_sregs.cs.selector, 0); ++ vcpu_sregs.cs.base = 0; ++ vcpu_sregs.cs.selector = 0; ++ vcpu.set_sregs(&vcpu_sregs).unwrap(); ++ ++ // Set the Instruction Pointer to the guest address where we loaded ++ // the code, and RCX to the MSR to be read. ++ let mut vcpu_regs = vcpu.get_regs().unwrap(); ++ vcpu_regs.rip = guest_addr; ++ vcpu_regs.rcx = 0x474f4f00; ++ vcpu.set_regs(&vcpu_regs).unwrap(); ++ ++ match vcpu.run().unwrap() { ++ VcpuExit::X86Rdmsr(exit) => { ++ assert_eq!(exit.reason, MsrExitReason::Unknown); ++ assert_eq!(exit.index, 0x474f4f00); ++ } ++ e => panic!("Unexpected exit: {:?}", e), ++ } ++ } ++ ++ #[cfg(target_arch = "x86_64")] ++ #[test] ++ fn test_userspace_hypercall_exit() { ++ use std::io::Write; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ ++ // Use `vmcall` or `vmmcall` depending on what's supported. ++ let cpuid = kvm.get_supported_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap(); ++ let supports_vmcall = cpuid ++ .as_slice() ++ .iter() ++ .find(|entry| entry.function == 1) ++ .map_or(false, |entry| entry.ecx & (1 << 5) != 0); ++ let supports_vmmcall = cpuid ++ .as_slice() ++ .iter() ++ .find(|entry| entry.function == 0x8000_0001) ++ .map_or(false, |entry| entry.ecx & (1 << 2) != 0); ++ #[rustfmt::skip] ++ let code = if supports_vmcall { ++ [ ++ 0x0F, 0x01, 0xC1, /* vmcall */ ++ 0xF4 /* hlt */ ++ ] ++ } else if supports_vmmcall { ++ [ ++ 0x0F, 0x01, 0xD9, /* vmmcall */ ++ 0xF4 /* hlt */ ++ ] ++ } else { ++ return; ++ }; ++ ++ if !vm.check_extension(Cap::ExitHypercall) { ++ return; ++ } ++ const KVM_HC_MAP_GPA_RANGE: u64 = 12; ++ let cap = kvm_enable_cap { ++ cap: Cap::ExitHypercall as u32, ++ args: [1 << KVM_HC_MAP_GPA_RANGE, 0, 0, 0], ++ ..Default::default() ++ }; ++ vm.enable_cap(&cap).unwrap(); ++ ++ let mem_size = 0x4000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x1000; ++ let slot: u32 = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: 0, ++ }; ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // Set up special registers ++ let mut vcpu_sregs = vcpu.get_sregs().unwrap(); ++ assert_ne!(vcpu_sregs.cs.base, 0); ++ assert_ne!(vcpu_sregs.cs.selector, 0); ++ vcpu_sregs.cs.base = 0; ++ vcpu_sregs.cs.selector = 0; ++ vcpu.set_sregs(&vcpu_sregs).unwrap(); ++ ++ // Set the Instruction Pointer to the guest address where we loaded ++ // the code, and RCX to the MSR to be read. ++ let mut vcpu_regs = vcpu.get_regs().unwrap(); ++ vcpu_regs.rip = guest_addr; ++ vcpu_regs.rax = KVM_HC_MAP_GPA_RANGE; ++ vcpu_regs.rbx = 0x1234000; ++ vcpu_regs.rcx = 1; ++ vcpu_regs.rdx = 0; ++ vcpu.set_regs(&vcpu_regs).unwrap(); ++ ++ match vcpu.run().unwrap() { ++ VcpuExit::Hypercall(exit) => { ++ assert_eq!(exit.nr, KVM_HC_MAP_GPA_RANGE); ++ assert_eq!(exit.args[0], 0x1234000); ++ assert_eq!(exit.args[1], 1); ++ assert_eq!(exit.args[2], 0); ++ } ++ e => panic!("Unexpected exit: {:?}", e), ++ } ++ } ++ ++ #[cfg(target_arch = "x86_64")] ++ #[test] ++ fn test_userspace_wrmsr_exit() { ++ use std::io::Write; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ #[rustfmt::skip] ++ let code = [ ++ 0x0F, 0x30, /* wrmsr */ ++ 0xF4 /* hlt */ ++ ]; ++ ++ if !vm.check_extension(Cap::X86UserSpaceMsr) { ++ return; ++ } ++ let cap = kvm_enable_cap { ++ cap: Cap::X86UserSpaceMsr as u32, ++ args: [MsrExitReason::Unknown.bits() as u64, 0, 0, 0], ++ ..Default::default() ++ }; ++ vm.enable_cap(&cap).unwrap(); ++ ++ let mem_size = 0x4000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x1000; ++ let slot: u32 = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: 0, ++ }; ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // Set up special registers ++ let mut vcpu_sregs = vcpu.get_sregs().unwrap(); ++ assert_ne!(vcpu_sregs.cs.base, 0); ++ assert_ne!(vcpu_sregs.cs.selector, 0); ++ vcpu_sregs.cs.base = 0; ++ vcpu_sregs.cs.selector = 0; ++ vcpu.set_sregs(&vcpu_sregs).unwrap(); ++ ++ // Set the Instruction Pointer to the guest address where we loaded ++ // the code, RCX to the MSR to be written, and EDX:EAX to the data to ++ // be written. ++ let mut vcpu_regs = vcpu.get_regs().unwrap(); ++ vcpu_regs.rip = guest_addr; ++ vcpu_regs.rcx = 0x474f4f00; ++ vcpu_regs.rax = 0xdeadbeef; ++ vcpu_regs.rdx = 0xd0c0ffee; ++ vcpu.set_regs(&vcpu_regs).unwrap(); ++ ++ match vcpu.run().unwrap() { ++ VcpuExit::X86Wrmsr(exit) => { ++ assert_eq!(exit.reason, MsrExitReason::Unknown); ++ assert_eq!(exit.index, 0x474f4f00); ++ assert_eq!(exit.data & 0xffffffff, 0xdeadbeef); ++ assert_eq!((exit.data >> 32) & 0xffffffff, 0xd0c0ffee); ++ } ++ e => panic!("Unexpected exit: {:?}", e), ++ } ++ } ++ ++ #[test] ++ #[cfg(target_arch = "x86_64")] ++ fn test_coalesced_pio() { ++ use crate::IoEventAddress; ++ use std::io::Write; ++ ++ const PORT: u64 = 0x2c; ++ const DATA: u64 = 0x39; ++ const SIZE: u32 = 1; ++ ++ #[rustfmt::skip] ++ let code = [ ++ 0xe6, 0x2c, // out 0x2c, al ++ 0xf4, // hlt ++ 0xe6, 0x2c, // out 0x2c, al ++ 0xf4, // hlt ++ ]; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ assert!(vm.check_extension(Cap::CoalescedPio)); ++ ++ // Prepare guest memory ++ let mem_size = 0x4000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x1000; ++ let slot = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: 0, ++ }; ++ ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let addr = IoEventAddress::Pio(PORT); ++ vm.register_coalesced_mmio(addr, SIZE).unwrap(); ++ ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // Map the MMIO ring ++ vcpu.map_coalesced_mmio_ring().unwrap(); ++ ++ // Set regs ++ let mut regs = vcpu.get_regs().unwrap(); ++ regs.rip = guest_addr; ++ regs.rax = DATA; ++ regs.rflags = 2; ++ vcpu.set_regs(®s).unwrap(); ++ ++ // Set sregs ++ let mut sregs = vcpu.get_sregs().unwrap(); ++ sregs.cs.base = 0; ++ sregs.cs.selector = 0; ++ vcpu.set_sregs(&sregs).unwrap(); ++ ++ // Run and check that the exit was caused by the hlt and not the port ++ // I/O ++ let exit = vcpu.run().unwrap(); ++ assert!(matches!(exit, VcpuExit::Hlt)); ++ ++ // Check that the ring buffer entry is what we expect ++ let entry = vcpu.coalesced_mmio_read().unwrap().unwrap(); ++ assert_eq!(entry.phys_addr, PORT); ++ assert_eq!(entry.len, 1); ++ assert_eq!(entry.data[0] as u64, DATA); ++ // SAFETY: this field is a u32 in all variants of the union, ++ // so access is always safe. ++ let pio = unsafe { entry.__bindgen_anon_1.pio }; ++ assert_eq!(pio, 1); ++ ++ // The ring buffer should be empty now ++ assert!(vcpu.coalesced_mmio_read().unwrap().is_none()); ++ ++ // Unregister and check that the next PIO write triggers an exit ++ vm.unregister_coalesced_mmio(addr, SIZE).unwrap(); ++ let exit = vcpu.run().unwrap(); ++ let VcpuExit::IoOut(port, data) = exit else { ++ panic!("Unexpected VM exit: {:?}", exit); ++ }; ++ assert_eq!(port, PORT as u16); ++ assert_eq!(data, (DATA as u8).to_le_bytes()); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "x86_64")] ++ fn test_coalesced_mmio() { ++ use crate::IoEventAddress; ++ use std::io::Write; ++ ++ const ADDR: u64 = 0x124; ++ const DATA: u64 = 0x39; ++ const SIZE: u32 = 2; ++ ++ #[rustfmt::skip] ++ let code = [ ++ 0x66, 0x31, 0xFF, // xor di,di ++ 0x66, 0xBF, 0x24, 0x01, // mov di, 0x124 ++ 0x67, 0x66, 0x89, 0x05, // mov WORD PTR [di], ax ++ 0xF4, // hlt ++ 0x66, 0x31, 0xFF, // xor di,di ++ 0x66, 0xBF, 0x24, 0x01, // mov di, 0x124 ++ 0x67, 0x66, 0x89, 0x05, // mov WORD PTR [di], ax ++ 0xF4, // hlt ++ ]; ++ ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ assert!(vm.check_extension(Cap::CoalescedMmio)); ++ ++ // Prepare guest memory ++ let mem_size = 0x4000; ++ let load_addr = mmap_anonymous(mem_size).as_ptr(); ++ let guest_addr: u64 = 0x1000; ++ let slot: u32 = 0; ++ let mem_region = kvm_userspace_memory_region { ++ slot, ++ guest_phys_addr: guest_addr, ++ memory_size: mem_size as u64, ++ userspace_addr: load_addr as u64, ++ flags: 0, ++ }; ++ ++ unsafe { ++ vm.set_user_memory_region(mem_region).unwrap(); ++ ++ // Get a mutable slice of `mem_size` from `load_addr`. ++ // This is safe because we mapped it before. ++ let mut slice = std::slice::from_raw_parts_mut(load_addr, mem_size); ++ slice.write_all(&code).unwrap(); ++ } ++ ++ let addr = IoEventAddress::Mmio(ADDR); ++ vm.register_coalesced_mmio(addr, SIZE).unwrap(); ++ ++ let mut vcpu = vm.create_vcpu(0).unwrap(); ++ ++ // Map the MMIO ring ++ vcpu.map_coalesced_mmio_ring().unwrap(); ++ ++ // Set regs ++ let mut regs = vcpu.get_regs().unwrap(); ++ regs.rip = guest_addr; ++ regs.rax = DATA; ++ regs.rdx = ADDR; ++ regs.rflags = 2; ++ vcpu.set_regs(®s).unwrap(); ++ ++ // Set sregs ++ let mut sregs = vcpu.get_sregs().unwrap(); ++ sregs.cs.base = 0; ++ sregs.cs.selector = 0; ++ vcpu.set_sregs(&sregs).unwrap(); ++ ++ // Run and check that the exit was caused by the hlt and not the MMIO ++ // access ++ let exit = vcpu.run().unwrap(); ++ assert!(matches!(exit, VcpuExit::Hlt)); ++ ++ // Check that the ring buffer entry is what we expect ++ let entry = vcpu.coalesced_mmio_read().unwrap().unwrap(); ++ assert_eq!(entry.phys_addr, ADDR); ++ assert_eq!(entry.len, SIZE); ++ assert_eq!(entry.data[0] as u64, DATA); ++ // SAFETY: this field is a u32 in all variants of the union, ++ // so access is always safe. ++ let pio = unsafe { entry.__bindgen_anon_1.pio }; ++ assert_eq!(pio, 0); ++ ++ // The ring buffer should be empty now ++ assert!(vcpu.coalesced_mmio_read().unwrap().is_none()); ++ ++ // Unregister and check that the next MMIO write triggers an exit ++ vm.unregister_coalesced_mmio(addr, SIZE).unwrap(); ++ let exit = vcpu.run().unwrap(); ++ let VcpuExit::MmioWrite(addr, data) = exit else { ++ panic!("Unexpected VM exit: {:?}", exit); ++ }; ++ assert_eq!(addr, ADDR); ++ assert_eq!(data, (DATA as u16).to_le_bytes()); + } + } +diff --git a/vendor/kvm-ioctls/src/ioctls/vm.rs b/vendor/kvm-ioctls/src/ioctls/vm.rs +index 6b9dc9c..39938ae 100644 +--- a/vendor/kvm-ioctls/src/ioctls/vm.rs ++++ b/vendor/kvm-ioctls/src/ioctls/vm.rs +@@ -1,3 +1,5 @@ ++// Copyright © 2024 Institute of Software, CAS. All rights reserved. ++// + // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + // SPDX-License-Identifier: Apache-2.0 OR MIT + // +@@ -20,15 +22,17 @@ use crate::ioctls::{KvmRunWrapper, Result}; + use crate::kvm_ioctls::*; + use vmm_sys_util::errno; + use vmm_sys_util::eventfd::EventFd; +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] ++use vmm_sys_util::ioctl::ioctl; ++#[cfg(target_arch = "x86_64")] + use vmm_sys_util::ioctl::ioctl_with_mut_ptr; +-use vmm_sys_util::ioctl::{ioctl, ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val}; ++use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val}; + + /// An address either in programmable I/O space or in memory mapped I/O space. + /// + /// The `IoEventAddress` is used for specifying the type when registering an event + /// in [register_ioevent](struct.VmFd.html#method.register_ioevent). +-#[derive(Debug)] ++#[derive(Debug, Clone, Copy)] + pub enum IoEventAddress { + /// Representation of an programmable I/O address. + Pio(u64), +@@ -42,7 +46,7 @@ pub enum IoEventAddress { + /// [`register_ioevent`](struct.VmFd.html#method.register_ioevent) + /// to disable filtering of events based on the datamatch flag. For details check the + /// [KVM API documentation](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt). +-#[derive(Debug)] ++#[derive(Debug, Clone, Copy)] + pub struct NoDatamatch; + impl From for u64 { + fn from(_: NoDatamatch) -> u64 { +@@ -111,6 +115,98 @@ impl VmFd { + } + } + ++ /// Creates/modifies a guest physical memory slot. ++ /// ++ /// See the documentation for `KVM_SET_USER_MEMORY_REGION2`. ++ /// ++ /// # Arguments ++ /// ++ /// * `user_memory_region2` - Guest physical memory slot. For details check the ++ /// `kvm_userspace_memory_region2` structure in the ++ /// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt). ++ /// ++ /// # Safety ++ /// ++ /// This function is unsafe because there is no guarantee `userspace_addr` points to a valid ++ /// memory region, nor the memory region lives as long as the kernel needs it to. ++ /// ++ /// The caller of this method must make sure that: ++ /// - the raw pointer (`userspace_addr`) points to valid memory ++ /// - the regions provided to KVM are not overlapping other memory regions. ++ /// - the guest_memfd points at a file created via KVM_CREATE_GUEST_MEMFD on ++ /// the current VM, and the target range must not be bound to any other memory region ++ /// ++ /// # Example ++ /// ++ /// ```rust ++ /// # extern crate kvm_ioctls; ++ /// extern crate kvm_bindings; ++ /// ++ /// use kvm_bindings::{ ++ /// kvm_create_guest_memfd, kvm_enable_cap, kvm_userspace_memory_region2, KVM_CAP_GUEST_MEMFD, ++ /// KVM_CAP_USER_MEMORY2, KVM_MEM_GUEST_MEMFD, ++ /// }; ++ /// use kvm_ioctls::Kvm; ++ /// use std::os::fd::RawFd; ++ /// ++ /// # #[cfg(target_arch = "x86_64")] ++ /// { ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// ++ /// let address_space = unsafe { libc::mmap(0 as _, 10000, 3, 34, -1, 0) }; ++ /// let userspace_addr = address_space as *const u8 as u64; ++ /// ++ /// let mut config = kvm_enable_cap { ++ /// cap: KVM_CAP_GUEST_MEMFD, ++ /// ..Default::default() ++ /// }; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// let gmem = kvm_create_guest_memfd { ++ /// size: 0x10000, ++ /// flags: 0, ++ /// reserved: [0; 6], ++ /// }; ++ /// ++ /// let fd: RawFd = unsafe { vm.create_guest_memfd(gmem).unwrap() }; ++ /// ++ /// config.cap = KVM_CAP_USER_MEMORY2; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// ++ /// let mem_region = kvm_userspace_memory_region2 { ++ /// slot: 0, ++ /// flags: KVM_MEM_GUEST_MEMFD, ++ /// guest_phys_addr: 0x10000 as u64, ++ /// memory_size: 0x10000 as u64, ++ /// userspace_addr, ++ /// guest_memfd_offset: 0, ++ /// guest_memfd: fd as u32, ++ /// pad1: 0, ++ /// pad2: [0; 14], ++ /// }; ++ /// unsafe { ++ /// vm.set_user_memory_region2(mem_region).unwrap(); ++ /// }; ++ /// } ++ /// ``` ++ pub unsafe fn set_user_memory_region2( ++ &self, ++ user_memory_region2: kvm_userspace_memory_region2, ++ ) -> Result<()> { ++ let ret = ioctl_with_ref(self, KVM_SET_USER_MEMORY_REGION2(), &user_memory_region2); ++ if ret == 0 { ++ Ok(()) ++ } else { ++ Err(errno::Error::last()) ++ } ++ } ++ + /// Sets the address of the three-page region in the VM's address space. + /// + /// See the documentation for `KVM_SET_TSS_ADDR`. +@@ -128,7 +224,7 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// vm.set_tss_address(0xfffb_d000).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_tss_address(&self, offset: usize) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd and we verify the return result. + let ret = unsafe { ioctl_with_val(self, KVM_SET_TSS_ADDR(), offset as c_ulong) }; +@@ -156,7 +252,7 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// vm.set_identity_map_address(0xfffb_c000).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_identity_map_address(&self, address: u64) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd and we verify the return result. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_IDENTITY_MAP_ADDR(), &address) }; +@@ -180,9 +276,9 @@ impl VmFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// vm.create_irq_chip().unwrap(); +- /// #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ /// #[cfg(target_arch = "aarch64")] + /// { + /// use kvm_bindings::{ + /// kvm_create_device, kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2, KVM_CREATE_DEVICE_TEST, +@@ -197,12 +293,7 @@ impl VmFd { + /// } + /// } + /// ``` +- #[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +- ))] ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + pub fn create_irq_chip(&self) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd and we verify the return result. + let ret = unsafe { ioctl(self, KVM_CREATE_IRQCHIP()) }; +@@ -237,7 +328,7 @@ impl VmFd { + /// irqchip.chip_id = KVM_IRQCHIP_PIC_MASTER; + /// vm.get_irqchip(&mut irqchip).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_irqchip(&self, irqchip: &mut kvm_irqchip) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_irqchip struct. + let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), irqchip) }; +@@ -273,7 +364,7 @@ impl VmFd { + /// // Your `irqchip` manipulation here. + /// vm.set_irqchip(&mut irqchip).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_irqchip(&self, irqchip: &kvm_irqchip) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_irqchip struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), irqchip) }; +@@ -300,10 +391,11 @@ impl VmFd { + /// + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); ++ /// vm.create_irq_chip().unwrap(); + /// let pit_config = kvm_pit_config::default(); + /// vm.create_pit2(pit_config).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn create_pit2(&self, pit_config: kvm_pit_config) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read + // the correct amount of memory from our pointer, and we verify the return result. +@@ -333,12 +425,13 @@ impl VmFd { + /// # use kvm_ioctls::Kvm; + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); ++ /// vm.create_irq_chip().unwrap(); + /// + /// let pit_config = kvm_pit_config::default(); + /// vm.create_pit2(pit_config).unwrap(); + /// let pitstate = vm.get_pit2().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_pit2(&self) -> Result { + let mut pitstate = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_pit_state2 struct. +@@ -368,6 +461,7 @@ impl VmFd { + /// # use kvm_ioctls::Kvm; + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); ++ /// vm.create_irq_chip().unwrap(); + /// + /// let pit_config = kvm_pit_config::default(); + /// vm.create_pit2(pit_config).unwrap(); +@@ -375,7 +469,7 @@ impl VmFd { + /// // Your `pitstate` manipulation here. + /// vm.set_pit2(&mut pitstate).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_pit2(&self, pitstate: &kvm_pit_state2) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_pit_state2 struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_PIT2(), pitstate) }; +@@ -404,7 +498,7 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// let clock = vm.get_clock().unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn get_clock(&self) -> Result { + let mut clock = Default::default(); + // SAFETY: Here we trust the kernel not to read past the end of the kvm_clock_data struct. +@@ -437,7 +531,7 @@ impl VmFd { + /// let mut clock = kvm_clock_data::default(); + /// vm.set_clock(&mut clock).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn set_clock(&self, clock: &kvm_clock_data) -> Result<()> { + // SAFETY: Here we trust the kernel not to read past the end of the kvm_clock_data struct. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_CLOCK(), clock) }; +@@ -478,15 +572,14 @@ impl VmFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let msi = kvm_msi::default(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// vm.create_irq_chip().unwrap(); + /// //vm.signal_msi(msi).unwrap(); + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn signal_msi(&self, msi: kvm_msi) -> Result { + // SAFETY: Safe because we allocated the structure and we know the kernel +@@ -523,17 +616,25 @@ impl VmFd { + /// + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// ++ /// #[cfg(target_arch = "x86_64")] + /// vm.create_irq_chip().unwrap(); + /// ++ /// #[cfg(target_arch = "riscv64")] ++ /// vm.create_device(&mut kvm_bindings::kvm_create_device { ++ /// type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_RISCV_AIA, ++ /// fd: 0, ++ /// flags: 0, ++ /// }) ++ /// .expect("Cannot create KVM vAIA device."); ++ /// + /// let irq_routing = kvm_irq_routing::default(); + /// vm.set_gsi_routing(&irq_routing).unwrap(); + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn set_gsi_routing(&self, irq_routing: &kvm_irq_routing) -> Result<()> { + // SAFETY: Safe because we allocated the structure and we know the kernel +@@ -738,7 +839,7 @@ impl VmFd { + /// }; + /// unsafe { vm.set_user_memory_region(mem_region).unwrap() }; + /// +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// // ASM code that just forces a MMIO Write. + /// let asm_code = [0xc6, 0x06, 0x00, 0x80, 0x00]; + /// #[cfg(target_arch = "aarch64")] +@@ -749,6 +850,13 @@ impl VmFd { + /// 0x00, 0x00, 0x00, + /// 0x14, /* b ; shouldn't get here, but if so loop forever */ + /// ]; ++ /// #[cfg(target_arch = "riscv64")] ++ /// let asm_code = [ ++ /// 0x17, 0x03, 0x00, 0x00, // auipc t1, 0; -> t1 ++ /// 0xa3, 0x23, 0x73, 0x00, // sw t2, t1 + 7; dirty current page ++ /// 0x23, 0x20, 0x75, 0x00, // sw t2, a0; trigger MMIO exit ++ /// 0x6f, 0x00, 0x00, 0x00, // j .;shouldn't get here, but if so loop forever ++ /// ]; + /// + /// // Write the code in the guest memory. This will generate a dirty page. + /// unsafe { +@@ -756,9 +864,9 @@ impl VmFd { + /// slice.write(&asm_code).unwrap(); + /// } + /// +- /// let vcpu_fd = vm.create_vcpu(0).unwrap(); ++ /// let mut vcpu_fd = vm.create_vcpu(0).unwrap(); + /// +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// // x86_64 specific registry setup. + /// let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap(); +@@ -788,6 +896,14 @@ impl VmFd { + /// vcpu_fd.set_one_reg(core_reg_base + 2 * 0, &mmio_addr.to_le_bytes()); // set X0 + /// } + /// ++ /// #[cfg(target_arch = "riscv64")] ++ /// { ++ /// let core_reg_base: u64 = 0x8030_0000_0200_0000; ++ /// let mmio_addr: u64 = guest_addr + mem_size as u64; ++ /// vcpu_fd.set_one_reg(core_reg_base, &guest_addr.to_le_bytes()); // set PC ++ /// vcpu_fd.set_one_reg(core_reg_base + 10, &mmio_addr.to_le_bytes()); // set A0 ++ /// } ++ /// + /// loop { + /// match vcpu_fd.run().expect("run failed") { + /// VcpuExit::MmioWrite(addr, data) => { +@@ -818,8 +934,7 @@ impl VmFd { + // For ease of access we are saving the bitmap in a u64 vector. We are using ceil to + // make sure we count all dirty pages even when `memory_size` is not a multiple of + // `page_size * 64`. +- let div_ceil = |dividend, divisor| (dividend + divisor - 1) / divisor; +- let bitmap_size = div_ceil(memory_size, page_size * 64); ++ let bitmap_size = memory_size.div_ceil(page_size * 64); + let mut bitmap = vec![0u64; bitmap_size]; + let dirtylog = kvm_dirty_log { + slot, +@@ -857,17 +972,16 @@ impl VmFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// let evtfd = EventFd::new(EFD_NONBLOCK).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// vm.create_irq_chip().unwrap(); + /// vm.register_irqfd(&evtfd, 0).unwrap(); + /// } + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()> { + let irqfd = kvm_irqfd { +@@ -908,7 +1022,7 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// let evtfd = EventFd::new(EFD_NONBLOCK).unwrap(); + /// let resamplefd = EventFd::new(EFD_NONBLOCK).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// vm.create_irq_chip().unwrap(); + /// vm.register_irqfd_with_resample(&evtfd, &resamplefd, 0) +@@ -916,10 +1030,9 @@ impl VmFd { + /// } + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn register_irqfd_with_resample( + &self, +@@ -964,7 +1077,7 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// let evtfd = EventFd::new(EFD_NONBLOCK).unwrap(); + /// let resamplefd = EventFd::new(EFD_NONBLOCK).unwrap(); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// vm.create_irq_chip().unwrap(); + /// vm.register_irqfd(&evtfd, 0).unwrap(); +@@ -975,10 +1088,9 @@ impl VmFd { + /// } + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()> { + let irqfd = kvm_irqfd { +@@ -1020,12 +1132,12 @@ impl VmFd { + /// fn arch_setup(vm_fd: &VmFd) { + /// // Arch-specific setup: + /// // For x86 architectures, it simply means calling vm.create_irq_chip().unwrap(). +- /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// # #[cfg(target_arch = "x86_64")] + /// # vm_fd.create_irq_chip().unwrap(); + /// // For Arm architectures, the IRQ controllers need to be setup first. + /// // Details please refer to the kernel documentation. + /// // https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt +- /// # #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { ++ /// # #[cfg(target_arch = "aarch64")] { + /// # vm_fd.create_vcpu(0).unwrap(); + /// # // ... rest of setup for Arm goes here + /// # } +@@ -1034,22 +1146,21 @@ impl VmFd { + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); + /// arch_setup(&vm); +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// { + /// vm.set_irq_line(4, true); + /// // ... + /// } +- /// #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ /// #[cfg(target_arch = "aarch64")] + /// { + /// vm.set_irq_line(0x01_00_0020, true); + /// // .... + /// } + /// ``` + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> { + let mut irq_level = kvm_irq_level::default(); +@@ -1159,7 +1270,8 @@ impl VmFd { + /// # use kvm_ioctls::Kvm; + /// use kvm_bindings::{ + /// kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2, kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3, +- /// kvm_device_type_KVM_DEV_TYPE_VFIO, KVM_CREATE_DEVICE_TEST, ++ /// kvm_device_type_KVM_DEV_TYPE_RISCV_AIA, kvm_device_type_KVM_DEV_TYPE_VFIO, ++ /// KVM_CREATE_DEVICE_TEST, + /// }; + /// let kvm = Kvm::new().unwrap(); + /// let vm = kvm.create_vm().unwrap(); +@@ -1168,29 +1280,33 @@ impl VmFd { + /// // whether the device type is supported. This will not create the device. + /// // To create the device the flag needs to be removed. + /// let mut device = kvm_bindings::kvm_create_device { +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// type_: kvm_device_type_KVM_DEV_TYPE_VFIO, +- /// #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ /// #[cfg(target_arch = "aarch64")] + /// type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3, ++ /// #[cfg(target_arch = "riscv64")] ++ /// type_: kvm_device_type_KVM_DEV_TYPE_RISCV_AIA, + /// fd: 0, + /// flags: KVM_CREATE_DEVICE_TEST, + /// }; + /// // On ARM, creating VGICv3 may fail due to hardware dependency. + /// // Retry to create VGICv2 in that case. + /// let device_fd = vm.create_device(&mut device).unwrap_or_else(|_| { +- /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ /// #[cfg(target_arch = "x86_64")] + /// panic!("Cannot create VFIO device."); +- /// #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ /// #[cfg(target_arch = "aarch64")] + /// { + /// device.type_ = kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2; + /// vm.create_device(&mut device) + /// .expect("Cannot create vGIC device") + /// } ++ /// #[cfg(target_arch = "riscv64")] ++ /// panic!("Cannot create vAIA device."); + /// }); + /// ``` + pub fn create_device(&self, device: &mut kvm_create_device) -> Result { + // SAFETY: Safe because we are calling this with the VM fd and we trust the kernel. +- let ret = unsafe { ioctl_with_ref(self, KVM_CREATE_DEVICE(), device) }; ++ let ret = unsafe { ioctl_with_mut_ref(self, KVM_CREATE_DEVICE(), device) }; + if ret == 0 { + // SAFETY: We validated the return of the function creating the fd and we trust the + // kernel. +@@ -1222,7 +1338,7 @@ impl VmFd { + /// let mut kvi = kvm_vcpu_init::default(); + /// vm.get_preferred_target(&mut kvi).unwrap(); + /// ``` +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + pub fn get_preferred_target(&self, kvi: &mut kvm_vcpu_init) -> Result<()> { + // SAFETY: The ioctl is safe because we allocated the struct and we know the + // kernel will write exactly the size of the struct. +@@ -1259,7 +1375,7 @@ impl VmFd { + /// let mut cap: kvm_enable_cap = Default::default(); + /// // This example cannot enable an arm/aarch64 capability since there + /// // is no capability available for these architectures. +- /// if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") { ++ /// if cfg!(target_arch = "x86_64") { + /// cap.cap = KVM_CAP_SPLIT_IRQCHIP; + /// // As per the KVM documentation, KVM_CAP_SPLIT_IRQCHIP only emulates + /// // the local APIC in kernel, expecting that a userspace IOAPIC will +@@ -1276,7 +1392,7 @@ impl VmFd { + /// vm.enable_cap(&cap).unwrap(); + /// } + /// ``` +- #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + pub fn enable_cap(&self, cap: &kvm_enable_cap) -> Result<()> { + // SAFETY: The ioctl is safe because we allocated the struct and we know the + // kernel will write exactly the size of the struct. +@@ -1326,6 +1442,156 @@ impl VmFd { + self.check_extension_int(c) > 0 + } + ++ /// Creates an anonymous file and returns a file descriptor that refers to it. ++ /// ++ /// See the documentation for `KVM_CREATE_GUEST_MEMFD`. ++ /// ++ /// Returns an io::Error when the file could not be created. ++ /// ++ /// # Arguments ++ /// ++ /// * kvm_create_guest_memfd - KVM create guest memfd structure. For details check the ++ /// `kvm_create_guest_memfd` structure in the ++ /// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt). ++ /// ++ /// # Example ++ /// ++ /// ```rust ++ /// # extern crate kvm_ioctls; ++ /// extern crate kvm_bindings; ++ /// ++ /// # use kvm_ioctls::Kvm; ++ /// use kvm_bindings::{kvm_create_guest_memfd, kvm_enable_cap, KVM_CAP_GUEST_MEMFD}; ++ /// use std::os::fd::RawFd; ++ /// ++ /// # #[cfg(target_arch = "x86_64")] ++ /// { ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// ++ /// let config = kvm_enable_cap { ++ /// cap: KVM_CAP_GUEST_MEMFD, ++ /// ..Default::default() ++ /// }; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// ++ /// let gmem = kvm_create_guest_memfd { ++ /// size: 0x1000, ++ /// flags: 0, ++ /// reserved: [0; 6], ++ /// }; ++ /// ++ /// let id: RawFd = vm.create_guest_memfd(gmem).unwrap(); ++ /// } ++ /// ``` ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] ++ pub fn create_guest_memfd(&self, gmem: kvm_create_guest_memfd) -> Result { ++ // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only ++ // read the correct amount of memory from our pointer, and we verify the return result. ++ let ret = unsafe { ioctl_with_ref(self, KVM_CREATE_GUEST_MEMFD(), &gmem) }; ++ if ret < 0 { ++ return Err(errno::Error::last()); ++ } ++ Ok(ret) ++ } ++ ++ /// Allows userspace to set memory attributes for a range of guest physical memory. ++ /// ++ /// See the documentation for `KVM_SET_MEMORY_ATTRIBUTES`. ++ /// ++ /// Returns an io::Error when the attributes could not be set. ++ /// ++ /// # Arguments ++ /// ++ /// * kvm_memory_attributes - KVM set memory attributes structure. For details check the ++ /// `kvm_memory_attributes` structure in the ++ /// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt). ++ /// ++ /// # Example ++ /// ++ /// ```rust ++ /// # extern crate kvm_ioctls; ++ /// extern crate kvm_bindings; ++ /// ++ /// # use kvm_ioctls::Kvm; ++ /// use kvm_bindings::{ ++ /// kvm_create_guest_memfd, kvm_enable_cap, kvm_memory_attributes, ++ /// kvm_userspace_memory_region2, KVM_CAP_GUEST_MEMFD, KVM_CAP_MEMORY_ATTRIBUTES, ++ /// KVM_CAP_USER_MEMORY2, KVM_MEMORY_ATTRIBUTE_PRIVATE, KVM_MEM_GUEST_MEMFD, ++ /// }; ++ /// use std::os::fd::RawFd; ++ /// ++ /// # #[cfg(target_arch = "x86_64")] ++ /// { ++ /// let kvm = Kvm::new().unwrap(); ++ /// let vm = kvm.create_vm().unwrap(); ++ /// let gmem = kvm_create_guest_memfd { ++ /// size: 0x10000, ++ /// flags: 0, ++ /// reserved: [0; 6], ++ /// }; ++ /// ++ /// let address_space = unsafe { libc::mmap(0 as _, 10000, 3, 34, -1, 0) }; ++ /// let userspace_addr = address_space as *const u8 as u64; ++ /// let mut config = kvm_enable_cap { ++ /// cap: KVM_CAP_GUEST_MEMFD, ++ /// ..Default::default() ++ /// }; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// ++ /// config.cap = KVM_CAP_USER_MEMORY2; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// config.cap = KVM_CAP_MEMORY_ATTRIBUTES; ++ /// ++ /// if vm.enable_cap(&config).is_err() { ++ /// return; ++ /// } ++ /// let fd: RawFd = unsafe { vm.create_guest_memfd(gmem).unwrap() }; ++ /// let mem_region = kvm_userspace_memory_region2 { ++ /// slot: 0, ++ /// flags: KVM_MEM_GUEST_MEMFD, ++ /// guest_phys_addr: 0x10000 as u64, ++ /// memory_size: 0x10000 as u64, ++ /// userspace_addr, ++ /// guest_memfd_offset: 0, ++ /// guest_memfd: fd as u32, ++ /// pad1: 0, ++ /// pad2: [0; 14], ++ /// }; ++ /// unsafe { ++ /// vm.set_user_memory_region2(mem_region).unwrap(); ++ /// }; ++ /// ++ /// let attr = kvm_memory_attributes { ++ /// address: 0x10000, ++ /// size: 0x10000, ++ /// attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64, ++ /// flags: 0, ++ /// }; ++ /// vm.set_memory_attributes(attr).unwrap(); ++ /// } ++ /// ``` ++ #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] ++ pub fn set_memory_attributes(&self, attr: kvm_memory_attributes) -> Result<()> { ++ // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read ++ // the correct amount of memory from our pointer, and we verify the return result. ++ let ret = unsafe { ioctl_with_ref(self, KVM_SET_MEMORY_ATTRIBUTES(), &attr) }; ++ if ret == 0 { ++ Ok(()) ++ } else { ++ Err(errno::Error::last()) ++ } ++ } ++ + /// Issues platform-specific memory encryption commands to manage encrypted VMs if + /// the platform supports creating those encrypted VMs. + /// +@@ -1362,7 +1628,7 @@ impl VmFd { + /// let mut init: kvm_sev_cmd = Default::default(); + /// unsafe { vm.encrypt_op(&mut init).unwrap() }; + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub unsafe fn encrypt_op(&self, op: *mut T) -> Result<()> { + let ret = ioctl_with_mut_ptr(self, KVM_MEMORY_ENCRYPT_OP(), op); + if ret == 0 { +@@ -1398,13 +1664,13 @@ impl VmFd { + /// let vm = kvm.create_vm().unwrap(); + /// + /// // Check whether SEV is enabled, optional. +- /// assert!(unsafe { vm.encrypt_op(null_mut() as *mut c_void) }.is_ok()); ++ /// unsafe { vm.encrypt_op(null_mut() as *mut c_void) }.unwrap(); + /// + /// // Initialize the SEV platform context. + /// let mut init: kvm_sev_cmd = Default::default(); + /// vm.encrypt_op_sev(&mut init).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn encrypt_op_sev(&self, op: &mut kvm_sev_cmd) -> Result<()> { + // SAFETY: Safe because we know that kernel will only read the correct amount of memory + // from our pointer and we know where it will write it (op.error). +@@ -1444,7 +1710,7 @@ impl VmFd { + /// + /// // Initialize the SEV platform context. + /// let mut init: kvm_sev_cmd = Default::default(); +- /// assert!(vm.encrypt_op_sev(&mut init).is_ok()); ++ /// vm.encrypt_op_sev(&mut init).unwrap(); + /// + /// // Create the memory encryption context. + /// let start_data: kvm_sev_launch_start = Default::default(); +@@ -1454,7 +1720,7 @@ impl VmFd { + /// sev_fd: sev.as_raw_fd() as _, + /// ..Default::default() + /// }; +- /// assert!(vm.encrypt_op_sev(&mut start).is_ok()); ++ /// vm.encrypt_op_sev(&mut start).unwrap(); + /// + /// let addr = unsafe { + /// libc::mmap( +@@ -1474,7 +1740,7 @@ impl VmFd { + /// }; + /// vm.register_enc_memory_region(&memory_region).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn register_enc_memory_region(&self, memory_region: &kvm_enc_region) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read + // the correct amount of memory from our pointer, and we verify the return result. +@@ -1520,7 +1786,7 @@ impl VmFd { + /// + /// // Initialize the SEV platform context. + /// let mut init: kvm_sev_cmd = Default::default(); +- /// assert!(vm.encrypt_op_sev(&mut init).is_ok()); ++ /// vm.encrypt_op_sev(&mut init).unwrap(); + /// + /// // Create the memory encryption context. + /// let start_data: kvm_sev_launch_start = Default::default(); +@@ -1530,7 +1796,7 @@ impl VmFd { + /// sev_fd: sev.as_raw_fd() as _, + /// ..Default::default() + /// }; +- /// assert!(vm.encrypt_op_sev(&mut start).is_ok()); ++ /// vm.encrypt_op_sev(&mut start).unwrap(); + /// + /// let addr = unsafe { + /// libc::mmap( +@@ -1551,7 +1817,7 @@ impl VmFd { + /// vm.register_enc_memory_region(&memory_region).unwrap(); + /// vm.unregister_enc_memory_region(&memory_region).unwrap(); + /// ``` +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + pub fn unregister_enc_memory_region(&self, memory_region: &kvm_enc_region) -> Result<()> { + // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read + // the correct amount of memory from our pointer, and we verify the return result. +@@ -1562,6 +1828,68 @@ impl VmFd { + Err(errno::Error::last()) + } + } ++ ++ /// Registers an address for coalesced MMIO. Write accesses to the address ++ /// will not cause a corresponding [`VcpuExit`](crate::VcpuExit), but ++ /// instead will be appended to the MMIO ring buffer. The [`VcpuFd`] can ++ /// read entries in the ring buffer via [`VcpuFd::coalesced_mmio_read()`]. ++ /// If entries are not read the buffer will eventually be full, ++ /// preventing further elements from being appended by the kernel. ++ /// ++ /// Needs `KVM_CAP_COALESCED_MMIO` ([`Cap::CoalescedMmio`](crate::Cap::CoalescedMmio)) ++ /// and/or `KVM_CAP_COALESCED_PIO` ([`Cap::CoalescedMmio`](crate::Cap::CoalescedPio)). ++ /// ++ /// See the documentation for `KVM_REGISTER_COALESCED_MMIO`. ++ /// ++ /// # Arguments ++ /// ++ /// * `addr` - Address being written to. ++ /// * `size` - The size of the write for the mechanism to trigger. ++ pub fn register_coalesced_mmio(&self, addr: IoEventAddress, size: u32) -> Result<()> { ++ let (addr, pio) = match addr { ++ IoEventAddress::Pio(addr) => (addr, 1), ++ IoEventAddress::Mmio(addr) => (addr, 0), ++ }; ++ let mut zone = kvm_coalesced_mmio_zone { ++ addr, ++ size, ++ ..Default::default() ++ }; ++ zone.__bindgen_anon_1.pio = pio; ++ ++ // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read ++ // the correct amount of memory from our pointer, and we verify the return result. ++ let ret = unsafe { ioctl_with_ref(self, KVM_REGISTER_COALESCED_MMIO(), &zone) }; ++ if ret != 0 { ++ return Err(errno::Error::last()); ++ } ++ Ok(()) ++ } ++ ++ /// Unregister an address that was previously registered via ++ /// [`register_coalesced_mmio()`](VmFd::register_coalesced_mmio). ++ /// ++ /// See the documentation for `KVM_UNREGISTER_COALESCED_MMIO`. ++ pub fn unregister_coalesced_mmio(&self, addr: IoEventAddress, size: u32) -> Result<()> { ++ let (addr, pio) = match addr { ++ IoEventAddress::Pio(addr) => (addr, 1), ++ IoEventAddress::Mmio(addr) => (addr, 0), ++ }; ++ let mut zone = kvm_coalesced_mmio_zone { ++ addr, ++ size, ++ ..Default::default() ++ }; ++ zone.__bindgen_anon_1.pio = pio; ++ ++ // SAFETY: Safe because we know that our file is a VM fd, we know the kernel will only read ++ // the correct amount of memory from our pointer, and we verify the return result. ++ let ret = unsafe { ioctl_with_ref(self, KVM_UNREGISTER_COALESCED_MMIO(), &zone) }; ++ if ret != 0 { ++ return Err(errno::Error::last()); ++ } ++ Ok(()) ++ } + } + + /// Helper function to create a new `VmFd`. +@@ -1586,9 +1914,9 @@ impl AsRawFd for VmFd { + /// * `vm` - The vm file descriptor. + /// * `flags` - Flags to be passed to `KVM_CREATE_DEVICE`. + #[cfg(test)] +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + pub(crate) fn create_gic_device(vm: &VmFd, flags: u32) -> DeviceFd { +- let mut gic_device = kvm_bindings::kvm_create_device { ++ let mut gic_device = kvm_create_device { + type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3, + fd: 0, + flags, +@@ -1610,15 +1938,16 @@ pub(crate) fn create_gic_device(vm: &VmFd, flags: u32) -> DeviceFd { + /// * `vgic` - The vGIC file descriptor. + /// * `nr_irqs` - Number of IRQs. + #[cfg(test)] +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + pub(crate) fn set_supported_nr_irqs(vgic: &DeviceFd, nr_irqs: u32) { +- let vgic_attr = kvm_bindings::kvm_device_attr { +- group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS, ++ let vgic_attr = kvm_device_attr { ++ group: KVM_DEV_ARM_VGIC_GRP_NR_IRQS, + attr: 0, + addr: &nr_irqs as *const u32 as u64, + flags: 0, + }; +- assert!(vgic.set_device_attr(&vgic_attr).is_ok()); ++ vgic.has_device_attr(&vgic_attr).unwrap(); ++ vgic.set_device_attr(&vgic_attr).unwrap(); + } + + /// Request the initialization of the vGIC. +@@ -1627,15 +1956,71 @@ pub(crate) fn set_supported_nr_irqs(vgic: &DeviceFd, nr_irqs: u32) { + /// + /// * `vgic` - The vGIC file descriptor. + #[cfg(test)] +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + pub(crate) fn request_gic_init(vgic: &DeviceFd) { +- let vgic_attr = kvm_bindings::kvm_device_attr { +- group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, +- attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT), ++ let vgic_attr = kvm_device_attr { ++ group: KVM_DEV_ARM_VGIC_GRP_CTRL, ++ attr: u64::from(KVM_DEV_ARM_VGIC_CTRL_INIT), + addr: 0, + flags: 0, + }; +- assert!(vgic.set_device_attr(&vgic_attr).is_ok()); ++ vgic.has_device_attr(&vgic_attr).unwrap(); ++ vgic.set_device_attr(&vgic_attr).unwrap(); ++} ++ ++/// Create a dummy AIA device. ++/// ++/// # Arguments ++/// ++/// * `vm` - The vm file descriptor. ++/// * `flags` - Flags to be passed to `KVM_CREATE_DEVICE`. ++#[cfg(test)] ++#[cfg(target_arch = "riscv64")] ++pub(crate) fn create_aia_device(vm: &VmFd, flags: u32) -> DeviceFd { ++ let mut aia_device = kvm_create_device { ++ type_: kvm_device_type_KVM_DEV_TYPE_RISCV_AIA, ++ fd: 0, ++ flags, ++ }; ++ vm.create_device(&mut aia_device) ++ .expect("Cannot create KVM vAIA device") ++} ++ ++/// Set supported number of IRQs for vAIA. ++/// ++/// # Arguments ++/// ++/// * `vaia` - The vAIA file descriptor. ++/// * `nr_irqs` - Number of IRQs. ++#[cfg(test)] ++#[cfg(target_arch = "riscv64")] ++pub(crate) fn set_supported_nr_irqs(vaia: &DeviceFd, nr_irqs: u32) { ++ let vaia_attr = kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ attr: u64::from(KVM_DEV_RISCV_AIA_CONFIG_SRCS), ++ addr: &nr_irqs as *const u32 as u64, ++ flags: 0, ++ }; ++ vaia.has_device_attr(&vaia_attr).unwrap(); ++ vaia.set_device_attr(&vaia_attr).unwrap(); ++} ++ ++/// Request the initialization of the vAIA. ++/// ++/// # Arguments ++/// ++/// * `vaia` - The vAIA file descriptor. ++#[cfg(test)] ++#[cfg(target_arch = "riscv64")] ++pub(crate) fn request_aia_init(vaia: &DeviceFd) { ++ let vaia_attr = kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_CTRL, ++ attr: u64::from(KVM_DEV_RISCV_AIA_CTRL_INIT), ++ addr: 0, ++ flags: 0, ++ }; ++ vaia.has_device_attr(&vaia_attr).unwrap(); ++ vaia.set_device_attr(&vaia_attr).unwrap(); + } + + #[cfg(test)] +@@ -1644,8 +2029,8 @@ mod tests { + use super::*; + use crate::Kvm; + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +- use std::{fs::OpenOptions, ptr::null_mut}; ++ #[cfg(target_arch = "x86_64")] ++ use std::{fs::OpenOptions, os::fd::IntoRawFd, ptr::null_mut}; + + use libc::EFD_NONBLOCK; + +@@ -1660,39 +2045,57 @@ mod tests { + userspace_addr: 0, + flags: 0, + }; +- assert!(unsafe { vm.set_user_memory_region(invalid_mem_region) }.is_err()); ++ unsafe { vm.set_user_memory_region(invalid_mem_region) }.unwrap_err(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ fn test_set_invalid_memory2() { ++ let kvm = Kvm::new().unwrap(); ++ let vm = kvm.create_vm().unwrap(); ++ let invalid_mem_region = kvm_userspace_memory_region2 { ++ slot: 0, ++ flags: 0, ++ guest_phys_addr: 0, ++ memory_size: 0, ++ userspace_addr: 0, ++ guest_memfd_offset: 0, ++ guest_memfd: 0, ++ pad1: 0, ++ pad2: [0; 14], ++ }; ++ unsafe { vm.set_user_memory_region2(invalid_mem_region) }.unwrap_err(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "x86_64")] + fn test_set_tss_address() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +- assert!(vm.set_tss_address(0xfffb_d000).is_ok()); ++ vm.set_tss_address(0xfffb_d000).unwrap(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_set_identity_map_address() { + let kvm = Kvm::new().unwrap(); + if kvm.check_extension(Cap::SetIdentityMapAddr) { + let vm = kvm.create_vm().unwrap(); +- assert!(vm.set_identity_map_address(0xfffb_c000).is_ok()); ++ vm.set_identity_map_address(0xfffb_c000).unwrap(); + vm.create_vcpu(0).unwrap(); + // Setting the identity map after creating a vCPU must fail. +- assert!(vm.set_identity_map_address(0xfffb_c000).is_err()); ++ vm.set_identity_map_address(0xfffb_c000).unwrap_err(); + } + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_irq_chip() { + use Cap; + + let kvm = Kvm::new().unwrap(); + assert!(kvm.check_extension(Cap::Irqchip)); + let vm = kvm.create_vm().unwrap(); +- assert!(vm.create_irq_chip().is_ok()); ++ vm.create_irq_chip().unwrap(); + + let mut irqchip = kvm_irqchip { + chip_id: KVM_IRQCHIP_PIC_MASTER, +@@ -1700,7 +2103,7 @@ mod tests { + }; + // Set the irq_base to a non-default value to check that set & get work. + irqchip.chip.pic.irq_base = 10; +- assert!(vm.set_irqchip(&irqchip).is_ok()); ++ vm.set_irqchip(&irqchip).unwrap(); + + // We initialize a dummy irq chip (`other_irqchip`) in which the + // function `get_irqchip` returns its result. +@@ -1708,14 +2111,14 @@ mod tests { + chip_id: KVM_IRQCHIP_PIC_MASTER, + ..Default::default() + }; +- assert!(vm.get_irqchip(&mut other_irqchip).is_ok()); ++ vm.get_irqchip(&mut other_irqchip).unwrap(); + + // Safe because we know that the irqchip type is PIC. + unsafe { assert_eq!(irqchip.chip.pic, other_irqchip.chip.pic) }; + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_irq_chip() { + use Cap; + +@@ -1726,7 +2129,7 @@ mod tests { + + // On ARM/arm64, a GICv2 is created. It's better to check ahead whether GICv2 + // can be emulated or not. +- let mut gic_device = kvm_bindings::kvm_create_device { ++ let mut gic_device = kvm_create_device { + type_: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2, + fd: 0, + flags: KVM_CREATE_DEVICE_TEST, +@@ -1737,11 +2140,14 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_pit2() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +- assert!(vm.create_pit2(kvm_pit_config::default()).is_ok()); ++ assert!(kvm.check_extension(Cap::Irqchip)); ++ vm.create_irq_chip().unwrap(); ++ ++ vm.create_pit2(kvm_pit_config::default()).unwrap(); + + let pit2 = vm.get_pit2().unwrap(); + vm.set_pit2(&pit2).unwrap(); +@@ -1753,7 +2159,7 @@ mod tests { + assert_eq!(pit2, other_pit2); + } + +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[test] + fn test_clock() { + let kvm = Kvm::new().unwrap(); +@@ -1784,24 +2190,24 @@ mod tests { + let kvm = Kvm::new().unwrap(); + let vm_fd = kvm.create_vm().unwrap(); + let evtfd = EventFd::new(EFD_NONBLOCK).unwrap(); +- assert!(vm_fd ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Pio(0xf4), NoDatamatch) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Mmio(0x1000), NoDatamatch) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Pio(0xc1), 0x7fu8) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Pio(0xc2), 0x1337u16) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Pio(0xc4), 0xdead_beefu32) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &IoEventAddress::Pio(0xc8), 0xdead_beef_dead_beefu64) +- .is_ok()); ++ .unwrap() + } + + #[test] +@@ -1815,33 +2221,33 @@ mod tests { + let mmio_addr = IoEventAddress::Mmio(0x1000); + + // First try to unregister addresses which have not been registered. +- assert!(vm_fd ++ vm_fd + .unregister_ioevent(&evtfd, &pio_addr, NoDatamatch) +- .is_err()); +- assert!(vm_fd ++ .unwrap_err(); ++ vm_fd + .unregister_ioevent(&evtfd, &mmio_addr, NoDatamatch) +- .is_err()); ++ .unwrap_err(); + + // Now register the addresses +- assert!(vm_fd ++ vm_fd + .register_ioevent(&evtfd, &pio_addr, NoDatamatch) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .register_ioevent(&evtfd, &mmio_addr, 0x1337u16) +- .is_ok()); ++ .unwrap(); + + // Try again unregistering the addresses. This time it should work + // since they have been previously registered. +- assert!(vm_fd ++ vm_fd + .unregister_ioevent(&evtfd, &pio_addr, NoDatamatch) +- .is_ok()); +- assert!(vm_fd ++ .unwrap(); ++ vm_fd + .unregister_ioevent(&evtfd, &mmio_addr, 0x1337u16) +- .is_ok()); ++ .unwrap(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_register_unregister_irqfd() { + let kvm = Kvm::new().unwrap(); + let vm_fd = kvm.create_vm().unwrap(); +@@ -1851,31 +2257,31 @@ mod tests { + let evtfd4 = EventFd::new(EFD_NONBLOCK).unwrap(); + let resamplefd = EventFd::new(EFD_NONBLOCK).unwrap(); + +- assert!(vm_fd.create_irq_chip().is_ok()); ++ vm_fd.create_irq_chip().unwrap(); + +- assert!(vm_fd.register_irqfd(&evtfd1, 4).is_ok()); +- assert!(vm_fd.register_irqfd(&evtfd2, 8).is_ok()); +- assert!(vm_fd.register_irqfd(&evtfd3, 4).is_ok()); +- assert!(vm_fd.unregister_irqfd(&evtfd2, 8).is_ok()); ++ vm_fd.register_irqfd(&evtfd1, 4).unwrap(); ++ vm_fd.register_irqfd(&evtfd2, 8).unwrap(); ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap(); ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); + // KVM irqfd doesn't report failure on this case:( +- assert!(vm_fd.unregister_irqfd(&evtfd2, 8).is_ok()); ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); + + // Duplicated eventfd registration. + // On x86_64 this fails as the event fd was already matched with a GSI. +- assert!(vm_fd.register_irqfd(&evtfd3, 4).is_err()); +- assert!(vm_fd.register_irqfd(&evtfd3, 5).is_err()); ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap_err(); ++ vm_fd.register_irqfd(&evtfd3, 5).unwrap_err(); + // KVM irqfd doesn't report failure on this case:( +- assert!(vm_fd.unregister_irqfd(&evtfd3, 5).is_ok()); ++ vm_fd.unregister_irqfd(&evtfd3, 5).unwrap(); + + if vm_fd.check_extension(Cap::IrqfdResample) { +- assert!(vm_fd ++ vm_fd + .register_irqfd_with_resample(&evtfd4, &resamplefd, 6) +- .is_ok()); +- assert!(vm_fd.unregister_irqfd(&evtfd4, 6).is_ok()); ++ .unwrap(); ++ vm_fd.unregister_irqfd(&evtfd4, 6).unwrap(); + } else { +- assert!(vm_fd ++ vm_fd + .register_irqfd_with_resample(&evtfd4, &resamplefd, 6) +- .is_err()); ++ .unwrap_err(); + } + } + +@@ -1902,44 +2308,102 @@ mod tests { + // Request the initialization of the vGIC. + request_gic_init(&vgic_fd); + +- assert!(vm_fd.register_irqfd(&evtfd1, 4).is_ok()); +- assert!(vm_fd.register_irqfd(&evtfd2, 8).is_ok()); +- assert!(vm_fd.register_irqfd(&evtfd3, 4).is_ok()); +- assert!(vm_fd.unregister_irqfd(&evtfd2, 8).is_ok()); ++ vm_fd.register_irqfd(&evtfd1, 4).unwrap(); ++ vm_fd.register_irqfd(&evtfd2, 8).unwrap(); ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap(); ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); + // KVM irqfd doesn't report failure on this case:( +- assert!(vm_fd.unregister_irqfd(&evtfd2, 8).is_ok()); ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); + + // Duplicated eventfd registration. + // On aarch64, this fails because setting up the interrupt controller is mandatory before + // registering any IRQ. +- assert!(vm_fd.register_irqfd(&evtfd3, 4).is_err()); +- assert!(vm_fd.register_irqfd(&evtfd3, 5).is_err()); ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap_err(); ++ vm_fd.register_irqfd(&evtfd3, 5).unwrap_err(); + // KVM irqfd doesn't report failure on this case:( +- assert!(vm_fd.unregister_irqfd(&evtfd3, 5).is_ok()); ++ vm_fd.unregister_irqfd(&evtfd3, 5).unwrap(); + + if vm_fd.check_extension(Cap::IrqfdResample) { +- assert!(vm_fd ++ vm_fd + .register_irqfd_with_resample(&evtfd4, &resamplefd, 6) +- .is_ok()); +- assert!(vm_fd.unregister_irqfd(&evtfd4, 6).is_ok()); ++ .unwrap(); ++ vm_fd.unregister_irqfd(&evtfd4, 6).unwrap(); + } else { +- assert!(vm_fd ++ vm_fd + .register_irqfd_with_resample(&evtfd4, &resamplefd, 6) +- .is_err()); ++ .unwrap_err(); + } + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "riscv64")] ++ fn test_register_unregister_irqfd() { ++ let kvm = Kvm::new().unwrap(); ++ let vm_fd = kvm.create_vm().unwrap(); ++ let evtfd1 = EventFd::new(EFD_NONBLOCK).unwrap(); ++ let evtfd2 = EventFd::new(EFD_NONBLOCK).unwrap(); ++ let evtfd3 = EventFd::new(EFD_NONBLOCK).unwrap(); ++ ++ // Create the vAIA device. ++ let vaia_fd = create_aia_device(&vm_fd, 0); ++ ++ // AIA on riscv64 requires at least one online vCPU prior to setting ++ // device attributes. Otherwise it would fail when trying ot set address ++ // of IMSIC. ++ vm_fd.create_vcpu(0).unwrap(); ++ ++ // Set maximum supported number of IRQs of the vAIA device to 128. ++ set_supported_nr_irqs(&vaia_fd, 128); ++ ++ // Before request vAIA device to initialize, APLIC and IMSIC must be set ++ let aplic_addr: u64 = 0x4000; ++ vaia_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: u64::from(KVM_DEV_RISCV_AIA_ADDR_APLIC), ++ addr: &aplic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ let imsic_addr: u64 = 0x8000; ++ vaia_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: 1u64, ++ addr: &imsic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ ++ // Initialize valid vAIA device. ++ request_aia_init(&vaia_fd); ++ ++ vm_fd.register_irqfd(&evtfd1, 4).unwrap(); ++ vm_fd.register_irqfd(&evtfd2, 8).unwrap(); ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap(); ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); ++ // KVM irqfd doesn't report failure on this case:( ++ vm_fd.unregister_irqfd(&evtfd2, 8).unwrap(); ++ ++ // Duplicated eventfd registration. ++ // On riscv64 this fails as the event fd was already matched with a GSI. ++ vm_fd.register_irqfd(&evtfd3, 4).unwrap_err(); ++ vm_fd.register_irqfd(&evtfd3, 5).unwrap_err(); ++ // KVM irqfd doesn't report failure on this case:( ++ vm_fd.unregister_irqfd(&evtfd3, 5).unwrap(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "x86_64")] + fn test_set_irq_line() { + let kvm = Kvm::new().unwrap(); + let vm_fd = kvm.create_vm().unwrap(); + +- assert!(vm_fd.create_irq_chip().is_ok()); ++ vm_fd.create_irq_chip().unwrap(); + +- assert!(vm_fd.set_irq_line(4, true).is_ok()); +- assert!(vm_fd.set_irq_line(4, false).is_ok()); +- assert!(vm_fd.set_irq_line(4, true).is_ok()); ++ vm_fd.set_irq_line(4, true).unwrap(); ++ vm_fd.set_irq_line(4, false).unwrap(); ++ vm_fd.set_irq_line(4, true).unwrap(); + } + + #[test] +@@ -1966,18 +2430,58 @@ mod tests { + // - irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.) (the vcpu_index field is ignored) + // - irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.) + // Hence, using irq_type = 1, irq_id = 32 (decimal), the irq field in hex is: 0x01_00_0020 +- assert!(vm_fd.set_irq_line(0x01_00_0020, true).is_ok()); +- assert!(vm_fd.set_irq_line(0x01_00_0020, false).is_ok()); +- assert!(vm_fd.set_irq_line(0x01_00_0020, true).is_ok()); ++ vm_fd.set_irq_line(0x01_00_0020, true).unwrap(); ++ vm_fd.set_irq_line(0x01_00_0020, false).unwrap(); ++ vm_fd.set_irq_line(0x01_00_0020, true).unwrap(); + + // Case 2: using irq_type = 2, vcpu_index = 0, irq_id = 16 (decimal), the irq field in hex is: 0x02_00_0010 +- assert!(vm_fd.set_irq_line(0x02_00_0010, true).is_ok()); +- assert!(vm_fd.set_irq_line(0x02_00_0010, false).is_ok()); +- assert!(vm_fd.set_irq_line(0x02_00_0010, true).is_ok()); ++ vm_fd.set_irq_line(0x02_00_0010, true).unwrap(); ++ vm_fd.set_irq_line(0x02_00_0010, false).unwrap(); ++ vm_fd.set_irq_line(0x02_00_0010, true).unwrap(); ++ } ++ ++ #[test] ++ #[cfg(target_arch = "riscv64")] ++ fn test_set_irq_line() { ++ let kvm = Kvm::new().unwrap(); ++ let vm_fd = kvm.create_vm().unwrap(); ++ vm_fd.create_vcpu(0).unwrap(); ++ ++ // Create the vAIA device. ++ let vaia_fd = create_aia_device(&vm_fd, 0); ++ // Set maximum supported number of IRQs of the vAIA device to 128. ++ set_supported_nr_irqs(&vaia_fd, 128); ++ ++ // Before request vAIA device to initialize, APLIC and IMSIC must be set ++ let aplic_addr: u64 = 0x4000; ++ vaia_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: u64::from(KVM_DEV_RISCV_AIA_ADDR_APLIC), ++ addr: &aplic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ let imsic_addr: u64 = 0x8000; ++ vaia_fd ++ .set_device_attr(&kvm_device_attr { ++ group: KVM_DEV_RISCV_AIA_GRP_ADDR, ++ attr: 1u64, ++ addr: &imsic_addr as *const u64 as u64, ++ flags: 0, ++ }) ++ .unwrap(); ++ ++ // Initialize valid vAIA device. ++ request_aia_init(&vaia_fd); ++ ++ vm_fd.set_irq_line(7, true).unwrap(); ++ vm_fd.set_irq_line(7, false).unwrap(); ++ vm_fd.set_irq_line(7, true).unwrap(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_faulty_vm_fd() { + let badf_errno = libc::EBADF; + +@@ -2073,15 +2577,19 @@ mod tests { + faulty_vm_fd.get_dirty_log(0, 0).unwrap_err().errno(), + badf_errno + ); ++ ++ // Don't drop the File object, or it'll notice the file it's trying to close is ++ // invalid and abort the process. ++ let _ = faulty_vm_fd.vm.into_raw_fd(); + } + + #[test] +- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++ #[cfg(target_arch = "aarch64")] + fn test_get_preferred_target() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +- let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default(); +- assert!(vm.get_preferred_target(&mut kvi).is_ok()); ++ let mut kvi = kvm_vcpu_init::default(); ++ vm.get_preferred_target(&mut kvi).unwrap(); + } + + /// As explained in the example code related to signal_msi(), sending +@@ -2089,31 +2597,30 @@ mod tests { + /// previously allocated from the guest itself. + #[test] + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + fn test_signal_msi_failure() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let msi = kvm_msi::default(); +- assert!(vm.signal_msi(msi).is_err()); ++ vm.signal_msi(msi).unwrap_err(); + } + + #[test] +- #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++ #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + fn test_enable_cap_failure() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + let cap: kvm_enable_cap = Default::default(); + // Providing the `kvm_enable_cap` structure filled with default() should + // always result in a failure as it is not a valid capability. +- assert!(vm.enable_cap(&cap).is_err()); ++ vm.enable_cap(&cap).unwrap_err(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + fn test_enable_split_irqchip_cap() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +@@ -2133,21 +2640,32 @@ mod tests { + // Because an IOAPIC supports 24 pins, that's the reason why this test + // picked this number as reference. + cap.args[0] = 24; +- assert!(vm.enable_cap(&cap).is_ok()); ++ vm.enable_cap(&cap).unwrap(); + } + + #[test] ++ #[cfg(any( ++ target_arch = "x86_64", ++ target_arch = "aarch64", ++ target_arch = "riscv64" ++ ))] + fn test_set_gsi_routing() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); +- if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") { +- let irq_routing = kvm_irq_routing::default(); +- // Expect failure for x86 since the irqchip is not created yet. +- assert!(vm.set_gsi_routing(&irq_routing).is_err()); +- vm.create_irq_chip().unwrap(); +- } + let irq_routing = kvm_irq_routing::default(); +- assert!(vm.set_gsi_routing(&irq_routing).is_ok()); ++ ++ // Expect failure for x86 since the irqchip is not created yet. ++ #[cfg(target_arch = "x86_64")] ++ vm.set_gsi_routing(&irq_routing).unwrap_err(); ++ #[cfg(target_arch = "x86_64")] ++ vm.create_irq_chip().unwrap(); ++ ++ // RISC-V 64-bit expect an AIA device to be created in advance of ++ // committing irq_routing table. ++ #[cfg(target_arch = "riscv64")] ++ create_aia_device(&vm, 0); ++ ++ vm.set_gsi_routing(&irq_routing).unwrap(); + } + + #[test] +@@ -2161,8 +2679,8 @@ mod tests { + + // Fails when input `id` = `max_vcpu_id` + let max_vcpu_id = kvm.get_max_vcpu_id(); +- let vcpu = vm.create_vcpu((max_vcpu_id - 1) as u64); +- assert!(vcpu.is_ok()); ++ vm.create_vcpu((max_vcpu_id - 1) as u64).unwrap(); ++ + let vcpu_err = vm.create_vcpu(max_vcpu_id as u64).err(); + assert_eq!(vcpu_err.unwrap().errno(), libc::EINVAL); + } +@@ -2175,18 +2693,18 @@ mod tests { + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[cfg_attr(not(has_sev), ignore)] + fn test_encrypt_op_sev() { + let kvm = Kvm::new().unwrap(); + let vm = kvm.create_vm().unwrap(); + + let mut init: kvm_sev_cmd = Default::default(); +- assert!(vm.encrypt_op_sev(&mut init).is_ok()); ++ vm.encrypt_op_sev(&mut init).unwrap(); + } + + #[test] +- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ #[cfg(target_arch = "x86_64")] + #[cfg_attr(not(has_sev), ignore)] + fn test_register_unregister_enc_memory_region() { + let sev = OpenOptions::new() +@@ -2202,7 +2720,7 @@ mod tests { + // https://www.kernel.org/doc/Documentation/virtual/kvm/amd-memory-encryption.rst + + let mut init: kvm_sev_cmd = Default::default(); +- assert!(vm.encrypt_op_sev(&mut init).is_ok()); ++ vm.encrypt_op_sev(&mut init).unwrap(); + + let start_data: kvm_sev_launch_start = Default::default(); + let mut start = kvm_sev_cmd { +@@ -2211,7 +2729,7 @@ mod tests { + sev_fd: sev.as_raw_fd() as _, + ..Default::default() + }; +- assert!(vm.encrypt_op_sev(&mut start).is_ok()); ++ vm.encrypt_op_sev(&mut start).unwrap(); + + let addr = unsafe { + libc::mmap( +@@ -2248,7 +2766,7 @@ mod tests { + .errno(), + libc::EINVAL + ); +- assert!(vm.register_enc_memory_region(&memory_region).is_ok()); +- assert!(vm.unregister_enc_memory_region(&memory_region).is_ok()); ++ vm.register_enc_memory_region(&memory_region).unwrap(); ++ vm.unregister_enc_memory_region(&memory_region).unwrap(); + } + } +diff --git a/vendor/kvm-ioctls/src/kvm_ioctls.rs b/vendor/kvm-ioctls/src/kvm_ioctls.rs +index 5b9360c..192b602 100644 +--- a/vendor/kvm-ioctls/src/kvm_ioctls.rs ++++ b/vendor/kvm-ioctls/src/kvm_ioctls.rs +@@ -13,18 +13,18 @@ use kvm_bindings::*; + + ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00); + ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list); + ioctl_io_nr!(KVM_CHECK_EXTENSION, KVMIO, 0x03); + ioctl_io_nr!(KVM_GET_VCPU_MMAP_SIZE, KVMIO, 0x04); + /* Available with KVM_CAP_EXT_CPUID */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2); + /* Available with KVM_CAP_EXT_EMUL_CPUID */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2); + /* Available with KVM_CAP_GET_MSR_FEATURES */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_MSR_FEATURE_INDEX_LIST, KVMIO, 0x0a, kvm_msr_list); + + // Ioctls for VM fds. +@@ -38,208 +38,213 @@ ioctl_iow_nr!( + 0x46, + kvm_userspace_memory_region + ); ++ioctl_iow_nr!( ++ KVM_SET_USER_MEMORY_REGION2, ++ KVMIO, ++ 0x49, ++ kvm_userspace_memory_region2 ++); + /* Available with KVM_CAP_SET_TSS_ADDR */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_io_nr!(KVM_SET_TSS_ADDR, KVMIO, 0x47); + /* Available with KVM_CAP_SET_IDENTITY_MAP_ADDR */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_IDENTITY_MAP_ADDR, KVMIO, 0x48, u64); ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] ++ioctl_iowr_nr!(KVM_CREATE_GUEST_MEMFD, KVMIO, 0xd4, kvm_create_guest_memfd); + /* Available with KVM_CAP_IRQCHIP */ +-#[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64", +- target_arch = "s390" +-))] ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "s390x"))] + ioctl_io_nr!(KVM_CREATE_IRQCHIP, KVMIO, 0x60); + /* Available with KVM_CAP_IRQCHIP */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level); ++/* Available with KVM_CAP_COALESCED_MMIO / KVM_CAP_COALESCED_PIO */ ++ioctl_iow_nr!( ++ KVM_REGISTER_COALESCED_MMIO, ++ KVMIO, ++ 0x67, ++ kvm_coalesced_mmio_zone ++); ++/* Available with KVM_CAP_COALESCED_MMIO / KVM_CAP_COALESCED_PIO */ ++ioctl_iow_nr!( ++ KVM_UNREGISTER_COALESCED_MMIO, ++ KVMIO, ++ 0x68, ++ kvm_coalesced_mmio_zone ++); + /* Available with KVM_CAP_IRQ_ROUTING */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + ioctl_iow_nr!(KVM_SET_GSI_ROUTING, KVMIO, 0x6a, kvm_irq_routing); + /* Available with KVM_CAP_IRQFD */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + ioctl_iow_nr!(KVM_IRQFD, KVMIO, 0x76, kvm_irqfd); + /* Available with KVM_CAP_PIT2 */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_CREATE_PIT2, KVMIO, 0x77, kvm_pit_config); + /* Available with KVM_CAP_IOEVENTFD */ + ioctl_iow_nr!(KVM_IOEVENTFD, KVMIO, 0x79, kvm_ioeventfd); + /* Available with KVM_CAP_IRQCHIP */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip); + /* Available with KVM_CAP_IRQCHIP */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip); + /* Available with KVM_CAP_ADJUST_CLOCK */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data); + /* Available with KVM_CAP_ADJUST_CLOCK */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_CLOCK, KVMIO, 0x7c, kvm_clock_data); + /* Available with KVM_CAP_PIT_STATE2 */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_PIT2, KVMIO, 0x9f, kvm_pit_state2); + /* Available with KVM_CAP_PIT_STATE2 */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2); + /* KVM_MEMORY_ENCRYPT_OP. Takes opaque platform dependent type: i.e. TDX or SEV */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong); + /* Available on SEV-enabled guests. */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_MEMORY_ENCRYPT_REG_REGION, KVMIO, 0xbb, kvm_enc_region); + /* Available on SEV-enabled guests. */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_MEMORY_ENCRYPT_UNREG_REGION, KVMIO, 0xbc, kvm_enc_region); + + // Ioctls for VCPU fds. + + ioctl_io_nr!(KVM_RUN, KVMIO, 0x80); +-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + ioctl_ior_nr!(KVM_GET_REGS, KVMIO, 0x81, kvm_regs); +-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + ioctl_iow_nr!(KVM_SET_REGS, KVMIO, 0x82, kvm_regs); + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", + target_arch = "powerpc", + target_arch = "powerpc64" + ))] + ioctl_ior_nr!(KVM_GET_SREGS, KVMIO, 0x83, kvm_sregs); + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", + target_arch = "powerpc", + target_arch = "powerpc64" + ))] + ioctl_iow_nr!(KVM_SET_SREGS, KVMIO, 0x84, kvm_sregs); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_TRANSLATE, KVMIO, 0x85, kvm_translation); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_MSRS, KVMIO, 0x88, kvm_msrs); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_MSRS, KVMIO, 0x89, kvm_msrs); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_FPU, KVMIO, 0x8c, kvm_fpu); +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_FPU, KVMIO, 0x8d, kvm_fpu); + /* Available with KVM_CAP_IRQCHIP */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_LAPIC, KVMIO, 0x8e, kvm_lapic_state); + /* Available with KVM_CAP_IRQCHIP */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_LAPIC, KVMIO, 0x8f, kvm_lapic_state); + /* Available with KVM_CAP_EXT_CPUID */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_CPUID2, KVMIO, 0x90, kvm_cpuid2); + /* Available with KVM_CAP_EXT_CPUID */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iowr_nr!(KVM_GET_CPUID2, KVMIO, 0x91, kvm_cpuid2); + /* Available with KVM_CAP_MP_STATE */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + ioctl_ior_nr!(KVM_GET_MP_STATE, KVMIO, 0x98, kvm_mp_state); + /* Available with KVM_CAP_MP_STATE */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", + target_arch = "aarch64", +- target_arch = "s390" ++ target_arch = "riscv64", ++ target_arch = "s390x" + ))] + ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state); ++/* Available with KVM_CAP_USER_NMI */ ++#[cfg(target_arch = "x86_64")] ++ioctl_io_nr!(KVM_NMI, KVMIO, 0x9a); + /* Available with KVM_CAP_VCPU_EVENTS */ +-#[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +-))] ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + ioctl_ior_nr!(KVM_GET_VCPU_EVENTS, KVMIO, 0x9f, kvm_vcpu_events); + /* Available with KVM_CAP_VCPU_EVENTS */ +-#[cfg(any( +- target_arch = "x86", +- target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" +-))] ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events); + /* Available with KVM_CAP_DEBUGREGS */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_DEBUGREGS, KVMIO, 0xa1, kvm_debugregs); + /* Available with KVM_CAP_DEBUGREGS */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_DEBUGREGS, KVMIO, 0xa2, kvm_debugregs); + /* Available with KVM_CAP_XSAVE */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_XSAVE, KVMIO, 0xa4, kvm_xsave); + /* Available with KVM_CAP_XSAVE */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_XSAVE, KVMIO, 0xa5, kvm_xsave); + /* Available with KVM_CAP_XCRS */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_ior_nr!(KVM_GET_XCRS, KVMIO, 0xa6, kvm_xcrs); + /* Available with KVM_CAP_XCRS */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_iow_nr!(KVM_SET_XCRS, KVMIO, 0xa7, kvm_xcrs); + /* Available with KVM_CAP_KVMCLOCK_CTRL */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_io_nr!(KVM_KVMCLOCK_CTRL, KVMIO, 0xad); + + /* Available with KVM_CAP_TSC_CONTROL */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_io_nr!(KVM_SET_TSC_KHZ, KVMIO, 0xa2); + /* Available with KVM_CAP_GET_TSC_KHZ */ +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++#[cfg(target_arch = "x86_64")] + ioctl_io_nr!(KVM_GET_TSC_KHZ, KVMIO, 0xa3); + + /* Available with KVM_CAP_ENABLE_CAP */ +-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] ++#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + ioctl_iow_nr!(KVM_ENABLE_CAP, KVMIO, 0xa3, kvm_enable_cap); + /* Available with KVM_CAP_SIGNAL_MSI */ + #[cfg(any( +- target_arch = "x86", + target_arch = "x86_64", +- target_arch = "arm", +- target_arch = "aarch64" ++ target_arch = "aarch64", ++ target_arch = "riscv64" + ))] + ioctl_iow_nr!(KVM_SIGNAL_MSI, KVMIO, 0xa5, kvm_msi); + /* Available with KVM_CAP_ONE_REG */ +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + ioctl_iow_nr!(KVM_GET_ONE_REG, KVMIO, 0xab, kvm_one_reg); +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg); +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init); +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(target_arch = "aarch64")] + ioctl_ior_nr!(KVM_ARM_PREFERRED_TARGET, KVMIO, 0xaf, kvm_vcpu_init); +-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list); + ++/* Available with KVM_CAP_X86_SMM */ ++#[cfg(target_arch = "x86_64")] ++ioctl_io_nr!(KVM_SMI, KVMIO, 0xb7); ++ + /* Available with KVM_CAP_ARM_SVE */ + #[cfg(target_arch = "aarch64")] + ioctl_iow_nr!(KVM_ARM_VCPU_FINALIZE, KVMIO, 0xc2, std::os::raw::c_int); +@@ -247,6 +252,14 @@ ioctl_iow_nr!(KVM_ARM_VCPU_FINALIZE, KVMIO, 0xc2, std::os::raw::c_int); + /* Available with KVM_CAP_SET_GUEST_DEBUG */ + ioctl_iow_nr!(KVM_SET_GUEST_DEBUG, KVMIO, 0x9b, kvm_guest_debug); + ++#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] ++ioctl_iow_nr!( ++ KVM_SET_MEMORY_ATTRIBUTES, ++ KVMIO, ++ 0xd2, ++ kvm_memory_attributes ++); ++ + // Device ioctls. + + /* Available with KVM_CAP_DEVICE_CTRL */ +diff --git a/vendor/kvm-ioctls/src/lib.rs b/vendor/kvm-ioctls/src/lib.rs +index a00f203..278e21b 100644 +--- a/vendor/kvm-ioctls/src/lib.rs ++++ b/vendor/kvm-ioctls/src/lib.rs +@@ -1,3 +1,5 @@ ++// Copyright © 2024 Institute of Software, CAS. All rights reserved. ++// + // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + // SPDX-License-Identifier: Apache-2.0 OR MIT + // +@@ -5,6 +7,9 @@ + // Use of this source code is governed by a BSD-style license that can be + // found in the THIRD-PARTY file. + #![deny(missing_docs)] ++#![deny(missing_copy_implementations)] ++#![deny(missing_debug_implementations)] ++#![warn(clippy::assertions_on_result_states)] + + //! A safe wrapper around the kernel's KVM interface. + //! +@@ -18,6 +23,7 @@ + //! + //! - x86_64 + //! - arm64 (experimental) ++//! - riscv64 (experimental) + //! + //! **NOTE:** The list of available ioctls is not extensive. + //! +@@ -27,6 +33,7 @@ + //! On the vCPU we are running machine specific code. This example is based on + //! the [LWN article](https://lwn.net/Articles/658511/) on using the KVM API. + //! The aarch64 example was modified accordingly. ++//! The riscv64 example was modified accordingly. + //! + //! To get code running on the vCPU we are going through the following steps: + //! +@@ -66,7 +73,7 @@ + //! let asm_code: &[u8]; + //! + //! // Setting up architectural dependent values. +-//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++//! #[cfg(target_arch = "x86_64")] + //! { + //! asm_code = &[ + //! 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */ +@@ -90,6 +97,15 @@ + //! 0x14, /* b ; shouldn't get here, but if so loop forever */ + //! ]; + //! } ++//! #[cfg(target_arch = "riscv64")] ++//! { ++//! asm_code = &[ ++//! 0x17, 0x03, 0x00, 0x00, // auipc t1, 0; -> t1 ++//! 0xa3, 0x23, 0x73, 0x00, // sw t2, t1 + 7; dirty current page ++//! 0x23, 0x20, 0x75, 0x00, // sw t2, a0; trigger MMIO exit ++//! 0x6f, 0x00, 0x00, 0x00, // j .;shouldn't get here, but if so loop forever ++//! ]; ++//! } + //! + //! // 1. Instantiate KVM. + //! let kvm = Kvm::new().unwrap(); +@@ -128,10 +144,10 @@ + //! } + //! + //! // 4. Create one vCPU. +-//! let vcpu_fd = vm.create_vcpu(0).unwrap(); ++//! let mut vcpu_fd = vm.create_vcpu(0).unwrap(); + //! + //! // 5. Initialize general purpose and special registers. +-//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++//! #[cfg(target_arch = "x86_64")] + //! { + //! // x86_64 specific registry setup. + //! let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap(); +@@ -162,6 +178,17 @@ + //! vcpu_fd.set_one_reg(core_reg_base + 2 * 0, &mmio_addr.to_le_bytes()); + //! } + //! ++//! #[cfg(target_arch = "riscv64")] ++//! { ++//! // riscv64 specific register setup. ++//! let core_reg_base: u64 = 0x8030_0000_0200_0000; ++//! let mmio_addr: u64 = guest_addr + mem_size as u64; ++//! // set PC ++//! vcpu_fd.set_one_reg(core_reg_base, &guest_addr.to_le_bytes()); ++//! // set A0 ++//! vcpu_fd.set_one_reg(core_reg_base + 10, &mmio_addr.to_le_bytes()); ++//! } ++//! + //! // 6. Run code on the vCPU. + //! loop { + //! match vcpu_fd.run().expect("run failed") { +@@ -192,7 +219,7 @@ + //! // Since on aarch64 there is not halt instruction, + //! // we break immediately after the last known instruction + //! // of the asm code example so that we avoid an infinite loop. +-//! #[cfg(target_arch = "aarch64")] ++//! #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + //! break; + //! } + //! VcpuExit::Hlt => { +@@ -217,10 +244,12 @@ mod ioctls; + pub use cap::Cap; + pub use ioctls::device::DeviceFd; + pub use ioctls::system::Kvm; +-pub use ioctls::vcpu::{VcpuExit, VcpuFd}; ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] ++pub use ioctls::vcpu::reg_size; ++pub use ioctls::vcpu::{HypercallExit, VcpuExit, VcpuFd}; + +-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +-pub use ioctls::vcpu::SyncReg; ++#[cfg(target_arch = "x86_64")] ++pub use ioctls::vcpu::{MsrExitReason, ReadMsrExit, SyncReg, WriteMsrExit}; + + pub use ioctls::vm::{IoEventAddress, NoDatamatch, VmFd}; + // The following example is used to verify that our public +@@ -228,7 +257,7 @@ pub use ioctls::vm::{IoEventAddress, NoDatamatch, VmFd}; + /// # Example + /// + /// ``` +-/// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++/// #[cfg(target_arch = "x86_64")] + /// use kvm_ioctls::{Error, KvmRunWrapper}; + /// ``` + pub use ioctls::KvmRunWrapper; +diff --git a/vendor/vmm-sys-util/.cargo-checksum.json b/vendor/vmm-sys-util/.cargo-checksum.json +index a90b668..de34117 100644 +--- a/vendor/vmm-sys-util/.cargo-checksum.json ++++ b/vendor/vmm-sys-util/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{"CHANGELOG.md":"835b7864bab328acbc7d62af2f9cea5f8b7193713cda499d49162c643b6af733","CODEOWNERS":"6da80e22d851aaf8a3531a1fa9d6dc2418cc6de26c1759db6bfdfc5dda32c703","Cargo.toml":"4f81b61c76c31646845df5829e6a2d3d0929fa2fa031d2d49e73725797b5ba7d","LICENSE-BSD-3-Clause":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","README.md":"49c4867574bcd896b33a9aba45e9cb02fa5b44899430343401305fa17fb5f3a5","coverage_config_aarch64.json":"3a91df4ec88e8b73823f20217332b076ead5e3cd352cb4b1ba083f73b825fa62","coverage_config_x86_64.json":"e5159dc03ada035e0dc27a977115eca0039fe595f426ccd3a8a59257484d2ecd","src/errno.rs":"e6c5699346bfed7fdfe061e30bfac96d4cc56e17d94aea369e28f98126e1903e","src/fam.rs":"91cc4f58dd99bacc828e707d9ae8d8b3771e9b3c491cfe238bf7e7a367b23420","src/lib.rs":"4521a8eeeeb3304fe36a0fa7881bdb420aaf4af9c469a1adfad535e1b47cf6ed","src/linux/aio.rs":"9f0f1bfc2489c09c1f723070910299171528e24ec99a82a4dfd55b3a6a44493c","src/linux/epoll.rs":"eb19e3a47479b934ebd6a5f8da291db3f600efc208ce464a0062baed5cf53fc7","src/linux/eventfd.rs":"a6da50e5ea00f57cca54bd6a5900a3fb479e707e70ff8a78d0ab5e1c593499bf","src/linux/fallocate.rs":"cc913a67892584d7125522ab2fde363c3d6e746e639b4bc4ff62640fbb206903","src/linux/ioctl.rs":"18453260ff88389347e23ff549eb1ecd334ecf0e2da34fcedf33128a98a547d1","src/linux/mod.rs":"6c8c3a7a8e49ba778e9c308ddeaef38e445dadfeb17e1362d476d0892e9b8ebd","src/linux/poll.rs":"0df06696596b6dc22884d19258848bcdbac026be7763d70c12059aeb075337e3","src/linux/seek_hole.rs":"7fe9a94452c40e7dc75690fa3230f803641ff8cb6651648724fbb07a93e44b50","src/linux/signal.rs":"9b6d50cf46d6334d2a5f1ce484f9af47a7eca48bd9edaa8704105c30dbc4bfc4","src/linux/sock_ctrl_msg.rs":"d102a0355061c92da7b87d10bc7c4386454d59a153d8e0787ce09ffa4e424352","src/linux/timerfd.rs":"68088850b33489e84b8a9fc04d0aa68d01ed5916f6cb3f58451e3e1d7de5fc5c","src/linux/write_zeroes.rs":"960c0e40c6333f83a737c37609362dcd91e12f407898a3c06b1b12d594daad34","src/metric.rs":"f48ac6edf2a84cdb67d9388d81116ccd876198027ea7026c94d112620e3e5fe4","src/rand.rs":"7f8e0a7e2a15342d449383c461c72af0c0ced3f2016f755165173098a42e5da1","src/syscall.rs":"55fba6cc4f7aa622cc7398a29d79e3d98102e089d30e9a1c79a6e105a052ea9b","src/tempfile.rs":"9446711c0e7864541f69bbeb20a86c19a3786477ac57e7ee7d6c3fa5bbf01f17","src/unix/file_traits.rs":"cc0df75e2efb9a314daafe96799b301c77da8bd8195100311e936d625c936493","src/unix/mod.rs":"7686c7c8f72f22a9a2ee80bb9a083f73b97bc6e76a277b87b7497c68e630a092","src/unix/tempdir.rs":"8c0efa43beade5586c7474319e2c2cd2bb261d913f0c47a72b6593c577715ba8","src/unix/terminal.rs":"74d4881db109e7698b68b99f3376a11708ecfed8efac7ec39c5d2a62c13274d7"},"package":"dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"} +\ No newline at end of file ++{"files":{"CHANGELOG.md":"e32224290f2ccd3df026a4d007e3a05e6c445bbcc06f290a65056a8c42679f8c","CODEOWNERS":"b61fcc4bd34427668424c0d6764eeb26fd224466b4d5dbd2da969b2c23240c1a","Cargo.toml":"7df53c5526d1aaee6b065e9461e13e13d9275b1adf737c2be8a36954496c0040","LICENSE-BSD-3-Clause":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","README.md":"49c4867574bcd896b33a9aba45e9cb02fa5b44899430343401305fa17fb5f3a5","coverage_config_aarch64.json":"3a91df4ec88e8b73823f20217332b076ead5e3cd352cb4b1ba083f73b825fa62","coverage_config_x86_64.json":"df83df24b4e373a921b86ff5978a4cd24b8e6a87ce8db66190bbcd91947cccb6","src/errno.rs":"e6c5699346bfed7fdfe061e30bfac96d4cc56e17d94aea369e28f98126e1903e","src/fam.rs":"496e3d91131d0d2e2fb64a75ff09bfa335c1e4a481c8d8b0aaecf24bab42e068","src/lib.rs":"6197742faa4dc2eb256de637ccbeac7a2f653a10cd820404b3a1bb324dbc6f68","src/linux/aio.rs":"1eebe7138f8e9f6367a87439c92e50601105e0326ef448612d4929a9bed0834c","src/linux/epoll.rs":"628824874a371637ed62df4ce56f73df1dde2f4dbfd981794398886a89796cdf","src/linux/eventfd.rs":"a6da50e5ea00f57cca54bd6a5900a3fb479e707e70ff8a78d0ab5e1c593499bf","src/linux/fallocate.rs":"5a7c02569e433cd29a2058975647781a07ce42288979732ae34cb7b71d468518","src/linux/ioctl.rs":"18453260ff88389347e23ff549eb1ecd334ecf0e2da34fcedf33128a98a547d1","src/linux/mod.rs":"6c8c3a7a8e49ba778e9c308ddeaef38e445dadfeb17e1362d476d0892e9b8ebd","src/linux/poll.rs":"52a6609117190489d2677d53737958e3f9d7222216e1ea204b1e19fa86aee173","src/linux/seek_hole.rs":"33111a5c94a6d2e6a5f03fc82092d6300680552d25ffec098f30093edc442bc5","src/linux/signal.rs":"9b6d50cf46d6334d2a5f1ce484f9af47a7eca48bd9edaa8704105c30dbc4bfc4","src/linux/sock_ctrl_msg.rs":"a54d4d321cedf3ce8856cfd2af029a692e676e754bdc5c252e2a4440c1904c6c","src/linux/timerfd.rs":"501f5373b3b733afe9e0606ac2b5b419b63433aa086fcfe434c493f7f4952d38","src/linux/write_zeroes.rs":"0a105f2b12d2c6722c3813c7bcf69df2d2d2884c24fa1f8bda3e3656b8ef03a2","src/metric.rs":"f48ac6edf2a84cdb67d9388d81116ccd876198027ea7026c94d112620e3e5fe4","src/rand.rs":"2531c160515c8e6e8506d2b7e9ae7329854831f700eb94da3329b00218a843ee","src/syscall.rs":"1b90fb6b941d1de8bc149205bafdff4826821311e5295b598b7440603bdabe6e","src/tempfile.rs":"74e985b6a90ce259b4619bca8c01e74dd5442a1efe587b9f7ed24ee36d2a2dc2","src/unix/file_traits.rs":"cc0df75e2efb9a314daafe96799b301c77da8bd8195100311e936d625c936493","src/unix/mod.rs":"7686c7c8f72f22a9a2ee80bb9a083f73b97bc6e76a277b87b7497c68e630a092","src/unix/tempdir.rs":"206cb8c87178da011fa77e2948029dfdac9ebf58fd408dcd6562672f35f020a5","src/unix/terminal.rs":"74d4881db109e7698b68b99f3376a11708ecfed8efac7ec39c5d2a62c13274d7"},"package":"1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"} +\ No newline at end of file +diff --git a/vendor/vmm-sys-util/CHANGELOG.md b/vendor/vmm-sys-util/CHANGELOG.md +index 2a08682..dd5145d 100644 +--- a/vendor/vmm-sys-util/CHANGELOG.md ++++ b/vendor/vmm-sys-util/CHANGELOG.md +@@ -1,4 +1,27 @@ + # Changelog ++ ++## v0.12.1 ++ ++### Changed ++- [[#215](https://github.com/rust-vmm/vmm-sys-util/pull/215)]: Make ++ `as_mut_fam_struct()` public and unsafe to let users modify fields of the ++ header other than the length. ++ ++## v0.12.0 ++ ++### Changed ++- Added all features to the generated docs.rs documentation. ++- Fixed a bug in `serde` implementation of `FamStructWrapper` which allowed out of ++ bounds memory access from Rust-safe code. See the related GHSA here: ++ https://github.com/rust-vmm/vmm-sys-util/security/advisories/GHSA-875g-mfp6-g7f9 ++ for more information. ++ ++## v0.11.2 ++ ++### Changed ++- [[#201](https://github.com/rust-vmm/vmm-sys-util/pull/201)] Updated `SyscallReturnCode` ++ to accept any signed integer type. ++ + ## v0.11.1 + + ### Changed +diff --git a/vendor/vmm-sys-util/CODEOWNERS b/vendor/vmm-sys-util/CODEOWNERS +index b0440e9..c650fc4 100644 +--- a/vendor/vmm-sys-util/CODEOWNERS ++++ b/vendor/vmm-sys-util/CODEOWNERS +@@ -1 +1 @@ +-* @liujing2 @sameo @andreeaflorescu @jiangliu ++* @liujing2 @sameo @andreeaflorescu @jiangliu @roypat @JonathanWoollett-Light +diff --git a/vendor/vmm-sys-util/Cargo.toml b/vendor/vmm-sys-util/Cargo.toml +index f1da15c..2719169 100644 +--- a/vendor/vmm-sys-util/Cargo.toml ++++ b/vendor/vmm-sys-util/Cargo.toml +@@ -12,14 +12,21 @@ + [package] + edition = "2021" + name = "vmm-sys-util" +-version = "0.11.1" ++version = "0.12.1" + authors = ["Intel Virtualization Team "] + description = "A system utility set" + readme = "README.md" + keywords = ["utils"] + license = "BSD-3-Clause" + repository = "https://github.com/rust-vmm/vmm-sys-util" +-resolver = "2" ++ ++[package.metadata.docs.rs] ++all-features = true ++rustdoc-args = [ ++ "--cfg", ++ "docsrs", ++] ++ + [dependencies.libc] + version = "0.2.39" + +@@ -30,10 +37,18 @@ optional = true + [dependencies.serde_derive] + version = "1.0.27" + optional = true ++ ++[dev-dependencies.bincode] ++version = "1.3.3" ++ + [dev-dependencies.serde_json] + version = "1.0.9" + + [features] +-with-serde = ["serde", "serde_derive"] ++with-serde = [ ++ "serde", ++ "serde_derive", ++] ++ + [target."cfg(any(target_os = \"linux\", target_os = \"android\"))".dependencies.bitflags] + version = "1.0" +diff --git a/vendor/vmm-sys-util/coverage_config_x86_64.json b/vendor/vmm-sys-util/coverage_config_x86_64.json +index 4277fc0..2c55cb3 100644 +--- a/vendor/vmm-sys-util/coverage_config_x86_64.json ++++ b/vendor/vmm-sys-util/coverage_config_x86_64.json +@@ -1,5 +1,5 @@ + { +- "coverage_score": 87.1, ++ "coverage_score": 84.39, + "exclude_path": "", + "crate_features": "" + } +diff --git a/vendor/vmm-sys-util/src/fam.rs b/vendor/vmm-sys-util/src/fam.rs +index 0d62b0f..13ba4c2 100644 +--- a/vendor/vmm-sys-util/src/fam.rs ++++ b/vendor/vmm-sys-util/src/fam.rs +@@ -50,6 +50,8 @@ impl fmt::Display for Error { + /// * the implementer should be a POD + /// * the implementor should contain a flexible array member of elements of type `Entry` + /// * `Entry` should be a POD ++/// * the implementor should ensures that the FAM length as returned by [`FamStruct::len()`] ++/// always describes correctly the length of the flexible array member. + /// + /// Violating these may cause problems. + /// +@@ -99,7 +101,7 @@ impl fmt::Display for Error { + /// self.len as usize + /// } + /// +-/// fn set_len(&mut self, len: usize) { ++/// unsafe fn set_len(&mut self, len: usize) { + /// self.len = len as u32 + /// } + /// +@@ -135,7 +137,12 @@ pub unsafe trait FamStruct { + /// + /// These type of structures contain a member that holds the FAM length. + /// This method will set the value of that member. +- fn set_len(&mut self, len: usize); ++ /// ++ /// # Safety ++ /// ++ /// The caller needs to ensure that `len` here reflects the correct number of entries of the ++ /// flexible array part of the struct. ++ unsafe fn set_len(&mut self, len: usize); + + /// Get max allowed FAM length + /// +@@ -169,9 +176,14 @@ impl FamStructWrapper { + /// + /// Get the capacity required by mem_allocator in order to hold + /// the provided number of [`FamStruct::Entry`](trait.FamStruct.html#associatedtype.Entry). +- fn mem_allocator_len(fam_len: usize) -> usize { +- let wrapper_size_in_bytes = size_of::() + fam_len * size_of::(); +- (wrapper_size_in_bytes + size_of::() - 1) / size_of::() ++ /// Returns `None` if the required length would overflow usize. ++ fn mem_allocator_len(fam_len: usize) -> Option { ++ let wrapper_size_in_bytes = ++ size_of::().checked_add(fam_len.checked_mul(size_of::())?)?; ++ ++ wrapper_size_in_bytes ++ .checked_add(size_of::().checked_sub(1)?)? ++ .checked_div(size_of::()) + } + + /// Convert `mem_allocator` len to FAM len. +@@ -206,7 +218,8 @@ impl FamStructWrapper { + return Err(Error::SizeLimitExceeded); + } + let required_mem_allocator_capacity = +- FamStructWrapper::::mem_allocator_len(num_elements); ++ FamStructWrapper::::mem_allocator_len(num_elements) ++ .ok_or(Error::SizeLimitExceeded)?; + + let mut mem_allocator = Vec::with_capacity(required_mem_allocator_capacity); + mem_allocator.push(T::default()); +@@ -214,7 +227,11 @@ impl FamStructWrapper { + // SAFETY: Safe as long T follows the requirements of being POD. + mem_allocator.push(unsafe { mem::zeroed() }) + } +- mem_allocator[0].set_len(num_elements); ++ // SAFETY: The flexible array part of the struct has `num_elements` capacity. We just ++ // initialized this in `mem_allocator`. ++ unsafe { ++ mem_allocator[0].set_len(num_elements); ++ } + + Ok(FamStructWrapper { mem_allocator }) + } +@@ -234,7 +251,8 @@ impl FamStructWrapper { + let mut adapter = FamStructWrapper::::new(entries.len())?; + + { +- let wrapper_entries = adapter.as_mut_fam_struct().as_mut_slice(); ++ // SAFETY: We are not modifying the length of the FamStruct ++ let wrapper_entries = unsafe { adapter.as_mut_fam_struct().as_mut_slice() }; + wrapper_entries.copy_from_slice(entries); + } + +@@ -271,7 +289,12 @@ impl FamStructWrapper { + } + + /// Get a mut reference to the actual [`FamStruct`](trait.FamStruct.html) instance. +- pub fn as_mut_fam_struct(&mut self) -> &mut T { ++ /// ++ /// # Safety ++ /// ++ /// Callers must not use the reference returned to modify the `len` filed of the underlying ++ /// `FamStruct`. See also the top-level documentation of [`FamStruct`]. ++ pub unsafe fn as_mut_fam_struct(&mut self) -> &mut T { + &mut self.mem_allocator[0] + } + +@@ -294,7 +317,8 @@ impl FamStructWrapper { + /// Modifying the container referenced by this pointer may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + pub fn as_mut_fam_struct_ptr(&mut self) -> *mut T { +- self.as_mut_fam_struct() ++ // SAFETY: We do not change the length of the underlying FamStruct. ++ unsafe { self.as_mut_fam_struct() } + } + + /// Get the elements slice. +@@ -304,7 +328,8 @@ impl FamStructWrapper { + + /// Get the mutable elements slice. + pub fn as_mut_slice(&mut self) -> &mut [T::Entry] { +- self.as_mut_fam_struct().as_mut_slice() ++ // SAFETY: We do not change the length of the underlying FamStruct. ++ unsafe { self.as_mut_fam_struct() }.as_mut_slice() + } + + /// Get the number of elements of type `FamStruct::Entry` currently in the vec. +@@ -326,17 +351,20 @@ impl FamStructWrapper { + /// + /// If the capacity is already reserved, this method doesn't do anything. + /// If not this will trigger a reallocation of the underlying buffer. +- fn reserve(&mut self, additional: usize) { ++ fn reserve(&mut self, additional: usize) -> Result<(), Error> { + let desired_capacity = self.len() + additional; + if desired_capacity <= self.capacity() { +- return; ++ return Ok(()); + } + + let current_mem_allocator_len = self.mem_allocator.len(); +- let required_mem_allocator_len = FamStructWrapper::::mem_allocator_len(desired_capacity); ++ let required_mem_allocator_len = FamStructWrapper::::mem_allocator_len(desired_capacity) ++ .ok_or(Error::SizeLimitExceeded)?; + let additional_mem_allocator_len = required_mem_allocator_len - current_mem_allocator_len; + + self.mem_allocator.reserve(additional_mem_allocator_len); ++ ++ Ok(()) + } + + /// Update the length of the FamStructWrapper. +@@ -352,7 +380,10 @@ impl FamStructWrapper { + /// + /// When len is greater than the max possible len it returns Error::SizeLimitExceeded. + fn set_len(&mut self, len: usize) -> Result<(), Error> { +- let additional_elements: isize = len as isize - self.len() as isize; ++ let additional_elements = isize::try_from(len) ++ .and_then(|len| isize::try_from(self.len()).map(|self_len| len - self_len)) ++ .map_err(|_| Error::SizeLimitExceeded)?; ++ + // If len == self.len there's nothing to do. + if additional_elements == 0 { + return Ok(()); +@@ -365,11 +396,12 @@ impl FamStructWrapper { + return Err(Error::SizeLimitExceeded); + } + // Reserve additional capacity. +- self.reserve(additional_elements as usize); ++ self.reserve(additional_elements as usize)?; + } + + let current_mem_allocator_len = self.mem_allocator.len(); +- let required_mem_allocator_len = FamStructWrapper::::mem_allocator_len(len); ++ let required_mem_allocator_len = ++ FamStructWrapper::::mem_allocator_len(len).ok_or(Error::SizeLimitExceeded)?; + // Update the len of the `mem_allocator`. + // SAFETY: This is safe since enough capacity has been reserved. + unsafe { +@@ -382,7 +414,11 @@ impl FamStructWrapper { + self.mem_allocator[i] = unsafe { mem::zeroed() } + } + // Update the len of the underlying `FamStruct`. +- self.as_mut_fam_struct().set_len(len); ++ // SAFETY: We just adjusted the memory for the underlying `mem_allocator` to hold `len` ++ // entries. ++ unsafe { ++ self.as_mut_fam_struct().set_len(len); ++ } + + // If the len needs to be decreased, deallocate unnecessary memory + if additional_elements < 0 { +@@ -445,9 +481,9 @@ impl PartialEq for FamStructWrapper { + impl Clone for FamStructWrapper { + fn clone(&self) -> Self { + // The number of entries (self.as_slice().len()) can't be > T::max_len() since `self` is a +- // valid `FamStructWrapper`. ++ // valid `FamStructWrapper`. This makes the .unwrap() safe. + let required_mem_allocator_capacity = +- FamStructWrapper::::mem_allocator_len(self.as_slice().len()); ++ FamStructWrapper::::mem_allocator_len(self.as_slice().len()).unwrap(); + + let mut mem_allocator = Vec::with_capacity(required_mem_allocator_capacity); + +@@ -469,7 +505,7 @@ impl Clone for FamStructWrapper { + + let mut adapter = FamStructWrapper { mem_allocator }; + { +- let wrapper_entries = adapter.as_mut_fam_struct().as_mut_slice(); ++ let wrapper_entries = adapter.as_mut_slice(); + wrapper_entries.copy_from_slice(self.as_slice()); + } + adapter +@@ -527,13 +563,23 @@ where + { + use serde::de::Error; + +- let header = seq ++ let header: X = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let entries: Vec = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + ++ if header.len() != entries.len() { ++ let msg = format!( ++ "Mismatch between length of FAM specified in FamStruct header ({}) \ ++ and actual size of FAM ({})", ++ header.len(), ++ entries.len() ++ ); ++ return Err(V::Error::custom(msg)); ++ } ++ + let mut result: Self::Value = FamStructWrapper::from_entries(entries.as_slice()) + .map_err(|e| V::Error::custom(format!("{:?}", e)))?; + result.mem_allocator[0] = header; +@@ -557,7 +603,7 @@ macro_rules! generate_fam_struct_impl { + self.$field_name as usize + } + +- fn set_len(&mut self, len: usize) { ++ unsafe fn set_len(&mut self, len: usize) { + self.$field_name = len as $field_type; + } + +@@ -581,6 +627,7 @@ macro_rules! generate_fam_struct_impl { + #[cfg(test)] + mod tests { + #![allow(clippy::undocumented_unsafe_blocks)] ++ + #[cfg(feature = "with-serde")] + use serde_derive::{Deserialize, Serialize}; + +@@ -589,7 +636,7 @@ mod tests { + const MAX_LEN: usize = 100; + + #[repr(C)] +- #[derive(Default, PartialEq, Eq)] ++ #[derive(Default, Debug, PartialEq, Eq)] + pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); + impl __IncompleteArrayField { + #[inline] +@@ -678,12 +725,30 @@ mod tests { + let fam_len = pair.0; + let mem_allocator_len = pair.1; + assert_eq!( +- mem_allocator_len, ++ Some(mem_allocator_len), + MockFamStructWrapper::mem_allocator_len(fam_len) + ); + } + } + ++ #[repr(C)] ++ #[derive(Default, PartialEq)] ++ struct MockFamStructU8 { ++ pub len: u32, ++ pub padding: u32, ++ pub entries: __IncompleteArrayField, ++ } ++ generate_fam_struct_impl!(MockFamStructU8, u8, entries, u32, len, 100); ++ type MockFamStructWrapperU8 = FamStructWrapper; ++ #[test] ++ fn test_invalid_type_conversion() { ++ let mut adapter = MockFamStructWrapperU8::new(10).unwrap(); ++ assert!(matches!( ++ adapter.set_len(0xffff_ffff_ffff_ff00), ++ Err(Error::SizeLimitExceeded) ++ )); ++ } ++ + #[test] + fn test_wrapper_len() { + for pair in MEM_ALLOCATOR_LEN_TO_FAM_LEN { +@@ -785,7 +850,7 @@ mod tests { + let num_elements = pair.0; + let required_mem_allocator_len = pair.1; + +- adapter.reserve(num_elements); ++ adapter.reserve(num_elements).unwrap(); + + assert!(adapter.mem_allocator.capacity() >= required_mem_allocator_len); + assert_eq!(0, adapter.len()); +@@ -794,7 +859,7 @@ mod tests { + + // test that when the capacity is already reserved, the method doesn't do anything + let current_capacity = adapter.capacity(); +- adapter.reserve(current_capacity - 1); ++ adapter.reserve(current_capacity - 1).unwrap(); + assert_eq!(current_capacity, adapter.capacity()); + } + +@@ -831,7 +896,8 @@ mod tests { + assert_eq!(adapter.as_slice()[i], i as u32); + assert_eq!(adapter.len(), i + 1); + assert!( +- adapter.mem_allocator.capacity() >= MockFamStructWrapper::mem_allocator_len(i + 1) ++ adapter.mem_allocator.capacity() ++ >= MockFamStructWrapper::mem_allocator_len(i + 1).unwrap() + ); + } + +@@ -858,7 +924,7 @@ mod tests { + assert_eq!(adapter.len(), num_retained_entries); + assert!( + adapter.mem_allocator.capacity() +- >= MockFamStructWrapper::mem_allocator_len(num_retained_entries) ++ >= MockFamStructWrapper::mem_allocator_len(num_retained_entries).unwrap() + ); + } + +@@ -910,7 +976,7 @@ mod tests { + assert_eq!(payload[0], 0xA5); + assert_eq!(payload[1], 0x1e); + } +- assert_eq!(wrapper.as_mut_fam_struct().padding, 5); ++ assert_eq!(unsafe { wrapper.as_mut_fam_struct() }.padding, 5); + let data = wrapper.into_raw(); + assert_eq!(data[0].len, 2); + assert_eq!(data[0].padding, 5); +@@ -996,53 +1062,81 @@ mod tests { + type FooFamStructWrapper = FamStructWrapper; + + let mut wrapper = FooFamStructWrapper::new(0).unwrap(); +- wrapper.as_mut_fam_struct().index = 1; +- wrapper.as_mut_fam_struct().flags = 2; +- wrapper.as_mut_fam_struct().length = 3; +- wrapper.push(3).unwrap(); +- wrapper.push(14).unwrap(); +- assert_eq!(wrapper.as_slice().len(), 3 + 2); +- assert_eq!(wrapper.as_slice()[3], 3); +- assert_eq!(wrapper.as_slice()[3 + 1], 14); +- +- let mut wrapper2 = wrapper.clone(); +- assert_eq!( +- wrapper.as_mut_fam_struct().index, +- wrapper2.as_mut_fam_struct().index +- ); +- assert_eq!( +- wrapper.as_mut_fam_struct().length, +- wrapper2.as_mut_fam_struct().length +- ); +- assert_eq!( +- wrapper.as_mut_fam_struct().flags, +- wrapper2.as_mut_fam_struct().flags +- ); +- assert_eq!(wrapper.as_slice(), wrapper2.as_slice()); +- assert_eq!( +- wrapper2.as_slice().len(), +- wrapper2.as_mut_fam_struct().length as usize +- ); +- assert!(wrapper == wrapper2); ++ // SAFETY: We do play with length here, but that's just for testing purposes :) ++ unsafe { ++ wrapper.as_mut_fam_struct().index = 1; ++ wrapper.as_mut_fam_struct().flags = 2; ++ wrapper.as_mut_fam_struct().length = 3; ++ wrapper.push(3).unwrap(); ++ wrapper.push(14).unwrap(); ++ assert_eq!(wrapper.as_slice().len(), 3 + 2); ++ assert_eq!(wrapper.as_slice()[3], 3); ++ assert_eq!(wrapper.as_slice()[3 + 1], 14); ++ ++ let mut wrapper2 = wrapper.clone(); ++ assert_eq!( ++ wrapper.as_mut_fam_struct().index, ++ wrapper2.as_mut_fam_struct().index ++ ); ++ assert_eq!( ++ wrapper.as_mut_fam_struct().length, ++ wrapper2.as_mut_fam_struct().length ++ ); ++ assert_eq!( ++ wrapper.as_mut_fam_struct().flags, ++ wrapper2.as_mut_fam_struct().flags ++ ); ++ assert_eq!(wrapper.as_slice(), wrapper2.as_slice()); ++ assert_eq!( ++ wrapper2.as_slice().len(), ++ wrapper2.as_mut_fam_struct().length as usize ++ ); ++ assert!(wrapper == wrapper2); + +- wrapper.as_mut_fam_struct().index = 3; +- assert!(wrapper != wrapper2); ++ wrapper.as_mut_fam_struct().index = 3; ++ assert!(wrapper != wrapper2); + +- wrapper.as_mut_fam_struct().length = 7; +- assert!(wrapper != wrapper2); ++ wrapper.as_mut_fam_struct().length = 7; ++ assert!(wrapper != wrapper2); + +- wrapper.push(1).unwrap(); +- assert_eq!(wrapper.as_mut_fam_struct().length, 8); +- assert!(wrapper != wrapper2); ++ wrapper.push(1).unwrap(); ++ assert_eq!(wrapper.as_mut_fam_struct().length, 8); ++ assert!(wrapper != wrapper2); + +- let mut wrapper2 = wrapper.clone(); +- assert!(wrapper == wrapper2); ++ let mut wrapper2 = wrapper.clone(); ++ assert!(wrapper == wrapper2); + +- // Dropping the original variable should not affect its clone. +- drop(wrapper); +- assert_eq!(wrapper2.as_mut_fam_struct().index, 3); +- assert_eq!(wrapper2.as_mut_fam_struct().length, 8); +- assert_eq!(wrapper2.as_mut_fam_struct().flags, 2); +- assert_eq!(wrapper2.as_slice(), [0, 0, 0, 3, 14, 0, 0, 1]); ++ // Dropping the original variable should not affect its clone. ++ drop(wrapper); ++ assert_eq!(wrapper2.as_mut_fam_struct().index, 3); ++ assert_eq!(wrapper2.as_mut_fam_struct().length, 8); ++ assert_eq!(wrapper2.as_mut_fam_struct().flags, 2); ++ assert_eq!(wrapper2.as_slice(), [0, 0, 0, 3, 14, 0, 0, 1]); ++ } ++ } ++ ++ #[cfg(feature = "with-serde")] ++ #[test] ++ fn test_bad_deserialize() { ++ #[repr(C)] ++ #[derive(Default, Debug, PartialEq, Serialize, Deserialize)] ++ struct Foo { ++ pub len: u32, ++ pub padding: u32, ++ pub entries: __IncompleteArrayField, ++ } ++ ++ generate_fam_struct_impl!(Foo, u32, entries, u32, len, 100); ++ ++ let state = FamStructWrapper::::new(0).unwrap(); ++ let mut bytes = bincode::serialize(&state).unwrap(); ++ ++ // The `len` field of the header is the first to be serialized. ++ // Writing at position 0 of the serialized data should change its value. ++ bytes[0] = 255; ++ ++ assert!( ++ matches!(bincode::deserialize::>(&bytes).map_err(|boxed| *boxed), Err(bincode::ErrorKind::Custom(s)) if s == *"Mismatch between length of FAM specified in FamStruct header (255) and actual size of FAM (0)") ++ ); + } + } +diff --git a/vendor/vmm-sys-util/src/lib.rs b/vendor/vmm-sys-util/src/lib.rs +index 1929816..0467825 100644 +--- a/vendor/vmm-sys-util/src/lib.rs ++++ b/vendor/vmm-sys-util/src/lib.rs +@@ -4,7 +4,8 @@ + //! Collection of modules that provides helpers and utilities used by multiple + //! [rust-vmm](https://github.com/rust-vmm/community) components. + +-#![deny(missing_docs)] ++#![deny(missing_docs, missing_debug_implementations)] ++#![cfg_attr(docsrs, feature(doc_auto_cfg))] + + #[cfg(any(target_os = "linux", target_os = "android"))] + mod linux; +diff --git a/vendor/vmm-sys-util/src/linux/aio.rs b/vendor/vmm-sys-util/src/linux/aio.rs +index 1e14ea0..98bc2cf 100644 +--- a/vendor/vmm-sys-util/src/linux/aio.rs ++++ b/vendor/vmm-sys-util/src/linux/aio.rs +@@ -223,7 +223,7 @@ impl IoContext { + ) -> Result { + let to = match timeout { + Some(val) => val as *mut libc::timespec, +- None => null_mut() as *mut libc::timespec, ++ None => null_mut(), + }; + + // SAFETY: It's safe because parameters are valid and we have checked the result. +diff --git a/vendor/vmm-sys-util/src/linux/epoll.rs b/vendor/vmm-sys-util/src/linux/epoll.rs +index b8e9b7b..c68d1f9 100644 +--- a/vendor/vmm-sys-util/src/linux/epoll.rs ++++ b/vendor/vmm-sys-util/src/linux/epoll.rs +@@ -19,6 +19,7 @@ use libc::{ + use crate::syscall::SyscallReturnCode; + + /// Wrapper over `EPOLL_CTL_*` operations that can be performed on a file descriptor. ++#[derive(Debug)] + #[repr(i32)] + pub enum ControlOperation { + /// Add a file descriptor to the interest list. +@@ -385,20 +386,12 @@ mod tests { + // For EPOLL_CTL_ADD behavior we will try to add some fds with different event masks into + // the interest list of epoll instance. + assert!(epoll +- .ctl( +- ControlOperation::Add, +- event_fd_1.as_raw_fd() as i32, +- event_1 +- ) ++ .ctl(ControlOperation::Add, event_fd_1.as_raw_fd(), event_1) + .is_ok()); + + // We can't add twice the same fd to epoll interest list. + assert!(epoll +- .ctl( +- ControlOperation::Add, +- event_fd_1.as_raw_fd() as i32, +- event_1 +- ) ++ .ctl(ControlOperation::Add, event_fd_1.as_raw_fd(), event_1) + .is_err()); + + let event_fd_2 = EventFd::new(libc::EFD_NONBLOCK).unwrap(); +@@ -406,7 +399,7 @@ mod tests { + assert!(epoll + .ctl( + ControlOperation::Add, +- event_fd_2.as_raw_fd() as i32, ++ event_fd_2.as_raw_fd(), + // For this fd, we want an Event instance that has `data` field set to other + // value than the value of the fd and `events` without EPOLLIN type set. + EpollEvent::new(EventSet::OUT, 10) +@@ -419,11 +412,7 @@ mod tests { + let event_fd_3 = EventFd::new(libc::EFD_NONBLOCK).unwrap(); + let event_3 = EpollEvent::new(EventSet::OUT | EventSet::IN, event_fd_3.as_raw_fd() as u64); + assert!(epoll +- .ctl( +- ControlOperation::Add, +- event_fd_3.as_raw_fd() as i32, +- event_3 +- ) ++ .ctl(ControlOperation::Add, event_fd_3.as_raw_fd(), event_3) + .is_ok()); + + // Let's check `epoll_wait()` behavior for our epoll instance. +@@ -457,11 +446,7 @@ mod tests { + // that we want to monitor this time on event_fd_1. + event_1 = EpollEvent::new(EventSet::OUT, 20); + assert!(epoll +- .ctl( +- ControlOperation::Modify, +- event_fd_1.as_raw_fd() as i32, +- event_1 +- ) ++ .ctl(ControlOperation::Modify, event_fd_1.as_raw_fd(), event_1) + .is_ok()); + + let event_fd_4 = EventFd::new(libc::EFD_NONBLOCK).unwrap(); +@@ -469,7 +454,7 @@ mod tests { + assert!(epoll + .ctl( + ControlOperation::Modify, +- event_fd_4.as_raw_fd() as i32, ++ event_fd_4.as_raw_fd(), + EpollEvent::default() + ) + .is_err()); +@@ -485,7 +470,7 @@ mod tests { + assert!(epoll + .ctl( + ControlOperation::Modify, +- event_fd_1.as_raw_fd() as i32, ++ event_fd_1.as_raw_fd(), + EpollEvent::default() + ) + .is_ok()); +@@ -498,7 +483,7 @@ mod tests { + assert!(epoll + .ctl( + ControlOperation::Delete, +- event_fd_2.as_raw_fd() as i32, ++ event_fd_2.as_raw_fd(), + EpollEvent::default() + ) + .is_ok()); +@@ -514,7 +499,7 @@ mod tests { + assert!(epoll + .ctl( + ControlOperation::Delete, +- event_fd_4.as_raw_fd() as i32, ++ event_fd_4.as_raw_fd(), + EpollEvent::default() + ) + .is_err()); +diff --git a/vendor/vmm-sys-util/src/linux/fallocate.rs b/vendor/vmm-sys-util/src/linux/fallocate.rs +index e3a7fed..904bff2 100644 +--- a/vendor/vmm-sys-util/src/linux/fallocate.rs ++++ b/vendor/vmm-sys-util/src/linux/fallocate.rs +@@ -14,6 +14,7 @@ use crate::errno::{errno_result, Error, Result}; + /// Operation to be performed on a given range when calling [`fallocate`] + /// + /// [`fallocate`]: fn.fallocate.html ++#[derive(Debug)] + pub enum FallocateMode { + /// Deallocating file space. + PunchHole, +diff --git a/vendor/vmm-sys-util/src/linux/poll.rs b/vendor/vmm-sys-util/src/linux/poll.rs +index 12809f0..54dd4b9 100644 +--- a/vendor/vmm-sys-util/src/linux/poll.rs ++++ b/vendor/vmm-sys-util/src/linux/poll.rs +@@ -47,6 +47,12 @@ const POLL_CONTEXT_MAX_EVENTS: usize = 16; + /// This should only be used with [`EpollContext`](struct.EpollContext.html). + pub struct EpollEvents(RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>); + ++impl std::fmt::Debug for EpollEvents { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ write!(f, "EpollEvents {{ ... }}") ++ } ++} ++ + impl EpollEvents { + /// Creates a new EpollEvents. + pub fn new() -> EpollEvents { +@@ -90,7 +96,7 @@ impl PollToken for usize { + + impl PollToken for u64 { + fn as_raw_token(&self) -> u64 { +- *self as u64 ++ *self + } + + fn from_raw_token(data: u64) -> Self { +@@ -142,6 +148,15 @@ pub struct PollEvent<'a, T> { + token: PhantomData, // Needed to satisfy usage of T + } + ++impl std::fmt::Debug for PollEvent<'_, T> { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ f.debug_struct("PollEvent") ++ .field("event", &"?") ++ .field("token", &self.token) ++ .finish() ++ } ++} ++ + impl<'a, T: PollToken> PollEvent<'a, T> { + /// Gets the token associated in + /// [`PollContext::add`](struct.PollContext.html#method.add) with this event. +@@ -189,6 +204,7 @@ impl<'a, T: PollToken> PollEvent<'a, T> { + + /// An iterator over a subset of events returned by + /// [`PollContext::wait`](struct.PollContext.html#method.wait). ++#[derive(Debug)] + pub struct PollEventIter<'a, I, T> + where + I: Iterator, +@@ -222,6 +238,16 @@ pub struct PollEvents<'a, T> { + tokens: PhantomData<[T]>, // Needed to satisfy usage of T + } + ++impl std::fmt::Debug for PollEvents<'_, T> { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ f.debug_struct("PollEventsOwned") ++ .field("count", &self.count) ++ .field("events", &"?") ++ .field("tokens", &self.tokens) ++ .finish() ++ } ++} ++ + impl<'a, T: PollToken> PollEvents<'a, T> { + /// Creates owned structure from borrowed [`PollEvents`](struct.PollEvents.html). + /// +@@ -270,6 +296,16 @@ pub struct PollEventsOwned { + tokens: PhantomData, // Needed to satisfy usage of T + } + ++impl std::fmt::Debug for PollEventsOwned { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ f.debug_struct("PollEventsOwned") ++ .field("count", &self.count) ++ .field("events", &"?") ++ .field("tokens", &self.tokens) ++ .finish() ++ } ++} ++ + impl PollEventsOwned { + /// Creates borrowed structure from owned structure + /// [`PollEventsOwned`](struct.PollEventsOwned.html). +@@ -286,7 +322,7 @@ impl PollEventsOwned { + } + + /// Watching events taken by [`PollContext`](struct.PollContext.html). +-#[derive(Copy, Clone)] ++#[derive(Debug, Copy, Clone)] + pub struct WatchingEvents(u32); + + impl WatchingEvents { +@@ -355,6 +391,7 @@ impl WatchingEvents { + /// assert_eq!(event.token(), 1); + /// } + /// ``` ++#[derive(Debug)] + pub struct EpollContext { + epoll_ctx: File, + // Needed to satisfy usage of T +@@ -699,6 +736,7 @@ impl IntoRawFd for EpollContext { + /// let tokens: Vec = pollevents.iter_readable().map(|e| e.token()).collect(); + /// assert_eq!(&tokens[..], &[2]); + /// ``` ++#[derive(Debug)] + pub struct PollContext { + epoll_ctx: EpollContext, + +@@ -834,6 +872,8 @@ impl PollContext { + let mut buf = [0u8; 512]; + let (res, len) = { + let mut buf_cursor = Cursor::new(&mut buf[..]); ++ // Oops, clippy bug. See https://github.com/rust-lang/rust-clippy/issues/9810 ++ #[allow(clippy::write_literal)] + ( + writeln!( + &mut buf_cursor, +diff --git a/vendor/vmm-sys-util/src/linux/seek_hole.rs b/vendor/vmm-sys-util/src/linux/seek_hole.rs +index 1392993..6c35455 100644 +--- a/vendor/vmm-sys-util/src/linux/seek_hole.rs ++++ b/vendor/vmm-sys-util/src/linux/seek_hole.rs +@@ -84,7 +84,7 @@ mod tests { + use std::path::PathBuf; + + fn seek_cur(file: &mut File) -> u64 { +- file.seek(SeekFrom::Current(0)).unwrap() ++ file.stream_position().unwrap() + } + + #[test] +@@ -154,7 +154,7 @@ mod tests { + assert_eq!(seek_cur(&mut file), 0xFFFF); + + // seek_hole at or after the end of the file should return None +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x10000).unwrap(), None); + assert_eq!(seek_cur(&mut file), 0); + assert_eq!(file.seek_hole(0x10001).unwrap(), None); +@@ -172,18 +172,18 @@ mod tests { + assert_eq!(seek_cur(&mut file), 0xFFFF); + + // seek_hole within data should return the next hole (EOF) +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); + + // seek_hole at EOF after data should return None +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x20000).unwrap(), None); + assert_eq!(seek_cur(&mut file), 0); + +@@ -193,21 +193,21 @@ mod tests { + assert_eq!(seek_cur(&mut file), 0); + assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF)); + assert_eq!(seek_cur(&mut file), 0xFFFF); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000)); + assert_eq!(seek_cur(&mut file), 0x20000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001)); + assert_eq!(seek_cur(&mut file), 0x20001); + + // seek_hole at EOF after a hole should return None +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x30000).unwrap(), None); + assert_eq!(seek_cur(&mut file), 0); + +@@ -218,10 +218,10 @@ mod tests { + // seek_hole within [0x20000, 0x30000) should now find the hole at EOF + assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000)); + assert_eq!(seek_cur(&mut file), 0x30000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000)); + assert_eq!(seek_cur(&mut file), 0x30000); +- file.seek(SeekFrom::Start(0)).unwrap(); ++ file.rewind().unwrap(); + assert_eq!(file.seek_hole(0x30000).unwrap(), None); + assert_eq!(seek_cur(&mut file), 0); + } +diff --git a/vendor/vmm-sys-util/src/linux/sock_ctrl_msg.rs b/vendor/vmm-sys-util/src/linux/sock_ctrl_msg.rs +index 0c19a11..9e69e2b 100644 +--- a/vendor/vmm-sys-util/src/linux/sock_ctrl_msg.rs ++++ b/vendor/vmm-sys-util/src/linux/sock_ctrl_msg.rs +@@ -98,7 +98,10 @@ fn set_msg_controllen(msg: &mut msghdr, cmsg_capacity: usize) { + + // This function is like CMSG_NEXT, but safer because it reads only from references, although it + // does some pointer arithmetic on cmsg_ptr. +-#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] ++#[cfg_attr( ++ feature = "cargo-clippy", ++ allow(clippy::cast_ptr_alignment, clippy::unnecessary_cast) ++)] + fn get_next_cmsg(msghdr: &msghdr, cmsg: &cmsghdr, cmsg_ptr: *mut cmsghdr) -> *mut cmsghdr { + let next_cmsg = (cmsg_ptr as *mut u8).wrapping_add(CMSG_ALIGN!(cmsg.cmsg_len)) as *mut cmsghdr; + if next_cmsg +@@ -151,7 +154,7 @@ impl CmsgBuffer { + } + + fn raw_sendmsg(fd: RawFd, out_data: &[D], out_fds: &[RawFd]) -> Result { +- let cmsg_capacity = CMSG_SPACE!(size_of::() * out_fds.len()); ++ let cmsg_capacity = CMSG_SPACE!(std::mem::size_of_val(out_fds)); + let mut cmsg_buffer = CmsgBuffer::with_capacity(cmsg_capacity); + + let mut iovecs = Vec::with_capacity(out_data.len()); +@@ -166,7 +169,7 @@ fn raw_sendmsg(fd: RawFd, out_data: &[D], out_fds: &[RawFd]) -> Re + + if !out_fds.is_empty() { + let cmsg = cmsghdr { +- cmsg_len: CMSG_LEN!(size_of::() * out_fds.len()), ++ cmsg_len: CMSG_LEN!(std::mem::size_of_val(out_fds)), + cmsg_level: SOL_SOCKET, + cmsg_type: SCM_RIGHTS, + #[cfg(all(target_env = "musl", target_pointer_width = "64"))] +@@ -175,7 +178,7 @@ fn raw_sendmsg(fd: RawFd, out_data: &[D], out_fds: &[RawFd]) -> Re + // SAFETY: Check comments below for each call. + unsafe { + // Safe because cmsg_buffer was allocated to be large enough to contain cmsghdr. +- write_unaligned(cmsg_buffer.as_mut_ptr() as *mut cmsghdr, cmsg); ++ write_unaligned(cmsg_buffer.as_mut_ptr(), cmsg); + // Safe because the cmsg_buffer was allocated to be large enough to hold out_fds.len() + // file descriptors. + copy_nonoverlapping( +@@ -200,12 +203,13 @@ fn raw_sendmsg(fd: RawFd, out_data: &[D], out_fds: &[RawFd]) -> Re + } + } + ++#[cfg_attr(feature = "cargo-clippy", allow(clippy::unnecessary_cast))] + unsafe fn raw_recvmsg( + fd: RawFd, + iovecs: &mut [iovec], + in_fds: &mut [RawFd], + ) -> Result<(usize, usize)> { +- let cmsg_capacity = CMSG_SPACE!(size_of::() * in_fds.len()); ++ let cmsg_capacity = CMSG_SPACE!(std::mem::size_of_val(in_fds)); + let mut cmsg_buffer = CmsgBuffer::with_capacity(cmsg_capacity); + let mut msg = new_msghdr(iovecs); + +@@ -241,7 +245,7 @@ unsafe fn raw_recvmsg( + // read. + let cmsg = (cmsg_ptr as *mut cmsghdr).read_unaligned(); + if cmsg.cmsg_level == SOL_SOCKET && cmsg.cmsg_type == SCM_RIGHTS { +- let fds_count = ((cmsg.cmsg_len - CMSG_LEN!(0)) as usize) / size_of::(); ++ let fds_count: usize = ((cmsg.cmsg_len - CMSG_LEN!(0)) as usize) / size_of::(); + // The sender can transmit more data than we can buffer. If a message is too long to + // fit in the supplied buffer, excess bytes may be discarded depending on the type of + // socket the message is received from. +diff --git a/vendor/vmm-sys-util/src/linux/timerfd.rs b/vendor/vmm-sys-util/src/linux/timerfd.rs +index 80f0789..a67198b 100644 +--- a/vendor/vmm-sys-util/src/linux/timerfd.rs ++++ b/vendor/vmm-sys-util/src/linux/timerfd.rs +@@ -19,6 +19,7 @@ use crate::errno::{errno_result, Result}; + + /// A safe wrapper around a Linux + /// [`timerfd`](http://man7.org/linux/man-pages/man2/timerfd_create.2.html). ++#[derive(Debug)] + pub struct TimerFd(File); + + impl TimerFd { +diff --git a/vendor/vmm-sys-util/src/linux/write_zeroes.rs b/vendor/vmm-sys-util/src/linux/write_zeroes.rs +index e6084da..4c9e77b 100644 +--- a/vendor/vmm-sys-util/src/linux/write_zeroes.rs ++++ b/vendor/vmm-sys-util/src/linux/write_zeroes.rs +@@ -28,7 +28,7 @@ pub trait PunchHole { + + impl PunchHole for File { + fn punch_hole(&mut self, offset: u64, length: u64) -> Result<()> { +- fallocate(self, FallocateMode::PunchHole, true, offset, length as u64) ++ fallocate(self, FallocateMode::PunchHole, true, offset, length) + .map_err(|e| Error::from_raw_os_error(e.errno())) + } + } +@@ -140,7 +140,7 @@ impl WriteZeroesAt for File { + + impl WriteZeroes for T { + fn write_zeroes(&mut self, length: usize) -> Result { +- let offset = self.seek(SeekFrom::Current(0))?; ++ let offset = self.stream_position()?; + let num_written = self.write_zeroes_at(offset, length)?; + // Advance the seek cursor as if we had done a real write(). + self.seek(SeekFrom::Current(num_written as i64))?; +@@ -171,7 +171,7 @@ mod tests { + + // Read back the data plus some overlap on each side. + let mut readback = [0u8; 16384]; +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.read_exact(&mut readback).unwrap(); + // Bytes before the write should still be 0. + for read in &readback[0..1234] { +@@ -190,10 +190,10 @@ mod tests { + f.seek(SeekFrom::Start(2345)).unwrap(); + f.write_all_zeroes(4321).unwrap(); + // Verify seek position after `write_all_zeroes()`. +- assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 2345 + 4321); ++ assert_eq!(f.stream_position().unwrap(), 2345 + 4321); + + // Read back the data and verify that it is now zero. +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.read_exact(&mut readback).unwrap(); + // Bytes before the write should still be 0. + for read in &readback[0..1234] { +@@ -228,19 +228,19 @@ mod tests { + // Write buffer of non-zero bytes. The size of the buffer will be the new + // size of the file. + let orig_data = [NON_ZERO_VALUE; SIZE]; +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.write_all(&orig_data).unwrap(); + assert_eq!(f.metadata().unwrap().len(), SIZE as u64); + + // Overwrite some of the data with zeroes. +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.write_all_zeroes(0x1_0001).unwrap(); + // Verify seek position after `write_all_zeroes()`. +- assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 0x1_0001); ++ assert_eq!(f.stream_position().unwrap(), 0x1_0001); + + // Read back the data and verify that it is now zero. + let mut readback = [0u8; SIZE]; +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.read_exact(&mut readback).unwrap(); + // Verify that `write_all_zeroes()` zeroed the intended region. + for read in &readback[0..0x1_0001] { +@@ -253,7 +253,7 @@ mod tests { + + // Now let's zero a certain region by using `write_all_zeroes_at()`. + f.write_all_zeroes_at(0x1_8001, 0x200).unwrap(); +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.read_exact(&mut readback).unwrap(); + + // Original data should still exist before the zeroed region. +@@ -281,7 +281,7 @@ mod tests { + // Write buffer of non-zero bytes. The size of the buffer will be the new + // size of the file. + let orig_data = [NON_ZERO_VALUE; SIZE]; +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.write_all(&orig_data).unwrap(); + assert_eq!(f.metadata().unwrap().len(), SIZE as u64); + +@@ -291,7 +291,7 @@ mod tests { + + // Read back the data. + let mut readback = [0u8; SIZE]; +- f.seek(SeekFrom::Start(0)).unwrap(); ++ f.rewind().unwrap(); + f.read_exact(&mut readback).unwrap(); + // Original data should still exist before the hole. + for read in &readback[0..0x1_0001] { +diff --git a/vendor/vmm-sys-util/src/rand.rs b/vendor/vmm-sys-util/src/rand.rs +index 097341f..8a88dd3 100644 +--- a/vendor/vmm-sys-util/src/rand.rs ++++ b/vendor/vmm-sys-util/src/rand.rs +@@ -19,7 +19,7 @@ pub fn timestamp_cycles() -> u64 { + #[cfg(target_arch = "x86_64")] + // SAFETY: Safe because there's nothing that can go wrong with this call. + unsafe { +- std::arch::x86_64::_rdtsc() as u64 ++ std::arch::x86_64::_rdtsc() + } + + #[cfg(not(target_arch = "x86_64"))] +@@ -124,13 +124,21 @@ mod tests { + // The 33 will be discarded as it is not a valid letter + // (upper or lower) or number. + let s = xor_pseudo_rng_u8_alphanumerics(&|| i); +- assert_eq!(vec![54, 55], s); ++ if cfg!(target_endian = "big") { ++ assert_eq!(vec![55, 54], s); ++ } else { ++ assert_eq!(vec![54, 55], s); ++ } + } + + #[test] + fn test_rand_alphanumerics_impl() { + let s = rand_alphanumerics_impl(&|| 14134, 5); +- assert_eq!("67676", s); ++ if cfg!(target_endian = "big") { ++ assert_eq!("76767", s); ++ } else { ++ assert_eq!("67676", s); ++ } + } + + #[test] +@@ -145,13 +153,21 @@ mod tests { + // The 33 will be discarded as it is not a valid letter + // (upper or lower) or number. + let s = xor_pseudo_rng_u8_bytes(&|| i); +- assert_eq!(vec![54, 33, 55, 0], s); ++ if cfg!(target_endian = "big") { ++ assert_eq!(vec![0, 55, 33, 54], s); ++ } else { ++ assert_eq!(vec![54, 33, 55, 0], s); ++ } + } + + #[test] + fn test_rand_bytes_impl() { + let s = rand_bytes_impl(&|| 1234567, 4); +- assert_eq!(vec![135, 214, 18, 0], s); ++ if cfg!(target_endian = "big") { ++ assert_eq!(vec![0, 18, 214, 135], s); ++ } else { ++ assert_eq!(vec![135, 214, 18, 0], s); ++ } + } + + #[test] +diff --git a/vendor/vmm-sys-util/src/syscall.rs b/vendor/vmm-sys-util/src/syscall.rs +index 6fb4d64..a89209a 100644 +--- a/vendor/vmm-sys-util/src/syscall.rs ++++ b/vendor/vmm-sys-util/src/syscall.rs +@@ -6,12 +6,13 @@ + use std::os::raw::c_int; + + /// Wrapper to interpret syscall exit codes and provide a rustacean `io::Result`. +-pub struct SyscallReturnCode(pub c_int); ++#[derive(Debug)] ++pub struct SyscallReturnCode + Eq = c_int>(pub T); + +-impl SyscallReturnCode { ++impl + Eq> SyscallReturnCode { + /// Returns the last OS error if value is -1 or Ok(value) otherwise. +- pub fn into_result(self) -> std::io::Result { +- if self.0 == -1 { ++ pub fn into_result(self) -> std::io::Result { ++ if self.0 == T::from(-1) { + Err(std::io::Error::last_os_error()) + } else { + Ok(self.0) +@@ -46,5 +47,14 @@ mod tests { + + syscall_code = SyscallReturnCode(-1); + assert!(syscall_code.into_empty_result().is_err()); ++ ++ let mut syscall_code_long = SyscallReturnCode(1i64); ++ match syscall_code_long.into_result() { ++ Ok(_value) => (), ++ _ => unreachable!(), ++ } ++ ++ syscall_code_long = SyscallReturnCode(-1i64); ++ assert!(syscall_code_long.into_result().is_err()); + } + } +diff --git a/vendor/vmm-sys-util/src/tempfile.rs b/vendor/vmm-sys-util/src/tempfile.rs +index 7d70f66..de663c9 100644 +--- a/vendor/vmm-sys-util/src/tempfile.rs ++++ b/vendor/vmm-sys-util/src/tempfile.rs +@@ -39,6 +39,7 @@ use crate::errno::{errno_result, Error, Result}; + /// Wrapper for working with temporary files. + /// + /// The file will be maintained for the lifetime of the `TempFile` object. ++#[derive(Debug)] + pub struct TempFile { + path: PathBuf, + file: Option, +@@ -60,22 +61,21 @@ impl TempFile { + let mut os_fname = prefix.as_ref().to_os_string(); + os_fname.push("XXXXXX"); + +- let raw_fname = match CString::new(os_fname.as_bytes()) { +- Ok(c_string) => c_string.into_raw(), +- Err(_) => return Err(Error::new(libc::EINVAL)), +- }; ++ let c_tempname = CString::new(os_fname.as_bytes()).map_err(|_| Error::new(libc::EINVAL))?; ++ let raw_tempname = c_tempname.into_raw(); + +- // SAFETY: Safe because `raw_fname` originates from CString::into_raw, meaning +- // it is a pointer to a nul-terminated sequence of characters. +- let fd = unsafe { libc::mkstemp(raw_fname) }; +- if fd == -1 { +- return errno_result(); +- } ++ // SAFETY: Safe because `c_tempname` is a null-terminated string, as it originates from ++ // `CString::into_raw`. ++ let ret = unsafe { libc::mkstemp(raw_tempname) }; ++ ++ // SAFETY: `raw_tempname` originates from `CString::into_raw`. ++ let c_tempname = unsafe { CString::from_raw(raw_tempname) }; ++ ++ let fd = match ret { ++ -1 => return errno_result(), ++ _ => ret, ++ }; + +- // SAFETY: raw_fname originates from a call to CString::into_raw. The length +- // of the string has not changed, as mkstemp returns a valid file name, and +- // '\0' cannot be part of a valid filename. +- let c_tempname = unsafe { CString::from_raw(raw_fname) }; + let os_tempname = OsStr::from_bytes(c_tempname.as_bytes()); + + // SAFETY: Safe because we checked `fd != -1` above and we uniquely own the file +diff --git a/vendor/vmm-sys-util/src/unix/tempdir.rs b/vendor/vmm-sys-util/src/unix/tempdir.rs +index 101d35a..980fc88 100644 +--- a/vendor/vmm-sys-util/src/unix/tempdir.rs ++++ b/vendor/vmm-sys-util/src/unix/tempdir.rs +@@ -16,6 +16,7 @@ use crate::errno::{errno_result, Error, Result}; + /// Wrapper over a temporary directory. + /// + /// The directory will be maintained for the lifetime of the `TempDir` object. ++#[derive(Debug)] + pub struct TempDir { + path: PathBuf, + } +diff --git a/vfio/Cargo.toml b/vfio/Cargo.toml +index ca4a130..bede7fa 100644 +--- a/vfio/Cargo.toml ++++ b/vfio/Cargo.toml +@@ -10,11 +10,11 @@ description = "Virtual function I/O" + byteorder = "1.4.3" + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } +-kvm-ioctls = "0.15.0" ++kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-ioctls = "0.19.1" + libc = "0.2" + log = "0.4" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + vfio-bindings = "0.3" + once_cell = "1.18.0" + address_space = { path = "../address_space" } +diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml +index d2890ed..91c89cd 100644 +--- a/virtio/Cargo.toml ++++ b/virtio/Cargo.toml +@@ -13,7 +13,7 @@ anyhow = "1.0" + libc = "0.2" + log = "0.4" + serde_json = "1.0" +-vmm-sys-util = "0.11.1" ++vmm-sys-util = "0.12.1" + once_cell = "1.18.0" + address_space = { path = "../address_space" } + machine_manager = { path = "../machine_manager" } +-- +2.43.0 + diff --git a/0006-introduce-riscv64-architecture-support.patch b/0006-introduce-riscv64-architecture-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..e322c2018fd3c718a99bdb0ec2189233b14c9a57 --- /dev/null +++ b/0006-introduce-riscv64-architecture-support.patch @@ -0,0 +1,28163 @@ +From 65d32bcb0af4b27863ffb92d7fc9500bc646ae83 Mon Sep 17 00:00:00 2001 +From: Ruoqing He +Date: Sun, 22 Dec 2024 16:46:47 +0800 +Subject: [PATCH] Introduce RISC-V MicroVM + +Signed-off-by: Ruoqing He +--- + Cargo.lock | 62 +- + Cargo.toml | 22 +- + acpi/src/acpi_table.rs | 6 + + address_space/Cargo.toml | 1 + + address_space/src/address_space.rs | 15 +- + address_space/src/host_mmap.rs | 3 +- + block_backend/src/file.rs | 28 +- + block_backend/src/lib.rs | 63 + + block_backend/src/qcow2/mod.rs | 83 +- + block_backend/src/qcow2/refcount.rs | 58 +- + block_backend/src/qcow2/table.rs | 15 +- + block_backend/src/raw.rs | 9 +- + boot_loader/Cargo.toml | 2 +- + boot_loader/src/lib.rs | 9 + + boot_loader/src/riscv64/mod.rs | 202 +++ + build.rs | 3 + + chardev_backend/src/chardev.rs | 254 +++- + cpu/Cargo.toml | 2 +- + cpu/src/lib.rs | 17 +- + cpu/src/riscv64/mod.rs | 205 +++ + cpu/src/x86_64/mod.rs | 2 +- + devices/Cargo.toml | 8 +- + devices/src/acpi/cpu_controller.rs | 16 +- + devices/src/acpi/ged.rs | 24 +- + devices/src/acpi/power.rs | 13 +- + devices/src/camera_backend/demo.rs | 94 +- + devices/src/camera_backend/mod.rs | 3 - + devices/src/camera_backend/ohcam.rs | 81 +- + .../src/interrupt_controller/aarch64/gicv3.rs | 77 +- + devices/src/interrupt_controller/mod.rs | 9 +- + .../src/interrupt_controller/riscv64/aia.rs | 172 +++ + .../src/interrupt_controller/riscv64/mod.rs | 94 ++ + devices/src/legacy/fwcfg.rs | 82 +- + devices/src/legacy/mod.rs | 2 +- + devices/src/legacy/pflash.rs | 15 +- + devices/src/legacy/pl011.rs | 36 +- + devices/src/legacy/pl031.rs | 14 +- + devices/src/legacy/ramfb.rs | 37 +- + devices/src/legacy/rtc.rs | 14 +- + devices/src/legacy/serial.rs | 51 +- + devices/src/lib.rs | 8 +- + devices/src/misc/mod.rs | 2 +- + devices/src/misc/pvpanic.rs | 55 +- + devices/src/misc/scream/mod.rs | 16 +- + devices/src/misc/scream/ohaudio.rs | 130 +- + devices/src/pci/bus.rs | 19 +- + devices/src/pci/config.rs | 2 +- + devices/src/pci/demo_device/mod.rs | 63 +- + devices/src/pci/host.rs | 27 +- + devices/src/pci/intx.rs | 8 +- + devices/src/pci/mod.rs | 83 +- + devices/src/pci/msix.rs | 9 - + devices/src/pci/root_port.rs | 62 +- + devices/src/scsi/bus.rs | 20 +- + devices/src/scsi/disk.rs | 143 +- + devices/src/smbios/smbios_table.rs | 4 +- + devices/src/sysbus/mod.rs | 239 +-- + devices/src/usb/camera.rs | 23 +- + devices/src/usb/config.rs | 24 +- + devices/src/usb/descriptor.rs | 22 +- + devices/src/usb/keyboard.rs | 17 +- + devices/src/usb/mod.rs | 44 +- + devices/src/usb/storage.rs | 68 +- + devices/src/usb/tablet.rs | 10 +- + devices/src/usb/uas.rs | 1289 +++++++++++++++++ + devices/src/usb/usbhost/host_usblib.rs | 19 + + devices/src/usb/usbhost/mod.rs | 58 +- + devices/src/usb/usbhost/ohusb.rs | 82 ++ + devices/src/usb/xhci/xhci_controller.rs | 62 +- + devices/src/usb/xhci/xhci_pci.rs | 9 +- + docs/config_guidebook.md | 9 +- + docs/stratovirt-img.md | 10 + + hypervisor/Cargo.toml | 2 +- + hypervisor/src/kvm/aarch64/mod.rs | 6 +- + hypervisor/src/kvm/interrupt.rs | 8 +- + hypervisor/src/kvm/mod.rs | 196 ++- + hypervisor/src/kvm/riscv64/aia.rs | 150 ++ + hypervisor/src/kvm/riscv64/config_regs.rs | 37 + + hypervisor/src/kvm/riscv64/core_regs.rs | 171 +++ + hypervisor/src/kvm/riscv64/cpu_caps.rs | 38 + + hypervisor/src/kvm/riscv64/mod.rs | 404 ++++++ + hypervisor/src/kvm/riscv64/timer_regs.rs | 50 + + hypervisor/src/kvm/x86_64/mod.rs | 8 +- + hypervisor/src/lib.rs | 10 + + .../src/test/aarch64/mod.rs | 19 +- + hypervisor/src/test/listener.rs | 40 + + hypervisor/src/test/mod.rs | 417 ++++++ + image/src/img.rs | 101 +- + image/src/main.rs | 3 +- + machine/src/aarch64/micro.rs | 50 +- + machine/src/aarch64/mod.rs | 2 +- + machine/src/aarch64/standard.rs | 90 +- + machine/src/error.rs | 4 +- + machine/src/lib.rs | 736 ++++++---- + machine/src/micro_common/mod.rs | 266 ++-- + machine/src/micro_common/syscall.rs | 9 +- + machine/src/riscv64/fdt.rs | 217 +++ + machine/src/riscv64/micro.rs | 278 ++++ + machine/src/riscv64/mod.rs | 14 + + machine/src/standard_common/mod.rs | 27 +- + machine/src/standard_common/syscall.rs | 1 + + machine/src/x86_64/micro.rs | 19 +- + machine/src/x86_64/mod.rs | 3 +- + machine/src/x86_64/standard.rs | 49 +- + machine_manager/src/cmdline.rs | 120 +- + machine_manager/src/config/camera.rs | 9 +- + machine_manager/src/config/chardev.rs | 765 ++++------ + machine_manager/src/config/demo_dev.rs | 97 -- + machine_manager/src/config/devices.rs | 45 +- + machine_manager/src/config/display.rs | 115 +- + machine_manager/src/config/drive.rs | 822 +++-------- + machine_manager/src/config/fs.rs | 115 -- + machine_manager/src/config/gpu.rs | 176 --- + machine_manager/src/config/iothread.rs | 28 +- + machine_manager/src/config/machine_config.rs | 718 ++++----- + machine_manager/src/config/mod.rs | 586 ++++---- + machine_manager/src/config/network.rs | 665 +++------ + machine_manager/src/config/numa.rs | 228 ++- + machine_manager/src/config/pci.rs | 138 +- + machine_manager/src/config/pvpanic_pci.rs | 66 - + machine_manager/src/config/rng.rs | 241 +-- + machine_manager/src/config/sasl_auth.rs | 37 +- + machine_manager/src/config/scsi.rs | 279 ---- + machine_manager/src/config/smbios.rs | 251 ++-- + machine_manager/src/config/tls_creds.rs | 58 +- + machine_manager/src/config/usb.rs | 99 -- + machine_manager/src/config/vfio.rs | 134 -- + machine_manager/src/config/vnc.rs | 62 +- + machine_manager/src/event_loop.rs | 47 +- + machine_manager/src/machine.rs | 35 +- + machine_manager/src/qmp/qmp_channel.rs | 7 +- + machine_manager/src/qmp/qmp_schema.rs | 11 + + machine_manager/src/signal_handler.rs | 2 +- + machine_manager/src/temp_cleaner.rs | 9 +- + migration/src/manager.rs | 20 + + migration/src/protocol.rs | 4 + + migration/src/snapshot.rs | 23 + + src/main.rs | 59 +- + tests/mod_test/src/libtest.rs | 8 +- + tests/mod_test/tests/pvpanic_test.rs | 2 +- + tests/mod_test/tests/usb_camera_test.rs | 17 +- + trace/src/lib.rs | 2 +- + trace/src/trace_scope.rs | 3 + + trace/trace_generator/src/lib.rs | 7 +- + trace/trace_info/acpi.toml | 23 + + trace/trace_info/camera.toml | 12 + + trace/trace_info/device_legacy.toml | 24 + + trace/trace_info/memory.toml | 41 + + trace/trace_info/misc.toml | 60 + + trace/trace_info/ui.toml | 60 + + trace/trace_info/usb.toml | 104 +- + trace/trace_info/virtio.toml | 24 +- + ui/src/input.rs | 28 + + ui/src/ohui_srv/channel.rs | 143 +- + ui/src/ohui_srv/mod.rs | 64 +- + ui/src/ohui_srv/msg.rs | 6 + + ui/src/ohui_srv/msg_handle.rs | 179 ++- + ui/src/vnc/client_io.rs | 8 +- + ui/src/vnc/mod.rs | 2 +- + ui/src/vnc/server_io.rs | 2 +- + util/Cargo.toml | 3 +- + util/src/aio/mod.rs | 15 +- + util/src/aio/raw.rs | 16 +- + util/src/device_tree.rs | 6 + + util/src/leak_bucket.rs | 4 +- + util/src/lib.rs | 2 +- + util/src/loop_context.rs | 74 +- + util/src/ohos_binding/audio/mod.rs | 5 + + util/src/ohos_binding/camera.rs | 6 +- + util/src/ohos_binding/hwf_adapter/mod.rs | 23 + + util/src/ohos_binding/hwf_adapter/usb.rs | 45 + + util/src/ohos_binding/mod.rs | 2 + + util/src/ohos_binding/usb.rs | 50 + + util/src/seccomp.rs | 20 + + util/src/socket.rs | 9 + + util/src/test_helper.rs | 34 +- + util/src/unix.rs | 86 +- + vendor/memoffset-0.7.1/.cargo-checksum.json | 1 - + vendor/memoffset-0.7.1/Cargo.toml | 36 - + vendor/memoffset-0.7.1/LICENSE | 19 - + vendor/memoffset-0.7.1/README.md | 65 - + vendor/memoffset-0.7.1/build.rs | 22 - + vendor/memoffset-0.7.1/src/lib.rs | 92 -- + vendor/memoffset-0.7.1/src/offset_of.rs | 356 ----- + vendor/memoffset-0.7.1/src/raw_field.rs | 226 --- + vendor/memoffset-0.7.1/src/span_of.rs | 263 ---- + vfio/Cargo.toml | 3 +- + vfio/src/lib.rs | 8 +- + vfio/src/vfio_pci.rs | 62 +- + virtio/src/device/balloon.rs | 9 +- + virtio/src/device/block.rs | 256 +++- + virtio/src/device/gpu.rs | 99 +- + virtio/src/device/net.rs | 247 +++- + virtio/src/device/rng.rs | 150 +- + virtio/src/device/scsi_cntlr.rs | 96 +- + virtio/src/device/serial.rs | 121 +- + virtio/src/lib.rs | 43 +- + virtio/src/queue/mod.rs | 3 +- + virtio/src/transport/virtio_mmio.rs | 116 +- + virtio/src/transport/virtio_pci.rs | 290 ++-- + virtio/src/vhost/kernel/mod.rs | 2 +- + virtio/src/vhost/kernel/net.rs | 91 +- + virtio/src/vhost/kernel/vsock.rs | 55 +- + virtio/src/vhost/user/block.rs | 78 +- + virtio/src/vhost/user/client.rs | 34 +- + virtio/src/vhost/user/fs.rs | 77 +- + virtio/src/vhost/user/mod.rs | 2 +- + virtio/src/vhost/user/net.rs | 32 +- + 208 files changed, 10607 insertions(+), 7601 deletions(-) + create mode 100644 boot_loader/src/riscv64/mod.rs + create mode 100644 cpu/src/riscv64/mod.rs + create mode 100644 devices/src/interrupt_controller/riscv64/aia.rs + create mode 100644 devices/src/interrupt_controller/riscv64/mod.rs + create mode 100644 devices/src/usb/uas.rs + create mode 100644 devices/src/usb/usbhost/ohusb.rs + create mode 100644 hypervisor/src/kvm/riscv64/aia.rs + create mode 100644 hypervisor/src/kvm/riscv64/config_regs.rs + create mode 100644 hypervisor/src/kvm/riscv64/core_regs.rs + create mode 100644 hypervisor/src/kvm/riscv64/cpu_caps.rs + create mode 100644 hypervisor/src/kvm/riscv64/mod.rs + create mode 100644 hypervisor/src/kvm/riscv64/timer_regs.rs + rename machine_manager/src/config/ramfb.rs => hypervisor/src/test/aarch64/mod.rs (55%) + create mode 100644 hypervisor/src/test/listener.rs + create mode 100644 hypervisor/src/test/mod.rs + create mode 100644 machine/src/riscv64/fdt.rs + create mode 100644 machine/src/riscv64/micro.rs + create mode 100644 machine/src/riscv64/mod.rs + delete mode 100644 machine_manager/src/config/demo_dev.rs + delete mode 100644 machine_manager/src/config/fs.rs + delete mode 100644 machine_manager/src/config/gpu.rs + delete mode 100644 machine_manager/src/config/pvpanic_pci.rs + delete mode 100644 machine_manager/src/config/scsi.rs + delete mode 100644 machine_manager/src/config/usb.rs + delete mode 100644 machine_manager/src/config/vfio.rs + create mode 100644 trace/trace_info/acpi.toml + create mode 100644 trace/trace_info/memory.toml + create mode 100644 util/src/ohos_binding/hwf_adapter/usb.rs + create mode 100644 util/src/ohos_binding/usb.rs + delete mode 100644 vendor/memoffset-0.7.1/.cargo-checksum.json + delete mode 100644 vendor/memoffset-0.7.1/Cargo.toml + delete mode 100644 vendor/memoffset-0.7.1/LICENSE + delete mode 100644 vendor/memoffset-0.7.1/README.md + delete mode 100644 vendor/memoffset-0.7.1/build.rs + delete mode 100644 vendor/memoffset-0.7.1/src/lib.rs + delete mode 100644 vendor/memoffset-0.7.1/src/offset_of.rs + delete mode 100644 vendor/memoffset-0.7.1/src/raw_field.rs + delete mode 100644 vendor/memoffset-0.7.1/src/span_of.rs + +diff --git a/Cargo.lock b/Cargo.lock +index 99a1e19..3dc781f 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -28,6 +28,7 @@ dependencies = [ + "nix 0.26.2", + "once_cell", + "thiserror", ++ "trace", + "util", + "vmm-sys-util", + ] +@@ -370,11 +371,11 @@ dependencies = [ + "anyhow", + "block_backend", + "byteorder", +- "cairo-rs", + "chardev_backend", + "clap", + "cpu", + "drm-fourcc", ++ "kvm-bindings", + "libc", + "libpulse-binding", + "libpulse-simple-binding", +@@ -388,6 +389,8 @@ dependencies = [ + "rusb", + "serde", + "serde_json", ++ "strum", ++ "strum_macros", + "thiserror", + "trace", + "ui", +@@ -426,7 +429,7 @@ version = "0.3.5" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" + dependencies = [ +- "memoffset 0.8.0", ++ "memoffset", + "rustc_version", + ] + +@@ -1003,15 +1006,6 @@ version = "2.5.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +-[[package]] +-name = "memoffset" +-version = "0.7.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +-dependencies = [ +- "autocfg", +-] +- + [[package]] + name = "memoffset" + version = "0.8.0" +@@ -1054,26 +1048,6 @@ version = "0.2.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +-[[package]] +-name = "mod_test" +-version = "2.4.0" +-dependencies = [ +- "acpi", +- "anyhow", +- "byteorder", +- "devices", +- "hex", +- "libc", +- "machine", +- "machine_manager", +- "rand", +- "serde", +- "serde_json", +- "util", +- "virtio", +- "vmm-sys-util", +-] +- + [[package]] + name = "nix" + version = "0.24.3" +@@ -1094,8 +1068,6 @@ dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +- "memoffset 0.7.1", +- "pin-utils", + "static_assertions", + ] + +@@ -1180,17 +1152,6 @@ version = "6.6.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +-[[package]] +-name = "ozone" +-version = "2.4.0" +-dependencies = [ +- "anyhow", +- "libc", +- "nix 0.26.2", +- "thiserror", +- "util", +-] +- + [[package]] + name = "pango" + version = "0.17.4" +@@ -1590,18 +1551,6 @@ dependencies = [ + "util", + ] + +-[[package]] +-name = "stratovirt-img" +-version = "2.4.0" +-dependencies = [ +- "anyhow", +- "block_backend", +- "libc", +- "log", +- "machine_manager", +- "util", +-] +- + [[package]] + name = "strsim" + version = "0.10.0" +@@ -1861,6 +1810,7 @@ dependencies = [ + "address_space", + "anyhow", + "byteorder", ++ "clap", + "devices", + "hypervisor", + "kvm-bindings", +diff --git a/Cargo.toml b/Cargo.toml +index a82f9b7..6a74e1a 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -17,31 +17,10 @@ trace = { path = "trace" } + + [workspace] + members = [ +- "ozone", +- "image", +- "tests/mod_test", + ] + + [features] + default = [] +-boot_time = ["machine/boot_time"] +-scream_alsa = ["machine/scream_alsa"] +-scream_pulseaudio = ["machine/scream_pulseaudio"] +-scream_ohaudio = ["machine/scream_ohaudio"] +-pvpanic = ["machine/pvpanic"] +-demo_device = ["machine/demo_device"] +-usb_host = ["machine/usb_host"] +-usb_camera_v4l2 = ["machine/usb_camera_v4l2"] +-usb_camera_oh = ["machine/usb_camera_oh"] +-gtk = ["machine/gtk"] +-vnc = ["machine/vnc"] +-vnc_auth = ["machine/vnc_auth"] +-ohui_srv = ["machine/ohui_srv"] +-ramfb = ["machine/ramfb"] +-virtio_gpu = ["machine/virtio_gpu"] +-trace_to_logger = ["trace/trace_to_logger"] +-trace_to_ftrace = ["trace/trace_to_ftrace"] +-trace_to_hitrace = ["trace/trace_to_hitrace"] + + [package.metadata.rpm.cargo] + buildflags = ["--release"] +@@ -55,3 +34,4 @@ panic = "abort" + [profile.release] + panic = "abort" + lto = true ++debug = false +diff --git a/acpi/src/acpi_table.rs b/acpi/src/acpi_table.rs +index 1577fd5..72c205c 100644 +--- a/acpi/src/acpi_table.rs ++++ b/acpi/src/acpi_table.rs +@@ -646,3 +646,9 @@ pub mod madt_subtable { + } + } + } ++ ++/// This module describes ACPI MADT's sub-tables on riscv64 platform. ++#[cfg(target_arch = "riscv64")] ++pub mod madt_subtable { ++ // TODO ++} +diff --git a/address_space/Cargo.toml b/address_space/Cargo.toml +index b9e7b1d..c77820d 100644 +--- a/address_space/Cargo.toml ++++ b/address_space/Cargo.toml +@@ -19,3 +19,4 @@ machine_manager = { path = "../machine_manager" } + migration = { path = "../migration" } + migration_derive = { path = "../migration/migration_derive" } + util = { path = "../util" } ++trace = { path = "../trace" } +diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs +index ae18dd8..fd419d7 100644 +--- a/address_space/src/address_space.rs ++++ b/address_space/src/address_space.rs +@@ -503,6 +503,7 @@ impl AddressSpace { + /// * `count` - Memory needed length + pub fn get_address_map( + &self, ++ cache: &Option, + addr: GuestAddress, + count: u64, + res: &mut Vec, +@@ -512,7 +513,7 @@ impl AddressSpace { + + loop { + let io_vec = self +- .addr_cache_init(start) ++ .get_host_address_from_cache(start, cache) + .map(|(hva, fr_len)| Iovec { + iov_base: hva, + iov_len: std::cmp::min(len, fr_len), +@@ -610,6 +611,7 @@ impl AddressSpace { + /// + /// Return Error if the `addr` is not mapped. + pub fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> { ++ trace::trace_scope_start!(address_space_read, args = (&addr, count)); + let view = self.flat_view.load(); + + view.read(dst, addr, count)?; +@@ -628,6 +630,7 @@ impl AddressSpace { + /// + /// Return Error if the `addr` is not mapped. + pub fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> { ++ trace::trace_scope_start!(address_space_write, args = (&addr, count)); + let view = self.flat_view.load(); + + if !*self.hyp_ioevtfd_enabled.get_or_init(|| false) { +@@ -649,6 +652,7 @@ impl AddressSpace { + src.read_to_end(&mut buf).unwrap(); + + if buf.len() <= 8 { ++ buf.resize(8, 0); + let data = u64::from_bytes(buf.as_slice()).unwrap(); + if *data == evtfd.data { + if let Err(e) = evtfd.fd.write(1) { +@@ -691,6 +695,10 @@ impl AddressSpace { + /// # Note + /// To use this method, it is necessary to implement `ByteCode` trait for your object. + pub fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { ++ trace::trace_scope_start!( ++ address_space_write_direct, ++ args = (host_addr, std::mem::size_of::()) ++ ); + // Mark vmm dirty page manually if live migration is active. + MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); + +@@ -730,6 +738,10 @@ impl AddressSpace { + /// # Note + /// To use this method, it is necessary to implement `ByteCode` trait for your object. + pub fn read_object_direct(&self, host_addr: u64) -> Result { ++ trace::trace_scope_start!( ++ address_space_read_direct, ++ args = (host_addr, std::mem::size_of::()) ++ ); + let mut obj = T::default(); + let mut dst = obj.as_mut_bytes(); + // SAFETY: host_addr is managed by address_space, it has been verified for legality. +@@ -744,6 +756,7 @@ impl AddressSpace { + + /// Update the topology of memory. + pub fn update_topology(&self) -> Result<()> { ++ trace::trace_scope_start!(address_update_topology); + let old_fv = self.flat_view.load(); + + let addr_range = AddressRange::new(GuestAddress(0), self.root.size()); +diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs +index ed2ce2e..ca30977 100644 +--- a/address_space/src/host_mmap.rs ++++ b/address_space/src/host_mmap.rs +@@ -205,6 +205,7 @@ fn touch_pages(start: u64, page_size: u64, nr_pages: u64) { + /// * `size` - Size of memory. + /// * `nr_vcpus` - Number of vcpus. + fn mem_prealloc(host_addr: u64, size: u64, nr_vcpus: u8) { ++ trace::trace_scope_start!(pre_alloc, args = (size)); + let page_size = host_page_size(); + let threads = max_nr_threads(nr_vcpus); + let nr_pages = (size + page_size - 1) / page_size; +@@ -294,7 +295,7 @@ pub fn create_default_mem(mem_config: &MachineMemConfig, thread_num: u8) -> Resu + pub fn create_backend_mem(mem_config: &MemZoneConfig, thread_num: u8) -> Result { + let mut f_back: Option = None; + +- if mem_config.memfd { ++ if mem_config.memfd() { + let anon_fd = memfd_create( + &CString::new("stratovirt_anon_mem")?, + MemFdCreateFlag::empty(), +diff --git a/block_backend/src/file.rs b/block_backend/src/file.rs +index 56fac1e..45ea154 100644 +--- a/block_backend/src/file.rs ++++ b/block_backend/src/file.rs +@@ -14,7 +14,10 @@ use std::{ + cell::RefCell, + fs::File, + io::{Seek, SeekFrom}, +- os::unix::prelude::{AsRawFd, RawFd}, ++ os::{ ++ linux::fs::MetadataExt, ++ unix::prelude::{AsRawFd, RawFd}, ++ }, + rc::Rc, + sync::{ + atomic::{AtomicBool, AtomicI64, AtomicU32, AtomicU64, Ordering}, +@@ -26,7 +29,7 @@ use anyhow::{Context, Result}; + use log::error; + use vmm_sys_util::epoll::EventSet; + +-use crate::{BlockIoErrorCallback, BlockProperty}; ++use crate::{qcow2::DEFAULT_SECTOR_SIZE, BlockIoErrorCallback, BlockProperty}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use util::{ + aio::{Aio, AioCb, AioEngine, Iovec, OpCode}, +@@ -102,7 +105,7 @@ impl FileDriver { + completecb: T, + ) -> Result<()> { + if req_list.is_empty() { +- return self.complete_request(opcode, &Vec::new(), 0, 0, completecb); ++ return self.complete_request(opcode, 0, completecb); + } + let single_req = req_list.len() == 1; + let cnt = Arc::new(AtomicU32::new(req_list.len() as u32)); +@@ -127,16 +130,10 @@ impl FileDriver { + self.process_request(OpCode::Preadv, req_list, completecb) + } + +- fn complete_request( +- &mut self, +- opcode: OpCode, +- iovec: &[Iovec], +- offset: usize, +- nbytes: u64, +- completecb: T, +- ) -> Result<()> { +- let aiocb = self.package_aiocb(opcode, iovec.to_vec(), offset, nbytes, completecb); +- (self.aio.borrow_mut().complete_func)(&aiocb, nbytes as i64) ++ pub fn complete_request(&mut self, opcode: OpCode, res: i64, completecb: T) -> Result<()> { ++ let iovec: Vec = Vec::new(); ++ let aiocb = self.package_aiocb(opcode, iovec.to_vec(), 0, 0, completecb); ++ (self.aio.borrow_mut().complete_func)(&aiocb, res) + } + + pub fn write_vectored(&mut self, req_list: Vec, completecb: T) -> Result<()> { +@@ -194,6 +191,11 @@ impl FileDriver { + unregister_event_helper(self.block_prop.iothread.as_ref(), &mut self.delete_evts) + } + ++ pub fn actual_size(&mut self) -> Result { ++ let meta_data = self.file.metadata()?; ++ Ok(meta_data.st_blocks() * DEFAULT_SECTOR_SIZE) ++ } ++ + pub fn disk_size(&mut self) -> Result { + let disk_size = self + .file +diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs +index cbe37df..b6f4251 100644 +--- a/block_backend/src/lib.rs ++++ b/block_backend/src/lib.rs +@@ -15,6 +15,7 @@ pub mod qcow2; + pub mod raw; + + use std::{ ++ fmt, + fs::File, + sync::{ + atomic::{AtomicBool, AtomicU64, Ordering}, +@@ -151,6 +152,66 @@ impl CreateOptions { + } + } + ++// Transform size into string with storage units. ++fn size_to_string(size: f64) -> Result { ++ let units = vec!["", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; ++ ++ // Switch to higher power if the integer part is >= 1000, ++ // For example: 1000 * 2^30 bytes ++ // It's better to output 0.978 TiB, rather than 1000 GiB. ++ let n = (size / 1000.0 * 1024.0).log2() as u64; ++ let idx = n / 10; ++ if idx >= units.len() as u64 { ++ bail!("Input value {} is too large", size); ++ } ++ let div = 1_u64 << (idx * 10); ++ ++ // Keep three significant digits and do not output any extra zeros, ++ // For example: 512 * 2^20 bytes ++ // It's better to output 512 MiB, rather than 512.000 MiB. ++ let num_str = format!("{:.3}", size / div as f64); ++ let num_str = num_str.trim_end_matches('0').trim_end_matches('.'); ++ ++ let res = format!("{} {}", num_str, units[idx as usize]); ++ Ok(res) ++} ++ ++#[derive(Default)] ++pub struct ImageInfo { ++ pub path: String, ++ pub format: String, ++ pub actual_size: u64, ++ pub virtual_size: u64, ++ pub cluster_size: Option, ++ pub snap_lists: Option, ++} ++ ++impl fmt::Display for ImageInfo { ++ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ writeln!( ++ f, ++ "image: {}\n\ ++ file format: {}\n\ ++ virtual size: {} ({} bytes)\n\ ++ disk size: {}", ++ self.path, ++ self.format, ++ size_to_string(self.virtual_size as f64).unwrap_or_else(|e| format!("{:?}", e)), ++ self.virtual_size, ++ size_to_string(self.actual_size as f64).unwrap_or_else(|e| format!("{:?}", e)) ++ )?; ++ ++ if let Some(cluster_size) = self.cluster_size { ++ writeln!(f, "cluster_size: {}", cluster_size)?; ++ } ++ ++ if let Some(snap_lists) = &self.snap_lists { ++ write!(f, "Snapshot list:\n{}", snap_lists)?; ++ } ++ Ok(()) ++ } ++} ++ + #[derive(Default, Clone, Copy)] + pub struct DiskFragments { + pub allocated_clusters: u64, +@@ -291,6 +352,8 @@ impl Default for BlockProperty { + pub trait BlockDriverOps: Send { + fn create_image(&mut self, options: &CreateOptions) -> Result; + ++ fn query_image(&mut self, image_info: &mut ImageInfo) -> Result<()>; ++ + fn check_image(&mut self, res: &mut CheckResult, quite: bool, fix: u64) -> Result<()>; + + fn disk_size(&mut self) -> Result; +diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs +index 2dd1e4a..1b5a3df 100644 +--- a/block_backend/src/qcow2/mod.rs ++++ b/block_backend/src/qcow2/mod.rs +@@ -50,7 +50,7 @@ use crate::{ + table::{Qcow2ClusterType, Qcow2Table}, + }, + BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, CheckResult, CreateOptions, +- SECTOR_SIZE, ++ ImageInfo, SECTOR_SIZE, + }; + use machine_manager::event_loop::EventLoop; + use machine_manager::qmp::qmp_schema::SnapshotInfo; +@@ -77,7 +77,7 @@ pub const QCOW2_OFLAG_ZERO: u64 = 1 << 0; + const QCOW2_OFFSET_COMPRESSED: u64 = 1 << 62; + pub const QCOW2_OFFSET_COPIED: u64 = 1 << 63; + const MAX_L1_SIZE: u64 = 32 * (1 << 20); +-const DEFAULT_SECTOR_SIZE: u64 = 512; ++pub(crate) const DEFAULT_SECTOR_SIZE: u64 = 512; + pub(crate) const QCOW2_MAX_L1_SIZE: u64 = 1 << 25; + + // The default flush interval is 30s. +@@ -341,6 +341,13 @@ impl Qcow2Driver { + .sync_aio + .borrow_mut() + .read_ctrl_cluster(self.header.refcount_table_offset, sz)?; ++ for block_offset in &self.refcount.refcount_table { ++ if *block_offset == 0 { ++ continue; ++ } ++ let rfb_offset = block_offset & REFCOUNT_TABLE_OFFSET_MASK; ++ self.refcount.refcount_table_map.insert(rfb_offset, 1); ++ } + Ok(()) + } + +@@ -435,7 +442,7 @@ impl Qcow2Driver { + l2_entry &= !QCOW2_OFLAG_ZERO; + let mut cluster_addr = l2_entry & L2_TABLE_OFFSET_MASK; + if cluster_addr == 0 { +- let new_addr = self.alloc_cluster(1, true)?; ++ let new_addr = self.alloc_cluster(1, false)?; + l2_entry = new_addr | QCOW2_OFFSET_COPIED; + cluster_addr = new_addr & L2_TABLE_OFFSET_MASK; + } else if l2_entry & QCOW2_OFFSET_COPIED == 0 { +@@ -865,6 +872,11 @@ impl Qcow2Driver { + self.table.l1_table_offset = new_l1_table_offset; + self.table.l1_size = snap.l1_size; + self.table.l1_table = snap_l1_table; ++ self.table.l1_table_map.clear(); ++ for l1_entry in self.table.l1_table.iter() { ++ let addr = l1_entry & L1_TABLE_OFFSET_MASK; ++ self.table.l1_table_map.insert(addr, 1); ++ } + + self.qcow2_update_snapshot_refcount(old_l1_table_offset, old_l1_size as usize, -1)?; + +@@ -1291,13 +1303,14 @@ impl Qcow2Driver { + return 0; + } + +- if check & METADATA_OVERLAP_CHECK_MAINHEADER != 0 && offset < self.header.cluster_size() { ++ let cluster_size = self.header.cluster_size(); ++ if check & METADATA_OVERLAP_CHECK_MAINHEADER != 0 && offset < cluster_size { + return METADATA_OVERLAP_CHECK_MAINHEADER as i64; + } + + let size = round_up( + self.refcount.offset_into_cluster(offset) + size, +- self.header.cluster_size(), ++ cluster_size, + ) + .unwrap() as usize; + let offset = self.refcount.start_of_cluster(offset) as usize; +@@ -1321,15 +1334,10 @@ impl Qcow2Driver { + } + + if check & METADATA_OVERLAP_CHECK_ACTIVEL2 != 0 { +- for l1_entry in &self.table.l1_table { +- if ranges_overlap( +- offset, +- size, +- (l1_entry & L1_TABLE_OFFSET_MASK) as usize, +- self.header.cluster_size() as usize, +- ) +- .unwrap() +- { ++ let num = size as u64 / cluster_size; ++ for i in 0..num { ++ let addr = offset as u64 + i * cluster_size; ++ if self.table.l1_table_map.contains_key(&addr) { + return METADATA_OVERLAP_CHECK_ACTIVEL2 as i64; + } + } +@@ -1340,7 +1348,7 @@ impl Qcow2Driver { + offset, + size, + self.header.refcount_table_offset as usize, +- self.header.refcount_table_clusters as usize * self.header.cluster_size() as usize, ++ self.header.refcount_table_clusters as usize * cluster_size as usize, + ) + .unwrap() + { +@@ -1348,15 +1356,10 @@ impl Qcow2Driver { + } + + if check & METADATA_OVERLAP_CHECK_REFCOUNTBLOCK != 0 { +- for block_offset in &self.refcount.refcount_table { +- if ranges_overlap( +- offset, +- size, +- (block_offset & REFCOUNT_TABLE_OFFSET_MASK) as usize, +- self.header.cluster_size() as usize, +- ) +- .unwrap() +- { ++ let num = size as u64 / cluster_size; ++ for i in 0..num { ++ let addr = offset as u64 + i * cluster_size; ++ if self.refcount.refcount_table_map.contains_key(&addr) { + return METADATA_OVERLAP_CHECK_REFCOUNTBLOCK as i64; + } + } +@@ -1640,6 +1643,18 @@ impl BlockDriverOps for Qcow2Driver { + Ok(image_info) + } + ++ fn query_image(&mut self, info: &mut ImageInfo) -> Result<()> { ++ info.format = "qcow2".to_string(); ++ info.virtual_size = self.disk_size()?; ++ info.actual_size = self.driver.actual_size()?; ++ info.cluster_size = Some(self.header.cluster_size()); ++ ++ if !self.snapshot.snapshots.is_empty() { ++ info.snap_lists = Some(self.qcow2_list_snapshots()); ++ } ++ Ok(()) ++ } ++ + fn check_image(&mut self, res: &mut CheckResult, quite: bool, fix: u64) -> Result<()> { + let cluster_size = self.header.cluster_size(); + let refcount_order = self.header.refcount_order; +@@ -1672,8 +1687,8 @@ impl BlockDriverOps for Qcow2Driver { + let mut copied = 0; + while copied < nbytes { + let pos = offset as u64 + copied; +- match self.host_offset_for_read(pos, nbytes - copied)? { +- HostRange::DataAddress(host_offset, cnt) => { ++ match self.host_offset_for_read(pos, nbytes - copied) { ++ Ok(HostRange::DataAddress(host_offset, cnt)) => { + let (begin, end) = iovecs_split(left, cnt); + left = end; + req_list.push(CombineRequest { +@@ -1683,12 +1698,16 @@ impl BlockDriverOps for Qcow2Driver { + }); + copied += cnt; + } +- HostRange::DataNotInit(cnt) => { ++ Ok(HostRange::DataNotInit(cnt)) => { + let (begin, end) = iovecs_split(left, cnt); + left = end; + iovec_write_zero(&begin); + copied += cnt; + } ++ Err(e) => { ++ error!("Failed to read vectored: {:?}", e); ++ return self.driver.complete_request(OpCode::Preadv, -1, completecb); ++ } + } + } + +@@ -1706,7 +1725,15 @@ impl BlockDriverOps for Qcow2Driver { + while copied < nbytes { + let pos = offset as u64 + copied; + let count = self.cluster_aligned_bytes(pos, nbytes - copied); +- let host_offset = self.host_offset_for_write(pos, count)?; ++ let host_offset = match self.host_offset_for_write(pos, count) { ++ Ok(host_offset) => host_offset, ++ Err(e) => { ++ error!("Failed to write vectored: {:?}", e); ++ return self ++ .driver ++ .complete_request(OpCode::Pwritev, -1, completecb); ++ } ++ }; + if let Some(end) = req_list.last_mut() { + if end.offset + end.nbytes == host_offset { + end.nbytes += count; +diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs +index 1a3dfdd..b58e371 100644 +--- a/block_backend/src/qcow2/refcount.rs ++++ b/block_backend/src/qcow2/refcount.rs +@@ -10,7 +10,7 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use std::{cell::RefCell, rc::Rc}; ++use std::{cell::RefCell, collections::HashMap, rc::Rc}; + + use anyhow::{bail, Context, Result}; + use log::{error, info}; +@@ -32,6 +32,9 @@ use util::{ + // The max refcount table size default is 4 clusters; + const MAX_REFTABLE_NUM: u64 = 4; + ++// Default refcount table map length, which can describe 512GiB data for 64Kib cluster. ++const REFCOUNT_TABLE_MAP_LEN: usize = 256; ++ + #[derive(Eq, PartialEq, Clone)] + pub enum Qcow2DiscardType { + Never, +@@ -64,6 +67,7 @@ impl DiscardTask { + #[derive(Clone)] + pub struct RefCount { + pub refcount_table: Vec, ++ pub refcount_table_map: HashMap, + sync_aio: Rc>, + pub(crate) refcount_blk_cache: Qcow2Cache, + pub discard_list: Vec, +@@ -87,6 +91,7 @@ impl RefCount { + pub fn new(sync_aio: Rc>) -> Self { + RefCount { + refcount_table: Vec::new(), ++ refcount_table_map: HashMap::with_capacity(REFCOUNT_TABLE_MAP_LEN), + sync_aio, + refcount_blk_cache: Qcow2Cache::default(), + discard_list: Vec::new(), +@@ -217,9 +222,11 @@ impl RefCount { + new_table.resize(new_table_size as usize, 0); + let start_offset = start_idx * self.cluster_size; + let mut table_offset = start_offset; ++ let mut added_rb = Vec::new(); + for i in 0..new_block_clusters { + if new_table[i as usize] == 0 { + new_table[i as usize] = table_offset; ++ added_rb.push(table_offset & REFCOUNT_TABLE_OFFSET_MASK); + table_offset += self.cluster_size; + } + } +@@ -247,6 +254,9 @@ impl RefCount { + let old_table_offset = self.refcount_table_offset; + let old_table_clusters = self.refcount_table_clusters; + self.refcount_table = new_table; ++ for rb_offset in added_rb.iter() { ++ self.refcount_table_map.insert(*rb_offset, 1); ++ } + self.refcount_table_offset = header.refcount_table_offset; + self.refcount_table_clusters = header.refcount_table_clusters; + self.refcount_table_size = new_table_size; +@@ -316,7 +326,7 @@ impl RefCount { + bail!("Failed to update refcount, offset is not aligned to cluster"); + } + let first_cluster = bytes_to_clusters(offset, self.cluster_size).unwrap(); +- let mut rc_vec = Vec::new(); ++ let mut rc_vec: Vec<(u64, u64, usize)> = Vec::with_capacity(clusters as usize); + let mut i = 0; + while i < clusters { + let rt_idx = (first_cluster + i) >> self.refcount_blk_bits; +@@ -381,6 +391,22 @@ impl RefCount { + self.refcount_blk_cache.flush(self.sync_aio.clone()) + } + ++ fn get_refcount_block_cache(&mut self, rt_idx: u64) -> Result>> { ++ let entry = self.refcount_blk_cache.get(rt_idx); ++ let cache_entry = if let Some(entry) = entry { ++ entry.clone() ++ } else { ++ self.load_refcount_block(rt_idx).with_context(|| { ++ format!("Failed to get refcount block cache, index is {}", rt_idx) ++ })?; ++ self.refcount_blk_cache ++ .get(rt_idx) ++ .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? ++ .clone() ++ }; ++ Ok(cache_entry) ++ } ++ + fn set_refcount( + &mut self, + rt_idx: u64, +@@ -391,18 +417,10 @@ impl RefCount { + ) -> Result<()> { + let is_add = added > 0; + let added_value = added.unsigned_abs() as u16; +- if !self.refcount_blk_cache.contains_keys(rt_idx) { +- self.load_refcount_block(rt_idx).with_context(|| { +- format!("Failed to get refcount block cache, index is {}", rt_idx) +- })?; +- } + let cache_entry = self +- .refcount_blk_cache +- .get(rt_idx) +- .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? +- .clone(); +- +- let mut rb_vec = Vec::new(); ++ .get_refcount_block_cache(rt_idx) ++ .with_context(|| "Get refcount block cache failed")?; ++ let mut rb_vec: Vec = Vec::with_capacity(clusters); + let mut borrowed_entry = cache_entry.borrow_mut(); + let is_dirty = borrowed_entry.dirty_info.is_dirty; + for i in 0..clusters { +@@ -471,17 +489,9 @@ impl RefCount { + ); + } + +- if !self.refcount_blk_cache.contains_keys(rt_idx) { +- self.load_refcount_block(rt_idx).with_context(|| { +- format!("Failed to get refcount block cache, index is {}", rt_idx) +- })?; +- } + let cache_entry = self +- .refcount_blk_cache +- .get(rt_idx) +- .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? +- .clone(); +- ++ .get_refcount_block_cache(rt_idx) ++ .with_context(|| "Get refcount block cache failed")?; + let rb_idx = self.cluster_in_rc_block(cluster) as usize; + let rc_value = cache_entry.borrow_mut().get_entry_map(rb_idx).unwrap(); + +@@ -542,6 +552,8 @@ impl RefCount { + + // Update refcount table. + self.refcount_table[rt_idx as usize] = alloc_offset; ++ let rb_offset = alloc_offset & REFCOUNT_TABLE_OFFSET_MASK; ++ self.refcount_table_map.insert(rb_offset, 1); + let rc_block = vec![0_u8; self.cluster_size as usize]; + let cache_entry = Rc::new(RefCell::new(CacheTable::new( + alloc_offset, +diff --git a/block_backend/src/qcow2/table.rs b/block_backend/src/qcow2/table.rs +index 5886bec..6554f3f 100644 +--- a/block_backend/src/qcow2/table.rs ++++ b/block_backend/src/qcow2/table.rs +@@ -10,7 +10,7 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use std::{cell::RefCell, rc::Rc}; ++use std::{cell::RefCell, collections::HashMap, rc::Rc}; + + use anyhow::{Context, Result}; + use log::info; +@@ -28,6 +28,9 @@ use crate::{ + use machine_manager::config::MAX_L2_CACHE_SIZE; + use util::num_ops::div_round_up; + ++// Default l1 table map length, which can describe 512GiB data for 64KiB cluster. ++const L1_TABLE_MAP_LEN: usize = 1024; ++ + #[derive(PartialEq, Eq, Debug)] + pub enum Qcow2ClusterType { + /// Cluster is unallocated. +@@ -81,6 +84,7 @@ pub struct Qcow2Table { + cluster_bits: u64, + cluster_size: u64, + pub l1_table: Vec, ++ pub l1_table_map: HashMap, + pub l1_table_offset: u64, + pub l1_size: u32, + pub l2_table_cache: Qcow2Cache, +@@ -96,6 +100,7 @@ impl Qcow2Table { + cluster_bits: 0, + cluster_size: 0, + l1_table: Vec::new(), ++ l1_table_map: HashMap::with_capacity(L1_TABLE_MAP_LEN), + l1_table_offset: 0, + l1_size: 0, + l2_table_cache: Qcow2Cache::default(), +@@ -143,6 +148,10 @@ impl Qcow2Table { + .sync_aio + .borrow_mut() + .read_ctrl_cluster(self.l1_table_offset, self.l1_size as u64)?; ++ for l1_entry in &self.l1_table { ++ let l1_entry_addr = l1_entry & L1_TABLE_OFFSET_MASK; ++ self.l1_table_map.insert(l1_entry_addr, 1); ++ } + Ok(()) + } + +@@ -185,7 +194,11 @@ impl Qcow2Table { + } + + pub fn update_l1_table(&mut self, l1_index: usize, l2_address: u64) { ++ let old_addr = self.l1_table[l1_index] & L1_TABLE_OFFSET_MASK; ++ let new_addr = l2_address & L1_TABLE_OFFSET_MASK; + self.l1_table[l1_index] = l2_address; ++ self.l1_table_map.remove(&old_addr); ++ self.l1_table_map.insert(new_addr, 1); + } + + pub fn update_l2_table( +diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs +index c051b3f..d8622d5 100644 +--- a/block_backend/src/raw.rs ++++ b/block_backend/src/raw.rs +@@ -25,7 +25,7 @@ use crate::{ + file::{CombineRequest, FileDriver}, + qcow2::is_aligned, + BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, CheckResult, CreateOptions, +- SECTOR_SIZE, ++ ImageInfo, SECTOR_SIZE, + }; + use util::{ + aio::{get_iov_size, raw_write, Aio, Iovec}, +@@ -92,6 +92,13 @@ impl BlockDriverOps for RawDriver { + Ok(image_info) + } + ++ fn query_image(&mut self, info: &mut ImageInfo) -> Result<()> { ++ info.format = "raw".to_string(); ++ info.virtual_size = self.disk_size()?; ++ info.actual_size = self.driver.actual_size()?; ++ Ok(()) ++ } ++ + fn check_image(&mut self, _res: &mut CheckResult, _quite: bool, _fix: u64) -> Result<()> { + bail!("This image format does not support checks"); + } +diff --git a/boot_loader/Cargo.toml b/boot_loader/Cargo.toml +index cbd2287..8570b82 100644 +--- a/boot_loader/Cargo.toml ++++ b/boot_loader/Cargo.toml +@@ -8,7 +8,7 @@ license = "Mulan PSL v2" + [dependencies] + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + log = "0.4" + address_space = { path = "../address_space" } + devices = { path = "../devices" } +diff --git a/boot_loader/src/lib.rs b/boot_loader/src/lib.rs +index 46955e8..9aa2888 100644 +--- a/boot_loader/src/lib.rs ++++ b/boot_loader/src/lib.rs +@@ -25,6 +25,7 @@ + //! + //! - `x86_64` + //! - `aarch64` ++//! - `riscv64` + //! + //! ## Examples + //! +@@ -87,6 +88,8 @@ + #[cfg(target_arch = "aarch64")] + mod aarch64; + pub mod error; ++#[cfg(target_arch = "riscv64")] ++pub mod riscv64; + #[cfg(target_arch = "x86_64")] + mod x86_64; + +@@ -98,6 +101,12 @@ pub use aarch64::AArch64BootLoader as BootLoader; + pub use aarch64::AArch64BootLoaderConfig as BootLoaderConfig; + pub use error::BootLoaderError; + ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::load_linux; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVBootLoader as BootLoader; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVBootLoaderConfig as BootLoaderConfig; + #[cfg(target_arch = "x86_64")] + pub use x86_64::load_linux; + #[cfg(target_arch = "x86_64")] +diff --git a/boot_loader/src/riscv64/mod.rs b/boot_loader/src/riscv64/mod.rs +new file mode 100644 +index 0000000..773ff26 +--- /dev/null ++++ b/boot_loader/src/riscv64/mod.rs +@@ -0,0 +1,202 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::fs::File; ++use std::io::Read; ++use std::path::{Path, PathBuf}; ++use std::sync::{Arc, Mutex}; ++ ++use crate::error::BootLoaderError; ++use address_space::{AddressSpace, GuestAddress}; ++use anyhow::{anyhow, Context, Result}; ++use devices::legacy::{error::LegacyError as FwcfgErrorKind, FwCfgEntryType, FwCfgOps}; ++use log::info; ++use util::byte_code::ByteCode; ++ ++const RISCV64_KERNEL_OFFSET: u64 = 0x20_0000; ++const SZ_4M: u64 = 0x00400000; ++ ++/// Boot loader config used for riscv. ++#[derive(Default, Debug)] ++pub struct RISCVBootLoaderConfig { ++ /// Path of kernel image. ++ pub kernel: Option, ++ /// Path of initrd image. ++ pub initrd: Option, ++ /// Start address of guest memory. ++ pub mem_start: u64, ++} ++ ++/// The start address for `kernel image`, `initrd image` and `dtb` in guest memory. ++pub struct RISCVBootLoader { ++ /// PC register on riscv platform. ++ pub boot_pc: u64, ++ /// Start address for `initrd image` in guest memory. ++ pub initrd_start: u64, ++ /// Initrd file size, 0 means no initrd file. ++ pub initrd_size: u64, ++ /// Start address for `dtb` in guest memory. ++ pub dtb_start: u64, ++} ++ ++fn load_kernel( ++ fwcfg: Option<&Arc>>, ++ kernel_start: u64, ++ kernel_path: &Path, ++ sys_mem: &Arc, ++) -> Result { ++ let mut kernel_image = ++ File::open(kernel_path).with_context(|| anyhow!(BootLoaderError::BootLoaderOpenKernel))?; ++ let kernel_size = kernel_image.metadata().unwrap().len(); ++ let kernel_end = kernel_start + kernel_size; ++ ++ if let Some(fw_cfg) = fwcfg { ++ let mut kernel_data = Vec::new(); ++ kernel_image.read_to_end(&mut kernel_data)?; ++ let mut lock_dev = fw_cfg.lock().unwrap(); ++ lock_dev ++ .add_data_entry( ++ FwCfgEntryType::KernelSize, ++ (kernel_size as u32).as_bytes().to_vec(), ++ ) ++ .with_context(|| anyhow!(FwcfgErrorKind::AddEntryErr("KernelSize".to_string())))?; ++ lock_dev ++ .add_data_entry(FwCfgEntryType::KernelData, kernel_data) ++ .with_context(|| anyhow!(FwcfgErrorKind::AddEntryErr("KernelData".to_string())))?; ++ } else { ++ if sys_mem ++ .memory_end_address() ++ .raw_value() ++ .checked_sub(kernel_end) ++ .is_none() ++ { ++ return Err(anyhow!(BootLoaderError::KernelOverflow( ++ kernel_start, ++ kernel_size ++ ))); ++ } ++ sys_mem ++ .write(&mut kernel_image, GuestAddress(kernel_start), kernel_size) ++ .with_context(|| "Fail to write kernel to guest memory")?; ++ } ++ Ok(kernel_end) ++} ++ ++fn load_initrd( ++ fwcfg: Option<&Arc>>, ++ initrd_path: &Path, ++ sys_mem: &Arc, ++ kernel_end: u64, ++) -> Result<(u64, u64)> { ++ let mut initrd_image = ++ File::open(initrd_path).with_context(|| anyhow!(BootLoaderError::BootLoaderOpenInitrd))?; ++ let initrd_size = initrd_image.metadata().unwrap().len(); ++ ++ let initrd_start = if let Some(addr) = sys_mem ++ .memory_end_address() ++ .raw_value() ++ .checked_sub(initrd_size) ++ .filter(|addr| addr >= &kernel_end) ++ { ++ addr ++ } else { ++ return Err(anyhow!(BootLoaderError::InitrdOverflow( ++ kernel_end, ++ initrd_size ++ ))); ++ }; ++ ++ if let Some(fw_cfg) = fwcfg { ++ let mut initrd_data = Vec::new(); ++ initrd_image.read_to_end(&mut initrd_data)?; ++ let mut lock_dev = fw_cfg.lock().unwrap(); ++ lock_dev ++ .add_data_entry( ++ FwCfgEntryType::InitrdAddr, ++ (initrd_start as u32).as_bytes().to_vec(), ++ ) ++ .with_context(|| anyhow!(FwcfgErrorKind::AddEntryErr("InitrdAddr".to_string())))?; ++ lock_dev ++ .add_data_entry( ++ FwCfgEntryType::InitrdSize, ++ (initrd_size as u32).as_bytes().to_vec(), ++ ) ++ .with_context(|| anyhow!(FwcfgErrorKind::AddEntryErr("InitrdSize".to_string())))?; ++ lock_dev ++ .add_data_entry(FwCfgEntryType::InitrdData, initrd_data) ++ .with_context(|| anyhow!(FwcfgErrorKind::AddEntryErr("InitrdData".to_string())))?; ++ } else { ++ sys_mem ++ .write(&mut initrd_image, GuestAddress(initrd_start), initrd_size) ++ .with_context(|| "Fail to write initrd to guest memory")?; ++ } ++ ++ Ok((initrd_start, initrd_size)) ++} ++ ++/// Load linux kernel and other boot source to Guest Memory. ++/// ++/// # Steps ++/// ++/// 1. Prepare for linux kernel boot env, return guest memory layout. ++/// 2. According guest memory layout, load linux kernel to guest memory. ++/// 3. According guest memory layout, load initrd image to guest memory. ++/// ++/// # Arguments ++/// ++/// * `config` - boot source config, contains kernel, initrd. ++/// * `sys_mem` - guest memory. ++/// ++/// # Errors ++/// ++/// Load kernel, initrd to guest memory failed. Boot source is broken or ++/// guest memory is abnormal. ++pub fn load_linux( ++ config: &RISCVBootLoaderConfig, ++ sys_mem: &Arc, ++ fwcfg: Option<&Arc>>, ++) -> Result { ++ // The memory layout is as follow: ++ // 1. kernel address: memory start + RISCV64_KERNEL_OFFSET ++ // 2. dtb address: kernel end + SZ_4M ++ // 3. initrd address: memory end - inird_size ++ let kernel_start = config.mem_start + RISCV64_KERNEL_OFFSET; ++ let boot_pc = if fwcfg.is_some() { 0 } else { kernel_start }; ++ ++ let kernel_end = load_kernel( ++ fwcfg, ++ kernel_start, ++ config.kernel.as_ref().unwrap(), ++ sys_mem, ++ ) ++ .with_context(|| "Fail to load kernel")?; ++ ++ let dtb_addr = kernel_end + SZ_4M; ++ ++ let mut initrd_start = 0_u64; ++ let mut initrd_size = 0_u64; ++ if config.initrd.is_some() { ++ let initrd_tuple = load_initrd(fwcfg, config.initrd.as_ref().unwrap(), sys_mem, kernel_end) ++ .with_context(|| "Fail to load initrd")?; ++ initrd_start = initrd_tuple.0; ++ initrd_size = initrd_tuple.1; ++ } else { ++ info!("No initrd image file."); ++ } ++ ++ Ok(RISCVBootLoader { ++ boot_pc, ++ initrd_start, ++ initrd_size, ++ dtb_start: dtb_addr, ++ }) ++} +diff --git a/build.rs b/build.rs +index 96f77ff..13b5a89 100644 +--- a/build.rs ++++ b/build.rs +@@ -16,6 +16,9 @@ fn ohos_env_configure() { + println!("cargo:rustc-link-arg=--verbose"); + println!("cargo:rustc-link-arg=--sysroot={}/sysroot", ohos_sdk_path); + println!("cargo:rustc-link-arg=-lpixman_static"); ++ if cfg!(feature = "usb_host") { ++ println!("cargo:rustc-link-arg=-lusb-1.0"); ++ } + println!( + "cargo:rustc-link-search={}/sysroot/usr/lib/aarch64-linux-ohos", + ohos_sdk_path +diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs +index 7a07a78..bd2b37d 100644 +--- a/chardev_backend/src/chardev.rs ++++ b/chardev_backend/src/chardev.rs +@@ -10,8 +10,9 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + ++use std::collections::VecDeque; + use std::fs::{read_link, File, OpenOptions}; +-use std::io::{Stdin, Stdout}; ++use std::io::{ErrorKind, Stdin, Stdout}; + use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; + use std::path::PathBuf; + use std::rc::Rc; +@@ -24,11 +25,12 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag}; + use nix::pty::openpty; + use nix::sys::termios::{cfmakeraw, tcgetattr, tcsetattr, SetArg, Termios}; + use vmm_sys_util::epoll::EventSet; ++use vmm_sys_util::eventfd::EventFd; + + use machine_manager::event_loop::EventLoop; + use machine_manager::machine::{PathInfo, PTY_PATH}; + use machine_manager::{ +- config::{ChardevConfig, ChardevType}, ++ config::{ChardevConfig, ChardevType, SocketType}, + temp_cleaner::TempCleaner, + }; + use util::file::clear_file; +@@ -39,6 +41,8 @@ use util::set_termi_raw_mode; + use util::socket::{SocketListener, SocketStream}; + use util::unix::limit_permission; + ++const BUF_QUEUE_SIZE: usize = 128; ++ + /// Provide the trait that helps handle the input data. + pub trait InputReceiver: Send { + /// Handle the input data and trigger interrupt if necessary. +@@ -85,13 +89,17 @@ pub struct Chardev { + /// Scheduled DPC to unpause input stream. + /// Unpause must be done inside event-loop + unpause_timer: Option, ++ /// output listener to notify when output stream fd can be written ++ output_listener_fd: Option>, ++ /// output buffer queue ++ outbuf: VecDeque>, + } + + impl Chardev { + pub fn new(chardev_cfg: ChardevConfig) -> Self { + Chardev { +- id: chardev_cfg.id, +- backend: chardev_cfg.backend, ++ id: chardev_cfg.id(), ++ backend: chardev_cfg.classtype, + listener: None, + input: None, + output: None, +@@ -100,17 +108,19 @@ impl Chardev { + dev: None, + wait_port: false, + unpause_timer: None, ++ output_listener_fd: None, ++ outbuf: VecDeque::with_capacity(BUF_QUEUE_SIZE), + } + } + + pub fn realize(&mut self) -> Result<()> { + match &self.backend { +- ChardevType::Stdio => { ++ ChardevType::Stdio { .. } => { + set_termi_raw_mode().with_context(|| "Failed to set terminal to raw mode")?; + self.input = Some(Arc::new(Mutex::new(std::io::stdin()))); + self.output = Some(Arc::new(Mutex::new(std::io::stdout()))); + } +- ChardevType::Pty => { ++ ChardevType::Pty { .. } => { + let (master, path) = + set_pty_raw_mode().with_context(|| "Failed to set pty to raw mode")?; + info!("Pty path is: {:?}", path); +@@ -125,58 +135,43 @@ impl Chardev { + self.input = Some(master_arc.clone()); + self.output = Some(master_arc); + } +- ChardevType::UnixSocket { +- path, +- server, +- nowait, +- } => { ++ ChardevType::Socket { server, nowait, .. } => { + if !*server || !*nowait { + bail!( + "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", + &self.id + ); + } +- +- clear_file(path.clone())?; +- let listener = SocketListener::bind_by_uds(path).with_context(|| { +- format!( +- "Failed to bind socket for chardev \'{}\', path: {}", +- &self.id, path +- ) +- })?; +- self.listener = Some(listener); +- +- // add file to temporary pool, so it could be cleaned when vm exit. +- TempCleaner::add_path(path.clone()); +- limit_permission(path).with_context(|| { +- format!( +- "Failed to change file permission for chardev \'{}\', path: {}", +- &self.id, path +- ) +- })?; +- } +- ChardevType::TcpSocket { +- host, +- port, +- server, +- nowait, +- } => { +- if !*server || !*nowait { +- bail!( +- "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", +- &self.id +- ); ++ let socket_type = self.backend.socket_type()?; ++ if let SocketType::Tcp { host, port } = socket_type { ++ let listener = SocketListener::bind_by_tcp(&host, port).with_context(|| { ++ format!( ++ "Failed to bind socket for chardev \'{}\', address: {}:{}", ++ &self.id, host, port ++ ) ++ })?; ++ self.listener = Some(listener); ++ } else if let SocketType::Unix { path } = socket_type { ++ clear_file(path.clone())?; ++ let listener = SocketListener::bind_by_uds(&path).with_context(|| { ++ format!( ++ "Failed to bind socket for chardev \'{}\', path: {}", ++ &self.id, path ++ ) ++ })?; ++ self.listener = Some(listener); ++ ++ // add file to temporary pool, so it could be cleaned when vm exit. ++ TempCleaner::add_path(path.clone()); ++ limit_permission(&path).with_context(|| { ++ format!( ++ "Failed to change file permission for chardev \'{}\', path: {}", ++ &self.id, path ++ ) ++ })?; + } +- +- let listener = SocketListener::bind_by_tcp(host, *port).with_context(|| { +- format!( +- "Failed to bind socket for chardev \'{}\', address: {}:{}", +- &self.id, host, port +- ) +- })?; +- self.listener = Some(listener); + } +- ChardevType::File(path) => { ++ ChardevType::File { path, .. } => { + let file = Arc::new(Mutex::new( + OpenOptions::new() + .read(true) +@@ -237,7 +232,7 @@ impl Chardev { + let unpause_fn = Box::new(move || { + let res = EventLoop::update_event( + vec![EventNotifier::new( +- NotifierOperation::Modify, ++ NotifierOperation::AddEvents, + input_fd, + None, + EventSet::IN | EventSet::HANG_UP, +@@ -261,6 +256,107 @@ impl Chardev { + self.unpause_timer = None; + } + } ++ ++ fn clear_outbuf(&mut self) { ++ self.outbuf.clear(); ++ } ++ ++ pub fn outbuf_is_full(&self) -> bool { ++ self.outbuf.len() == self.outbuf.capacity() ++ } ++ ++ pub fn fill_outbuf(&mut self, buf: Vec, listener_fd: Option>) -> Result<()> { ++ match self.backend { ++ ChardevType::File { .. } | ChardevType::Pty { .. } | ChardevType::Stdio { .. } => { ++ if self.output.is_none() { ++ bail!("chardev has no output"); ++ } ++ return write_buffer_sync(self.output.as_ref().unwrap().clone(), buf); ++ } ++ ChardevType::Socket { .. } => (), ++ } ++ ++ if self.output.is_none() { ++ return Ok(()); ++ } ++ ++ if self.outbuf_is_full() { ++ bail!("Failed to append buffer because output buffer queue is full"); ++ } ++ self.outbuf.push_back(buf); ++ self.output_listener_fd = listener_fd; ++ ++ let event_notifier = EventNotifier::new( ++ NotifierOperation::AddEvents, ++ self.stream_fd.unwrap(), ++ None, ++ EventSet::OUT, ++ Vec::new(), ++ ); ++ EventLoop::update_event(vec![event_notifier], None)?; ++ Ok(()) ++ } ++ ++ fn consume_outbuf(&mut self) -> Result<()> { ++ let output = self.output.as_ref().unwrap(); ++ while !self.outbuf.is_empty() { ++ if write_buffer_async(output.clone(), self.outbuf.front_mut().unwrap())? { ++ break; ++ } ++ self.outbuf.pop_front(); ++ } ++ Ok(()) ++ } ++} ++ ++fn write_buffer_sync(writer: Arc>, buf: Vec) -> Result<()> { ++ let len = buf.len(); ++ let mut written = 0; ++ let mut locked_writer = writer.lock().unwrap(); ++ ++ while written < len { ++ match locked_writer.write(&buf[written..len]) { ++ Ok(n) => written += n, ++ Err(e) => bail!("chardev failed to write file with error {:?}", e), ++ } ++ } ++ locked_writer ++ .flush() ++ .with_context(|| "chardev failed to flush")?; ++ Ok(()) ++} ++ ++// If write is blocked, return true. Otherwise return false. ++fn write_buffer_async( ++ writer: Arc>, ++ buf: &mut Vec, ++) -> Result { ++ let len = buf.len(); ++ let mut locked_writer = writer.lock().unwrap(); ++ let mut written = 0; ++ ++ while written < len { ++ match locked_writer.write(&buf[written..len]) { ++ Ok(0) => break, ++ Ok(n) => written += n, ++ Err(e) => { ++ let err_type = e.kind(); ++ if err_type != ErrorKind::WouldBlock && err_type != ErrorKind::Interrupted { ++ bail!("chardev failed to write data with error {:?}", e); ++ } ++ break; ++ } ++ } ++ } ++ locked_writer ++ .flush() ++ .with_context(|| "chardev failed to flush")?; ++ ++ if written == len { ++ return Ok(false); ++ } ++ buf.drain(0..written); ++ Ok(true) + } + + fn set_pty_raw_mode() -> Result<(i32, PathBuf)> { +@@ -453,10 +549,10 @@ fn get_socket_notifier(chardev: Arc>) -> Option { + locked_receiver.set_paused(); + + return Some(vec![EventNotifier::new( +- NotifierOperation::Modify, ++ NotifierOperation::DeleteEvents, + stream_fd, + None, +- EventSet::HANG_UP, ++ EventSet::IN, + vec![], + )]); + } +@@ -486,12 +582,53 @@ fn get_socket_notifier(chardev: Arc>) -> Option { + None + }); + ++ let handling_chardev = cloned_chardev.clone(); ++ let output_handler = Rc::new(move |event, fd| { ++ if event & EventSet::OUT != EventSet::OUT { ++ return None; ++ } ++ ++ let mut locked_cdev = handling_chardev.lock().unwrap(); ++ if let Err(e) = locked_cdev.consume_outbuf() { ++ error!("Failed to consume outbuf with error {:?}", e); ++ locked_cdev.clear_outbuf(); ++ return Some(vec![EventNotifier::new( ++ NotifierOperation::DeleteEvents, ++ fd, ++ None, ++ EventSet::OUT, ++ Vec::new(), ++ )]); ++ } ++ ++ if locked_cdev.output_listener_fd.is_some() { ++ let fd = locked_cdev.output_listener_fd.as_ref().unwrap(); ++ if let Err(e) = fd.write(1) { ++ error!("Failed to write eventfd with error {:?}", e); ++ return None; ++ } ++ locked_cdev.output_listener_fd = None; ++ } ++ ++ if locked_cdev.outbuf.is_empty() { ++ Some(vec![EventNotifier::new( ++ NotifierOperation::DeleteEvents, ++ fd, ++ None, ++ EventSet::OUT, ++ Vec::new(), ++ )]) ++ } else { ++ None ++ } ++ }); ++ + Some(vec![EventNotifier::new( + NotifierOperation::AddShared, + stream_fd, + Some(listener_fd), + EventSet::IN | EventSet::HANG_UP, +- vec![input_handler], ++ vec![input_handler, output_handler], + )]) + }); + +@@ -510,11 +647,10 @@ impl EventNotifierHelper for Chardev { + let notifier = { + let backend = chardev.lock().unwrap().backend.clone(); + match backend { +- ChardevType::Stdio => get_terminal_notifier(chardev), +- ChardevType::Pty => get_terminal_notifier(chardev), +- ChardevType::UnixSocket { .. } => get_socket_notifier(chardev), +- ChardevType::TcpSocket { .. } => get_socket_notifier(chardev), +- ChardevType::File(_) => None, ++ ChardevType::Stdio { .. } => get_terminal_notifier(chardev), ++ ChardevType::Pty { .. } => get_terminal_notifier(chardev), ++ ChardevType::Socket { .. } => get_socket_notifier(chardev), ++ ChardevType::File { .. } => None, + } + }; + notifier.map_or(Vec::new(), |value| vec![value]) +diff --git a/cpu/Cargo.toml b/cpu/Cargo.toml +index 1be3d7b..44265b6 100644 +--- a/cpu/Cargo.toml ++++ b/cpu/Cargo.toml +@@ -9,7 +9,7 @@ description = "CPU emulation" + [dependencies] + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + nix = { version = "0.26.2", default-features = false, features = ["fs", "feature"] } + log = "0.4" + libc = "0.2" +diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs +index 873cb49..3da91b1 100644 +--- a/cpu/src/lib.rs ++++ b/cpu/src/lib.rs +@@ -26,12 +26,15 @@ + //! + //! - `x86_64` + //! - `aarch64` ++//! - `riscv64` + + pub mod error; + + #[allow(clippy::upper_case_acronyms)] + #[cfg(target_arch = "aarch64")] + mod aarch64; ++#[cfg(target_arch = "riscv64")] ++mod riscv64; + #[cfg(target_arch = "x86_64")] + mod x86_64; + +@@ -52,6 +55,14 @@ pub use aarch64::PMU_INTR; + #[cfg(target_arch = "aarch64")] + pub use aarch64::PPI_BASE; + pub use error::CpuError; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVCPUBootConfig as CPUBootConfig; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVCPUState as ArchCPU; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVCPUTopology as CPUTopology; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::RISCVRegsIndex as RegsIndex; + #[cfg(target_arch = "x86_64")] + pub use x86_64::X86CPUBootConfig as CPUBootConfig; + #[cfg(target_arch = "x86_64")] +@@ -118,7 +129,7 @@ pub trait CPUInterface { + /// Realize `CPU` structure, set registers value for `CPU`. + fn realize( + &self, +- boot: &Option, ++ boot: &CPUBootConfig, + topology: &CPUTopology, + #[cfg(target_arch = "aarch64")] features: &CPUFeatures, + ) -> Result<()>; +@@ -160,7 +171,7 @@ pub trait CPUHypervisorOps: Send + Sync { + fn set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &Option, ++ boot_config: &CPUBootConfig, + #[cfg(target_arch = "aarch64")] vcpu_config: &CPUFeatures, + ) -> Result<()>; + +@@ -310,7 +321,7 @@ impl CPU { + impl CPUInterface for CPU { + fn realize( + &self, +- boot: &Option, ++ boot: &CPUBootConfig, + topology: &CPUTopology, + #[cfg(target_arch = "aarch64")] config: &CPUFeatures, + ) -> Result<()> { +diff --git a/cpu/src/riscv64/mod.rs b/cpu/src/riscv64/mod.rs +new file mode 100644 +index 0000000..5fd97a3 +--- /dev/null ++++ b/cpu/src/riscv64/mod.rs +@@ -0,0 +1,205 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::sync::{Arc, Mutex}; ++ ++use anyhow::{Context, Result}; ++use kvm_bindings::{ ++ kvm_mp_state as MpState, ++ // AIA CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ kvm_riscv_aia_csr as AiaCsrs, ++ // CONFIG registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ kvm_riscv_config as ConfigRegs, ++ // CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ kvm_riscv_core as CoreRegs, ++ // General CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ kvm_riscv_csr as Csrs, ++ // TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ kvm_riscv_timer as TimerRegs, ++ KVM_MP_STATE_RUNNABLE as MP_STATE_RUNNABLE, ++}; ++ ++use crate::CPU; ++use migration::{ ++ DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, ++}; ++use migration_derive::{ByteCode, Desc}; ++use util::byte_code::ByteCode; ++ ++/// RISCV CPU booting configure information ++#[derive(Default, Copy, Clone, Debug)] ++pub struct RISCVCPUBootConfig { ++ pub fdt_addr: u64, ++ pub boot_pc: u64, ++} ++ ++#[derive(Copy, Clone, Debug, PartialEq, Eq)] ++pub enum RISCVRegsIndex { ++ MpState, ++ ConfigRegs, ++ CoreRegs, ++ AiaCsrs, ++ Csrs, ++ TimerRegs, ++} ++ ++#[derive(Default, Copy, Clone, Debug)] ++pub struct RISCVCPUTopology {} ++ ++impl RISCVCPUTopology { ++ pub fn new() -> Self { ++ RISCVCPUTopology::default() ++ } ++ ++ pub fn set_topology(self, _topology: (u8, u8, u8)) -> Self { ++ self ++ } ++} ++ ++/// riscv64 CPU architect information ++#[repr(C)] ++#[derive(Copy, Clone, Desc, ByteCode)] ++#[desc_version(compat_version = "0.1.0")] ++pub struct RISCVCPUState { ++ /// The vcpu id, `0` means primary CPU. ++ pub apic_id: u32, ++ /// Vcpu mpstate register. ++ pub mp_state: MpState, ++ /// Vcpu core registers. ++ pub core_regs: CoreRegs, ++ /// AIA CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ pub aia_csrs: AiaCsrs, ++ /// General CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ pub csrs: Csrs, ++ /// CONFIG registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ pub config_regs: ConfigRegs, ++ /// TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG ++ pub timer_regs: TimerRegs, ++ /// XLEN to determine RV64 or RV32 ++ pub xlen: u64, ++} ++ ++impl RISCVCPUState { ++ /// Allocates a new `RISCVCPUState`. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_id` - ID of this `CPU`. ++ pub fn new(vcpu_id: u32) -> Self { ++ let mp_state = MpState { ++ mp_state: MP_STATE_RUNNABLE, ++ }; ++ ++ RISCVCPUState { ++ apic_id: vcpu_id, ++ mp_state, ++ xlen: 64, ++ ..Default::default() ++ } ++ } ++ ++ pub fn set(&mut self, cpu_state: &Arc>) { ++ let locked_cpu_state = cpu_state.lock().unwrap(); ++ self.apic_id = locked_cpu_state.apic_id; ++ self.mp_state = locked_cpu_state.mp_state; ++ self.core_regs = locked_cpu_state.core_regs; ++ self.aia_csrs = locked_cpu_state.aia_csrs; ++ self.csrs = locked_cpu_state.csrs; ++ self.config_regs = locked_cpu_state.config_regs; ++ self.timer_regs = locked_cpu_state.timer_regs; ++ self.xlen = locked_cpu_state.xlen; ++ } ++ ++ /// Set cpu topology ++ /// ++ /// # Arguments ++ /// ++ /// * `topology` - RISCV CPU Topology ++ pub fn set_cpu_topology(&mut self, _topology: &RISCVCPUTopology) -> Result<()> { ++ Ok(()) ++ } ++ ++ /// Get config_regs value. ++ pub fn config_regs(&self) -> ConfigRegs { ++ self.config_regs ++ } ++ ++ /// Get core_regs value. ++ pub fn core_regs(&self) -> CoreRegs { ++ self.core_regs ++ } ++ ++ /// Get timer_regs value. ++ pub fn timer_regs(&self) -> TimerRegs { ++ self.timer_regs ++ } ++ ++ /// Get aia csrs. ++ pub fn aia_csrs(&self) -> AiaCsrs { ++ self.aia_csrs ++ } ++ ++ /// Get csrs. ++ pub fn csrs(&self) -> Csrs { ++ self.csrs ++ } ++ ++ /// Set core registers before boot ++ /// See https://elixir.bootlin.com/linux/v6.6/source/Documentation/riscv/boot.rst ++ pub fn set_core_reg(&mut self, boot_config: &RISCVCPUBootConfig) { ++ // Set core regs. ++ self.core_regs.regs.a0 = self.apic_id as u64; ++ self.core_regs.regs.a1 = boot_config.fdt_addr; ++ self.core_regs.regs.pc = boot_config.boot_pc; ++ } ++ ++ /// Get regs_len. ++ pub fn get_xlen(&self) -> u64 { ++ self.xlen ++ } ++} ++ ++impl StateTransfer for CPU { ++ fn get_state_vec(&self) -> Result> { ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::CoreRegs)?; ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::MpState)?; ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::TimerRegs)?; ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::ConfigRegs)?; ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::AiaCsrs)?; ++ self.hypervisor_cpu ++ .get_regs(self.arch_cpu.clone(), RISCVRegsIndex::Csrs)?; ++ ++ Ok(self.arch_cpu.lock().unwrap().as_bytes().to_vec()) ++ } ++ ++ fn set_state(&self, state: &[u8]) -> Result<()> { ++ let cpu_state = *RISCVCPUState::from_bytes(state) ++ .with_context(|| MigrationError::FromBytesError("CPU"))?; ++ ++ let mut cpu_state_locked = self.arch_cpu.lock().unwrap(); ++ *cpu_state_locked = cpu_state; ++ drop(cpu_state_locked); ++ ++ Ok(()) ++ } ++ ++ fn get_device_alias(&self) -> u64 { ++ MigrationManager::get_desc_alias(&RISCVCPUState::descriptor().name).unwrap_or(!0) ++ } ++} ++ ++impl MigrationHook for CPU {} +diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs +index acb6fb2..0a8ad16 100644 +--- a/cpu/src/x86_64/mod.rs ++++ b/cpu/src/x86_64/mod.rs +@@ -75,7 +75,7 @@ pub enum X86RegsIndex { + + /// X86 CPU booting configure information + #[allow(clippy::upper_case_acronyms)] +-#[derive(Default, Clone, Debug, Copy)] ++#[derive(Default, Clone, Debug)] + pub struct X86CPUBootConfig { + pub prot64_mode: bool, + /// Register %rip value +diff --git a/devices/Cargo.toml b/devices/Cargo.toml +index 2e6574e..01bea56 100644 +--- a/devices/Cargo.toml ++++ b/devices/Cargo.toml +@@ -12,6 +12,8 @@ anyhow = "1.0" + libc = "0.2" + log = "0.4" + serde = { version = "1.0", features = ["derive"] } ++strum = "0.24.1" ++strum_macros = "0.24.3" + vmm-sys-util = "0.12.1" + byteorder = "1.4.3" + drm-fourcc = ">=2.2.0" +@@ -34,9 +36,9 @@ psimple = { version = "2.27", package = "libpulse-simple-binding", optional = tr + alsa = { version = "0.7.0", optional = true } + rusb = { version = "0.9", optional = true } + libusb1-sys = { version = "0.6.4", optional = true } +-cairo-rs = { version = "0.17.10", optional = true } + trace = { path = "../trace" } + clap = { version = "=4.1.4", default-features = false, features = ["std", "derive"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + + [features] + default = [] +@@ -46,8 +48,8 @@ scream_pulseaudio = ["scream", "dep:pulse", "dep:psimple", "machine_manager/scre + scream_ohaudio = ["scream", "machine_manager/scream_ohaudio", "util/scream_ohaudio"] + pvpanic = ["machine_manager/pvpanic"] + demo_device = ["machine_manager/demo_device", "ui/console", "util/pixman"] +-usb_host = ["dep:libusb1-sys", "dep:rusb", "machine_manager/usb_host"] ++usb_host = ["dep:libusb1-sys", "dep:rusb", "machine_manager/usb_host", "util/usb_host"] + usb_camera = ["machine_manager/usb_camera"] +-usb_camera_v4l2 = ["usb_camera", "dep:cairo-rs", "dep:v4l2-sys-mit", "machine_manager/usb_camera_v4l2", "util/usb_camera_v4l2"] ++usb_camera_v4l2 = ["usb_camera", "dep:v4l2-sys-mit", "machine_manager/usb_camera_v4l2", "util/usb_camera_v4l2"] + usb_camera_oh = ["usb_camera", "machine_manager/usb_camera_oh", "util/usb_camera_oh"] + ramfb = ["ui/console", "util/pixman"] +diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs +index 73f2601..4fe256c 100644 +--- a/devices/src/acpi/cpu_controller.rs ++++ b/devices/src/acpi/cpu_controller.rs +@@ -19,7 +19,7 @@ use anyhow::{bail, Context, Result}; + use log::{error, info}; + use vmm_sys_util::eventfd::EventFd; + +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; + use crate::{Device, DeviceBase}; + use acpi::{ + AcpiError, AcpiLocalApic, AmlAcquire, AmlAddressSpaceType, AmlArg, AmlBuffer, AmlBuilder, +@@ -99,11 +99,11 @@ impl CpuController { + self.max_cpus = max_cpus; + self.cpu_config = Some(cpu_config); + self.hotplug_cpu_req = Some(hotplug_cpu_req); +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, region_base, region_size, "CPUController") + .with_context(|| AcpiError::Alignment(region_size.try_into().unwrap()))?; + let dev = Arc::new(Mutex::new(self)); + let ret_dev = dev.clone(); +- sysbus.attach_device(&dev, region_base, region_size, "CPUController")?; ++ sysbus.attach_device(&dev)?; + Ok(ret_dev) + } + +@@ -157,8 +157,8 @@ impl CpuController { + None + } + +- pub fn get_boot_config(&self) -> CPUBootConfig { +- self.cpu_config.as_ref().unwrap().boot_config ++ pub fn get_boot_config(&self) -> &CPUBootConfig { ++ &self.cpu_config.as_ref().unwrap().boot_config + } + + pub fn get_hotplug_cpu_info(&self) -> (String, u8) { +@@ -329,15 +329,11 @@ impl SysBusDevOps for CpuController { + } + true + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl AmlBuilder for CpuController { + fn aml_bytes(&self) -> Vec { +- let res = self.base.res; ++ let res = self.base.res.clone(); + let mut cpu_hotplug_controller = AmlDevice::new("PRES"); + cpu_hotplug_controller.append_child(AmlNameDecl::new("_HID", AmlEisaId::new("PNP0A06"))); + cpu_hotplug_controller.append_child(AmlNameDecl::new( +diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs +index f50e1b1..602a999 100644 +--- a/devices/src/acpi/ged.rs ++++ b/devices/src/acpi/ged.rs +@@ -19,7 +19,7 @@ use anyhow::{Context, Result}; + use vmm_sys_util::epoll::EventSet; + use vmm_sys_util::eventfd::EventFd; + +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; + use crate::{Device, DeviceBase}; + use acpi::{ + AcpiError, AmlActiveLevel, AmlAddressSpaceType, AmlAnd, AmlBuilder, AmlDevice, AmlEdgeLevel, +@@ -35,7 +35,7 @@ use address_space::GuestAddress; + use machine_manager::event; + use machine_manager::event_loop::EventLoop; + use machine_manager::qmp::qmp_channel::QmpChannel; +-use util::loop_context::{read_fd, EventNotifier, NotifierOperation}; ++use util::loop_context::{create_new_eventfd, read_fd, EventNotifier, NotifierOperation}; + use util::{loop_context::NotifierCallback, num_ops::write_data_u32}; + + #[derive(Clone, Copy)] +@@ -96,13 +96,13 @@ impl Ged { + region_base: u64, + region_size: u64, + ) -> Result>> { +- self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); ++ self.set_sys_resource(sysbus, region_base, region_size, "Ged") + .with_context(|| AcpiError::Alignment(region_size as u32))?; + self.battery_present = battery_present; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "Ged")?; ++ sysbus.attach_device(&dev)?; + + let ged = dev.lock().unwrap(); + ged.register_acpi_powerdown_event(ged_event.power_button) +@@ -120,8 +120,9 @@ impl Ged { + read_fd(power_down_fd); + ged_clone + .notification_type +- .store(AcpiEvent::PowerDown as u32, Ordering::SeqCst); ++ .fetch_or(AcpiEvent::PowerDown as u32, Ordering::SeqCst); + ged_clone.inject_interrupt(); ++ trace::ged_inject_acpi_event(AcpiEvent::PowerDown as u32); + if QmpChannel::is_connected() { + event!(Powerdown); + } +@@ -149,8 +150,9 @@ impl Ged { + read_fd(cpu_resize_fd); + clone_ged + .notification_type +- .store(AcpiEvent::CpuResize as u32, Ordering::SeqCst); ++ .fetch_or(AcpiEvent::CpuResize as u32, Ordering::SeqCst); + clone_ged.inject_interrupt(); ++ trace::ged_inject_acpi_event(AcpiEvent::CpuResize as u32); + if QmpChannel::is_connected() { + event!(CpuResize); + } +@@ -174,6 +176,7 @@ impl Ged { + self.notification_type + .fetch_or(evt as u32, Ordering::SeqCst); + self.inject_interrupt(); ++ trace::ged_inject_acpi_event(evt as u32); + } + } + +@@ -203,16 +206,13 @@ impl SysBusDevOps for Ged { + let value = self + .notification_type + .swap(AcpiEvent::Nothing as u32, Ordering::SeqCst); ++ trace::ged_read(value); + write_data_u32(data, value) + } + + fn write(&mut self, _data: &[u8], _base: GuestAddress, _offset: u64) -> bool { + true + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl AmlBuilder for Ged { +@@ -228,6 +228,8 @@ impl AmlBuilder for Ged { + let irq_base = INTERRUPT_PPIS_COUNT + INTERRUPT_SGIS_COUNT; + #[cfg(target_arch = "x86_64")] + let irq_base = 0; ++ #[cfg(target_arch = "riscv64")] ++ let irq_base = 0; + res.append_child(AmlExtendedInterrupt::new( + AmlResourceUsage::Consumer, + AmlEdgeLevel::Edge, +diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs +index a51071d..d64486f 100644 +--- a/devices/src/acpi/power.rs ++++ b/devices/src/acpi/power.rs +@@ -18,7 +18,7 @@ use anyhow::{Context, Result}; + use log::info; + + use crate::acpi::ged::{AcpiEvent, Ged}; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; + use crate::{Device, DeviceBase}; + use acpi::{ + AcpiError, AmlAddressSpaceType, AmlBuilder, AmlDevice, AmlField, AmlFieldAccessType, +@@ -154,6 +154,8 @@ impl PowerDev { + // unit: mW + self.regs[REG_IDX_BAT_PRATE] = + (self.regs[REG_IDX_BAT_PRATE] * self.regs[REG_IDX_BAT_PVOLT]) / 1000; ++ ++ trace::power_status_read(&self.regs); + Ok(()) + } + +@@ -181,11 +183,11 @@ impl PowerDev { + region_base: u64, + region_size: u64, + ) -> Result<()> { +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, region_base, region_size, "PowerDev") + .with_context(|| AcpiError::Alignment(region_size as u32))?; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "PowerDev")?; ++ sysbus.attach_device(&dev)?; + + let pdev_available: bool; + { +@@ -253,16 +255,13 @@ impl SysBusDevOps for PowerDev { + return false; + } + let value = self.regs[reg_idx as usize]; ++ trace::power_read(reg_idx, value); + write_data_u32(data, value) + } + + fn write(&mut self, _data: &[u8], _base: GuestAddress, _offset: u64) -> bool { + true + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl AmlBuilder for PowerDev { +diff --git a/devices/src/camera_backend/demo.rs b/devices/src/camera_backend/demo.rs +index b3ff2e9..19b1d4d 100644 +--- a/devices/src/camera_backend/demo.rs ++++ b/devices/src/camera_backend/demo.rs +@@ -13,13 +13,10 @@ + //! Demo backend for vCamera device, that helps for testing. + + use std::fs::read_to_string; +-use std::ops::Deref; + use std::sync::{Arc, Mutex}; + + use anyhow::{bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; +-#[cfg(not(target_env = "ohos"))] +-use cairo::{Format, ImageSurface}; + use log::{debug, error, info}; + use rand::{thread_rng, Rng}; + use serde::{Deserialize, Serialize}; +@@ -239,20 +236,13 @@ impl ImageFrame { + ImageMode::Random => RgbColor::from(self.frame_idx as u8 % 8), + }; + debug!("Demo Image color {:?}", color); +- let mut surface = ImageSurface::create(Format::Rgb24, width as i32, height as i32)?; +- let cr = cairo::Context::new(&surface)?; + let (r, g, b) = get_rgb_color(&color); +- cr.set_source_rgb(r as f64, g as f64, b as f64); +- cr.rectangle(0.0, 0.0, width as f64, height as f64); +- cr.fill()?; +- cr.paint()?; +- drop(cr); +- let data = surface.data()?; ++ let data = init_img(width, height, (r, g, b)); + let image = match format { + FmtType::Mjpg => build_fake_mjpg(width, height), +- FmtType::Yuy2 => convert_to_yuy2(data.deref(), width, height), +- FmtType::Rgb565 => data.deref().to_vec(), +- FmtType::Nv12 => bail!("demo device does not support NV12 now"), ++ FmtType::Yuy2 => convert_to_yuy2(&data, width, height), ++ FmtType::Rgb565 => data, ++ FmtType::Nv12 => convert_to_nv12(&data, width, height), + }; + self.frame_idx += 1; + if self.frame_idx > FRAME_IDX_LIMIT { +@@ -269,7 +259,12 @@ fn read_config(path: &str) -> Result { + } + + fn build_format_list() -> Vec { +- vec![build_yuy2_list(), build_mjpg_list(), build_rgb565_list()] ++ vec![ ++ build_yuy2_list(), ++ build_mjpg_list(), ++ build_rgb565_list(), ++ build_nv12_list(), ++ ] + } + + fn build_yuy2_list() -> CameraFormatList { +@@ -377,6 +372,33 @@ fn build_rgb565_list() -> CameraFormatList { + } + } + ++fn build_nv12_list() -> CameraFormatList { ++ CameraFormatList { ++ format: FmtType::Nv12, ++ fmt_index: 4, ++ frame: vec![ ++ CameraFrame { ++ width: 1280, ++ height: 720, ++ interval: INTERVALS_PER_SEC / 10, ++ index: 1, ++ }, ++ CameraFrame { ++ width: 640, ++ height: 480, ++ interval: INTERVALS_PER_SEC / 30, ++ index: 2, ++ }, ++ CameraFrame { ++ width: 480, ++ height: 240, ++ interval: INTERVALS_PER_SEC / 30, ++ index: 3, ++ }, ++ ], ++ } ++} ++ + impl CameraBackend for DemoCameraBackend { + fn set_fmt(&mut self, cam_fmt: &CamBasicFmt) -> Result<()> { + *self.cur_format.lock().unwrap() = *cam_fmt; +@@ -502,6 +524,48 @@ fn clip(x: i32) -> u8 { + } + } + ++fn init_img(width: u32, height: u32, color: (u8, u8, u8)) -> Vec { ++ let len = height * width; ++ let (r, g, b) = color; ++ let mut img: Vec = Vec::with_capacity((len * 4) as usize); ++ for _ in 0..len { ++ img.push(b); ++ img.push(g); ++ img.push(r); ++ img.push(255); ++ } ++ img ++} ++ ++fn convert_to_nv12(source: &[u8], width: u32, height: u32) -> Vec { ++ let pixel = 4; ++ let len = height * width; ++ let mut img_nv12: Vec = Vec::with_capacity(len as usize); ++ for i in 0..len { ++ let idx = (i * pixel) as usize; ++ let (b, g, r) = ( ++ source[idx] as f32, ++ source[idx + 1] as f32, ++ source[idx + 2] as f32, ++ ); ++ let y = (0.299 * r + 0.587 * g + 0.114 * b) as u8; ++ img_nv12.push(y); ++ } ++ for i in 0..(width * height / 2) { ++ let idx = (i * 2 * pixel) as usize; ++ let (b, g, r) = ( ++ source[idx] as f32, ++ source[idx + 1] as f32, ++ source[idx + 2] as f32, ++ ); ++ let u = (-0.147 * r - 0.289 * g + 0.436 * b + 128_f32) as u8; ++ let v = (0.615 * r - 0.515 * g - 0.100 * b + 128_f32) as u8; ++ img_nv12.push(u); ++ img_nv12.push(v); ++ } ++ img_nv12 ++} ++ + fn convert_to_yuy2(source: &[u8], width: u32, height: u32) -> Vec { + let pixbytes = 4; + let sz = width * height * 2; +diff --git a/devices/src/camera_backend/mod.rs b/devices/src/camera_backend/mod.rs +index a4e919a..00723e5 100644 +--- a/devices/src/camera_backend/mod.rs ++++ b/devices/src/camera_backend/mod.rs +@@ -14,7 +14,6 @@ + //! Backend devices, such as v4l2, usb, or demo device, etc., shall implement trait + //! CameraBackend. + +-#[cfg(not(target_env = "ohos"))] + pub mod demo; + #[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))] + pub mod ohcam; +@@ -26,7 +25,6 @@ use std::sync::{Arc, Mutex}; + + use anyhow::{bail, Context, Result}; + +-#[cfg(not(target_env = "ohos"))] + use self::demo::DemoCameraBackend; + #[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))] + use self::ohcam::OhCameraBackend; +@@ -205,7 +203,6 @@ pub fn create_cam_backend( + cameradev.id, + cameradev.path, + )?)), +- #[cfg(not(target_env = "ohos"))] + CamBackendType::Demo => Arc::new(Mutex::new(DemoCameraBackend::new( + config.id, + cameradev.path, +diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs +index f27abb1..55b6a80 100755 +--- a/devices/src/camera_backend/ohcam.rs ++++ b/devices/src/camera_backend/ohcam.rs +@@ -20,6 +20,12 @@ use crate::camera_backend::{ + CamBasicFmt, CameraBackend, CameraBrokenCallback, CameraFormatList, CameraFrame, + CameraNotifyCallback, FmtType, + }; ++#[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++))] ++use trace::trace_scope::Scope; + use util::aio::Iovec; + use util::ohos_binding::camera::*; + +@@ -29,6 +35,9 @@ static OHCAM_CALLBACK: Lazy = Lazy::new(|| RwLock::new(OhCamCallBack::d + // In UVC, interval's unit is 100ns. + // So, fps * interval / 10_000_000 == 1. + const FPS_INTERVAL_TRANS: u32 = 10_000_000; ++const RESOLUTION_WHITELIST: [(i32, i32); 2] = [(640, 480), (1280, 720)]; ++const FRAME_FORMAT_WHITELIST: [i32; 2] = [CAMERA_FORMAT_YUYV422, CAMERA_FORMAT_NV12]; ++const FPS_WHITELIST: [i32; 1] = [30]; + + #[derive(Default)] + struct OhCamCallBack { +@@ -76,6 +85,33 @@ impl OhCamCallBack { + } + } + ++#[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++))] ++#[derive(Clone, Default)] ++struct OhCameraAsyncScope { ++ next_frame_id: u64, ++ async_scope: Option, ++} ++ ++#[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++))] ++impl OhCameraAsyncScope { ++ fn start(&mut self) { ++ self.async_scope = Some(trace::ohcam_next_frame(true, self.next_frame_id)); ++ self.next_frame_id += 1; ++ } ++ ++ fn stop(&mut self) { ++ self.async_scope = None; ++ } ++} ++ + #[derive(Clone)] + pub struct OhCameraBackend { + id: String, +@@ -84,6 +120,12 @@ pub struct OhCameraBackend { + ctx: OhCamera, + fmt_list: Vec, + selected_profile: u8, ++ #[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++ ))] ++ async_scope: Box, + } + + // SAFETY: Send and Sync is not auto-implemented for raw pointer type. +@@ -95,6 +137,8 @@ unsafe impl Sync for OhCameraBackend {} + fn cam_fmt_from_oh(t: i32) -> Result { + let fmt = match t { + CAMERA_FORMAT_YUV420SP => FmtType::Nv12, ++ CAMERA_FORMAT_NV12 => FmtType::Nv12, ++ CAMERA_FORMAT_YUYV422 => FmtType::Yuy2, + CAMERA_FORMAT_MJPEG => FmtType::Mjpg, + _ => bail!("OHCAM: No supported type {}", t), + }; +@@ -116,6 +160,12 @@ impl OhCameraBackend { + ctx, + fmt_list: vec![], + selected_profile: 0, ++ #[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++ ))] ++ async_scope: Box::new(OhCameraAsyncScope::default()), + }) + } + } +@@ -158,6 +208,12 @@ impl CameraBackend for OhCameraBackend { + fn video_stream_off(&mut self) -> Result<()> { + self.ctx.stop_stream(); + OHCAM_CALLBACK.write().unwrap().clear_buffer(); ++ #[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++ ))] ++ self.async_scope.stop(); + Ok(()) + } + +@@ -166,14 +222,13 @@ impl CameraBackend for OhCameraBackend { + + for idx in 0..self.profile_cnt { + match self.ctx.get_profile(self.camidx as i32, idx as i32) { +- Ok((fmt, width, height, mut fps)) => { +- if (fmt != CAMERA_FORMAT_YUV420SP) && (fmt != CAMERA_FORMAT_MJPEG) { ++ Ok((fmt, width, height, fps)) => { ++ if !FRAME_FORMAT_WHITELIST.iter().any(|&x| x == fmt) ++ || !RESOLUTION_WHITELIST.iter().any(|&x| x == (width, height)) ++ || !FPS_WHITELIST.iter().any(|&x| x == fps) ++ { + continue; + } +- // NOTE: windows camera APP doesn't support fps lower than 30, and some OH PC only support 15 fps. +- if fps < 30 { +- fps = 30; +- } + + let frame = CameraFrame { + width: width as u32, +@@ -197,6 +252,12 @@ impl CameraBackend for OhCameraBackend { + fn reset(&mut self) { + OHCAM_CALLBACK.write().unwrap().clear_buffer(); + self.ctx.reset_camera(); ++ #[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++ ))] ++ self.async_scope.stop(); + } + + fn get_format_by_index(&self, format_index: u8, frame_index: u8) -> Result { +@@ -236,6 +297,12 @@ impl CameraBackend for OhCameraBackend { + } + + fn next_frame(&mut self) -> Result<()> { ++ #[cfg(any( ++ feature = "trace_to_logger", ++ feature = "trace_to_ftrace", ++ all(target_env = "ohos", feature = "trace_to_hitrace") ++ ))] ++ self.async_scope.start(); + self.ctx.next_frame(); + OHCAM_CALLBACK.write().unwrap().clear_buffer(); + Ok(()) +@@ -251,6 +318,8 @@ impl CameraBackend for OhCameraBackend { + bail!("Invalid frame offset {} or len {}", frame_offset, len); + } + ++ trace::trace_scope_start!(ohcam_get_frame, args = (frame_offset, len)); ++ + let mut copied = 0; + for iov in iovecs { + if len == copied { +diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs +index b9cb520..60babf0 100644 +--- a/devices/src/interrupt_controller/aarch64/gicv3.rs ++++ b/devices/src/interrupt_controller/aarch64/gicv3.rs +@@ -41,35 +41,58 @@ pub struct GICv3Config { + pub trait GICv3Access: Send + Sync { + fn init_gic( + &self, +- nr_irqs: u32, +- redist_regions: Vec, +- dist_base: u64, +- ) -> Result<()>; ++ _nr_irqs: u32, ++ _redist_regions: Vec, ++ _dist_base: u64, ++ ) -> Result<()> { ++ Ok(()) ++ } + +- /// Returns `gicr_attr` of `vCPU`. +- fn vcpu_gicr_attr(&self, cpu: usize) -> u64; ++ fn vcpu_gicr_attr(&self, _cpu: usize) -> u64 { ++ 0 ++ } + +- fn access_gic_distributor(&self, offset: u64, gicd_value: &mut u32, write: bool) -> Result<()>; ++ fn access_gic_distributor( ++ &self, ++ _offset: u64, ++ _gicd_value: &mut u32, ++ _write: bool, ++ ) -> Result<()> { ++ Ok(()) ++ } + + fn access_gic_redistributor( + &self, +- offset: u64, +- cpu: usize, +- gicr_value: &mut u32, +- write: bool, +- ) -> Result<()>; ++ _offset: u64, ++ _cpu: usize, ++ _gicr_value: &mut u32, ++ _write: bool, ++ ) -> Result<()> { ++ Ok(()) ++ } + + fn access_gic_cpu( + &self, +- offset: u64, +- cpu: usize, +- gicc_value: &mut u64, +- write: bool, +- ) -> Result<()>; ++ _offset: u64, ++ _cpu: usize, ++ _gicc_value: &mut u64, ++ _write: bool, ++ ) -> Result<()> { ++ Ok(()) ++ } + +- fn access_gic_line_level(&self, offset: u64, gicll_value: &mut u32, write: bool) -> Result<()>; ++ fn access_gic_line_level( ++ &self, ++ _offset: u64, ++ _gicll_value: &mut u32, ++ _write: bool, ++ ) -> Result<()> { ++ Ok(()) ++ } + +- fn pause(&self) -> Result<()>; ++ fn pause(&self) -> Result<()> { ++ Ok(()) ++ } + } + + #[derive(Clone, Copy)] +@@ -328,13 +351,21 @@ impl GICDevice for GICv3 { + } + + pub trait GICv3ItsAccess: Send + Sync { +- fn init_gic_its(&self, msi_base: u64) -> Result<()>; ++ fn init_gic_its(&self, _msi_base: u64) -> Result<()> { ++ Ok(()) ++ } + +- fn access_gic_its(&self, attr: u32, its_value: &mut u64, write: bool) -> Result<()>; ++ fn access_gic_its(&self, _attr: u32, _its_value: &mut u64, _write: bool) -> Result<()> { ++ Ok(()) ++ } + +- fn access_gic_its_tables(&self, save: bool) -> Result<()>; ++ fn access_gic_its_tables(&self, _save: bool) -> Result<()> { ++ Ok(()) ++ } + +- fn reset(&self) -> Result<()>; ++ fn reset(&self) -> Result<()> { ++ Ok(()) ++ } + } + + pub struct GICv3Its { +diff --git a/devices/src/interrupt_controller/mod.rs b/devices/src/interrupt_controller/mod.rs +index 4a0453c..07a6328 100644 +--- a/devices/src/interrupt_controller/mod.rs ++++ b/devices/src/interrupt_controller/mod.rs +@@ -18,16 +18,19 @@ + //! + //! This module offers support for: + //! 1. Create hypervisor-based interrupt controller. +-//! 2. Manager lifecycle for `GIC`. ++//! 2. Manager lifecycle for in-kernel interrupt chips. + //! + //! ## Platform Support + //! + //! - `aarch64` ++//! - `riscv64` + + #[allow(clippy::upper_case_acronyms)] + #[cfg(target_arch = "aarch64")] + mod aarch64; + mod error; ++#[cfg(target_arch = "riscv64")] ++mod riscv64; + + #[cfg(target_arch = "aarch64")] + pub use aarch64::{ +@@ -36,6 +39,8 @@ pub use aarch64::{ + GICv3ItsState, GICv3State, GicRedistRegion, InterruptController, GIC_IRQ_INTERNAL, GIC_IRQ_MAX, + }; + pub use error::InterruptError; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::{AIAAccess, AIAConfig, AIADevice, InterruptController, AIA}; + + use std::sync::Arc; + +@@ -81,6 +86,8 @@ pub trait LineIrqManager: Send + Sync { + } + + pub trait MsiIrqManager: Send + Sync { ++ fn irqfd_enable(&self) -> bool; ++ + fn allocate_irq(&self, _vector: MsiVector) -> Result { + Ok(0) + } +diff --git a/devices/src/interrupt_controller/riscv64/aia.rs b/devices/src/interrupt_controller/riscv64/aia.rs +new file mode 100644 +index 0000000..d6cd779 +--- /dev/null ++++ b/devices/src/interrupt_controller/riscv64/aia.rs +@@ -0,0 +1,172 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::sync::{Arc, Mutex}; ++ ++use anyhow::{Context, Result}; ++use kvm_bindings::{KVM_DEV_RISCV_APLIC_SIZE, KVM_DEV_RISCV_IMSIC_SIZE}; ++use log::{error, info}; ++ ++use super::{AIAConfig, AIADevice}; ++use machine_manager::machine::{MachineLifecycle, VmState}; ++use util::device_tree::{self, FdtBuilder}; ++ ++/// Access wrapper for AIA. ++pub trait AIAAccess: Send + Sync { ++ fn init_aia(&self, nr_irqs: u32, aia_addr: u64) -> Result<()>; ++ ++ fn pause(&self) -> Result<()>; ++} ++ ++/// A wrapper around creating and managing a `AIA`. ++pub struct AIA { ++ /// The handler for the AIA device to access the corresponding device in hypervisor. ++ pub hypervisor_aia: Arc, ++ /// Number of vCPUs, determines the number of redistributor and CPU interface. ++ pub(crate) vcpu_count: u32, ++ /// Maximum irq number. ++ pub(crate) nr_irqs: u32, ++ /// IMSIC's start addr. ++ pub(crate) imsic_start_addr_of: Vec, ++ /// APLIC's start addr. ++ pub(crate) aplic_start_addr: u64, ++ /// Base address in the guest physical address space of AIA ++ dist_base: u64, ++ /// AIA distributor region size. ++ dist_size: u64, ++ /// Lifecycle state for AIA. ++ state: Arc>, ++} ++ ++impl AIA { ++ pub fn new(hypervisor_aia: Arc, config: &AIAConfig) -> Result { ++ use kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE; ++ // Calculate AIA's IMSIC start address ++ let mut imsic_start_addr_of = Vec::new(); ++ for i in 0..config.vcpu_count { ++ imsic_start_addr_of.push(config.region_range.0 + (i * KVM_DEV_RISCV_IMSIC_SIZE) as u64); ++ } ++ let aplic_start_addr = ++ (config.vcpu_count * KVM_DEV_RISCV_IMSIC_SIZE) as u64 + config.region_range.0; ++ ++ Ok(AIA { ++ hypervisor_aia, ++ vcpu_count: config.vcpu_count, ++ nr_irqs: config.max_irq, ++ imsic_start_addr_of, ++ aplic_start_addr, ++ state: Arc::new(Mutex::new(VmState::Created)), ++ dist_base: config.region_range.0, ++ dist_size: config.region_range.1, ++ }) ++ } ++} ++ ++impl MachineLifecycle for AIA { ++ fn pause(&self) -> bool { ++ // VM change state will flush REDIST pending tables into guest RAM. ++ if let Err(e) = self.hypervisor_aia.pause() { ++ error!( ++ "Failed to flush REDIST pending tables into guest RAM, error: {:?}", ++ e ++ ); ++ return false; ++ } ++ ++ let mut state = self.state.lock().unwrap(); ++ *state = VmState::Running; ++ ++ true ++ } ++ ++ fn notify_lifecycle(&self, old: VmState, new: VmState) -> bool { ++ let state = self.state.lock().unwrap(); ++ if *state != old { ++ error!("AIA lifecycle error: state check failed."); ++ return false; ++ } ++ drop(state); ++ ++ match (old, new) { ++ (VmState::Running, VmState::Paused) => self.pause(), ++ _ => true, ++ } ++ } ++} ++ ++impl AIADevice for AIA { ++ fn realize(&self) -> Result<()> { ++ self.hypervisor_aia ++ .init_aia(self.nr_irqs, self.dist_base) ++ .with_context(|| "Failed to init AIA")?; ++ ++ let mut state = self.state.lock().unwrap(); ++ *state = VmState::Running; ++ ++ Ok(()) ++ } ++ ++ fn generate_fdt(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let node = format!("imsics@{:x}", self.imsic_start_addr_of[0] as u32); ++ let imsics_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_u32("phandle", device_tree::AIA_IMSIC_PHANDLE)?; ++ fdt.set_property_u32("riscv,num-ids", 2047)?; ++ ++ let mut reg_cells = Vec::new(); ++ reg_cells.push(0); ++ reg_cells.push(self.imsic_start_addr_of[0] as u32); ++ reg_cells.push(0); ++ reg_cells.push(self.vcpu_count * KVM_DEV_RISCV_IMSIC_SIZE); ++ info!("imsic regs: {:?}", ®_cells); ++ fdt.set_property_array_u32("reg", ®_cells)?; ++ ++ let mut irq_cells = Vec::new(); ++ for i in 0..self.vcpu_count { ++ irq_cells.push(device_tree::INTC_PHANDLE_START + i); ++ irq_cells.push(9); ++ } ++ fdt.set_property_array_u32("interrupts-extended", &irq_cells)?; ++ ++ fdt.set_property("msi-controller", &Vec::new())?; ++ fdt.set_property("interrupt-controller", &Vec::new())?; ++ fdt.set_property_u32("#interrupt-cells", 0)?; ++ fdt.set_property_string("compatible", "riscv,imsics")?; ++ fdt.end_node(imsics_node_dep)?; ++ ++ // APLIC ++ let node = format!("aplic@{:x}", self.aplic_start_addr as u32); ++ let aplic_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_u32("phandle", device_tree::AIA_APLIC_PHANDLE)?; ++ fdt.set_property_u32("riscv,num-sources", 96)?; ++ ++ let mut reg_cells = Vec::new(); ++ reg_cells.push(0); ++ reg_cells.push(self.aplic_start_addr as u32); ++ reg_cells.push(0); ++ reg_cells.push(KVM_DEV_RISCV_APLIC_SIZE); ++ info!("aplic regs: {:?}", ®_cells); ++ fdt.set_property_array_u32("reg", ®_cells)?; ++ ++ fdt.set_property_u32("msi-parent", device_tree::AIA_IMSIC_PHANDLE)?; ++ fdt.set_property("interrupt-controller", &Vec::new())?; ++ fdt.set_property_u32("#interrupt-cells", 2)?; ++ fdt.set_property_string("compatible", "riscv,aplic")?; ++ ++ fdt.end_node(aplic_node_dep)?; ++ ++ Ok(()) ++ } ++ ++ fn reset(&self) -> Result<()> { ++ Ok(()) ++ } ++} +diff --git a/devices/src/interrupt_controller/riscv64/mod.rs b/devices/src/interrupt_controller/riscv64/mod.rs +new file mode 100644 +index 0000000..d6da2f7 +--- /dev/null ++++ b/devices/src/interrupt_controller/riscv64/mod.rs +@@ -0,0 +1,94 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++mod aia; ++ ++use std::sync::Arc; ++ ++use anyhow::{Context, Result}; ++ ++pub use aia::{AIAAccess, AIA}; ++use machine_manager::machine::{MachineLifecycle, VmState}; ++use util::device_tree::{self, FdtBuilder}; ++ ++pub struct AIAConfig { ++ /// Config number of CPUs handled by the device ++ pub vcpu_count: u32, ++ /// Config maximum number of irqs handled by the device ++ pub max_irq: u32, ++ /// Config AIA address range ++ pub region_range: (u64, u64), ++} ++ ++impl AIAConfig { ++ pub fn check_sanity(&self) -> Result<()> { ++ // Yet implemented ++ Ok(()) ++ } ++} ++ ++/// A wrapper for `AIA` must perform the function. ++pub trait AIADevice: MachineLifecycle { ++ /// Realize function for hypervisor_based `AIA` device. ++ fn realize(&self) -> Result<()>; ++ ++ /// Reset 'AIA' ++ fn reset(&self) -> Result<()> { ++ Ok(()) ++ } ++ ++ /// Constructs `fdt` node for `AIA`. ++ /// ++ /// # Arguments ++ /// ++ /// * `fdt` - Device tree presented by bytes. ++ fn generate_fdt(&self, fdt: &mut FdtBuilder) -> Result<()>; ++} ++ ++#[derive(Clone)] ++/// A wrapper around creating and using a hypervisor-based interrupt controller. ++pub struct InterruptController { ++ aia: Arc, ++} ++ ++impl InterruptController { ++ /// Constructs a new hypervisor_based `InterruptController`. ++ pub fn new( ++ aia: Arc, ++ ) -> InterruptController { ++ InterruptController { aia } ++ } ++ ++ pub fn realize(&self) -> Result<()> { ++ self.aia ++ .realize() ++ .with_context(|| "Failed to realize AIA")?; ++ Ok(()) ++ } ++ ++ /// Reset the InterruptController ++ pub fn reset(&self) -> Result<()> { ++ self.aia.reset().with_context(|| "Failed to reset AIA") ++ } ++ ++ /// Change `InterruptController` lifecycle state to `Stopped`. ++ pub fn stop(&self) { ++ self.aia.notify_lifecycle(VmState::Running, VmState::Paused); ++ } ++} ++ ++impl device_tree::CompileFDT for InterruptController { ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ self.aia.generate_fdt(fdt)?; ++ Ok(()) ++ } ++} +diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs +index 2abf436..e8fb9d1 100644 +--- a/devices/src/legacy/fwcfg.rs ++++ b/devices/src/legacy/fwcfg.rs +@@ -19,14 +19,14 @@ use byteorder::{BigEndian, ByteOrder}; + use log::{error, warn}; + + use crate::legacy::error::LegacyError; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::{ + AmlBuilder, AmlDevice, AmlInteger, AmlNameDecl, AmlResTemplate, AmlScopeBuilder, AmlString, + }; + #[cfg(target_arch = "x86_64")] + use acpi::{AmlIoDecode, AmlIoResource}; +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + use acpi::{AmlMemory32Fixed, AmlReadAndWrite}; + use address_space::{AddressSpace, GuestAddress}; + use util::byte_code::ByteCode; +@@ -361,11 +361,14 @@ impl FwCfgCommon { + + /// Select the entry by the key specified + fn select_entry(&mut self, key: u16) { ++ let ret; + self.cur_offset = 0; + if (key & FW_CFG_ENTRY_MASK) >= self.max_entry() { + self.cur_entry = FW_CFG_INVALID; ++ ret = 0; + } else { + self.cur_entry = key; ++ ret = 1; + + // unwrap() is safe because we have checked the range of `key`. + let selected_entry = self.get_entry_mut().unwrap(); +@@ -373,6 +376,8 @@ impl FwCfgCommon { + cb.select_callback(); + } + } ++ ++ trace::fwcfg_select_entry(key, get_key_name(key as usize), ret); + } + + fn add_entry( +@@ -404,11 +409,12 @@ impl FwCfgCommon { + warn!("Entry not empty, will override"); + } + +- entry.data = data; ++ entry.data = data.clone(); + entry.select_cb = select_cb; + entry.allow_write = allow_write; + entry.write_cb = write_cb; + ++ trace::fwcfg_add_entry(key, get_key_name(key as usize), data); + Ok(()) + } + +@@ -467,11 +473,8 @@ impl FwCfgCommon { + } + } + +- let file = FwCfgFile::new( +- data.len() as u32, +- FW_CFG_FILE_FIRST + index as u16, +- filename, +- ); ++ let data_len = data.len(); ++ let file = FwCfgFile::new(data_len as u32, FW_CFG_FILE_FIRST + index as u16, filename); + self.files.insert(index, file); + self.files.iter_mut().skip(index + 1).for_each(|f| { + f.select += 1; +@@ -489,6 +492,8 @@ impl FwCfgCommon { + FW_CFG_FILE_FIRST as usize + index, + FwCfgEntry::new(data, select_cb, write_cb, allow_write), + ); ++ ++ trace::fwcfg_add_file(index, filename, data_len); + Ok(()) + } + +@@ -650,6 +655,8 @@ impl FwCfgCommon { + + self.cur_offset = offset; + write_dma_result(&self.mem_space, dma_addr, dma.control)?; ++ ++ trace::fwcfg_read_data(0); + Ok(()) + } + +@@ -743,6 +750,8 @@ impl FwCfgCommon { + value <<= 8 * size as u64; + } + self.cur_offset = cur_offset; ++ ++ trace::fwcfg_read_data(value); + Ok(value) + } + +@@ -808,7 +817,7 @@ fn get_io_count(data_len: usize) -> usize { + } + + fn common_read( +- #[cfg(target_arch = "aarch64")] fwcfg_arch: &mut FwCfgMem, ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] fwcfg_arch: &mut FwCfgMem, + #[cfg(target_arch = "x86_64")] fwcfg_arch: &mut FwCfgIO, + data: &mut [u8], + base: GuestAddress, +@@ -825,13 +834,13 @@ fn common_read( + } + + /// FwCfg MMIO Device use for AArch64 platform +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub struct FwCfgMem { + base: SysBusDevBase, + fwcfg: FwCfgCommon, + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + impl FwCfgMem { + pub fn new(sys_mem: Arc) -> Self { + FwCfgMem { +@@ -847,18 +856,18 @@ impl FwCfgMem { + region_size: u64, + ) -> Result>> { + self.fwcfg.common_realize()?; +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, region_base, region_size, "FwCfgMem") + .with_context(|| "Failed to allocate system resource for FwCfg.")?; + + let dev = Arc::new(Mutex::new(self)); + sysbus +- .attach_device(&dev, region_base, region_size, "FwCfgMem") ++ .attach_device(&dev) + .with_context(|| "Failed to attach FwCfg device to system bus.")?; + Ok(dev) + } + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + fn read_bytes( + fwcfg_arch: &mut FwCfgMem, + data: &mut [u8], +@@ -913,14 +922,14 @@ fn read_bytes( + true + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + impl FwCfgOps for FwCfgMem { + fn fw_cfg_common(&mut self) -> &mut FwCfgCommon { + &mut self.fwcfg + } + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + impl Device for FwCfgMem { + fn device_base(&self) -> &DeviceBase { + &self.base.base +@@ -931,7 +940,7 @@ impl Device for FwCfgMem { + } + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + impl SysBusDevOps for FwCfgMem { + fn sysbusdev_base(&self) -> &SysBusDevBase { + &self.base +@@ -980,19 +989,15 @@ impl SysBusDevOps for FwCfgMem { + true + } + +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } +- + fn set_sys_resource( + &mut self, + _sysbus: &mut SysBus, + region_base: u64, + region_size: u64, ++ region_name: &str, + ) -> Result<()> { +- let res = self.get_sys_resource_mut().unwrap(); +- res.region_base = region_base; +- res.region_size = region_size; ++ self.sysbusdev_base_mut() ++ .set_sys(-1, region_base, region_size, region_name); + Ok(()) + } + +@@ -1013,30 +1018,19 @@ pub struct FwCfgIO { + impl FwCfgIO { + pub fn new(sys_mem: Arc) -> Self { + FwCfgIO { +- base: SysBusDevBase { +- base: DeviceBase::default(), +- dev_type: SysBusDevType::FwCfg, +- res: SysRes { +- region_base: FW_CFG_IO_BASE, +- region_size: FW_CFG_IO_SIZE, +- irq: -1, +- }, +- ..Default::default() +- }, ++ base: SysBusDevBase::new(SysBusDevType::FwCfg), + fwcfg: FwCfgCommon::new(sys_mem), + } + } + + pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { + self.fwcfg.common_realize()?; +- let region_base = self.base.res.region_base; +- let region_size = self.base.res.region_size; +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, FW_CFG_IO_BASE, FW_CFG_IO_SIZE, "FwCfgIO") + .with_context(|| "Failed to allocate system resource for FwCfg.")?; + + let dev = Arc::new(Mutex::new(self)); + sysbus +- .attach_device(&dev, region_base, region_size, "FwCfgIO") ++ .attach_device(&dev) + .with_context(|| "Failed to attach FwCfg device to system bus.")?; + Ok(dev) + } +@@ -1165,19 +1159,15 @@ impl SysBusDevOps for FwCfgIO { + true + } + +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } +- + fn set_sys_resource( + &mut self, + _sysbus: &mut SysBus, + region_base: u64, + region_size: u64, ++ region_name: &str, + ) -> Result<()> { +- let res = self.get_sys_resource_mut().unwrap(); +- res.region_base = region_base; +- res.region_size = region_size; ++ self.sysbusdev_base_mut() ++ .set_sys(-1, region_base, region_size, region_name); + Ok(()) + } + +@@ -1258,7 +1248,7 @@ pub trait FwCfgOps: Send + Sync { + } + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + impl AmlBuilder for FwCfgMem { + fn aml_bytes(&self) -> Vec { + let mut acpi_dev = AmlDevice::new("FWCF"); +diff --git a/devices/src/legacy/mod.rs b/devices/src/legacy/mod.rs +index 00632fe..74cc2e4 100644 +--- a/devices/src/legacy/mod.rs ++++ b/devices/src/legacy/mod.rs +@@ -53,5 +53,5 @@ pub use pl011::PL011; + #[cfg(target_arch = "aarch64")] + pub use pl031::{PL031, RTC_CR, RTC_DR, RTC_IMSC, RTC_LR}; + #[cfg(all(feature = "ramfb", target_arch = "aarch64"))] +-pub use ramfb::Ramfb; ++pub use ramfb::{Ramfb, RamfbConfig}; + pub use serial::{Serial, SERIAL_ADDR}; +diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs +index e100392..6c225f6 100644 +--- a/devices/src/legacy/pflash.rs ++++ b/devices/src/legacy/pflash.rs +@@ -18,7 +18,7 @@ use anyhow::{anyhow, bail, Context, Result}; + use log::{error, warn}; + + use super::error::LegacyError; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::AmlBuilder; + use address_space::{FileBackend, GuestAddress, HostMemMapping, Region}; +@@ -214,7 +214,7 @@ impl PFlash { + backend: Option, + ) -> Result<()> { + let region_size = Self::flash_region_size(region_max_size, &backend, self.read_only)?; +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, region_base, region_size, "PflashRom") + .with_context(|| "Failed to allocate system resource for PFlash.")?; + + let host_mmap = Arc::new(HostMemMapping::new( +@@ -893,20 +893,15 @@ impl SysBusDevOps for PFlash { + } + } + +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } +- + fn set_sys_resource( + &mut self, + _sysbus: &mut SysBus, + region_base: u64, + region_size: u64, ++ region_name: &str, + ) -> Result<()> { +- let res = self.get_sys_resource_mut().unwrap(); +- res.region_base = region_base; +- res.region_size = region_size; +- res.irq = 0; ++ self.sysbusdev_base_mut() ++ .set_sys(0, region_base, region_size, region_name); + Ok(()) + } + +diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs +index 24a34ef..f5fdafa 100644 +--- a/devices/src/legacy/pl011.rs ++++ b/devices/src/legacy/pl011.rs +@@ -13,11 +13,10 @@ + use std::sync::{Arc, Mutex}; + + use anyhow::{Context, Result}; +-use log::{debug, error}; +-use vmm_sys_util::eventfd::EventFd; ++use log::error; + + use super::error::LegacyError; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::{ + AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlExtendedInterrupt, AmlIntShare, +@@ -36,7 +35,7 @@ use migration::{ + }; + use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; +-use util::loop_context::EventNotifierHelper; ++use util::loop_context::{create_new_eventfd, EventNotifierHelper}; + use util::num_ops::read_data_u32; + + const PL011_FLAG_TXFE: u8 = 0x80; +@@ -135,7 +134,7 @@ impl PL011 { + Ok(PL011 { + base: SysBusDevBase { + dev_type: SysBusDevType::PL011, +- interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)), ++ interrupt_evt: Some(Arc::new(create_new_eventfd()?)), + ..Default::default() + }, + paused: false, +@@ -166,12 +165,12 @@ impl PL011 { + .unwrap() + .realize() + .with_context(|| "Failed to realize chardev")?; +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.set_sys_resource(sysbus, region_base, region_size, "PL011") + .with_context(|| "Failed to set system resource for PL011.")?; + + let dev = Arc::new(Mutex::new(self)); + sysbus +- .attach_device(&dev, region_base, region_size, "PL011") ++ .attach_device(&dev) + .with_context(|| "Failed to attach PL011 to system bus.")?; + + bs.lock().unwrap().kernel_cmdline.push(Param { +@@ -353,20 +352,10 @@ impl SysBusDevOps for PL011 { + match offset >> 2 { + 0 => { + let ch = value as u8; +- +- if let Some(output) = &mut self.chardev.lock().unwrap().output { +- let mut locked_output = output.lock().unwrap(); +- if let Err(e) = locked_output.write_all(&[ch]) { +- debug!("Failed to write to pl011 output fd, error is {:?}", e); +- } +- if let Err(e) = locked_output.flush() { +- debug!("Failed to flush pl011, error is {:?}", e); +- } +- } else { +- debug!("Failed to get output fd"); ++ if let Err(e) = self.chardev.lock().unwrap().fill_outbuf(vec![ch], None) { ++ error!("Failed to append pl011 data to outbuf of chardev, {:?}", e); + return false; + } +- + self.state.int_level |= INT_TX; + self.interrupt(); + } +@@ -425,10 +414,6 @@ impl SysBusDevOps for PL011 { + + true + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl StateTransfer for PL011 { +@@ -486,8 +471,9 @@ mod test { + #[test] + fn test_receive() { + let chardev_cfg = ChardevConfig { +- id: "chardev".to_string(), +- backend: ChardevType::Stdio, ++ classtype: ChardevType::Stdio { ++ id: "chardev".to_string(), ++ }, + }; + let mut pl011_dev = PL011::new(SerialConfig { + chardev: chardev_cfg, +diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs +index a5790dd..9ad650b 100644 +--- a/devices/src/legacy/pl031.rs ++++ b/devices/src/legacy/pl031.rs +@@ -15,10 +15,9 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH}; + + use anyhow::{Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; +-use vmm_sys_util::eventfd::EventFd; + + use super::error::LegacyError; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::AmlBuilder; + use address_space::GuestAddress; +@@ -28,6 +27,7 @@ use migration::{ + }; + use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; ++use util::loop_context::create_new_eventfd; + use util::num_ops::write_data_u32; + + /// Registers for pl031 from ARM PrimeCell Real Time Clock Technical Reference Manual. +@@ -100,12 +100,12 @@ impl PL031 { + region_base: u64, + region_size: u64, + ) -> Result<()> { +- self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); ++ self.set_sys_resource(sysbus, region_base, region_size, "PL031") + .with_context(|| LegacyError::SetSysResErr)?; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "PL031")?; ++ sysbus.attach_device(&dev)?; + + MigrationManager::register_device_instance( + PL031State::descriptor(), +@@ -198,10 +198,6 @@ impl SysBusDevOps for PL031 { + + true + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl AmlBuilder for PL031 { +diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs +index 470fcd7..3945de4 100644 +--- a/devices/src/legacy/ramfb.rs ++++ b/devices/src/legacy/ramfb.rs +@@ -16,6 +16,7 @@ use std::sync::{Arc, Mutex, Weak}; + use std::time::Duration; + + use anyhow::{Context, Result}; ++use clap::{ArgAction, Parser}; + use drm_fourcc::DrmFourcc; + use log::error; + +@@ -24,6 +25,7 @@ use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::AmlBuilder; + use address_space::{AddressSpace, GuestAddress}; ++use machine_manager::config::valid_id; + use machine_manager::event_loop::EventLoop; + use ui::console::{ + console_init, display_graphic_update, display_replace_surface, ConsoleType, DisplayConsole, +@@ -39,6 +41,17 @@ const INSTALL_CHECK_INTERVEL_MS: u64 = 500; + const INSTALL_RELEASE_INTERVEL_MS: u64 = 200; + const INSTALL_PRESS_INTERVEL_MS: u64 = 100; + ++#[derive(Parser, Debug, Clone)] ++#[command(no_binary_name(true))] ++pub struct RamfbConfig { ++ #[arg(long, value_parser = ["ramfb"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long, default_value = "false", action = ArgAction::Append)] ++ pub install: bool, ++} ++ + #[repr(packed)] + struct RamfbCfg { + _addr: u64, +@@ -239,7 +252,7 @@ impl Ramfb { + + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_dynamic_device(&dev)?; ++ sysbus.attach_device(&dev)?; + Ok(()) + } + } +@@ -317,3 +330,25 @@ fn set_press_event(install: Arc, data: *const u8) { + install.store(false, Ordering::Release); + } + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_ramfb_config_cmdline_parser() { ++ // Test1: install. ++ let ramfb_cmd1 = "ramfb,id=ramfb0,install=true"; ++ let ramfb_config = ++ RamfbConfig::try_parse_from(str_slip_to_clap(ramfb_cmd1, true, false)).unwrap(); ++ assert_eq!(ramfb_config.id, "ramfb0"); ++ assert_eq!(ramfb_config.install, true); ++ ++ // Test2: Default. ++ let ramfb_cmd2 = "ramfb,id=ramfb0"; ++ let ramfb_config = ++ RamfbConfig::try_parse_from(str_slip_to_clap(ramfb_cmd2, true, false)).unwrap(); ++ assert_eq!(ramfb_config.install, false); ++ } ++} +diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs +index 8334c2d..1e49808 100644 +--- a/devices/src/legacy/rtc.rs ++++ b/devices/src/legacy/rtc.rs +@@ -15,7 +15,6 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH}; + + use anyhow::Result; + use log::{debug, error, warn}; +-use vmm_sys_util::eventfd::EventFd; + + use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; + use crate::{Device, DeviceBase}; +@@ -24,6 +23,7 @@ use acpi::{ + AmlResTemplate, AmlScopeBuilder, + }; + use address_space::GuestAddress; ++use util::loop_context::create_new_eventfd; + use util::time::{mktime64, NANOSECONDS_PER_SECOND}; + + /// IO port of RTC device to select Register to read/write. +@@ -124,9 +124,9 @@ impl RTC { + res: SysRes { + region_base: RTC_PORT_INDEX, + region_size: 8, +- irq: -1, ++ ..Default::default() + }, +- interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)), ++ interrupt_evt: Some(Arc::new(create_new_eventfd()?)), + ..Default::default() + }, + cmos_data: [0_u8; 128], +@@ -269,10 +269,10 @@ impl RTC { + pub fn realize(mut self, sysbus: &mut SysBus) -> Result<()> { + let region_base = self.base.res.region_base; + let region_size = self.base.res.region_size; +- self.set_sys_resource(sysbus, region_base, region_size)?; ++ self.set_sys_resource(sysbus, region_base, region_size, "RTC")?; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "RTC")?; ++ sysbus.attach_device(&dev)?; + Ok(()) + } + +@@ -391,10 +391,6 @@ impl SysBusDevOps for RTC { + } + } + +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } +- + fn reset(&mut self) -> Result<()> { + self.cmos_data.fill(0); + self.init_rtc_reg(); +diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs +index 7c5b907..8067bc2 100644 +--- a/devices/src/legacy/serial.rs ++++ b/devices/src/legacy/serial.rs +@@ -15,10 +15,9 @@ use std::sync::{Arc, Mutex}; + + use anyhow::{bail, Context, Result}; + use log::{debug, error}; +-use vmm_sys_util::eventfd::EventFd; + + use super::error::LegacyError; +-use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use crate::{Device, DeviceBase}; + use acpi::{ + AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlExtendedInterrupt, +@@ -27,6 +26,8 @@ use acpi::{ + }; + use address_space::GuestAddress; + use chardev_backend::chardev::{Chardev, InputReceiver}; ++#[cfg(target_arch = "riscv64")] ++use machine_manager::config::{BootSource, Param}; + use machine_manager::{config::SerialConfig, event_loop::EventLoop}; + use migration::{ + snapshot::SERIAL_SNAPSHOT_ID, DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, +@@ -34,7 +35,7 @@ use migration::{ + }; + use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; +-use util::loop_context::EventNotifierHelper; ++use util::loop_context::{create_new_eventfd, EventNotifierHelper}; + + pub const SERIAL_ADDR: u64 = 0x3f8; + +@@ -138,24 +139,30 @@ impl Serial { + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, ++ #[cfg(target_arch = "riscv64")] bs: &Arc>, + ) -> Result<()> { + self.chardev + .lock() + .unwrap() + .realize() + .with_context(|| "Failed to realize chardev")?; +- self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); +- self.set_sys_resource(sysbus, region_base, region_size) ++ self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); ++ self.set_sys_resource(sysbus, region_base, region_size, "Serial") + .with_context(|| LegacyError::SetSysResErr)?; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "Serial")?; ++ sysbus.attach_device(&dev)?; + + MigrationManager::register_device_instance( + SerialState::descriptor(), + dev.clone(), + SERIAL_SNAPSHOT_ID, + ); ++ #[cfg(target_arch = "riscv64")] ++ bs.lock().unwrap().kernel_cmdline.push(Param { ++ param_type: "earlycon".to_string(), ++ value: format!("uart,mmio,0x{:08x}", region_base), ++ }); + let locked_dev = dev.lock().unwrap(); + locked_dev.chardev.lock().unwrap().set_receiver(&dev); + EventLoop::update_event( +@@ -297,19 +304,10 @@ impl Serial { + + self.rbr.push_back(data); + self.state.lsr |= UART_LSR_DR; +- } else { +- let output = self.chardev.lock().unwrap().output.clone(); +- if output.is_none() { +- self.update_iir(); +- bail!("serial: failed to get output fd."); +- } +- let mut locked_output = output.as_ref().unwrap().lock().unwrap(); +- locked_output +- .write_all(&[data]) +- .with_context(|| "serial: failed to write.")?; +- locked_output +- .flush() +- .with_context(|| "serial: failed to flush.")?; ++ } else if let Err(e) = ++ self.chardev.lock().unwrap().fill_outbuf(vec![data], None) ++ { ++ bail!("Failed to append data to output buffer of chardev, {:?}", e); + } + + self.update_iir(); +@@ -413,13 +411,10 @@ impl SysBusDevOps for Serial { + } + } + ++ #[cfg(target_arch = "x86_64")] + fn get_irq(&self, _sysbus: &mut SysBus) -> Result { + Ok(UART_IRQ) + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl AmlBuilder for Serial { +@@ -490,8 +485,9 @@ mod test { + fn test_methods_of_serial() { + // test new method + let chardev_cfg = ChardevConfig { +- id: "chardev".to_string(), +- backend: ChardevType::Stdio, ++ classtype: ChardevType::Stdio { ++ id: "chardev".to_string(), ++ }, + }; + let mut usart = Serial::new(SerialConfig { + chardev: chardev_cfg.clone(), +@@ -545,8 +541,9 @@ mod test { + #[test] + fn test_serial_migration_interface() { + let chardev_cfg = ChardevConfig { +- id: "chardev".to_string(), +- backend: ChardevType::Stdio, ++ classtype: ChardevType::Stdio { ++ id: "chardev".to_string(), ++ }, + }; + let mut usart = Serial::new(SerialConfig { + chardev: chardev_cfg, +diff --git a/devices/src/lib.rs b/devices/src/lib.rs +index a155ff6..e6d43b3 100644 +--- a/devices/src/lib.rs ++++ b/devices/src/lib.rs +@@ -28,6 +28,8 @@ pub mod smbios; + pub mod sysbus; + pub mod usb; + ++#[cfg(target_arch = "riscv64")] ++pub use interrupt_controller::{AIAAccess, AIAConfig, AIADevice, InterruptController, AIA}; + #[cfg(target_arch = "aarch64")] + pub use interrupt_controller::{ + GICDevice, GICVersion, GICv2, GICv2Access, GICv3, GICv3Access, GICv3ItsAccess, GICv3ItsState, +@@ -39,6 +41,10 @@ pub use legacy::error::LegacyError as LegacyErrs; + pub use scsi::bus as ScsiBus; + pub use scsi::disk as ScsiDisk; + ++use std::any::Any; ++ ++use util::AsAny; ++ + #[derive(Clone, Default)] + pub struct DeviceBase { + /// Name of this device +@@ -53,7 +59,7 @@ impl DeviceBase { + } + } + +-pub trait Device { ++pub trait Device: Any + AsAny { + fn device_base(&self) -> &DeviceBase; + + fn device_base_mut(&mut self) -> &mut DeviceBase; +diff --git a/devices/src/misc/mod.rs b/devices/src/misc/mod.rs +index 36c2d9c..0e0c015 100644 +--- a/devices/src/misc/mod.rs ++++ b/devices/src/misc/mod.rs +@@ -14,7 +14,7 @@ + pub mod scream; + + #[cfg(feature = "scream")] +-mod ivshmem; ++pub mod ivshmem; + + #[cfg(feature = "pvpanic")] + pub mod pvpanic; +diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs +index e2d29dd..38c2ecb 100644 +--- a/devices/src/misc/pvpanic.rs ++++ b/devices/src/misc/pvpanic.rs +@@ -16,7 +16,9 @@ use std::sync::{ + }; + + use anyhow::{bail, Context, Result}; ++use clap::Parser; + use log::{debug, error, info}; ++use serde::{Deserialize, Serialize}; + + use crate::pci::{ + config::{ +@@ -29,17 +31,44 @@ use crate::pci::{ + }; + use crate::{Device, DeviceBase}; + use address_space::{GuestAddress, Region, RegionOps}; +-use machine_manager::config::{PvpanicDevConfig, PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; ++use machine_manager::config::{get_pci_df, valid_id}; + + const PVPANIC_PCI_REVISION_ID: u8 = 1; + const PVPANIC_PCI_VENDOR_ID: u16 = PCI_VENDOR_ID_REDHAT_QUMRANET; + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + // param size in Region::init_io_region must greater than 4 + const PVPANIC_REG_BAR_SIZE: u64 = 0x4; + #[cfg(target_arch = "x86_64")] + const PVPANIC_REG_BAR_SIZE: u64 = 0x1; + ++pub const PVPANIC_PANICKED: u32 = 1 << 0; ++pub const PVPANIC_CRASHLOADED: u32 = 1 << 1; ++ ++#[derive(Parser, Debug, Clone, Serialize, Deserialize)] ++#[command(no_binary_name(true))] ++pub struct PvpanicDevConfig { ++ #[arg(long, value_parser = ["pvpanic"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ #[arg(long, alias = "supported-features", default_value = "3", value_parser = valid_supported_features)] ++ pub supported_features: u32, ++} ++ ++fn valid_supported_features(f: &str) -> Result { ++ let features = f.parse::()?; ++ let supported_features = match features & !(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) { ++ 0 => features, ++ _ => bail!("Unsupported pvpanic device features {}", features), ++ }; ++ Ok(supported_features) ++} ++ + #[derive(Copy, Clone)] + pub struct PvPanicState { + supported_features: u32, +@@ -244,6 +273,7 @@ impl PciDevOps for PvPanicPci { + mod tests { + use super::*; + use crate::pci::{host::tests::create_pci_host, le_read_u16, PciHost}; ++ use machine_manager::config::str_slip_to_clap; + + fn init_pvpanic_dev(devfn: u8, supported_features: u32, dev_id: &str) -> Arc> { + let pci_host = create_pci_host(); +@@ -253,6 +283,9 @@ mod tests { + let config = PvpanicDevConfig { + id: dev_id.to_string(), + supported_features, ++ classtype: "".to_string(), ++ bus: "pcie.0".to_string(), ++ addr: (3, 0), + }; + let pvpanic_dev = PvPanicPci::new(&config, devfn, root_bus.clone()); + assert_eq!(pvpanic_dev.base.base.id, "pvpanic_test".to_string()); +@@ -264,6 +297,24 @@ mod tests { + pci_host + } + ++ #[test] ++ fn test_pvpanic_cmdline_parser() { ++ // Test1: Right. ++ let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7,supported-features=0"; ++ let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); ++ assert_eq!(result.unwrap().supported_features, 0); ++ ++ // Test2: Default value. ++ let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7"; ++ let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); ++ assert_eq!(result.unwrap().supported_features, 3); ++ ++ // Test3: Illegal value. ++ let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7,supported-features=4"; ++ let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); ++ assert!(result.is_err()); ++ } ++ + #[test] + fn test_pvpanic_attached() { + let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); +diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs +index 85b73ee..496c96c 100644 +--- a/devices/src/misc/scream/mod.rs ++++ b/devices/src/misc/scream/mod.rs +@@ -186,7 +186,7 @@ impl ShmemStreamFmt { + } + + /// Audio stream data structure. +-#[derive(Default)] ++#[derive(Debug, Default)] + pub struct StreamData { + pub fmt: ShmemStreamFmt, + chunk_idx: u16, +@@ -295,8 +295,14 @@ impl StreamData { + let header = &mut unsafe { std::slice::from_raw_parts_mut(hva as *mut ShmemHeader, 1) }[0]; + let play = &header.play; + +- while play.fmt.fmt_generation == self.fmt.fmt_generation && self.chunk_idx != play.chunk_idx +- { ++ loop { ++ if play.fmt.fmt_generation != self.fmt.fmt_generation { ++ break; ++ } ++ if self.chunk_idx == play.chunk_idx { ++ thread::sleep(time::Duration::from_micros(POLL_DELAY_US)); ++ continue; ++ } + // If the difference between the currently processed chunk_idx and the chunk_idx in + // the shared memory is greater than 4, the processing of the backend device is too + // slow and the backward data is skipped. +@@ -396,8 +402,10 @@ impl FromStr for ScreamInterface { + } + + #[derive(Parser, Debug, Clone)] +-#[command(name = "ivshmem_scream")] ++#[command(no_binary_name(true))] + pub struct ScreamConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long)] +diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs +index 7029410..2349d93 100755 +--- a/devices/src/misc/scream/ohaudio.rs ++++ b/devices/src/misc/scream/ohaudio.rs +@@ -12,12 +12,12 @@ + + use std::os::raw::c_void; + use std::sync::{ +- atomic::{fence, AtomicI32, Ordering}, ++ atomic::{fence, AtomicBool, AtomicI32, Ordering}, + Arc, Mutex, + }; + use std::{cmp, ptr, thread, time}; + +-use log::{error, warn}; ++use log::error; + + use crate::misc::scream::{AudioInterface, ScreamDirection, ShmemStreamHeader, StreamData}; + use util::ohos_binding::audio::*; +@@ -35,13 +35,17 @@ struct StreamUnit { + pub len: u64, + } + +-const STREAM_DATA_VEC_CAPACITY: usize = 30; ++const STREAM_DATA_VEC_CAPACITY: usize = 15; ++const FLUSH_DELAY_THRESHOLD_MS: u64 = 100; ++const FLUSH_DELAY_MS: u64 = 5; ++const FLUSH_DELAY_CNT: u64 = 200; + + struct OhAudioRender { + ctx: Option, + stream_data: Arc>>, +- prepared_data: u32, ++ data_size: AtomicI32, + start: bool, ++ flushing: AtomicBool, + } + + impl Default for OhAudioRender { +@@ -49,23 +53,14 @@ impl Default for OhAudioRender { + OhAudioRender { + ctx: None, + stream_data: Arc::new(Mutex::new(Vec::with_capacity(STREAM_DATA_VEC_CAPACITY))), +- prepared_data: 0, ++ data_size: AtomicI32::new(0), + start: false, ++ flushing: AtomicBool::new(false), + } + } + } + + impl OhAudioRender { +- #[inline(always)] +- fn check_data_ready(&self, recv_data: &StreamData) -> bool { +- let size = recv_data.fmt.size as u32 / 8; +- let channels = recv_data.fmt.channels as u32; +- let rate = recv_data.fmt.get_rate(); +- // Wait for data of 500 ms ready. +- // FIXME: the value of rate is wrong. +- self.prepared_data >= (size * channels * rate / 2) +- } +- + fn check_fmt_update(&mut self, recv_data: &StreamData) { + if self.ctx.is_some() + && !self.ctx.as_ref().unwrap().check_fmt( +@@ -77,46 +72,64 @@ impl OhAudioRender { + self.destroy(); + } + } ++ ++ fn flush(&mut self) { ++ self.flushing.store(true, Ordering::Release); ++ let mut cnt = 0; ++ while (cnt < FLUSH_DELAY_CNT) && (self.flushing.load(Ordering::Acquire)) { ++ thread::sleep(time::Duration::from_millis(FLUSH_DELAY_MS)); ++ cnt += 1; ++ } ++ // We need to wait for 100ms to ensure the audio data has ++ // been flushed before stop renderer. ++ thread::sleep(time::Duration::from_millis(FLUSH_DELAY_THRESHOLD_MS)); ++ let _ = self.ctx.as_ref().unwrap().flush_renderer(); ++ } + } + + impl OhAudioProcess for OhAudioRender { + fn init(&mut self, stream: &StreamData) -> bool { +- let mut context = AudioContext::new(AudioStreamType::Render); +- match context.init( +- stream.fmt.size, +- stream.fmt.get_rate(), +- stream.fmt.channels, +- AudioProcessCb::RendererCb(Some(on_write_data_cb)), +- ptr::addr_of!(*self) as *mut c_void, +- ) { +- Ok(()) => self.ctx = Some(context), +- Err(e) => { +- error!("failed to create oh audio render context: {}", e); +- return false; ++ if self.ctx.is_none() { ++ let mut context = AudioContext::new(AudioStreamType::Render); ++ match context.init( ++ stream.fmt.size, ++ stream.fmt.get_rate(), ++ stream.fmt.channels, ++ AudioProcessCb::RendererCb(Some(on_write_data_cb)), ++ ptr::addr_of!(*self) as *mut c_void, ++ ) { ++ Ok(()) => self.ctx = Some(context), ++ Err(e) => { ++ error!("failed to create oh audio render context: {}", e); ++ return false; ++ } + } + } + match self.ctx.as_ref().unwrap().start() { + Ok(()) => { + self.start = true; +- true ++ trace::oh_scream_render_init(&self.ctx); + } + Err(e) => { + error!("failed to start oh audio renderer: {}", e); +- false + } + } ++ self.start + } + + fn destroy(&mut self) { + if self.ctx.is_some() { + if self.start { ++ self.flush(); + self.ctx.as_mut().unwrap().stop(); + self.start = false; + } + self.ctx = None; + } +- self.stream_data.lock().unwrap().clear(); +- self.prepared_data = 0; ++ let mut locked_data = self.stream_data.lock().unwrap(); ++ locked_data.clear(); ++ self.data_size.store(0, Ordering::Relaxed); ++ trace::oh_scream_render_destroy(); + } + + fn process(&mut self, recv_data: &StreamData) -> i32 { +@@ -124,18 +137,30 @@ impl OhAudioProcess for OhAudioRender { + + fence(Ordering::Acquire); + ++ trace::trace_scope_start!(ohaudio_render_process, args = (recv_data)); ++ + let su = StreamUnit { + addr: recv_data.audio_base, + len: recv_data.audio_size as u64, + }; +- self.stream_data.lock().unwrap().push(su); ++ let mut locked_data = self.stream_data.lock().unwrap(); ++ // When audio data is not consumed in time, we remove old chunk ++ // and push new one. So audio-playing won't delay. One chunk means ++ // 20 ms data. ++ if locked_data.len() >= STREAM_DATA_VEC_CAPACITY { ++ let remove_size = locked_data[0].len; ++ locked_data.remove(0); ++ self.data_size ++ .fetch_sub(remove_size as i32, Ordering::Relaxed); ++ } ++ locked_data.push(su); ++ self.data_size ++ .fetch_add(recv_data.audio_size as i32, Ordering::Relaxed); ++ drop(locked_data); + +- if !self.start { +- self.prepared_data += recv_data.audio_size; +- if self.check_data_ready(recv_data) && !self.init(recv_data) { +- error!("failed to init oh audio"); +- self.destroy(); +- } ++ if !self.start && !self.init(recv_data) { ++ error!("failed to init oh audio"); ++ self.destroy(); + } + 0 + } +@@ -185,6 +210,7 @@ impl OhAudioProcess for OhAudioCapture { + match self.ctx.as_ref().unwrap().start() { + Ok(()) => { + self.start = true; ++ trace::oh_scream_capture_init(&self.ctx); + true + } + Err(e) => { +@@ -197,11 +223,12 @@ impl OhAudioProcess for OhAudioCapture { + fn destroy(&mut self) { + if self.ctx.is_some() { + if self.start { +- self.ctx.as_mut().unwrap().stop(); + self.start = false; ++ self.ctx.as_mut().unwrap().stop(); + } + self.ctx = None; + } ++ trace::oh_scream_capture_destroy(); + } + + fn preprocess(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) { +@@ -214,6 +241,9 @@ impl OhAudioProcess for OhAudioCapture { + + fn process(&mut self, recv_data: &StreamData) -> i32 { + self.check_fmt_update(recv_data); ++ ++ trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); ++ + if !self.start && !self.init(recv_data) { + self.destroy(); + return 0; +@@ -239,7 +269,13 @@ extern "C" fn on_write_data_cb( + .as_mut() + .unwrap_unchecked() + }; +- if !render.start { ++ let data_size = render.data_size.load(Ordering::Relaxed); ++ ++ trace::trace_scope_start!(ohaudio_write_cb, args = (length, data_size)); ++ ++ if !render.flushing.load(Ordering::Acquire) && data_size < length { ++ // SAFETY: we checked len. ++ unsafe { ptr::write_bytes(buffer as *mut u8, 0, length as usize) }; + return 0; + } + +@@ -255,6 +291,7 @@ extern "C" fn on_write_data_cb( + unsafe { + ptr::copy_nonoverlapping(su.addr as *const u8, dst_addr as *mut u8, len as usize) + }; ++ trace::oh_scream_on_write_data_cb(len as usize); + + dst_addr += len; + left -= len; +@@ -265,8 +302,16 @@ extern "C" fn on_write_data_cb( + su.addr += len; + } + } ++ render ++ .data_size ++ .fetch_sub(length - left as i32, Ordering::Relaxed); ++ + if left > 0 { +- warn!("data in stream unit list is not enough"); ++ // SAFETY: we checked len. ++ unsafe { ptr::write_bytes(dst_addr as *mut u8, 0, left as usize) }; ++ } ++ if render.flushing.load(Ordering::Acquire) && su_list.is_empty() { ++ render.flushing.store(false, Ordering::Release); + } + 0 + } +@@ -284,6 +329,8 @@ extern "C" fn on_read_data_cb( + .unwrap_unchecked() + }; + ++ trace::trace_scope_start!(ohaudio_read_cb, args = (length)); ++ + loop { + if !capture.start { + return 0; +@@ -306,6 +353,7 @@ extern "C" fn on_read_data_cb( + len as usize, + ) + }; ++ trace::oh_scream_on_read_data_cb(len as usize); + left -= len; + src_addr += len; + capture.cur_pos += len; +diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs +index b0f5dc8..7974666 100644 +--- a/devices/src/pci/bus.rs ++++ b/devices/src/pci/bus.rs +@@ -94,7 +94,7 @@ impl PciBus { + /// # Arguments + /// + /// * `bus_num` - The bus number. +- /// * `devfn` - Slot number << 8 | device number. ++ /// * `devfn` - Slot number << 3 | Function number. + pub fn get_device(&self, bus_num: u8, devfn: u8) -> Option>> { + if let Some(dev) = self.devices.get(&devfn) { + return Some((*dev).clone()); +@@ -275,7 +275,7 @@ mod tests { + use crate::pci::bus::PciBus; + use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; + use crate::pci::root_port::RootPort; +- use crate::pci::{PciDevBase, PciHost}; ++ use crate::pci::{PciDevBase, PciHost, RootPortConfig}; + use crate::{Device, DeviceBase}; + use address_space::{AddressSpace, Region}; + +@@ -372,8 +372,12 @@ mod tests { + let pci_host = create_pci_host(); + let locked_pci_host = pci_host.lock().unwrap(); + let root_bus = Arc::downgrade(&locked_pci_host.root_bus); +- +- let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); ++ let root_port_config = RootPortConfig { ++ addr: (1, 0), ++ id: "pcie.1".to_string(), ++ ..Default::default() ++ }; ++ let root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.realize().unwrap(); + + // Test device is attached to the root bus. +@@ -421,7 +425,12 @@ mod tests { + let locked_pci_host = pci_host.lock().unwrap(); + let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + +- let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); ++ let root_port_config = RootPortConfig { ++ id: "pcie.1".to_string(), ++ addr: (1, 0), ++ ..Default::default() ++ }; ++ let root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.realize().unwrap(); + + let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); +diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs +index 1e66456..16c9b6a 100644 +--- a/devices/src/pci/config.rs ++++ b/devices/src/pci/config.rs +@@ -1020,7 +1020,7 @@ impl PciConfig { + /// + /// # Arguments + /// +- /// * `devfn` - Slot number << 3 | function number. ++ /// * `devfn` - Slot number << 3 | Function number. + /// * `port_num` - Port number. + /// * `dev_type` - Device type. + pub fn add_pcie_cap(&mut self, devfn: u8, port_num: u8, dev_type: u8) -> Result { +diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs +index 7789536..ff35f47 100644 +--- a/devices/src/pci/demo_device/mod.rs ++++ b/devices/src/pci/demo_device/mod.rs +@@ -42,6 +42,7 @@ use std::{ + }; + + use anyhow::{bail, Result}; ++use clap::Parser; + use log::error; + + use crate::pci::demo_device::{ +@@ -57,7 +58,30 @@ use crate::pci::{ + use crate::pci::{demo_device::base_device::BaseDevice, PciDevBase}; + use crate::{Device, DeviceBase}; + use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; +-use machine_manager::config::DemoDevConfig; ++use machine_manager::config::{get_pci_df, valid_id}; ++ ++/// Config struct for `demo_dev`. ++/// Contains demo_dev device's attr. ++#[derive(Parser, Debug, Clone)] ++#[command(no_binary_name(true))] ++pub struct DemoDevConfig { ++ #[arg(long, value_parser = ["pcie-demo-dev"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ // Different device implementations can be configured based on this parameter ++ #[arg(long, alias = "device_type")] ++ pub device_type: Option, ++ #[arg(long, alias = "bar_num", default_value = "0")] ++ pub bar_num: u8, ++ // Every bar has the same size just for simplification. ++ #[arg(long, alias = "bar_size", default_value = "0")] ++ pub bar_size: u64, ++} + + pub struct DemoDev { + base: PciDevBase, +@@ -71,14 +95,15 @@ impl DemoDev { + pub fn new( + cfg: DemoDevConfig, + devfn: u8, +- _sys_mem: Arc, ++ sys_mem: Arc, + parent_bus: Weak>, + ) -> Self { + // You can choose different device function based on the parameter of device_type. +- let device: Arc> = match cfg.device_type.as_str() { +- "demo-gpu" => Arc::new(Mutex::new(DemoGpu::new(_sys_mem, cfg.id.clone()))), +- "demo-input" => Arc::new(Mutex::new(DemoKbdMouse::new(_sys_mem))), +- "demo-display" => Arc::new(Mutex::new(DemoDisplay::new(_sys_mem))), ++ let device_type = cfg.device_type.clone().unwrap_or_default(); ++ let device: Arc> = match device_type.as_str() { ++ "demo-gpu" => Arc::new(Mutex::new(DemoGpu::new(sys_mem, cfg.id.clone()))), ++ "demo-input" => Arc::new(Mutex::new(DemoKbdMouse::new(sys_mem))), ++ "demo-display" => Arc::new(Mutex::new(DemoDisplay::new(sys_mem))), + _ => Arc::new(Mutex::new(BaseDevice::new())), + }; + DemoDev { +@@ -234,3 +259,29 @@ pub trait DeviceTypeOperation: Send { + fn realize(&mut self) -> Result<()>; + fn unrealize(&mut self) -> Result<()>; + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ #[test] ++ fn test_parse_demo_dev() { ++ // Test1: Right. ++ let demo_cmd1 = "pcie-demo-dev,bus=pcie.0,addr=0x4,id=test_0,device_type=demo-gpu,bar_num=3,bar_size=4096"; ++ let result = DemoDevConfig::try_parse_from(str_slip_to_clap(demo_cmd1, true, false)); ++ assert!(result.is_ok()); ++ let demo_cfg = result.unwrap(); ++ assert_eq!(demo_cfg.id, "test_0".to_string()); ++ assert_eq!(demo_cfg.device_type, Some("demo-gpu".to_string())); ++ assert_eq!(demo_cfg.bar_num, 3); ++ assert_eq!(demo_cfg.bar_size, 4096); ++ ++ // Test2: Default bar_num/bar_size. ++ let demo_cmd2 = "pcie-demo-dev,bus=pcie.0,addr=4.0,id=test_0,device_type=demo-gpu"; ++ let result = DemoDevConfig::try_parse_from(str_slip_to_clap(demo_cmd2, true, false)); ++ assert!(result.is_ok()); ++ let demo_cfg = result.unwrap(); ++ assert_eq!(demo_cfg.bar_num, 0); ++ assert_eq!(demo_cfg.bar_size, 0); ++ } ++} +diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs +index b6a44da..c144723 100644 +--- a/devices/src/pci/host.rs ++++ b/devices/src/pci/host.rs +@@ -327,7 +327,7 @@ fn build_osc_for_aml(pci_host_bridge: &mut AmlDevice) { + pci_host_bridge.append_child(method); + } + +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + fn build_osc_for_aml(pci_host_bridge: &mut AmlDevice) { + // _OSC means Operating System Capabilities. + pci_host_bridge.append_child(AmlNameDecl::new("SUPP", AmlInteger(0))); +@@ -412,6 +412,8 @@ fn build_prt_for_aml(pci_bus: &mut AmlDevice, irq: i32) { + let irqs = irq as u8 + i; + #[cfg(target_arch = "aarch64")] + let irqs = irq as u8 + PCI_INTR_BASE + i; ++ #[cfg(target_arch = "riscv64")] ++ let irqs = irq as u8 + i; + let mut gsi = AmlDevice::new(format!("GSI{}", i).as_str()); + gsi.append_child(AmlNameDecl::new("_HID", AmlEisaId::new("PNP0C0F"))); + gsi.append_child(AmlNameDecl::new("_UID", AmlString(i.to_string()))); +@@ -547,7 +549,7 @@ pub mod tests { + use super::*; + use crate::pci::bus::PciBus; + use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE, SECONDARY_BUS_NUM}; +- use crate::pci::root_port::RootPort; ++ use crate::pci::root_port::{RootPort, RootPortConfig}; + use crate::pci::{PciDevBase, Result}; + use crate::{Device, DeviceBase}; + use address_space::Region; +@@ -658,7 +660,12 @@ pub mod tests { + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let pio_addr_ops = PciHost::build_pio_addr_ops(pci_host.clone()); + let pio_data_ops = PciHost::build_pio_data_ops(pci_host.clone()); +- let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); ++ let root_port_config = RootPortConfig { ++ addr: (1, 0), ++ id: "pcie.1".to_string(), ++ ..Default::default() ++ }; ++ let root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.realize().unwrap(); + + let mut data = [0_u8; 4]; +@@ -735,10 +742,20 @@ pub mod tests { + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let mmconfig_region_ops = PciHost::build_mmconfig_ops(pci_host.clone()); + +- let mut root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); ++ let root_port_config = RootPortConfig { ++ addr: (1, 0), ++ id: "pcie.1".to_string(), ++ ..Default::default() ++ }; ++ let mut root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.write_config(SECONDARY_BUS_NUM as usize, &[1]); + root_port.realize().unwrap(); +- let mut root_port = RootPort::new("pcie.2".to_string(), 16, 0, root_bus, false); ++ let root_port_config = RootPortConfig { ++ addr: (2, 0), ++ id: "pcie.2".to_string(), ++ ..Default::default() ++ }; ++ let mut root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.write_config(SECONDARY_BUS_NUM as usize, &[2]); + root_port.realize().unwrap(); + +diff --git a/devices/src/pci/intx.rs b/devices/src/pci/intx.rs +index bf53fa5..b0624fe 100644 +--- a/devices/src/pci/intx.rs ++++ b/devices/src/pci/intx.rs +@@ -16,8 +16,7 @@ use anyhow::Result; + use log::error; + + use crate::interrupt_controller::LineIrqManager; +-use crate::pci::{swizzle_map_irq, PciBus, PciConfig, INTERRUPT_PIN, PCI_INTR_BASE, PCI_PIN_NUM}; +-use util::test_helper::{is_test_enabled, trigger_intx}; ++use crate::pci::{swizzle_map_irq, PciBus, PciConfig, INTERRUPT_PIN, PCI_PIN_NUM}; + + pub type InterruptHandler = Box Result<()> + Send + Sync>; + +@@ -96,11 +95,6 @@ impl Intx { + let irq = locked_intx_state.gsi_base + self.irq_pin; + let level = locked_intx_state.irq_count[self.irq_pin as usize] != 0; + +- if is_test_enabled() { +- trigger_intx(irq + PCI_INTR_BASE as u32, change); +- return; +- } +- + let irq_handler = &locked_intx_state.irq_handler; + if let Err(e) = irq_handler.set_level_irq(irq, level) { + error!( +diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs +index 4a8d942..7a90d6e 100644 +--- a/devices/src/pci/mod.rs ++++ b/devices/src/pci/mod.rs +@@ -28,22 +28,25 @@ pub use error::PciError; + pub use host::PciHost; + pub use intx::{init_intx, InterruptHandler, PciIntxState}; + pub use msix::{init_msix, MsiVector}; +-pub use root_port::RootPort; ++pub use root_port::{RootPort, RootPortConfig}; + +-use std::{ +- mem::size_of, +- sync::{Arc, Mutex, Weak}, +-}; ++use std::any::{Any, TypeId}; ++use std::collections::HashMap; ++use std::mem::size_of; ++use std::sync::{Arc, Mutex, Weak}; + + use anyhow::{bail, Result}; + use byteorder::{ByteOrder, LittleEndian}; + +-use crate::{ +- pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}, +- MsiIrqManager, +-}; +-use crate::{Device, DeviceBase}; +-use util::AsAny; ++#[cfg(feature = "scream")] ++use crate::misc::ivshmem::Ivshmem; ++#[cfg(feature = "pvpanic")] ++use crate::misc::pvpanic::PvPanicPci; ++use crate::pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}; ++use crate::usb::xhci::xhci_pci::XhciPciDevice; ++use crate::{Device, DeviceBase, MsiIrqManager}; ++#[cfg(feature = "demo_device")] ++use demo_device::DemoDev; + + const BDF_FUNC_SHIFT: u8 = 3; + pub const PCI_SLOT_MAX: u8 = 32; +@@ -142,7 +145,7 @@ pub struct PciDevBase { + pub parent_bus: Weak>, + } + +-pub trait PciDevOps: Device + Send + AsAny { ++pub trait PciDevOps: Device + Send { + /// Get base property of pci device. + fn pci_base(&self) -> &PciDevBase; + +@@ -200,7 +203,7 @@ pub trait PciDevOps: Device + Send + AsAny { + /// # Arguments + /// + /// * `bus_num` - Bus number. +- /// * `devfn` - Slot number << 8 | Function number. ++ /// * `devfn` - Slot number << 3 | Function number. + /// + /// # Returns + /// +@@ -270,6 +273,57 @@ pub trait PciDevOps: Device + Send + AsAny { + } + } + ++pub type ToPciDevOpsFunc = fn(&dyn Any) -> &dyn PciDevOps; ++ ++static mut PCIDEVOPS_HASHMAP: Option> = None; ++ ++pub fn convert_to_pcidevops(item: &dyn Any) -> &dyn PciDevOps { ++ // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of ++ // the conversion is its own structure type, so the conversion result will definitely not be `None`. ++ let t = item.downcast_ref::().unwrap(); ++ t as &dyn PciDevOps ++} ++ ++pub fn register_pcidevops_type() -> Result<()> { ++ let type_id = TypeId::of::(); ++ // SAFETY: PCIDEVOPS_HASHMAP will be built in `type_init` function sequentially in the main thread. ++ // And will not be changed after `type_init`. ++ unsafe { ++ if PCIDEVOPS_HASHMAP.is_none() { ++ PCIDEVOPS_HASHMAP = Some(HashMap::new()); ++ } ++ let types = PCIDEVOPS_HASHMAP.as_mut().unwrap(); ++ if types.get(&type_id).is_some() { ++ bail!("Type Id {:?} has been registered.", type_id); ++ } ++ types.insert(type_id, convert_to_pcidevops::); ++ } ++ ++ Ok(()) ++} ++ ++pub fn devices_register_pcidevops_type() -> Result<()> { ++ #[cfg(feature = "scream")] ++ register_pcidevops_type::()?; ++ #[cfg(feature = "pvpanic")] ++ register_pcidevops_type::()?; ++ register_pcidevops_type::()?; ++ #[cfg(feature = "demo_device")] ++ register_pcidevops_type::()?; ++ register_pcidevops_type::() ++} ++ ++pub fn to_pcidevops(dev: &dyn Device) -> Option<&dyn PciDevOps> { ++ let type_id = dev.type_id(); ++ // SAFETY: PCIDEVOPS_HASHMAP has been built. And this function is called without changing hashmap. ++ unsafe { ++ let types = PCIDEVOPS_HASHMAP.as_mut().unwrap(); ++ let func = types.get(&type_id)?; ++ let pcidev = func(dev.as_any()); ++ Some(pcidev) ++ } ++} ++ + /// Init multifunction for pci devices. + /// + /// # Arguments +@@ -349,11 +403,10 @@ pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { + + #[cfg(test)] + mod tests { ++ use super::*; + use crate::DeviceBase; + use address_space::{AddressSpace, Region}; + +- use super::*; +- + #[test] + fn test_le_write_u16_01() { + let mut buf: [u8; 2] = [0; 2]; +diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs +index 1d1e30b..451a663 100644 +--- a/devices/src/pci/msix.rs ++++ b/devices/src/pci/msix.rs +@@ -32,7 +32,6 @@ use migration_derive::{ByteCode, Desc}; + use util::{ + byte_code::ByteCode, + num_ops::{ranges_overlap, round_up}, +- test_helper::{add_msix_msg, is_test_enabled}, + }; + + pub const MSIX_TABLE_ENTRY_SIZE: u16 = 16; +@@ -401,14 +400,6 @@ impl Msix { + pub fn send_msix(&self, vector: u16, dev_id: u16) { + let msg = self.get_message(vector); + +- if is_test_enabled() { +- let data = msg.data; +- let mut addr: u64 = msg.address_hi as u64; +- addr = (addr << 32) + msg.address_lo as u64; +- add_msix_msg(addr, data); +- return; +- } +- + let msix_vector = MsiVector { + msg_addr_lo: msg.address_lo, + msg_addr_hi: msg.address_hi, +diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs +index 4013027..6396c0c 100644 +--- a/devices/src/pci/root_port.rs ++++ b/devices/src/pci/root_port.rs +@@ -14,6 +14,7 @@ use std::sync::atomic::{AtomicU16, Ordering}; + use std::sync::{Arc, Mutex, Weak}; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser}; + use log::{error, info}; + use once_cell::sync::OnceCell; + +@@ -39,17 +40,41 @@ use crate::pci::{ + }; + use crate::{Device, DeviceBase, MsiIrqManager}; + use address_space::Region; ++use machine_manager::config::{get_pci_df, parse_bool, valid_id}; + use machine_manager::qmp::qmp_channel::send_device_deleted_msg; + use migration::{ + DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, + }; + use migration_derive::{ByteCode, Desc}; +-use util::{byte_code::ByteCode, num_ops::ranges_overlap}; ++use util::{ ++ byte_code::ByteCode, ++ num_ops::{ranges_overlap, str_to_num}, ++}; + + const DEVICE_ID_RP: u16 = 0x000c; + + static FAST_UNPLUG_FEATURE: OnceCell = OnceCell::new(); + ++/// Basic information of RootPort like port number. ++#[derive(Parser, Debug, Clone, Default)] ++#[command(no_binary_name(true))] ++pub struct RootPortConfig { ++ #[arg(long, value_parser = ["pcie-root-port"])] ++ pub classtype: String, ++ #[arg(long, value_parser = str_to_num::)] ++ pub port: u8, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] ++ pub multifunction: bool, ++ #[arg(long, default_value = "0")] ++ pub chassis: u8, ++} ++ + /// Device state root port. + #[repr(C)] + #[derive(Copy, Clone, Desc, ByteCode)] +@@ -81,22 +106,15 @@ impl RootPort { + /// + /// # Arguments + /// +- /// * `name` - Root port name. +- /// * `devfn` - Device number << 3 | Function number. +- /// * `port_num` - Root port number. ++ /// * `cfg` - Root port config. + /// * `parent_bus` - Weak reference to the parent bus. +- pub fn new( +- name: String, +- devfn: u8, +- port_num: u8, +- parent_bus: Weak>, +- multifunction: bool, +- ) -> Self { ++ pub fn new(cfg: RootPortConfig, parent_bus: Weak>) -> Self { ++ let devfn = cfg.addr.0 << 3 | cfg.addr.1; + #[cfg(target_arch = "x86_64")] + let io_region = Region::init_container_region(1 << 16, "RootPortIo"); + let mem_region = Region::init_container_region(u64::max_value(), "RootPortMem"); + let sec_bus = Arc::new(Mutex::new(PciBus::new( +- name.clone(), ++ cfg.id.clone(), + #[cfg(target_arch = "x86_64")] + io_region.clone(), + mem_region.clone(), +@@ -104,18 +122,18 @@ impl RootPort { + + Self { + base: PciDevBase { +- base: DeviceBase::new(name, true), ++ base: DeviceBase::new(cfg.id, true), + config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), + devfn, + parent_bus, + }, +- port_num, ++ port_num: cfg.port, + sec_bus, + #[cfg(target_arch = "x86_64")] + io_region, + mem_region, + dev_id: Arc::new(AtomicU16::new(0)), +- multifunction, ++ multifunction: cfg.multifunction, + hpev_notified: false, + } + } +@@ -694,7 +712,12 @@ mod tests { + fn test_read_config() { + let pci_host = create_pci_host(); + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); +- let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); ++ let root_port_config = RootPortConfig { ++ addr: (1, 0), ++ id: "pcie.1".to_string(), ++ ..Default::default() ++ }; ++ let root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.realize().unwrap(); + + let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); +@@ -710,7 +733,12 @@ mod tests { + fn test_write_config() { + let pci_host = create_pci_host(); + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); +- let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); ++ let root_port_config = RootPortConfig { ++ addr: (1, 0), ++ id: "pcie.1".to_string(), ++ ..Default::default() ++ }; ++ let root_port = RootPort::new(root_port_config, root_bus.clone()); + root_port.realize().unwrap(); + let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); + +diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs +index 9546743..0b018c6 100644 +--- a/devices/src/scsi/bus.rs ++++ b/devices/src/scsi/bus.rs +@@ -666,7 +666,7 @@ impl ScsiRequest { + let mut not_supported_flag = false; + let mut sense = None; + let mut status = GOOD; +- let found_lun = self.dev.lock().unwrap().config.lun; ++ let found_lun = self.dev.lock().unwrap().dev_cfg.lun; + + // Requested lun id is not equal to found device id means it may be a target request. + // REPORT LUNS is also a target request command. +@@ -766,7 +766,7 @@ fn scsi_cdb_length(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i32 { + } + } + +-fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { ++pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { + let dev_lock = dev.lock().unwrap(); + let block_size = dev_lock.block_size as i32; + drop(dev_lock); +@@ -824,7 +824,7 @@ fn scsi_cdb_lba(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i64 { + } + } + +-fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { ++pub fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { + match cdb[0] { + WRITE_6 + | WRITE_10 +@@ -1174,7 +1174,7 @@ fn scsi_command_emulate_mode_sense( + if dev_lock.state.features & (1 << SCSI_DISK_F_DPOFUA) != 0 { + dev_specific_parameter = 0x10; + } +- if dev_lock.config.read_only { ++ if dev_lock.drive_cfg.readonly { + // Readonly. + dev_specific_parameter |= 0x80; + } +@@ -1362,7 +1362,7 @@ fn scsi_command_emulate_report_luns( + let dev_lock = dev.lock().unwrap(); + // Byte 0-3: Lun List Length. Byte 4-7: Reserved. + let mut outbuf: Vec = vec![0; 8]; +- let target = dev_lock.config.target; ++ let target = dev_lock.dev_cfg.target; + + if cmd.xfer < 16 { + bail!("scsi REPORT LUNS xfer {} too short!", cmd.xfer); +@@ -1383,17 +1383,17 @@ fn scsi_command_emulate_report_luns( + + for (_pos, device) in scsi_bus_clone.devices.iter() { + let device_lock = device.lock().unwrap(); +- if device_lock.config.target != target { ++ if device_lock.dev_cfg.target != target { + drop(device_lock); + continue; + } + let len = outbuf.len(); +- if device_lock.config.lun < 256 { ++ if device_lock.dev_cfg.lun < 256 { + outbuf.push(0); +- outbuf.push(device_lock.config.lun as u8); ++ outbuf.push(device_lock.dev_cfg.lun as u8); + } else { +- outbuf.push(0x40 | ((device_lock.config.lun >> 8) & 0xff) as u8); +- outbuf.push((device_lock.config.lun & 0xff) as u8); ++ outbuf.push(0x40 | ((device_lock.dev_cfg.lun >> 8) & 0xff) as u8); ++ outbuf.push((device_lock.dev_cfg.lun & 0xff) as u8); + } + outbuf.resize(len + 8, 0); + drop(device_lock); +diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs +index 6c4652e..37aca3d 100644 +--- a/devices/src/scsi/disk.rs ++++ b/devices/src/scsi/disk.rs +@@ -14,11 +14,12 @@ use std::collections::HashMap; + use std::sync::{Arc, Mutex, Weak}; + + use anyhow::{bail, Result}; ++use clap::Parser; + + use crate::ScsiBus::{aio_complete_cb, ScsiBus, ScsiCompleteCb}; + use crate::{Device, DeviceBase}; + use block_backend::{create_block_backend, BlockDriverOps, BlockProperty}; +-use machine_manager::config::{DriveFile, ScsiDevConfig, VmConfig}; ++use machine_manager::config::{valid_id, DriveConfig, DriveFile, VmConfig}; + use machine_manager::event_loop::EventLoop; + use util::aio::{Aio, AioEngine, WriteZeroesState}; + +@@ -57,6 +58,49 @@ pub const SCSI_DISK_DEFAULT_BLOCK_SIZE: u32 = 1 << SCSI_DISK_DEFAULT_BLOCK_SIZE_ + pub const SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT: u32 = 11; + pub const SCSI_CDROM_DEFAULT_BLOCK_SIZE: u32 = 1 << SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT; + ++// Stratovirt uses scsi mod in only virtio-scsi and usb-storage. Scsi's channel/target/lun ++// of usb-storage are both 0. Scsi's channel/target/lun of virtio-scsi is no more than 0/255/16383. ++// Set valid range of channel/target according to the range of virtio-scsi as 0/255. ++// ++// For stratovirt doesn't support `Flat space addressing format`(14 bits for lun) and only supports ++// `peripheral device addressing format`(8 bits for lun) now, lun should be less than 255(2^8 - 1) temporarily. ++const SCSI_MAX_CHANNEL: i64 = 0; ++const SCSI_MAX_TARGET: i64 = 255; ++const SUPPORT_SCSI_MAX_LUN: i64 = 255; ++ ++#[derive(Parser, Clone, Debug, Default)] ++#[command(no_binary_name(true))] ++pub struct ScsiDevConfig { ++ #[arg(long, value_parser = ["scsi-cd", "scsi-hd"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long, value_parser = valid_scsi_bus)] ++ pub bus: String, ++ /// Scsi four level hierarchical address(host, channel, target, lun). ++ #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..=SCSI_MAX_CHANNEL))] ++ pub channel: u8, ++ #[arg(long, alias = "scsi-id", value_parser = clap::value_parser!(u8).range(..=SCSI_MAX_TARGET))] ++ pub target: u8, ++ #[arg(long, value_parser = clap::value_parser!(u16).range(..=SUPPORT_SCSI_MAX_LUN))] ++ pub lun: u16, ++ #[arg(long)] ++ pub drive: String, ++ #[arg(long)] ++ pub serial: Option, ++ #[arg(long)] ++ pub bootindex: Option, ++} ++ ++// Scsi device should has bus named as "$parent_cntlr_name.0". ++fn valid_scsi_bus(bus: &str) -> Result { ++ let strs = bus.split('.').collect::>(); ++ if strs.len() != 2 || strs[1] != "0" { ++ bail!("Invalid scsi bus {}", bus); ++ } ++ Ok(bus.to_string()) ++} ++ + #[derive(Clone, Default)] + pub struct ScsiDevState { + /// Features which the scsi device supports. +@@ -99,7 +143,9 @@ impl Device for ScsiDevice { + pub struct ScsiDevice { + pub base: DeviceBase, + /// Configuration of the scsi device. +- pub config: ScsiDevConfig, ++ pub dev_cfg: ScsiDevConfig, ++ /// Configuration of the scsi device's drive. ++ pub drive_cfg: DriveConfig, + /// State of the scsi device. + pub state: ScsiDevState, + /// Block backend opened by scsi device. +@@ -129,13 +175,19 @@ unsafe impl Sync for ScsiDevice {} + + impl ScsiDevice { + pub fn new( +- config: ScsiDevConfig, +- scsi_type: u32, ++ dev_cfg: ScsiDevConfig, ++ drive_cfg: DriveConfig, + drive_files: Arc>>, + ) -> ScsiDevice { ++ let scsi_type = match dev_cfg.classtype.as_str() { ++ "scsi-hd" => SCSI_TYPE_DISK, ++ _ => SCSI_TYPE_ROM, ++ }; ++ + ScsiDevice { +- base: DeviceBase::new(config.id.clone(), false), +- config, ++ base: DeviceBase::new(dev_cfg.id.clone(), false), ++ dev_cfg, ++ drive_cfg, + state: ScsiDevState::new(), + block_backend: None, + req_align: 1, +@@ -164,35 +216,35 @@ impl ScsiDevice { + } + } + +- if let Some(serial) = &self.config.serial { ++ if let Some(serial) = &self.dev_cfg.serial { + self.state.serial = serial.clone(); + } + + let drive_files = self.drive_files.lock().unwrap(); +- // File path can not be empty string. And it has also been checked in CmdParser::parse. +- let file = VmConfig::fetch_drive_file(&drive_files, &self.config.path_on_host)?; ++ // File path can not be empty string. And it has also been checked in command parsing by using `Clap`. ++ let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; + +- let alignments = VmConfig::fetch_drive_align(&drive_files, &self.config.path_on_host)?; ++ let alignments = VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; + self.req_align = alignments.0; + self.buf_align = alignments.1; +- let drive_id = VmConfig::get_drive_id(&drive_files, &self.config.path_on_host)?; ++ let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; + + let mut thread_pool = None; +- if self.config.aio_type != AioEngine::Off { ++ if self.drive_cfg.aio != AioEngine::Off { + thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); + } +- let aio = Aio::new(Arc::new(aio_complete_cb), self.config.aio_type, thread_pool)?; ++ let aio = Aio::new(Arc::new(aio_complete_cb), self.drive_cfg.aio, thread_pool)?; + let conf = BlockProperty { + id: drive_id, +- format: self.config.format, ++ format: self.drive_cfg.format, + iothread, +- direct: self.config.direct, ++ direct: self.drive_cfg.direct, + req_align: self.req_align, + buf_align: self.buf_align, + discard: false, + write_zeroes: WriteZeroesState::Off, +- l2_cache_size: self.config.l2_cache_size, +- refcount_cache_size: self.config.refcount_cache_size, ++ l2_cache_size: self.drive_cfg.l2_cache_size, ++ refcount_cache_size: self.drive_cfg.refcount_cache_size, + }; + let backend = create_block_backend(file, aio, conf)?; + let disk_size = backend.lock().unwrap().disk_size()?; +@@ -202,3 +254,60 @@ impl ScsiDevice { + Ok(()) + } + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_scsi_device_cmdline_parser() { ++ // Test1: Right. ++ let cmdline1 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0,serial=123456,bootindex=1"; ++ let config = ++ ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline1, true, false)).unwrap(); ++ assert_eq!(config.id, "scsi0-0-0-0"); ++ assert_eq!(config.bus, "scsi0.0"); ++ assert_eq!(config.target, 0); ++ assert_eq!(config.lun, 0); ++ assert_eq!(config.drive, "drive-0-0-0-0"); ++ assert_eq!(config.serial.unwrap(), "123456"); ++ assert_eq!(config.bootindex.unwrap(), 1); ++ ++ // Test2: Default value. ++ let cmdline2 = "scsi-cd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let config = ++ ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline2, true, false)).unwrap(); ++ assert_eq!(config.channel, 0); ++ assert_eq!(config.serial, None); ++ assert_eq!(config.bootindex, None); ++ ++ // Test3: Illegal value. ++ let cmdline3 = "scsi-hd,bus=scsi0.0,scsi-id=256,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ let cmdline3 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=256,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ let cmdline3 = "illegal,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ ++ // Test4: Missing necessary parameters. ++ let cmdline4 = "scsi-hd,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "scsi-hd,bus=scsi0.0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,id=scsi0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0"; ++ let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ } ++} +diff --git a/devices/src/smbios/smbios_table.rs b/devices/src/smbios/smbios_table.rs +index 9211bd8..f476025 100644 +--- a/devices/src/smbios/smbios_table.rs ++++ b/devices/src/smbios/smbios_table.rs +@@ -656,9 +656,9 @@ impl SmbiosTable { + fn build_type0(&mut self, type0: SmbiosType0Config) { + let mut table0: SmbiosType0Table = SmbiosType0Table::new(); + +- if let Some(vender) = type0.vender { ++ if let Some(vendor) = type0.vendor { + table0.header.vendor_idx = table0.str_index + 1; +- table0.set_str(vender); ++ table0.set_str(vendor); + } + + if let Some(version) = type0.version { +diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs +index ca039ab..4bcc760 100644 +--- a/devices/src/sysbus/mod.rs ++++ b/devices/src/sysbus/mod.rs +@@ -14,16 +14,30 @@ pub mod error; + + pub use error::SysBusError; + ++use std::any::{Any, TypeId}; ++use std::collections::HashMap; + use std::fmt; + use std::sync::{Arc, Mutex}; + + use anyhow::{bail, Context, Result}; + use vmm_sys_util::eventfd::EventFd; + ++#[cfg(target_arch = "x86_64")] ++use crate::acpi::cpu_controller::CpuController; ++use crate::acpi::ged::Ged; ++#[cfg(target_arch = "aarch64")] ++use crate::acpi::power::PowerDev; ++#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] ++use crate::legacy::Ramfb; ++#[cfg(target_arch = "x86_64")] ++use crate::legacy::{FwCfgIO, RTC}; ++#[cfg(target_arch = "aarch64")] ++use crate::legacy::{FwCfgMem, PL011, PL031}; ++use crate::legacy::{PFlash, Serial}; ++use crate::pci::PciHost; + use crate::{Device, DeviceBase, IrqState, LineIrqManager, TriggerMode}; + use acpi::{AmlBuilder, AmlScope}; + use address_space::{AddressSpace, GuestAddress, Region, RegionIoEventFd, RegionOps}; +-use util::AsAny; + + // Now that the serial device use a hardcoded IRQ number (4), and the starting + // free IRQ number can be 5. +@@ -38,6 +52,11 @@ pub const IRQ_BASE: i32 = 32; + #[cfg(target_arch = "aarch64")] + pub const IRQ_MAX: i32 = 191; + ++#[cfg(target_arch = "riscv64")] ++pub const IRQ_BASE: i32 = 1; ++#[cfg(target_arch = "riscv64")] ++pub const IRQ_MAX: i32 = 2047; ++ + pub struct SysBus { + #[cfg(target_arch = "x86_64")] + pub sys_io: Arc, +@@ -52,26 +71,18 @@ pub struct SysBus { + + impl fmt::Debug for SysBus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ let mut debug = f.debug_struct("SysBus"); ++ + #[cfg(target_arch = "x86_64")] +- let debug = f +- .debug_struct("SysBus") +- .field("sys_io", &self.sys_io) +- .field("sys_mem", &self.sys_mem) +- .field("free_irqs", &self.free_irqs) +- .field("min_free_irq", &self.min_free_irq) +- .field("mmio_region", &self.mmio_region) +- .field("min_free_base", &self.min_free_base) +- .finish(); +- #[cfg(target_arch = "aarch64")] +- let debug = f +- .debug_struct("SysBus") ++ let debug = debug.field("sys_io", &self.sys_io); ++ ++ debug + .field("sys_mem", &self.sys_mem) + .field("free_irqs", &self.free_irqs) + .field("min_free_irq", &self.min_free_irq) + .field("mmio_region", &self.mmio_region) + .field("min_free_base", &self.min_free_base) +- .finish(); +- debug ++ .finish() + } + } + +@@ -112,84 +123,82 @@ impl SysBus { + } + } + +- pub fn attach_device( +- &mut self, +- dev: &Arc>, +- region_base: u64, +- region_size: u64, +- region_name: &str, +- ) -> Result<()> { +- let region_ops = self.build_region_ops(dev); +- let region = Region::init_io_region(region_size, region_ops, region_name); +- let locked_dev = dev.lock().unwrap(); +- +- region.set_ioeventfds(&locked_dev.ioeventfds()); +- match locked_dev.sysbusdev_base().dev_type { +- SysBusDevType::Serial if cfg!(target_arch = "x86_64") => { +- #[cfg(target_arch = "x86_64")] +- self.sys_io +- .root() +- .add_subregion(region, region_base) +- .with_context(|| { +- format!( +- "Failed to register region in I/O space: offset={},size={}", +- region_base, region_size +- ) +- })?; +- } +- SysBusDevType::FwCfg if cfg!(target_arch = "x86_64") => { +- #[cfg(target_arch = "x86_64")] +- self.sys_io +- .root() +- .add_subregion(region, region_base) +- .with_context(|| { +- format!( +- "Failed to register region in I/O space: offset 0x{:x}, size {}", +- region_base, region_size +- ) +- })?; +- } +- SysBusDevType::Rtc if cfg!(target_arch = "x86_64") => { +- #[cfg(target_arch = "x86_64")] +- self.sys_io ++ pub fn attach_device(&mut self, dev: &Arc>) -> Result<()> { ++ let res = dev.lock().unwrap().get_sys_resource().clone(); ++ let region_base = res.region_base; ++ let region_size = res.region_size; ++ let region_name = res.region_name; ++ ++ // region_base/region_size are both 0 means this device doesn't have its own memory layout. ++ // The normally allocated device region_base is above the `MEM_LAYOUT[LayoutEntryType::Mmio as usize].0`. ++ if region_base != 0 && region_size != 0 { ++ let region_ops = self.build_region_ops(dev); ++ let region = Region::init_io_region(region_size, region_ops, ®ion_name); ++ let locked_dev = dev.lock().unwrap(); ++ ++ region.set_ioeventfds(&locked_dev.ioeventfds()); ++ match locked_dev.sysbusdev_base().dev_type { ++ SysBusDevType::Serial if cfg!(target_arch = "x86_64") => { ++ #[cfg(target_arch = "x86_64")] ++ self.sys_io ++ .root() ++ .add_subregion(region, region_base) ++ .with_context(|| { ++ format!( ++ "Failed to register region in I/O space: offset={},size={}", ++ region_base, region_size ++ ) ++ })?; ++ } ++ SysBusDevType::FwCfg if cfg!(target_arch = "x86_64") => { ++ #[cfg(target_arch = "x86_64")] ++ self.sys_io ++ .root() ++ .add_subregion(region, region_base) ++ .with_context(|| { ++ format!( ++ "Failed to register region in I/O space: offset 0x{:x}, size {}", ++ region_base, region_size ++ ) ++ })?; ++ } ++ SysBusDevType::Rtc if cfg!(target_arch = "x86_64") => { ++ #[cfg(target_arch = "x86_64")] ++ self.sys_io ++ .root() ++ .add_subregion(region, region_base) ++ .with_context(|| { ++ format!( ++ "Failed to register region in I/O space: offset 0x{:x}, size {}", ++ region_base, region_size ++ ) ++ })?; ++ } ++ _ => self ++ .sys_mem + .root() + .add_subregion(region, region_base) + .with_context(|| { + format!( +- "Failed to register region in I/O space: offset 0x{:x}, size {}", ++ "Failed to register region in memory space: offset={},size={}", + region_base, region_size + ) +- })?; ++ })?, + } +- _ => self +- .sys_mem +- .root() +- .add_subregion(region, region_base) +- .with_context(|| { +- format!( +- "Failed to register region in memory space: offset={},size={}", +- region_base, region_size +- ) +- })?, + } + + self.devices.push(dev.clone()); + Ok(()) + } +- +- pub fn attach_dynamic_device( +- &mut self, +- dev: &Arc>, +- ) -> Result<()> { +- self.devices.push(dev.clone()); +- Ok(()) +- } + } + +-#[derive(Copy, Clone)] ++#[derive(Clone)] + pub struct SysRes { ++ // Note: region_base/region_size are both 0 means that this device doesn't have its own memory layout. ++ // The normally allocated device memory region is above the `MEM_LAYOUT[LayoutEntryType::Mmio as usize].0`. + pub region_base: u64, + pub region_size: u64, ++ pub region_name: String, + pub irq: i32, + } + +@@ -198,6 +207,7 @@ impl Default for SysRes { + Self { + region_base: 0, + region_size: 0, ++ region_name: "".to_string(), + irq: -1, + } + } +@@ -251,15 +261,16 @@ impl SysBusDevBase { + } + } + +- pub fn set_sys(&mut self, irq: i32, region_base: u64, region_size: u64) { ++ pub fn set_sys(&mut self, irq: i32, region_base: u64, region_size: u64, region_name: &str) { + self.res.irq = irq; + self.res.region_base = region_base; + self.res.region_size = region_size; ++ self.res.region_name = region_name.to_string(); + } + } + + /// Operations for sysbus devices. +-pub trait SysBusDevOps: Device + Send + AmlBuilder + AsAny { ++pub trait SysBusDevOps: Device + Send + AmlBuilder { + fn sysbusdev_base(&self) -> &SysBusDevBase; + + fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase; +@@ -300,8 +311,8 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder + AsAny { + Ok(irq) + } + +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- None ++ fn get_sys_resource(&mut self) -> &mut SysRes { ++ &mut self.sysbusdev_base_mut().res + } + + fn set_sys_resource( +@@ -309,18 +320,20 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder + AsAny { + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, ++ region_name: &str, + ) -> Result<()> { + let irq = self.get_irq(sysbus)?; + let interrupt_evt = self.sysbusdev_base().interrupt_evt.clone(); + let irq_manager = sysbus.irq_manager.clone(); + ++ // marker + self.sysbusdev_base_mut().irq_state = +- IrqState::new(irq as u32, interrupt_evt, irq_manager, TriggerMode::Edge); ++ IrqState::new(irq as u32, None, irq_manager, TriggerMode::Edge); + let irq_state = &mut self.sysbusdev_base_mut().irq_state; + irq_state.register_irq()?; + + self.sysbusdev_base_mut() +- .set_sys(irq, region_base, region_size); ++ .set_sys(irq, region_base, region_size, region_name); + Ok(()) + } + +@@ -350,3 +363,65 @@ impl AmlBuilder for SysBus { + scope.aml_bytes() + } + } ++ ++pub type ToSysBusDevOpsFunc = fn(&dyn Any) -> &dyn SysBusDevOps; ++ ++static mut SYSBUSDEVTYPE_HASHMAP: Option> = None; ++ ++pub fn convert_to_sysbusdevops(item: &dyn Any) -> &dyn SysBusDevOps { ++ // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of ++ // the conversion is its own structure type, so the conversion result will definitely not be `None`. ++ let t = item.downcast_ref::().unwrap(); ++ t as &dyn SysBusDevOps ++} ++ ++pub fn register_sysbusdevops_type() -> Result<()> { ++ let type_id = TypeId::of::(); ++ // SAFETY: SYSBUSDEVTYPE_HASHMAP will be built in `type_init` function sequentially in the main thread. ++ // And will not be changed after `type_init`. ++ unsafe { ++ if SYSBUSDEVTYPE_HASHMAP.is_none() { ++ SYSBUSDEVTYPE_HASHMAP = Some(HashMap::new()); ++ } ++ let types = SYSBUSDEVTYPE_HASHMAP.as_mut().unwrap(); ++ if types.get(&type_id).is_some() { ++ bail!("Type Id {:?} has been registered.", type_id); ++ } ++ types.insert(type_id, convert_to_sysbusdevops::); ++ } ++ ++ Ok(()) ++} ++ ++pub fn devices_register_sysbusdevops_type() -> Result<()> { ++ #[cfg(target_arch = "x86_64")] ++ { ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ } ++ #[cfg(target_arch = "aarch64")] ++ { ++ register_sysbusdevops_type::()?; ++ #[cfg(all(feature = "ramfb"))] ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ } ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::()?; ++ register_sysbusdevops_type::() ++} ++ ++pub fn to_sysbusdevops(dev: &dyn Device) -> Option<&dyn SysBusDevOps> { ++ let type_id = dev.type_id(); ++ // SAFETY: SYSBUSDEVTYPE_HASHMAP has been built. And this function is called without changing hashmap. ++ unsafe { ++ let types = SYSBUSDEVTYPE_HASHMAP.as_mut().unwrap(); ++ let func = types.get(&type_id)?; ++ let sysbusdev = func(dev.as_any()); ++ Some(sysbusdev) ++ } ++} +diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs +index bd7ae9f..79cc1ba 100644 +--- a/devices/src/usb/camera.rs ++++ b/devices/src/usb/camera.rs +@@ -41,14 +41,10 @@ use machine_manager::event_loop::{register_event_helper, unregister_event_helper + use util::aio::{iov_discard_front_direct, Iovec}; + use util::byte_code::ByteCode; + use util::loop_context::{ +- read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, ++ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, ++ NotifierOperation, + }; + +-// CRC16 of "STRATOVIRT" +-const UVC_VENDOR_ID: u16 = 0xB74C; +-// The first 4 chars of "VIDEO", 5 substitutes V. +-const UVC_PRODUCT_ID: u16 = 0x51DE; +- + const INTERFACE_ID_CONTROL: u8 = 0; + const INTERFACE_ID_STREAMING: u8 = 1; + +@@ -95,8 +91,10 @@ const FRAME_SIZE_1280_720: u32 = 1280 * 720 * 2; + const USB_CAMERA_BUFFER_LEN: usize = 12 * 1024; + + #[derive(Parser, Debug, Clone)] +-#[command(name = "usb_camera")] ++#[command(no_binary_name(true))] + pub struct UsbCameraConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] +@@ -433,8 +431,8 @@ fn gen_desc_device_camera(fmt_list: Vec) -> Result Result<()> { + info!("Camera {} unrealize", self.device_id()); ++ self.unregister_camera_fd()?; + self.camera_backend.lock().unwrap().reset(); + Ok(()) + } + ++ fn cancel_packet(&mut self, _packet: &Arc>) {} ++ + fn reset(&mut self) { + info!("Camera {} device reset", self.device_id()); + self.base.addr = 0; +@@ -809,7 +810,7 @@ impl UsbDevice for UsbCamera { + } + } + Err(e) => { +- warn!("Camera descriptor error {:?}", e); ++ warn!("Received incorrect USB Camera descriptor message: {:?}", e); + locked_packet.status = UsbPacketStatus::Stall; + return; + } +diff --git a/devices/src/usb/config.rs b/devices/src/usb/config.rs +index 3dda38b..1b34345 100644 +--- a/devices/src/usb/config.rs ++++ b/devices/src/usb/config.rs +@@ -206,6 +206,7 @@ pub const USB_DT_DEBUG: u8 = 10; + pub const USB_DT_INTERFACE_ASSOCIATION: u8 = 11; + pub const USB_DT_BOS: u8 = 15; + pub const USB_DT_DEVICE_CAPABILITY: u8 = 16; ++pub const USB_DT_PIPE_USAGE: u8 = 36; + pub const USB_DT_ENDPOINT_COMPANION: u8 = 48; + + /// USB SuperSpeed Device Capability. +@@ -218,8 +219,10 @@ pub const USB_DT_DEVICE_SIZE: u8 = 18; + pub const USB_DT_CONFIG_SIZE: u8 = 9; + pub const USB_DT_INTERFACE_SIZE: u8 = 9; + pub const USB_DT_ENDPOINT_SIZE: u8 = 7; ++pub const USB_DT_DEVICE_QUALIFIER_SIZE: u8 = 10; + pub const USB_DT_BOS_SIZE: u8 = 5; + pub const USB_DT_SS_CAP_SIZE: u8 = 10; ++pub const USB_DT_PIPE_USAGE_SIZE: u8 = 4; + pub const USB_DT_SS_EP_COMP_SIZE: u8 = 6; + + /// USB Endpoint Descriptor +@@ -236,8 +239,27 @@ pub const USB_CONFIGURATION_ATTR_ONE: u8 = 1 << 7; + pub const USB_CONFIGURATION_ATTR_SELF_POWER: u8 = 1 << 6; + pub const USB_CONFIGURATION_ATTR_REMOTE_WAKEUP: u8 = 1 << 5; + +-// USB Class ++/// USB Class + pub const USB_CLASS_HID: u8 = 3; + pub const USB_CLASS_MASS_STORAGE: u8 = 8; + pub const USB_CLASS_VIDEO: u8 = 0xe; + pub const USB_CLASS_MISCELLANEOUS: u8 = 0xef; ++ ++/// USB Subclass ++pub const USB_SUBCLASS_BOOT: u8 = 0x01; ++pub const USB_SUBCLASS_SCSI: u8 = 0x06; ++ ++/// USB Interface Protocol ++pub const USB_IFACE_PROTOCOL_KEYBOARD: u8 = 0x01; ++pub const USB_IFACE_PROTOCOL_BOT: u8 = 0x50; ++pub const USB_IFACE_PROTOCOL_UAS: u8 = 0x62; ++ ++/// CRC16 of "STRATOVIRT" ++pub const USB_VENDOR_ID_STRATOVIRT: u16 = 0xB74C; ++ ++/// USB Product IDs ++pub const USB_PRODUCT_ID_UVC: u16 = 0x0001; ++pub const USB_PRODUCT_ID_KEYBOARD: u16 = 0x0002; ++pub const USB_PRODUCT_ID_STORAGE: u16 = 0x0003; ++pub const USB_PRODUCT_ID_TABLET: u16 = 0x0004; ++pub const USB_PRODUCT_ID_UAS: u16 = 0x0005; +diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs +index bdb30f7..ca4c51e 100644 +--- a/devices/src/usb/descriptor.rs ++++ b/devices/src/usb/descriptor.rs +@@ -349,11 +349,25 @@ impl UsbDescriptor { + } + + fn get_device_qualifier_descriptor(&self) -> Result> { +- if let Some(desc) = self.device_qualifier_desc.as_ref() { +- Ok(desc.qualifier_desc.as_bytes().to_vec()) +- } else { +- bail!("Device qualifier descriptor not found"); ++ if self.device_desc.is_none() { ++ bail!("device qualifier descriptor not found"); + } ++ ++ // SAFETY: device_desc has just been checked ++ let device_desc = &self.device_desc.as_ref().unwrap().device_desc; ++ let device_qualifier_desc = UsbDeviceQualifierDescriptor { ++ bLength: USB_DT_DEVICE_QUALIFIER_SIZE, ++ bDescriptorType: USB_DT_DEVICE_QUALIFIER, ++ bcdUSB: device_desc.bcdUSB, ++ bDeviceClass: device_desc.bDeviceClass, ++ bDeviceSubClass: device_desc.bDeviceSubClass, ++ bDeviceProtocol: device_desc.bDeviceProtocol, ++ bMaxPacketSize0: device_desc.bMaxPacketSize0, ++ bNumConfigurations: device_desc.bNumConfigurations, ++ bReserved: 0, ++ }; ++ ++ Ok(device_qualifier_desc.as_bytes().to_vec()) + } + + fn get_debug_descriptor(&self) -> Result> { +diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs +index 73dc8ed..5329142 100644 +--- a/devices/src/usb/keyboard.rs ++++ b/devices/src/usb/keyboard.rs +@@ -38,7 +38,7 @@ static DESC_DEVICE_KEYBOARD: Lazy> = Lazy::new(|| { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + idVendor: 0x0627, +- idProduct: 0x0001, ++ idProduct: USB_PRODUCT_ID_KEYBOARD, + bcdDevice: 0, + iManufacturer: STR_MANUFACTURER_INDEX, + iProduct: STR_PRODUCT_KEYBOARD_INDEX, +@@ -76,8 +76,8 @@ static DESC_IFACE_KEYBOARD: Lazy> = Lazy::new(|| { + bAlternateSetting: 0, + bNumEndpoints: 1, + bInterfaceClass: USB_CLASS_HID, +- bInterfaceSubClass: 1, +- bInterfaceProtocol: 1, ++ bInterfaceSubClass: USB_SUBCLASS_BOOT, ++ bInterfaceProtocol: USB_IFACE_PROTOCOL_KEYBOARD, + iInterface: 0, + }, + other_desc: vec![Arc::new(UsbDescOther { +@@ -121,8 +121,10 @@ const DESC_STRINGS: [&str; 5] = [ + ]; + + #[derive(Parser, Clone, Debug, Default)] +-#[command(name = "usb_keyboard")] ++#[command(no_binary_name(true))] + pub struct UsbKeyboardConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long)] +@@ -217,6 +219,8 @@ impl UsbDevice for UsbKeyboard { + Ok(()) + } + ++ fn cancel_packet(&mut self, _packet: &Arc>) {} ++ + fn reset(&mut self) { + info!("Keyboard device reset"); + self.base.remote_wakeup = 0; +@@ -237,7 +241,10 @@ impl UsbDevice for UsbKeyboard { + } + } + Err(e) => { +- warn!("Keyboard descriptor error {:?}", e); ++ warn!( ++ "Received incorrect USB Keyboard descriptor message: {:?}", ++ e ++ ); + locked_packet.status = UsbPacketStatus::Stall; + return; + } +diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs +index 08cef7e..44f5d88 100644 +--- a/devices/src/usb/mod.rs ++++ b/devices/src/usb/mod.rs +@@ -20,6 +20,7 @@ pub mod hid; + pub mod keyboard; + pub mod storage; + pub mod tablet; ++pub mod uas; + #[cfg(feature = "usb_host")] + pub mod usbhost; + pub mod xhci; +@@ -60,6 +61,12 @@ pub enum UsbPacketStatus { + IoError, + } + ++impl Default for UsbPacketStatus { ++ fn default() -> Self { ++ Self::NoDev ++ } ++} ++ + /// USB request used to transfer to USB device. + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +@@ -343,6 +350,10 @@ pub trait UsbDevice: Send + Sync { + fn unrealize(&mut self) -> Result<()> { + Ok(()) + } ++ ++ /// Cancel specified USB packet. ++ fn cancel_packet(&mut self, packet: &Arc>); ++ + /// Handle the attach ops when attach device to controller. + fn handle_attach(&mut self) -> Result<()> { + let usb_dev = self.usb_device_base_mut(); +@@ -385,10 +396,10 @@ pub trait UsbDevice: Send + Sync { + } + } + +- /// Handle control pakcet. ++ /// Handle control packet. + fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest); + +- /// Handle data pakcet. ++ /// Handle data packet. + fn handle_data(&mut self, packet: &Arc>); + + /// Unique device id. +@@ -483,7 +494,10 @@ pub trait TransferOps: Send + Sync { + } + + /// Usb packet used for device transfer data. ++#[derive(Default)] + pub struct UsbPacket { ++ /// USB packet unique identifier. ++ pub packet_id: u32, + /// USB packet id. + pub pid: u32, + pub is_async: bool, +@@ -498,6 +512,10 @@ pub struct UsbPacket { + pub ep_number: u8, + /// Transfer for complete packet. + pub xfer_ops: Option>>, ++ /// Target USB device for this packet. ++ pub target_dev: Option>>, ++ /// Stream id. ++ pub stream: u32, + } + + impl std::fmt::Display for UsbPacket { +@@ -512,12 +530,15 @@ impl std::fmt::Display for UsbPacket { + + impl UsbPacket { + pub fn new( ++ packet_id: u32, + pid: u32, + ep_number: u8, + iovecs: Vec, + xfer_ops: Option>>, ++ target_dev: Option>>, + ) -> Self { + Self { ++ packet_id, + pid, + is_async: false, + iovecs, +@@ -526,6 +547,8 @@ impl UsbPacket { + actual_length: 0, + ep_number, + xfer_ops, ++ target_dev, ++ stream: 0, + } + } + +@@ -573,7 +596,7 @@ impl UsbPacket { + self.actual_length = copied as u32; + } + +- pub fn get_iovecs_size(&mut self) -> u64 { ++ pub fn get_iovecs_size(&self) -> u64 { + let mut size = 0; + for iov in &self.iovecs { + size += iov.iov_len; +@@ -583,21 +606,6 @@ impl UsbPacket { + } + } + +-impl Default for UsbPacket { +- fn default() -> UsbPacket { +- UsbPacket { +- pid: 0, +- is_async: false, +- iovecs: Vec::new(), +- parameter: 0, +- status: UsbPacketStatus::NoDev, +- actual_length: 0, +- ep_number: 0, +- xfer_ops: None, +- } +- } +-} +- + #[cfg(test)] + mod tests { + use super::*; +diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs +index b227ecc..2f924d8 100644 +--- a/devices/src/usb/storage.rs ++++ b/devices/src/usb/storage.rs +@@ -17,6 +17,7 @@ use std::{ + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; ++use clap::Parser; + use log::{error, info, warn}; + use once_cell::sync::Lazy; + +@@ -32,9 +33,10 @@ use crate::{ + ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, GOOD, + SCSI_CMD_BUF_SIZE, + }, +- ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}, ++ ScsiDisk::{ScsiDevConfig, ScsiDevice}, + }; +-use machine_manager::config::{DriveFile, UsbStorageConfig}; ++use machine_manager::config::{DriveConfig, DriveFile}; ++use util::aio::AioEngine; + + // Storage device descriptor + static DESC_DEVICE_STORAGE: Lazy> = Lazy::new(|| { +@@ -43,7 +45,7 @@ static DESC_DEVICE_STORAGE: Lazy> = Lazy::new(|| { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + idVendor: USB_STORAGE_VENDOR_ID, +- idProduct: 0x0001, ++ idProduct: USB_PRODUCT_ID_STORAGE, + bcdDevice: 0, + iManufacturer: STR_MANUFACTURER_INDEX, + iProduct: STR_PRODUCT_STORAGE_INDEX, +@@ -82,8 +84,8 @@ static DESC_IFACE_STORAGE: Lazy> = Lazy::new(|| { + bAlternateSetting: 0, + bNumEndpoints: 2, + bInterfaceClass: USB_CLASS_MASS_STORAGE, +- bInterfaceSubClass: 0x06, // SCSI +- bInterfaceProtocol: 0x50, // Bulk-only ++ bInterfaceSubClass: USB_SUBCLASS_SCSI, ++ bInterfaceProtocol: USB_IFACE_PROTOCOL_BOT, + iInterface: 0, + }, + other_desc: vec![], +@@ -221,6 +223,21 @@ impl UsbStorageState { + } + } + ++#[derive(Parser, Clone, Debug)] ++#[command(no_binary_name(true))] ++pub struct UsbStorageConfig { ++ #[arg(long, value_parser = ["usb-storage"])] ++ pub classtype: String, ++ #[arg(long)] ++ pub id: String, ++ #[arg(long)] ++ pub drive: String, ++ #[arg(long)] ++ bus: Option, ++ #[arg(long)] ++ port: Option, ++} ++ + /// USB storage device. + pub struct UsbStorage { + base: UsbDeviceBase, +@@ -228,7 +245,9 @@ pub struct UsbStorage { + /// USB controller used to notify controller to transfer data. + cntlr: Option>>, + /// Configuration of the USB storage device. +- pub config: UsbStorageConfig, ++ pub dev_cfg: UsbStorageConfig, ++ /// Configuration of the USB storage device's drive. ++ pub drive_cfg: DriveConfig, + /// Scsi bus attached to this usb-storage device. + scsi_bus: Arc>, + /// Effective scsi backend. +@@ -305,26 +324,37 @@ impl UsbMsdCsw { + + impl UsbStorage { + pub fn new( +- config: UsbStorageConfig, ++ dev_cfg: UsbStorageConfig, ++ drive_cfg: DriveConfig, + drive_files: Arc>>, +- ) -> Self { +- let scsi_type = match &config.media as &str { +- "disk" => SCSI_TYPE_DISK, +- _ => SCSI_TYPE_ROM, ++ ) -> Result { ++ if drive_cfg.aio != AioEngine::Off || drive_cfg.direct { ++ bail!("USB-storage: \"aio=off,direct=false\" must be configured."); ++ } ++ ++ let scsidev_classtype = match &drive_cfg.media as &str { ++ "disk" => "scsi-hd".to_string(), ++ _ => "scsi-cd".to_string(), ++ }; ++ let scsi_dev_cfg = ScsiDevConfig { ++ classtype: scsidev_classtype, ++ drive: dev_cfg.drive.clone(), ++ ..Default::default() + }; + +- Self { +- base: UsbDeviceBase::new(config.id.clone().unwrap(), USB_DEVICE_BUFFER_DEFAULT_LEN), ++ Ok(Self { ++ base: UsbDeviceBase::new(dev_cfg.id.clone(), USB_DEVICE_BUFFER_DEFAULT_LEN), + state: UsbStorageState::new(), + cntlr: None, +- config: config.clone(), ++ dev_cfg, ++ drive_cfg: drive_cfg.clone(), + scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), + scsi_dev: Arc::new(Mutex::new(ScsiDevice::new( +- config.scsi_cfg, +- scsi_type, ++ scsi_dev_cfg, ++ drive_cfg, + drive_files, + ))), +- } ++ }) + } + + fn handle_control_packet(&mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest) { +@@ -542,6 +572,8 @@ impl UsbDevice for UsbStorage { + Ok(storage) + } + ++ fn cancel_packet(&mut self, _packet: &Arc>) {} ++ + fn reset(&mut self) { + info!("Storage device reset"); + self.base.remote_wakeup = 0; +@@ -563,7 +595,7 @@ impl UsbDevice for UsbStorage { + self.handle_control_packet(&mut locked_packet, device_req) + } + Err(e) => { +- warn!("Storage descriptor error {:?}", e); ++ warn!("Received incorrect USB Storage descriptor message: {:?}", e); + locked_packet.status = UsbPacketStatus::Stall; + } + } +diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs +index 67a1513..a4bfebf 100644 +--- a/devices/src/usb/tablet.rs ++++ b/devices/src/usb/tablet.rs +@@ -44,7 +44,7 @@ static DESC_DEVICE_TABLET: Lazy> = Lazy::new(|| { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + idVendor: 0x0627, +- idProduct: 0x0001, ++ idProduct: USB_PRODUCT_ID_TABLET, + bcdDevice: 0, + iManufacturer: STR_MANUFACTURER_INDEX, + iProduct: STR_PRODUCT_TABLET_INDEX, +@@ -114,8 +114,10 @@ const STR_SERIAL_TABLET_INDEX: u8 = 4; + const DESC_STRINGS: [&str; 5] = ["", "StratoVirt", "StratoVirt USB Tablet", "HID Tablet", "2"]; + + #[derive(Parser, Clone, Debug, Default)] +-#[command(name = "usb_tablet")] ++#[command(no_binary_name(true))] + pub struct UsbTabletConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long)] +@@ -260,6 +262,8 @@ impl UsbDevice for UsbTablet { + Ok(()) + } + ++ fn cancel_packet(&mut self, _packet: &Arc>) {} ++ + fn reset(&mut self) { + info!("Tablet device reset"); + self.base.remote_wakeup = 0; +@@ -280,7 +284,7 @@ impl UsbDevice for UsbTablet { + } + } + Err(e) => { +- warn!("Tablet descriptor error {:?}", e); ++ warn!("Received incorrect USB Tablet descriptor message: {:?}", e); + locked_packet.status = UsbPacketStatus::Stall; + return; + } +diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs +new file mode 100644 +index 0000000..4bdfc39 +--- /dev/null ++++ b/devices/src/usb/uas.rs +@@ -0,0 +1,1289 @@ ++// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::array; ++use std::cmp::min; ++use std::collections::{HashMap, VecDeque}; ++use std::mem::size_of; ++use std::sync::{Arc, Mutex, Weak}; ++ ++use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; ++use log::{debug, error, info, warn}; ++use once_cell::sync::Lazy; ++use strum::EnumCount; ++use strum_macros::EnumCount; ++ ++use super::config::*; ++use super::descriptor::{ ++ UsbConfigDescriptor, UsbDescConfig, UsbDescDevice, UsbDescEndpoint, UsbDescIface, ++ UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, ++ UsbSuperSpeedEndpointCompDescriptor, ++}; ++use super::xhci::xhci_controller::XhciDevice; ++use super::{ ++ UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus, ++ USB_DEVICE_BUFFER_DEFAULT_LEN, ++}; ++use crate::{ ++ ScsiBus::{ ++ scsi_cdb_xfer, scsi_cdb_xfer_mode, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ++ ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, ++ SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, SCSI_SENSE_OVERLAPPED_COMMANDS, ++ }, ++ ScsiDisk::{ScsiDevConfig, ScsiDevice}, ++}; ++use machine_manager::config::{DriveConfig, DriveFile}; ++use util::byte_code::ByteCode; ++ ++// Size of UasIUBody ++const UAS_IU_BODY_SIZE: usize = 30; ++ ++// Size of cdb in UAS Command IU ++const UAS_COMMAND_CDB_SIZE: usize = 16; ++ ++// UAS Pipe IDs ++const UAS_PIPE_ID_COMMAND: u8 = 0x01; ++const UAS_PIPE_ID_STATUS: u8 = 0x02; ++const UAS_PIPE_ID_DATA_IN: u8 = 0x03; ++const UAS_PIPE_ID_DATA_OUT: u8 = 0x04; ++ ++// UAS Streams Attributes ++const UAS_MAX_STREAMS_BM_ATTR: u8 = 0; ++const UAS_MAX_STREAMS: usize = 1 << UAS_MAX_STREAMS_BM_ATTR; ++ ++// UAS IU IDs ++const UAS_IU_ID_COMMAND: u8 = 0x01; ++const UAS_IU_ID_SENSE: u8 = 0x03; ++const UAS_IU_ID_RESPONSE: u8 = 0x04; ++const UAS_IU_ID_TASK_MGMT: u8 = 0x05; ++const UAS_IU_ID_READ_READY: u8 = 0x06; ++const UAS_IU_ID_WRITE_READY: u8 = 0x07; ++ ++// UAS Response Codes ++const _UAS_RC_TMF_COMPLETE: u8 = 0x00; ++const _UAS_RC_INVALID_IU: u8 = 0x02; ++const UAS_RC_TMF_NOT_SUPPORTED: u8 = 0x04; ++const _UAS_RC_TMF_FAILED: u8 = 0x05; ++const _UAS_RC_TMF_SUCCEEDED: u8 = 0x08; ++const _UAS_RC_INCORRECT_LUN: u8 = 0x09; ++const _UAS_RC_OVERLAPPED_TAG: u8 = 0x0A; ++ ++// UAS Task Management Functions ++const _UAS_TMF_ABORT_TASK: u8 = 0x01; ++const _UAS_TMF_ABORT_TASK_SET: u8 = 0x02; ++const _UAS_TMF_CLEAR_TASK_SET: u8 = 0x04; ++const _UAS_TMF_LOGICAL_UNIT_RESET: u8 = 0x08; ++const _UAS_TMF_I_T_NEXUS_RESET: u8 = 0x10; ++const _UAS_TMF_CLEAR_ACA: u8 = 0x40; ++const _UAS_TMF_QUERY_TASK: u8 = 0x80; ++const _UAS_TMF_QUERY_TASK_SET: u8 = 0x81; ++const _UAS_TMF_QUERY_ASYNC_EVENT: u8 = 0x82; ++ ++#[derive(Parser, Clone, Debug)] ++#[command(no_binary_name(true))] ++pub struct UsbUasConfig { ++ #[arg(long, value_parser = ["usb-uas"])] ++ pub classtype: String, ++ #[arg(long)] ++ pub drive: String, ++ #[arg(long)] ++ pub id: Option, ++ #[arg(long)] ++ pub speed: Option, ++ #[arg(long)] ++ bus: Option, ++ #[arg(long)] ++ port: Option, ++} ++ ++pub struct UsbUas { ++ base: UsbDeviceBase, ++ scsi_bus: Arc>, ++ scsi_device: Arc>, ++ commands_high: VecDeque, ++ statuses_high: VecDeque>>, ++ commands_super: [Option; UAS_MAX_STREAMS + 1], ++ statuses_super: [Option>>; UAS_MAX_STREAMS + 1], ++ data: [Option>>; UAS_MAX_STREAMS + 1], ++ data_ready_sent: bool, ++} ++ ++#[derive(Debug, EnumCount)] ++enum UsbUasStringId { ++ #[allow(unused)] ++ Invalid = 0, ++ Manufacturer = 1, ++ Product = 2, ++ SerialNumber = 3, ++ ConfigHigh = 4, ++ ConfigSuper = 5, ++} ++ ++const UAS_DESC_STRINGS: [&str; UsbUasStringId::COUNT] = [ ++ "", ++ "StratoVirt", ++ "StratoVirt USB Uas", ++ "5", ++ "High speed config (usb 2.0)", ++ "Super speed config (usb 3.0)", ++]; ++ ++struct UasRequest { ++ data: Option>>, ++ status: Arc>, ++ iu: UasIU, ++ completed: bool, ++} ++ ++impl ScsiRequestOps for UasRequest { ++ fn scsi_request_complete_cb( ++ &mut self, ++ scsi_status: u8, ++ scsi_sense: Option, ++ ) -> Result<()> { ++ let tag = u16::from_be(self.iu.header.tag); ++ let sense = scsi_sense.unwrap_or(SCSI_SENSE_NO_SENSE); ++ UsbUas::fill_sense(&mut self.status.lock().unwrap(), tag, scsi_status, &sense); ++ self.complete(); ++ Ok(()) ++ } ++} ++ ++#[derive(Debug, PartialEq, Eq)] ++enum UasPacketStatus { ++ Completed = 0, ++ Pending = 1, ++} ++ ++impl From for UasPacketStatus { ++ fn from(status: bool) -> Self { ++ match status { ++ true => Self::Completed, ++ false => Self::Pending, ++ } ++ } ++} ++ ++#[allow(non_snake_case)] ++#[repr(C, packed)] ++#[derive(Copy, Clone, Debug, Default)] ++struct UsbPipeUsageDescriptor { ++ bLength: u8, ++ bDescriptorType: u8, ++ bPipeId: u8, ++ bReserved: u8, ++} ++ ++impl ByteCode for UsbPipeUsageDescriptor {} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIUHeader { ++ id: u8, ++ reserved: u8, ++ tag: u16, ++} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIUCommand { ++ prio_task_attr: u8, // 6:3 priority, 2:0 task attribute ++ reserved_1: u8, ++ add_cdb_len: u8, ++ reserved_2: u8, ++ lun: u64, ++ cdb: [u8; UAS_COMMAND_CDB_SIZE], ++ add_cdb: [u8; 1], // not supported by stratovirt ++} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIUSense { ++ status_qualifier: u16, ++ status: u8, ++ reserved: [u8; 7], ++ sense_length: u16, ++ sense_data: [u8; 18], ++} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIUResponse { ++ add_response_info: [u8; 3], ++ response_code: u8, ++} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIUTaskManagement { ++ function: u8, ++ reserved: u8, ++ task_tag: u16, ++ lun: u64, ++} ++ ++#[repr(C, packed)] ++#[derive(Clone, Copy)] ++union UasIUBody { ++ command: UasIUCommand, ++ sense: UasIUSense, ++ response: UasIUResponse, ++ task_management: UasIUTaskManagement, ++ raw_data: [u8; UAS_IU_BODY_SIZE], ++} ++ ++impl Default for UasIUBody { ++ fn default() -> Self { ++ Self { ++ raw_data: [0; UAS_IU_BODY_SIZE], ++ } ++ } ++} ++ ++#[repr(C, packed)] ++#[derive(Default, Clone, Copy)] ++struct UasIU { ++ header: UasIUHeader, ++ body: UasIUBody, ++} ++ ++impl ByteCode for UasIU {} ++ ++static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { ++ Arc::new(UsbDescDevice { ++ device_desc: UsbDeviceDescriptor { ++ bLength: USB_DT_DEVICE_SIZE, ++ bDescriptorType: USB_DT_DEVICE, ++ bcdUSB: 0x0300, ++ bDeviceClass: 0, ++ bDeviceSubClass: 0, ++ bDeviceProtocol: 0, ++ bMaxPacketSize0: 9, ++ idVendor: USB_VENDOR_ID_STRATOVIRT, ++ idProduct: USB_PRODUCT_ID_UAS, ++ bcdDevice: 0, ++ iManufacturer: UsbUasStringId::Manufacturer as u8, ++ iProduct: UsbUasStringId::Product as u8, ++ iSerialNumber: UsbUasStringId::SerialNumber as u8, ++ bNumConfigurations: 1, ++ }, ++ configs: vec![Arc::new(UsbDescConfig { ++ config_desc: UsbConfigDescriptor { ++ bLength: USB_DT_CONFIG_SIZE, ++ bDescriptorType: USB_DT_CONFIGURATION, ++ wTotalLength: 0, ++ bNumInterfaces: 1, ++ bConfigurationValue: 1, ++ iConfiguration: UsbUasStringId::ConfigSuper as u8, ++ bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, ++ bMaxPower: 50, ++ }, ++ iad_desc: vec![], ++ interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_SUPER.clone()], ++ })], ++ }) ++}); ++ ++static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { ++ Arc::new(UsbDescIface { ++ interface_desc: UsbInterfaceDescriptor { ++ bLength: USB_DT_INTERFACE_SIZE, ++ bDescriptorType: USB_DT_INTERFACE, ++ bInterfaceNumber: 0, ++ bAlternateSetting: 1, ++ bNumEndpoints: 4, ++ bInterfaceClass: USB_CLASS_MASS_STORAGE, ++ bInterfaceSubClass: USB_SUBCLASS_SCSI, ++ bInterfaceProtocol: USB_IFACE_PROTOCOL_UAS, ++ iInterface: 0, ++ }, ++ other_desc: vec![], ++ endpoints: vec![ ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 1024, ++ bInterval: 0, ++ }, ++ extra: [ ++ UsbSuperSpeedEndpointCompDescriptor { ++ bLength: USB_DT_SS_EP_COMP_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT_COMPANION, ++ bMaxBurst: 15, ++ bmAttributes: 0, ++ wBytesPerInterval: 0, ++ } ++ .as_bytes(), ++ UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_COMMAND, ++ bReserved: 0, ++ } ++ .as_bytes(), ++ ] ++ .concat() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 1024, ++ bInterval: 0, ++ }, ++ extra: [ ++ UsbSuperSpeedEndpointCompDescriptor { ++ bLength: USB_DT_SS_EP_COMP_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT_COMPANION, ++ bMaxBurst: 15, ++ bmAttributes: UAS_MAX_STREAMS_BM_ATTR, ++ wBytesPerInterval: 0, ++ } ++ .as_bytes(), ++ UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_STATUS, ++ bReserved: 0, ++ } ++ .as_bytes(), ++ ] ++ .concat() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 1024, ++ bInterval: 0, ++ }, ++ extra: [ ++ UsbSuperSpeedEndpointCompDescriptor { ++ bLength: USB_DT_SS_EP_COMP_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT_COMPANION, ++ bMaxBurst: 15, ++ bmAttributes: UAS_MAX_STREAMS_BM_ATTR, ++ wBytesPerInterval: 0, ++ } ++ .as_bytes(), ++ UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_DATA_IN, ++ bReserved: 0, ++ } ++ .as_bytes(), ++ ] ++ .concat() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 1024, ++ bInterval: 0, ++ }, ++ extra: [ ++ UsbSuperSpeedEndpointCompDescriptor { ++ bLength: USB_DT_SS_EP_COMP_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT_COMPANION, ++ bMaxBurst: 15, ++ bmAttributes: UAS_MAX_STREAMS_BM_ATTR, ++ wBytesPerInterval: 0, ++ } ++ .as_bytes(), ++ UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_DATA_OUT, ++ bReserved: 0, ++ } ++ .as_bytes(), ++ ] ++ .concat() ++ .to_vec(), ++ }), ++ ], ++ }) ++}); ++ ++static DESC_DEVICE_UAS_HIGH: Lazy> = Lazy::new(|| { ++ Arc::new(UsbDescDevice { ++ device_desc: UsbDeviceDescriptor { ++ bLength: USB_DT_DEVICE_SIZE, ++ bDescriptorType: USB_DT_DEVICE, ++ bcdUSB: 0x0200, ++ bDeviceClass: 0, ++ bDeviceSubClass: 0, ++ bDeviceProtocol: 0, ++ bMaxPacketSize0: 64, ++ idVendor: USB_VENDOR_ID_STRATOVIRT, ++ idProduct: USB_PRODUCT_ID_UAS, ++ bcdDevice: 0, ++ iManufacturer: UsbUasStringId::Manufacturer as u8, ++ iProduct: UsbUasStringId::Product as u8, ++ iSerialNumber: UsbUasStringId::SerialNumber as u8, ++ bNumConfigurations: 1, ++ }, ++ configs: vec![Arc::new(UsbDescConfig { ++ config_desc: UsbConfigDescriptor { ++ bLength: USB_DT_CONFIG_SIZE, ++ bDescriptorType: USB_DT_CONFIGURATION, ++ wTotalLength: 0, ++ bNumInterfaces: 1, ++ bConfigurationValue: 1, ++ iConfiguration: UsbUasStringId::ConfigHigh as u8, ++ bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, ++ bMaxPower: 50, ++ }, ++ iad_desc: vec![], ++ interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_HIGH.clone()], ++ })], ++ }) ++}); ++ ++static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { ++ Arc::new(UsbDescIface { ++ interface_desc: UsbInterfaceDescriptor { ++ bLength: USB_DT_INTERFACE_SIZE, ++ bDescriptorType: USB_DT_INTERFACE, ++ bInterfaceNumber: 0, ++ bAlternateSetting: 1, ++ bNumEndpoints: 4, ++ bInterfaceClass: USB_CLASS_MASS_STORAGE, ++ bInterfaceSubClass: USB_SUBCLASS_SCSI, ++ bInterfaceProtocol: USB_IFACE_PROTOCOL_UAS, ++ iInterface: 0, ++ }, ++ other_desc: vec![], ++ endpoints: vec![ ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 512, ++ bInterval: 0, ++ }, ++ extra: UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_COMMAND, ++ bReserved: 0, ++ } ++ .as_bytes() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 512, ++ bInterval: 0, ++ }, ++ extra: UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_STATUS, ++ bReserved: 0, ++ } ++ .as_bytes() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 512, ++ bInterval: 0, ++ }, ++ extra: UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_DATA_IN, ++ bReserved: 0, ++ } ++ .as_bytes() ++ .to_vec(), ++ }), ++ Arc::new(UsbDescEndpoint { ++ endpoint_desc: UsbEndpointDescriptor { ++ bLength: USB_DT_ENDPOINT_SIZE, ++ bDescriptorType: USB_DT_ENDPOINT, ++ bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, ++ bmAttributes: USB_ENDPOINT_ATTR_BULK, ++ wMaxPacketSize: 512, ++ bInterval: 0, ++ }, ++ extra: UsbPipeUsageDescriptor { ++ bLength: USB_DT_PIPE_USAGE_SIZE, ++ bDescriptorType: USB_DT_PIPE_USAGE, ++ bPipeId: UAS_PIPE_ID_DATA_OUT, ++ bReserved: 0, ++ } ++ .as_bytes() ++ .to_vec(), ++ }), ++ ], ++ }) ++}); ++ ++// NOTE: Fake BOT interface descriptor is needed here since Windows UASP driver always expects two ++// interfaces: both BOT and UASP. It also anticipates the UASP descriptor to be the second one. ++// Therefore, the first one can be a BOT storage stub. ++static DESC_IFACE_EMPTY: Lazy> = Lazy::new(|| { ++ Arc::new(UsbDescIface { ++ interface_desc: UsbInterfaceDescriptor { ++ bLength: USB_DT_INTERFACE_SIZE, ++ bDescriptorType: USB_DT_INTERFACE, ++ bInterfaceNumber: 0, ++ bAlternateSetting: 0, ++ bNumEndpoints: 0, ++ bInterfaceClass: USB_CLASS_MASS_STORAGE, ++ bInterfaceSubClass: USB_SUBCLASS_SCSI, ++ bInterfaceProtocol: USB_IFACE_PROTOCOL_BOT, ++ iInterface: 0, ++ }, ++ other_desc: vec![], ++ endpoints: vec![], ++ }) ++}); ++ ++fn complete_async_packet(packet: &Arc>) { ++ let locked_packet = packet.lock().unwrap(); ++ ++ if let Some(xfer_ops) = locked_packet.xfer_ops.as_ref() { ++ if let Some(xfer_ops) = xfer_ops.clone().upgrade() { ++ drop(locked_packet); ++ xfer_ops.lock().unwrap().submit_transfer(); ++ } ++ } ++} ++ ++impl UsbUas { ++ pub fn new( ++ uas_config: UsbUasConfig, ++ drive_cfg: DriveConfig, ++ drive_files: Arc>>, ++ ) -> Self { ++ let scsidev_classtype = match &drive_cfg.media as &str { ++ "disk" => "scsi-hd".to_string(), ++ _ => "scsi-cd".to_string(), ++ }; ++ let scsi_dev_cfg = ScsiDevConfig { ++ classtype: scsidev_classtype, ++ drive: uas_config.drive.clone(), ++ ..Default::default() ++ }; ++ ++ let mut base = UsbDeviceBase::new( ++ uas_config.id.clone().unwrap(), ++ USB_DEVICE_BUFFER_DEFAULT_LEN, ++ ); ++ ++ base.speed = match uas_config.speed.as_deref() { ++ Some("super") => USB_SPEED_SUPER, ++ _ => USB_SPEED_HIGH, ++ }; ++ ++ Self { ++ base, ++ scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), ++ scsi_device: Arc::new(Mutex::new(ScsiDevice::new( ++ scsi_dev_cfg, ++ drive_cfg, ++ drive_files, ++ ))), ++ commands_high: VecDeque::new(), ++ commands_super: array::from_fn(|_| None), ++ statuses_high: VecDeque::new(), ++ statuses_super: array::from_fn(|_| None), ++ data: array::from_fn(|_| None), ++ data_ready_sent: false, ++ } ++ } ++ ++ fn streams_enabled(&self) -> bool { ++ self.base.speed == USB_SPEED_SUPER ++ } ++ ++ fn cancel_io(&mut self) { ++ self.commands_high = VecDeque::new(); ++ self.commands_super = array::from_fn(|_| None); ++ self.statuses_high = VecDeque::new(); ++ self.statuses_super = array::from_fn(|_| None); ++ self.data = array::from_fn(|_| None); ++ self.data_ready_sent = false; ++ } ++ ++ fn peek_next_status(&self, stream: usize) -> Option<&Arc>> { ++ match self.streams_enabled() { ++ true => self.statuses_super[stream].as_ref(), ++ false => self.statuses_high.front(), ++ } ++ } ++ ++ fn take_next_status(&mut self, stream: usize) -> Arc> { ++ match self.streams_enabled() { ++ true => self.statuses_super[stream].take().unwrap(), ++ false => self.statuses_high.pop_front().unwrap(), ++ } ++ } ++ ++ fn queue_status(&mut self, status: &Arc>, stream: usize) { ++ match self.streams_enabled() { ++ true => self.statuses_super[stream] = Some(Arc::clone(status)), ++ false => self.statuses_high.push_back(Arc::clone(status)), ++ }; ++ } ++ ++ fn peek_next_command(&self, stream: usize) -> Option<&UasIU> { ++ match self.streams_enabled() { ++ true => self.commands_super[stream].as_ref(), ++ false => self.commands_high.front(), ++ } ++ } ++ ++ fn take_next_command(&mut self, stream: usize) -> UasIU { ++ match self.streams_enabled() { ++ true => self.commands_super[stream].take().unwrap(), ++ false => self.commands_high.pop_front().unwrap(), ++ } ++ } ++ ++ fn queue_command(&mut self, command: UasIU, stream: usize) { ++ match self.streams_enabled() { ++ true => self.commands_super[stream] = Some(command), ++ false => self.commands_high.push_back(command), ++ } ++ } ++ ++ fn handle_iu_command( ++ &mut self, ++ iu: &UasIU, ++ mut uas_request: UasRequest, ++ ) -> Result { ++ // SAFETY: iu is guaranteed to be of type command ++ let add_cdb_len = unsafe { iu.body.command.add_cdb_len }; ++ let tag = u16::from_be(iu.header.tag); ++ ++ if add_cdb_len > 0 { ++ Self::fill_fake_sense( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ &SCSI_SENSE_INVALID_PARAM_VALUE, ++ ); ++ uas_request.complete(); ++ bail!("additional cdb length is not supported"); ++ } ++ ++ if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { ++ Self::fill_fake_sense( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ &SCSI_SENSE_INVALID_TAG, ++ ); ++ uas_request.complete(); ++ bail!("invalid tag {}", tag); ++ } ++ ++ if self.streams_enabled() && self.commands_super[tag as usize].is_some() { ++ Self::fill_fake_sense( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ &SCSI_SENSE_OVERLAPPED_COMMANDS, ++ ); ++ uas_request.complete(); ++ bail!("overlapped tag {}", tag); ++ } ++ ++ let (scsi_iovec, scsi_iovec_size) = match uas_request.data.as_ref() { ++ Some(data) => { ++ let mut locked_data = data.lock().unwrap(); ++ let iov_size = locked_data.get_iovecs_size() as u32; ++ locked_data.actual_length = iov_size; ++ (locked_data.iovecs.clone(), iov_size) ++ } ++ None => (Vec::new(), 0), ++ }; ++ ++ // SAFETY: iu is guaranteed to of type command ++ let cdb = unsafe { iu.body.command.cdb }; ++ // SAFETY: iu is guaranteed to of type command ++ let lun = unsafe { iu.body.command.lun } as u16; ++ trace::usb_uas_handle_iu_command(self.device_id(), cdb[0]); ++ let uas_request = Box::new(uas_request); ++ let scsi_request = ScsiRequest::new( ++ cdb, ++ lun, ++ scsi_iovec, ++ scsi_iovec_size, ++ Arc::clone(&self.scsi_device), ++ uas_request, ++ ) ++ .with_context(|| "Failed to create SCSI request.")?; ++ ++ if scsi_request.cmd.xfer > scsi_request.datalen ++ && scsi_request.cmd.mode != ScsiXferMode::ScsiXferNone ++ { ++ bail!( ++ "insufficient buffer provided (requested length {}, provided length {})", ++ scsi_request.cmd.xfer, ++ scsi_request.datalen ++ ); ++ } ++ ++ let scsi_request = match scsi_request.opstype { ++ EMULATE_SCSI_OPS => scsi_request.emulate_execute(), ++ _ => scsi_request.execute(), ++ } ++ .with_context(|| "Failed to execute SCSI request.")?; ++ ++ let upper_request = &mut scsi_request.lock().unwrap().upper_req; ++ let uas_request = upper_request ++ .as_mut() ++ .as_any_mut() ++ .downcast_mut::() ++ .unwrap(); ++ ++ Ok(uas_request.completed.into()) ++ } ++ ++ fn handle_iu_task_management( ++ &mut self, ++ iu: &UasIU, ++ mut uas_request: UasRequest, ++ ) -> Result { ++ let tag = u16::from_be(iu.header.tag); ++ ++ if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { ++ Self::fill_fake_sense( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ &SCSI_SENSE_INVALID_TAG, ++ ); ++ uas_request.complete(); ++ bail!("invalid tag {}", tag); ++ } ++ ++ if self.streams_enabled() && self.commands_super[tag as usize].is_some() { ++ Self::fill_fake_sense( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ &SCSI_SENSE_OVERLAPPED_COMMANDS, ++ ); ++ uas_request.complete(); ++ bail!("overlapped tag {}", tag); ++ } ++ ++ // SAFETY: iu is guaranteed to be of type task management ++ let tmf = unsafe { iu.body.task_management.function }; ++ ++ #[allow(clippy::match_single_binding)] ++ match tmf { ++ _ => { ++ warn!("UAS {} device unsupported TMF {}.", self.device_id(), tmf); ++ Self::fill_response( ++ &mut uas_request.status.lock().unwrap(), ++ tag, ++ UAS_RC_TMF_NOT_SUPPORTED, ++ ); ++ } ++ }; ++ ++ uas_request.complete(); ++ Ok(UasPacketStatus::Completed) ++ } ++ ++ fn fill_response(packet: &mut UsbPacket, tag: u16, code: u8) { ++ let mut iu = UasIU::new(UAS_IU_ID_RESPONSE, tag); ++ iu.body.response.response_code = code; ++ let iu_len = size_of::() + size_of::(); ++ Self::fill_packet(packet, &mut iu, iu_len); ++ } ++ ++ fn fill_sense(packet: &mut UsbPacket, tag: u16, status: u8, sense: &ScsiSense) { ++ let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); ++ // SAFETY: iu is guaranteed to be of type status ++ let iu_sense = unsafe { &mut iu.body.sense }; ++ ++ iu_sense.status = status; ++ iu_sense.status_qualifier = 0_u16.to_be(); ++ iu_sense.sense_length = 0_u16.to_be(); ++ ++ if status != GOOD { ++ iu_sense.sense_length = 18_u16.to_be(); ++ iu_sense.sense_data[0] = 0x71; // Error code: deferred errors ++ iu_sense.sense_data[2] = sense.key; ++ iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 ++ iu_sense.sense_data[12] = sense.asc; ++ iu_sense.sense_data[13] = sense.ascq; ++ } ++ ++ let sense_len = iu_sense.sense_length as usize; ++ let real_sense_len = size_of::() - iu_sense.sense_data.len() + sense_len; ++ let iu_len = size_of::() + real_sense_len; ++ trace::usb_uas_fill_sense(status, iu_len, sense_len); ++ Self::fill_packet(packet, &mut iu, iu_len); ++ } ++ ++ fn fill_fake_sense(packet: &mut UsbPacket, tag: u16, sense: &ScsiSense) { ++ let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); ++ // SAFETY: iu is guaranteed to be of type status ++ let iu_sense = unsafe { &mut iu.body.sense }; ++ ++ iu_sense.status = CHECK_CONDITION; ++ iu_sense.status_qualifier = 0_u16.to_be(); ++ iu_sense.sense_length = 18_u16.to_be(); ++ iu_sense.sense_data[0] = 0x70; // Error code: current errors ++ iu_sense.sense_data[2] = sense.key; ++ iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 ++ iu_sense.sense_data[12] = sense.asc; ++ iu_sense.sense_data[13] = sense.ascq; ++ ++ let iu_len = size_of::() + size_of::(); ++ trace::usb_uas_fill_fake_sense(CHECK_CONDITION, iu_len, 18); ++ Self::fill_packet(packet, &mut iu, iu_len); ++ } ++ ++ fn fill_read_ready(packet: &mut UsbPacket, tag: u16) { ++ let mut iu = UasIU::new(UAS_IU_ID_READ_READY, tag); ++ let iu_len = size_of::(); ++ Self::fill_packet(packet, &mut iu, iu_len); ++ } ++ ++ fn fill_write_ready(packet: &mut UsbPacket, tag: u16) { ++ let mut iu = UasIU::new(UAS_IU_ID_WRITE_READY, tag); ++ let iu_len = size_of::(); ++ Self::fill_packet(packet, &mut iu, iu_len); ++ } ++ ++ fn fill_packet(packet: &mut UsbPacket, iu: &mut UasIU, iu_len: usize) { ++ let iov_size = packet.get_iovecs_size() as usize; ++ let iu_len = min(iov_size, iu_len); ++ trace::usb_uas_fill_packet(iov_size); ++ packet.transfer_packet(iu.as_mut_bytes(), iu_len); ++ } ++ ++ fn try_start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { ++ let command = self.peek_next_command(stream); ++ ++ if let Some(command) = command { ++ // SAFETY: iu is guaranteed to be of type command ++ let cdb = unsafe { &command.body.command.cdb }; ++ let xfer_len = scsi_cdb_xfer(cdb, Arc::clone(&self.scsi_device)); ++ trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); ++ ++ if xfer_len > 0 { ++ self.try_start_next_data(stream) ++ } else { ++ self.try_start_next_non_data(stream) ++ } ++ } else { ++ debug!( ++ "UAS {} device no inflight command when trying to start the next transfer.", ++ self.device_id() ++ ); ++ UasPacketStatus::Pending ++ } ++ } ++ ++ fn try_start_next_data(&mut self, stream: usize) -> UasPacketStatus { ++ let status = self.peek_next_status(stream); ++ ++ if status.is_none() { ++ debug!( ++ "UAS {} device no inflight status when trying to start the next data transfer.", ++ self.device_id() ++ ); ++ return UasPacketStatus::Pending; ++ } ++ ++ if !self.data_ready_sent { ++ return self.fill_data_ready(stream); ++ } ++ ++ if self.data[stream].is_some() { ++ self.start_next_transfer(stream) ++ } else { ++ debug!( ++ "UAS {} device no inflight data when trying to start the next data transfer.", ++ self.device_id() ++ ); ++ UasPacketStatus::Pending ++ } ++ } ++ ++ fn fill_data_ready(&mut self, stream: usize) -> UasPacketStatus { ++ // SAFETY: status must have been checked in try_start_next_data ++ let status = self.take_next_status(stream); ++ let mut locked_status = status.lock().unwrap(); ++ ++ // SAFETY: command must have been checked in try_start_next_transfer ++ let iu = self.peek_next_command(stream).unwrap(); ++ let tag = u16::from_be(iu.header.tag); ++ ++ // SAFETY: iu is guaranteed to be of type command ++ let cdb = unsafe { &iu.body.command.cdb }; ++ let xfer_mode = scsi_cdb_xfer_mode(cdb); ++ ++ match xfer_mode { ++ ScsiXferMode::ScsiXferFromDev => Self::fill_read_ready(&mut locked_status, tag), ++ ScsiXferMode::ScsiXferToDev => Self::fill_write_ready(&mut locked_status, tag), ++ ScsiXferMode::ScsiXferNone => { ++ warn!( ++ "UAS {} device cannot fill data ready, operation {} is not a data transfer.", ++ self.device_id(), ++ cdb[0] ++ ); ++ Self::fill_fake_sense(&mut locked_status, tag, &SCSI_SENSE_INVALID_PARAM_VALUE); ++ } ++ } ++ ++ let status_async = locked_status.is_async; ++ drop(locked_status); ++ ++ if status_async { ++ complete_async_packet(&status); ++ } ++ ++ self.data_ready_sent = true; ++ trace::usb_uas_fill_data_ready(self.device_id(), self.data_ready_sent); ++ UasPacketStatus::Completed ++ } ++ ++ fn try_start_next_non_data(&mut self, stream: usize) -> UasPacketStatus { ++ let status = self.peek_next_status(stream); ++ ++ if status.is_none() { ++ debug!( ++ "UAS {} device no inflight status when trying to start the next non-data transfer.", ++ self.device_id() ++ ); ++ return UasPacketStatus::Pending; ++ } ++ ++ self.start_next_transfer(stream) ++ } ++ ++ fn start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { ++ trace::usb_uas_start_next_transfer(self.device_id(), stream); ++ ++ // SAFETY: status must have been checked in try_start_next_data or try_start_next_non_data ++ let status = self.take_next_status(stream); ++ ++ // SAFETY: command must have been checked in try_start_next_transfer ++ let command = self.take_next_command(stream); ++ ++ let mut uas_request = UasRequest::new(&status, &command); ++ uas_request.data = self.data[stream].take(); ++ ++ let result = match command.header.id { ++ UAS_IU_ID_COMMAND => self.handle_iu_command(&command, uas_request), ++ UAS_IU_ID_TASK_MGMT => self.handle_iu_task_management(&command, uas_request), ++ _ => Err(anyhow!("impossible command IU {}", command.header.id)), ++ }; ++ ++ self.data_ready_sent = false; ++ self.try_start_next_transfer(stream); ++ ++ match result { ++ Ok(result) => result, ++ Err(err) => { ++ error!("UAS {} device error: {:#?}.", self.device_id(), err); ++ UasPacketStatus::Completed ++ } ++ } ++ } ++} ++ ++impl UsbDevice for UsbUas { ++ fn usb_device_base(&self) -> &UsbDeviceBase { ++ &self.base ++ } ++ ++ fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { ++ &mut self.base ++ } ++ ++ fn realize(mut self) -> Result>> { ++ info!("UAS {} device realize.", self.device_id()); ++ self.base.reset_usb_endpoint(); ++ let mut desc_strings: Vec = ++ UAS_DESC_STRINGS.iter().map(|str| str.to_string()).collect(); ++ let prefix = &desc_strings[UsbUasStringId::SerialNumber as usize]; ++ desc_strings[UsbUasStringId::SerialNumber as usize] = ++ self.base.generate_serial_number(prefix); ++ ++ match self.base.speed { ++ USB_SPEED_HIGH => self ++ .base ++ .init_descriptor(DESC_DEVICE_UAS_HIGH.clone(), desc_strings)?, ++ USB_SPEED_SUPER => self ++ .base ++ .init_descriptor(DESC_DEVICE_UAS_SUPER.clone(), desc_strings)?, ++ _ => bail!("USB UAS unsupported device speed {}.", self.base.speed), ++ } ++ ++ // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not ++ // supported. ++ let mut locked_scsi_device = self.scsi_device.lock().unwrap(); ++ locked_scsi_device.realize(None)?; ++ locked_scsi_device.parent_bus = Arc::downgrade(&self.scsi_bus); ++ drop(locked_scsi_device); ++ self.scsi_bus ++ .lock() ++ .unwrap() ++ .devices ++ .insert((0, 0), Arc::clone(&self.scsi_device)); ++ ++ let uas = Arc::new(Mutex::new(self)); ++ Ok(uas) ++ } ++ ++ fn cancel_packet(&mut self, _packet: &Arc>) { ++ self.cancel_io(); ++ } ++ ++ fn reset(&mut self) { ++ info!("UAS {} device reset.", self.device_id()); ++ self.base.remote_wakeup = 0; ++ self.base.addr = 0; ++ self.cancel_io(); ++ } ++ ++ fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest) { ++ let mut locked_packet = packet.lock().unwrap(); ++ trace::usb_uas_handle_control( ++ locked_packet.packet_id, ++ self.device_id(), ++ device_req.as_bytes(), ++ ); ++ ++ match self ++ .base ++ .handle_control_for_descriptor(&mut locked_packet, device_req) ++ { ++ Ok(handled) => { ++ if handled { ++ debug!( ++ "UAS {} device control handled by descriptor, return directly.", ++ self.device_id() ++ ); ++ return; ++ } ++ ++ error!( ++ "UAS {} device unhandled control request {:?}.", ++ self.device_id(), ++ device_req ++ ); ++ locked_packet.status = UsbPacketStatus::Stall; ++ } ++ Err(err) => { ++ warn!( ++ "{} received incorrect UAS descriptor message: {:?}", ++ self.device_id(), ++ err ++ ); ++ locked_packet.status = UsbPacketStatus::Stall; ++ } ++ } ++ } ++ ++ fn handle_data(&mut self, packet: &Arc>) { ++ let locked_packet = packet.lock().unwrap(); ++ let stream = locked_packet.stream as usize; ++ let ep_number = locked_packet.ep_number; ++ let packet_id = locked_packet.packet_id; ++ trace::usb_uas_handle_data(self.device_id(), ep_number, stream); ++ drop(locked_packet); ++ ++ if self.streams_enabled() && (stream > UAS_MAX_STREAMS || stream == 0) { ++ warn!("UAS {} device invalid stream {}.", self.device_id(), stream); ++ packet.lock().unwrap().status = UsbPacketStatus::Stall; ++ return; ++ } ++ ++ // NOTE: The architecture of this device is rather simple: it first waits for all of the ++ // required USB packets to arrive, and only then creates and sends an actual UAS request. ++ // The number of USB packets differs from 2 to 4 and depends on whether the command involves ++ // data transfers or not. Since the packets arrive in arbitrary order, some of them may be ++ // queued asynchronously. Note that the command packet is always completed right away. For ++ // all the other types of packets, their asynchronous status is determined by the return ++ // value of try_start_next_transfer(). All the asynchronously queued packets will be ++ // completed in scsi_request_complete_cb() callback. ++ match ep_number { ++ UAS_PIPE_ID_COMMAND => { ++ if self.streams_enabled() && self.commands_super[stream].is_some() { ++ warn!( ++ "UAS {} device multiple command packets on stream {}.", ++ self.device_id(), ++ stream ++ ); ++ packet.lock().unwrap().status = UsbPacketStatus::Stall; ++ return; ++ } ++ ++ let mut locked_packet = packet.lock().unwrap(); ++ let mut iu = UasIU::default(); ++ let iov_size = locked_packet.get_iovecs_size() as usize; ++ let iu_len = min(iov_size, size_of::()); ++ locked_packet.transfer_packet(iu.as_mut_bytes(), iu_len); ++ ++ trace::usb_uas_command_received(packet_id, self.device_id()); ++ self.queue_command(iu, stream); ++ self.try_start_next_transfer(stream); ++ trace::usb_uas_command_completed(packet_id, self.device_id()); ++ } ++ UAS_PIPE_ID_STATUS => { ++ if self.streams_enabled() && self.statuses_super[stream].is_some() { ++ warn!( ++ "UAS {} device multiple status packets on stream {}.", ++ self.device_id(), ++ stream ++ ); ++ packet.lock().unwrap().status = UsbPacketStatus::Stall; ++ return; ++ } ++ ++ trace::usb_uas_status_received(packet_id, self.device_id()); ++ self.queue_status(packet, stream); ++ let result = self.try_start_next_transfer(stream); ++ ++ match result { ++ UasPacketStatus::Completed => { ++ trace::usb_uas_status_completed(packet_id, self.device_id()) ++ } ++ UasPacketStatus::Pending => { ++ packet.lock().unwrap().is_async = true; ++ trace::usb_uas_status_queued_async(packet_id, self.device_id()); ++ } ++ } ++ } ++ UAS_PIPE_ID_DATA_OUT | UAS_PIPE_ID_DATA_IN => { ++ if self.data[stream].is_some() { ++ warn!( ++ "UAS {} device multiple data packets on stream {}.", ++ self.device_id(), ++ stream ++ ); ++ packet.lock().unwrap().status = UsbPacketStatus::Stall; ++ return; ++ } ++ ++ trace::usb_uas_data_received(packet_id, self.device_id()); ++ self.data[stream] = Some(Arc::clone(packet)); ++ let result = self.try_start_next_transfer(stream); ++ ++ match result { ++ UasPacketStatus::Completed => { ++ trace::usb_uas_data_completed(packet_id, self.device_id()) ++ } ++ UasPacketStatus::Pending => { ++ packet.lock().unwrap().is_async = true; ++ trace::usb_uas_data_queued_async(packet_id, self.device_id()); ++ } ++ } ++ } ++ _ => { ++ error!( ++ "UAS {} device bad endpoint number {}.", ++ self.device_id(), ++ ep_number ++ ); ++ } ++ } ++ } ++ ++ fn set_controller(&mut self, _controller: std::sync::Weak>) {} ++ ++ fn get_controller(&self) -> Option>> { ++ None ++ } ++ ++ fn get_wakeup_endpoint(&self) -> &UsbEndpoint { ++ self.base.get_endpoint(true, 1) ++ } ++} ++ ++impl UasRequest { ++ fn new(status: &Arc>, iu: &UasIU) -> Self { ++ Self { ++ data: None, ++ status: Arc::clone(status), ++ iu: *iu, ++ completed: false, ++ } ++ } ++ ++ fn complete(&mut self) { ++ let status = &self.status; ++ let status_async = status.lock().unwrap().is_async; ++ ++ // NOTE: Due to the specifics of this device, it waits for all of the required USB packets ++ // to arrive before starting an actual transfer. Therefore, some packets may arrive earlier ++ // than others, and they won't be completed right away (except for command packets) but ++ // rather queued asynchronously. A certain packet may also be async if it was the last to ++ // arrive and UasRequest didn't complete right away. ++ if status_async { ++ complete_async_packet(status); ++ } ++ ++ if let Some(data) = &self.data { ++ let data_async = data.lock().unwrap().is_async; ++ ++ if data_async { ++ complete_async_packet(data); ++ } ++ } ++ ++ self.completed = true; ++ } ++} ++ ++impl UasIUHeader { ++ fn new(id: u8, tag: u16) -> Self { ++ UasIUHeader { ++ id, ++ reserved: 0, ++ tag: tag.to_be(), ++ } ++ } ++} ++ ++impl UasIU { ++ fn new(id: u8, tag: u16) -> Self { ++ Self { ++ header: UasIUHeader::new(id, tag), ++ body: UasIUBody::default(), ++ } ++ } ++} +diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs +index 2ee7a9d..e558f81 100644 +--- a/devices/src/usb/usbhost/host_usblib.rs ++++ b/devices/src/usb/usbhost/host_usblib.rs +@@ -16,6 +16,8 @@ use std::{ + }; + + use libc::{c_int, c_uint, c_void, EPOLLIN, EPOLLOUT}; ++#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++use libusb1_sys::{constants::LIBUSB_SUCCESS, libusb_context, libusb_set_option}; + use libusb1_sys::{ + constants::{ + LIBUSB_ERROR_ACCESS, LIBUSB_ERROR_BUSY, LIBUSB_ERROR_INTERRUPTED, +@@ -380,3 +382,20 @@ pub fn free_host_transfer(transfer: *mut libusb_transfer) { + // SAFETY: have checked the validity of transfer before call libusb_free_transfer. + unsafe { libusb1_sys::libusb_free_transfer(transfer) }; + } ++ ++#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++pub fn set_option(opt: u32) -> Result<()> { ++ // SAFETY: This function will only configure a specific option within libusb, null for ctx is valid. ++ let err = unsafe { ++ libusb_set_option( ++ std::ptr::null_mut() as *mut libusb_context, ++ opt, ++ std::ptr::null_mut() as *mut c_void, ++ ) ++ }; ++ if err != LIBUSB_SUCCESS { ++ return Err(from_libusb(err)); ++ } ++ ++ Ok(()) ++} +diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs +index e34d117..3da8cf0 100644 +--- a/devices/src/usb/usbhost/mod.rs ++++ b/devices/src/usb/usbhost/mod.rs +@@ -11,6 +11,8 @@ + // See the Mulan PSL v2 for more details. + + mod host_usblib; ++#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++mod ohusb; + + use std::{ + collections::LinkedList, +@@ -20,7 +22,9 @@ use std::{ + time::Duration, + }; + +-use anyhow::{anyhow, bail, Result}; ++#[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] ++use anyhow::Context as anyhowContext; ++use anyhow::{anyhow, Result}; + use clap::Parser; + use libc::c_int; + use libusb1_sys::{ +@@ -50,6 +54,8 @@ use machine_manager::{ + event_loop::{register_event_helper, unregister_event_helper}, + temp_cleaner::{ExitNotifier, TempCleaner}, + }; ++#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++use ohusb::OhUsbDev; + use util::{ + byte_code::ByteCode, + link_list::{List, Node}, +@@ -357,8 +363,10 @@ impl IsoQueue { + } + + #[derive(Parser, Clone, Debug, Default)] +-#[command(name = "usb_host")] ++#[command(no_binary_name(true))] + pub struct UsbHostConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long, default_value = "0")] +@@ -402,6 +410,8 @@ pub struct UsbHost { + iso_queues: Arc>>>>, + iso_urb_frames: u32, + iso_urb_count: u32, ++ #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++ oh_dev: OhUsbDev, + } + + // SAFETY: Send and Sync is not auto-implemented for util::link_list::List. +@@ -412,6 +422,9 @@ unsafe impl Send for UsbHost {} + + impl UsbHost { + pub fn new(config: UsbHostConfig) -> Result { ++ #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++ let oh_dev = OhUsbDev::new()?; ++ + let mut context = Context::new()?; + context.set_log_level(rusb::LogLevel::None); + let iso_urb_frames = config.iso_urb_frames; +@@ -432,9 +445,12 @@ impl UsbHost { + iso_queues: Arc::new(Mutex::new(LinkedList::new())), + iso_urb_frames, + iso_urb_count, ++ #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++ oh_dev, + }) + } + ++ #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] + fn find_libdev(&self) -> Option> { + if self.config.vendorid != 0 && self.config.productid != 0 { + self.find_dev_by_vendor_product() +@@ -447,6 +463,7 @@ impl UsbHost { + } + } + ++ #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] + fn find_dev_by_bus_addr(&self) -> Option> { + self.context + .devices() +@@ -463,6 +480,7 @@ impl UsbHost { + .unwrap_or_else(|| None) + } + ++ #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] + fn find_dev_by_vendor_product(&self) -> Option> { + self.context + .devices() +@@ -480,6 +498,7 @@ impl UsbHost { + .unwrap_or_else(|| None) + } + ++ #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] + fn find_dev_by_bus_port(&self) -> Option> { + let hostport: Vec<&str> = self.config.hostport.as_ref().unwrap().split('.').collect(); + let mut port: Vec = Vec::new(); +@@ -642,8 +661,7 @@ impl UsbHost { + } + } + +- fn open_and_init(&mut self) -> Result<()> { +- self.handle = Some(self.libdev.as_ref().unwrap().open()?); ++ fn init_usbdev(&mut self) -> Result<()> { + self.config.hostbus = self.libdev.as_ref().unwrap().bus_number(); + self.config.hostaddr = self.libdev.as_ref().unwrap().address(); + trace::usb_host_open_started(self.config.hostbus, self.config.hostaddr); +@@ -980,6 +998,26 @@ impl UsbHost { + + locked_packet.is_async = true; + } ++ ++ #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] ++ fn open_usbdev(&mut self) -> Result<()> { ++ self.libdev = Some( ++ self.find_libdev() ++ .with_context(|| format!("Invalid USB host config: {:?}", self.config))?, ++ ); ++ self.handle = Some(self.libdev.as_ref().unwrap().open()?); ++ Ok(()) ++ } ++ ++ #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] ++ fn open_usbdev(&mut self) -> Result<()> { ++ self.handle = Some( ++ self.oh_dev ++ .open(self.config.clone(), self.context.clone())?, ++ ); ++ self.libdev = Some(self.handle.as_ref().unwrap().device()); ++ Ok(()) ++ } + } + + impl Drop for UsbHost { +@@ -1021,13 +1059,9 @@ impl UsbDevice for UsbHost { + } + + fn realize(mut self) -> Result>> { +- self.libdev = self.find_libdev(); +- if self.libdev.is_none() { +- bail!("Invalid USB host config: {:?}", self.config); +- } +- + info!("Open and init usbhost device: {:?}", self.config); +- self.open_and_init()?; ++ self.open_usbdev()?; ++ self.init_usbdev()?; + + let usbhost = Arc::new(Mutex::new(self)); + let notifiers = EventNotifierHelper::internal_notifiers(usbhost.clone()); +@@ -1045,6 +1079,8 @@ impl UsbDevice for UsbHost { + Ok(()) + } + ++ fn cancel_packet(&mut self, _packet: &Arc>) {} ++ + fn reset(&mut self) { + info!("Usb Host device {} reset", self.device_id()); + if self.handle.is_none() { +@@ -1292,7 +1328,7 @@ impl UsbDevice for UsbHost { + } + } + +-fn check_device_valid(device: &Device) -> bool { ++pub fn check_device_valid(device: &Device) -> bool { + let ddesc = match device.device_descriptor() { + Ok(ddesc) => ddesc, + Err(_) => return false, +diff --git a/devices/src/usb/usbhost/ohusb.rs b/devices/src/usb/usbhost/ohusb.rs +new file mode 100644 +index 0000000..469a17a +--- /dev/null ++++ b/devices/src/usb/usbhost/ohusb.rs +@@ -0,0 +1,82 @@ ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::os::fd::AsRawFd; ++use std::ptr; ++ ++use anyhow::{bail, Context as anyhowContext, Result}; ++use libusb1_sys::constants::LIBUSB_OPTION_NO_DEVICE_DISCOVERY; ++use log::{error, info}; ++use rusb::{Context, DeviceHandle, UsbContext}; ++ ++use super::host_usblib::set_option; ++use super::{check_device_valid, UsbHostConfig}; ++use util::ohos_binding::usb::*; ++ ++pub struct OhUsbDev { ++ dev: OhusbDevice, ++ lib: OhUsb, ++} ++ ++impl Drop for OhUsbDev { ++ fn drop(&mut self) { ++ if let Err(e) = self.lib.close_device(ptr::addr_of_mut!(self.dev)) { ++ error!("Failed to close usb device with error {:?}", e) ++ } ++ } ++} ++ ++impl OhUsbDev { ++ pub fn new() -> Result { ++ // In combination with libusb_wrap_sys_device(), in order to access a device directly without prior device scanning on ohos. ++ set_option(LIBUSB_OPTION_NO_DEVICE_DISCOVERY)?; ++ ++ Ok(Self { ++ dev: OhusbDevice { ++ busNum: u8::MAX, ++ devAddr: u8::MAX, ++ fd: -1, ++ }, ++ lib: OhUsb::new()?, ++ }) ++ } ++ ++ pub fn open(&mut self, cfg: UsbHostConfig, ctx: Context) -> Result> { ++ self.dev.busNum = cfg.hostbus; ++ self.dev.devAddr = cfg.hostaddr; ++ ++ match self.lib.open_device(ptr::addr_of_mut!(self.dev))? { ++ 0 => { ++ if self.dev.fd < 0 { ++ bail!( ++ "Failed to open usb device due to invalid fd {}", ++ self.dev.fd ++ ); ++ } ++ } ++ _ => bail!("Failed to open usb device"), ++ } ++ info!("OH USB: open_device: returned fd is {}", self.dev.fd); ++ ++ // SAFETY: fd is valid. ++ let handle = unsafe { ++ ctx.open_device_with_fd(self.dev.fd.as_raw_fd()) ++ .with_context(|| format!("os last error: {:?}", std::io::Error::last_os_error()))? ++ }; ++ ++ if !check_device_valid(&handle.device()) { ++ bail!("Invalid USB host config: {:?}", cfg); ++ } ++ ++ Ok(handle) ++ } ++} +diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs +index 178aafc..a588771 100644 +--- a/devices/src/usb/xhci/xhci_controller.rs ++++ b/devices/src/usb/xhci/xhci_controller.rs +@@ -690,6 +690,7 @@ pub struct XhciDevice { + /// Runtime Register. + mfindex_start: Duration, + timer_id: Option, ++ packet_count: u32, + } + + impl XhciDevice { +@@ -726,6 +727,7 @@ impl XhciDevice { + } + + let xhci = XhciDevice { ++ packet_count: 0, + oper, + usb_ports: Vec::new(), + numports_3: p3, +@@ -923,6 +925,11 @@ impl XhciDevice { + Ok(()) + } + ++ fn generate_packet_id(&mut self) -> u32 { ++ self.packet_count = self.packet_count.wrapping_add(1); ++ self.packet_count ++ } ++ + fn get_slot_id(&self, evt: &mut XhciEvent, trb: &XhciTRB) -> u32 { + let slot_id = (trb.control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK; + if slot_id < 1 || slot_id > self.slots.len() as u32 { +@@ -1075,7 +1082,7 @@ impl XhciDevice { + for i in 1..=self.slots[(slot_id - 1) as usize].endpoints.len() as u32 { + let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(i - 1) as usize]; + if epctx.enabled { +- self.flush_ep_transfer(slot_id, i, TRBCCode::Invalid)?; ++ self.cancel_all_ep_transfers(slot_id, i, TRBCCode::Invalid)?; + } + } + self.slots[(slot_id - 1) as usize].usb_port = None; +@@ -1182,11 +1189,15 @@ impl XhciDevice { + index: 0, + length: 0, + }; ++ let target_dev = Arc::downgrade(dev) as Weak>; ++ let packet_id = self.generate_packet_id(); + let p = Arc::new(Mutex::new(UsbPacket::new( ++ packet_id, + USB_TOKEN_OUT as u32, + 0, + Vec::new(), + None, ++ Some(target_dev), + ))); + trace::usb_handle_control(&locked_dev.usb_device_base().base.id, &device_req); + locked_dev.handle_control(&p, &device_req); +@@ -1432,7 +1443,7 @@ impl XhciDevice { + trace::usb_xhci_unimplemented(&"Endpoint already disabled".to_string()); + return Ok(TRBCCode::Success); + } +- self.flush_ep_transfer(slot_id, ep_id, TRBCCode::Invalid)?; ++ self.cancel_all_ep_transfers(slot_id, ep_id, TRBCCode::Invalid)?; + let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; + if self.oper.dcbaap != 0 { + epctx.set_state(EP_DISABLED)?; +@@ -1465,7 +1476,7 @@ impl XhciDevice { + ); + return Ok(TRBCCode::ContextStateError); + } +- if self.flush_ep_transfer(slot_id, ep_id, TRBCCode::Stopped)? > 0 { ++ if self.cancel_all_ep_transfers(slot_id, ep_id, TRBCCode::Stopped)? > 0 { + trace::usb_xhci_unimplemented(&format!( + "Endpoint stop when xfers running, slot_id {} epid {}", + slot_id, ep_id +@@ -1495,7 +1506,7 @@ impl XhciDevice { + error!("Endpoint is not halted"); + return Ok(TRBCCode::ContextStateError); + } +- if self.flush_ep_transfer(slot_id, ep_id, TRBCCode::Invalid)? > 0 { ++ if self.cancel_all_ep_transfers(slot_id, ep_id, TRBCCode::Invalid)? > 0 { + warn!("endpoint reset when xfers running!"); + } + let slot = &mut self.slots[(slot_id - 1) as usize]; +@@ -1925,13 +1936,33 @@ impl XhciDevice { + trb.parameter + }; + +- self.mem_space +- .get_address_map(GuestAddress(dma_addr), chunk as u64, &mut vec)?; ++ self.mem_space.get_address_map( ++ &None, ++ GuestAddress(dma_addr), ++ chunk as u64, ++ &mut vec, ++ )?; + } + } ++ ++ let target_dev = ++ if let Ok(target_dev) = self.get_usb_dev(locked_xfer.slotid, locked_xfer.epid) { ++ Some(Arc::downgrade(&target_dev) as Weak>) ++ } else { ++ None ++ }; ++ ++ let packet_id = self.generate_packet_id(); + let (_, ep_number) = endpoint_id_to_number(locked_xfer.epid as u8); + let xfer_ops = Arc::downgrade(xfer) as Weak>; +- let packet = UsbPacket::new(dir as u32, ep_number, vec, Some(xfer_ops)); ++ let packet = UsbPacket::new( ++ packet_id, ++ dir as u32, ++ ep_number, ++ vec, ++ Some(xfer_ops), ++ target_dev, ++ ); + Ok(Arc::new(Mutex::new(packet))) + } + +@@ -1971,8 +2002,8 @@ impl XhciDevice { + } + + /// Flush transfer in endpoint in some case such as stop endpoint. +- fn flush_ep_transfer(&mut self, slotid: u32, epid: u32, report: TRBCCode) -> Result { +- trace::usb_xhci_flush_ep_transfer(&slotid, &epid); ++ fn cancel_all_ep_transfers(&mut self, slotid: u32, epid: u32, report: TRBCCode) -> Result { ++ trace::usb_xhci_cancel_all_ep_transfers(&slotid, &epid); + let mut cnt = 0; + let mut report = report; + while let Some(xfer) = self.slots[(slotid - 1) as usize].endpoints[(epid - 1) as usize] +@@ -1983,7 +2014,7 @@ impl XhciDevice { + if locked_xfer.complete { + continue; + } +- cnt += self.do_ep_transfer(slotid, epid, &mut locked_xfer, report)?; ++ cnt += self.cancel_one_ep_transfer(slotid, epid, &mut locked_xfer, report)?; + if cnt != 0 { + // Only report once. + report = TRBCCode::Invalid; +@@ -1995,7 +2026,7 @@ impl XhciDevice { + Ok(cnt) + } + +- fn do_ep_transfer( ++ fn cancel_one_ep_transfer( + &mut self, + slotid: u32, + ep_id: u32, +@@ -2008,6 +2039,15 @@ impl XhciDevice { + if report != TRBCCode::Invalid { + xfer.status = report; + xfer.submit_transfer()?; ++ let locked_packet = xfer.packet.lock().unwrap(); ++ ++ if let Some(usb_dev) = locked_packet.target_dev.as_ref() { ++ if let Some(usb_dev) = usb_dev.clone().upgrade() { ++ drop(locked_packet); ++ let mut locked_usb_dev = usb_dev.lock().unwrap(); ++ locked_usb_dev.cancel_packet(&xfer.packet); ++ } ++ } + } + xfer.running_async = false; + killed = 1; +diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs +index 0b3373c..0e8ffd2 100644 +--- a/devices/src/usb/xhci/xhci_pci.rs ++++ b/devices/src/usb/xhci/xhci_pci.rs +@@ -39,7 +39,8 @@ use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; + use machine_manager::config::{get_pci_df, valid_id}; + use machine_manager::event_loop::register_event_helper; + use util::loop_context::{ +- read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, ++ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, ++ NotifierOperation, + }; + + /// 5.2 PCI Configuration Registers(USB) +@@ -67,8 +68,10 @@ const XHCI_MSIX_PBA_OFFSET: u32 = 0x3800; + + /// XHCI controller configuration. + #[derive(Parser, Clone, Debug, Default)] +-#[command(name = "nec-usb-xhci")] ++#[command(no_binary_name(true))] + pub struct XhciConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: Option, + #[arg(long)] +@@ -120,7 +123,7 @@ impl XhciPciDevice { + XHCI_PCI_CONFIG_LENGTH as u64, + "XhciPciContainer", + ), +- doorbell_fd: Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()), ++ doorbell_fd: Arc::new(create_new_eventfd().unwrap()), + delete_evts: Vec::new(), + iothread: config.iothread.clone(), + } +diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md +index 7a3c87e..1619540 100644 +--- a/docs/config_guidebook.md ++++ b/docs/config_guidebook.md +@@ -938,7 +938,7 @@ Six properties can be set for Virtio-Scsi controller. + * bus: bus number of the device. + * addr: including slot number and function number. + * iothread: indicate which iothread will be used, if not specified the main thread will be used. (optional) +-* num-queues: the optional num-queues attribute controls the number of request queues to be used for the scsi controller. If not set, the default block queue number is 1. The max queues number supported is no more than 32. (optional) ++* num-queues: the optional num-queues attribute controls the number of request queues to be used for the scsi controller. If not set, the default queue number is the smaller one of vCPU count and the max queues number (e.g, min(vcpu_count, 32)). The max queues number supported is no more than 32. (optional) + * queue-size: the optional virtqueue size for all the queues. Configuration range is (2, 1024] and queue size must be power of 2. Default queue size is 256. + ```shell + -device virtio-scsi-pci,id=,bus=,addr=<0x3>[,multifunction={on|off}][,iothread=][,num-queues=][,queue-size=] +@@ -1036,7 +1036,7 @@ Sample Configuration: + ```shell + -object authz-simple,id=authz0,identity=username + -object tls-creds-x509,id=vnc-tls-creds0,dir=/etc/pki/vnc +--vnc 0.0.0.0:0,tls-creds=vnc-tls-creds0,sasl=on,sasl-authz=authz0 ++-vnc 0.0.0.0:0,tls-creds=vnc-tls-creds0,sasl,sasl-authz=authz0 + ``` + + Note: 1. Only one client can be connected at the same time. Follow-up clients connections will result in failure. 2. TLS encrypted transmission can be configured separately, but authentication must be used together with encryption. +@@ -1107,14 +1107,15 @@ Usually used in conjunction with VNC, the final images is rendered to the VNC cl + + Sample Configuration: + ```shell +--device virtio-gpu-pci,id=,bus=pcie.0,addr=0x2.0x0[,max_outputs=][,edid=true|false][,xres=][,yres= ][,max_hostmem=] ++-device virtio-gpu-pci,id=,bus=pcie.0,addr=0x2.0x0[,max_outputs=][,edid=true|false][,xres=][,yres= ][,max_hostmem=][,enable_bar0=true|false] + ``` + +-In addition to the required slot information, five optional properties are supported for virtio-gpu. ++In addition to the required slot information, six optional properties are supported for virtio-gpu. + * max_outputs: Number of screens supported by the current graphics card. The maximum value is 16. (can switch by using ctrl + alt + , for details, see vnc Client switchover) + * edid: Edid feature, the virtual machine's kernel may checks this feature for HiDPi. You are advised to set to true. + * xres/yres: The size of the login windows. + * max_hostmem: The maximum memory that a graphics card can occupy on the host is expressed in byte. You are advised to set not less than 256MiB, otherwise the final supported resolutions is affected. ++* enable_bar0: Enable a 64M bar0 in virtio-gpu. + + Note: + 1. Only virtio-gpu 2D supported. +diff --git a/docs/stratovirt-img.md b/docs/stratovirt-img.md +index e44be8d..7021e56 100644 +--- a/docs/stratovirt-img.md ++++ b/docs/stratovirt-img.md +@@ -35,6 +35,16 @@ stratovirt-img create -f qcow2 -o cluster-size=65536 img_path img_size + + Note: 1. The cluster size can be only be set for `qcow2` or default to 65536. 2. Disk format is default to raw. + ++## Info ++ ++Query the information of virtual disk. ++ ++Sample Configuration: ++ ++```shell ++stratovirt-img info img_path ++``` ++ + ## Check + + Check if there are some mistakes on the image and choose to fix. +diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml +index 97f4190..b766c95 100644 +--- a/hypervisor/Cargo.toml ++++ b/hypervisor/Cargo.toml +@@ -8,7 +8,7 @@ license = "Mulan PSL v2" + [dependencies] + anyhow = "1.0" + thiserror = "1.0" +-kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + kvm-ioctls = "0.19.1" + libc = "0.2" + log = "0.4" +diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs +index 5d2a938..0721236 100644 +--- a/hypervisor/src/kvm/aarch64/mod.rs ++++ b/hypervisor/src/kvm/aarch64/mod.rs +@@ -135,7 +135,7 @@ impl KvmCpu { + pub fn arch_set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &Option, ++ boot_config: &CPUBootConfig, + vcpu_config: &CPUFeatures, + ) -> Result<()> { + let mut kvi = self.kvi.lock().unwrap(); +@@ -169,9 +169,7 @@ impl KvmCpu { + } + drop(kvi); + +- if let Some(cfg) = boot_config { +- arch_cpu.lock().unwrap().set_core_reg(cfg); +- } ++ arch_cpu.lock().unwrap().set_core_reg(boot_config); + + self.arch_vcpu_init()?; + +diff --git a/hypervisor/src/kvm/interrupt.rs b/hypervisor/src/kvm/interrupt.rs +index ea9e779..c98eba8 100644 +--- a/hypervisor/src/kvm/interrupt.rs ++++ b/hypervisor/src/kvm/interrupt.rs +@@ -34,9 +34,9 @@ const IOAPIC_NUM_PINS: u32 = 24; + const PIC_MASTER_PINS: u32 = 8; + #[cfg(target_arch = "x86_64")] + const PIC_SLACE_PINS: u32 = 8; +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + const IOCHIP_NUM_PINS: u32 = 192; +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + const KVM_IRQCHIP: u32 = 0; + + /// Return the max number kvm supports. +@@ -122,9 +122,9 @@ impl IrqRouteTable { + } + + /// Init irq route table in arch aarch64. +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub fn init_irq_route_table(&mut self) { +- for i in 0..IOCHIP_NUM_PINS { ++ for i in 0..20 { + self.irq_routes + .push(create_irq_route_entry(i, KVM_IRQCHIP, i)); + // This unwrap() will never fail, it is safe. +diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs +index b88aeed..5669655 100644 +--- a/hypervisor/src/kvm/mod.rs ++++ b/hypervisor/src/kvm/mod.rs +@@ -12,6 +12,8 @@ + + #[cfg(target_arch = "aarch64")] + pub mod aarch64; ++#[cfg(target_arch = "riscv64")] ++pub mod riscv64; + #[cfg(target_arch = "x86_64")] + pub mod x86_64; + +@@ -25,6 +27,8 @@ pub mod vm_state; + pub use aarch64::gicv2::KvmGICv2; + #[cfg(target_arch = "aarch64")] + pub use aarch64::gicv3::{KvmGICv3, KvmGICv3Its}; ++#[cfg(target_arch = "riscv64")] ++pub use riscv64::aia::KvmAIA; + + use std::collections::HashMap; + use std::sync::atomic::{AtomicBool, Ordering}; +@@ -63,6 +67,8 @@ use cpu::{ + CpuLifecycleState, RegsIndex, CPU, VCPU_TASK_SIGNAL, + }; + use devices::{pci::MsiVector, IrqManager, LineIrqManager, MsiIrqManager, TriggerMode}; ++#[cfg(target_arch = "riscv64")] ++use devices::{AIAConfig, InterruptController, AIA}; + #[cfg(target_arch = "aarch64")] + use devices::{ + GICVersion, GICv2, GICv3, GICv3ItsState, GICv3State, ICGICConfig, InterruptController, +@@ -73,6 +79,8 @@ use machine_manager::machine::HypervisorType; + #[cfg(target_arch = "aarch64")] + use migration::snapshot::{GICV3_ITS_SNAPSHOT_ID, GICV3_SNAPSHOT_ID}; + use migration::{MigrateMemSlot, MigrateOps, MigrationManager}; ++#[cfg(target_arch = "riscv64")] ++use riscv64::cpu_caps::RISCVCPUCaps as CPUCaps; + use util::test_helper::is_test_enabled; + #[cfg(target_arch = "x86_64")] + use x86_64::cpu_caps::X86CPUCaps as CPUCaps; +@@ -88,6 +96,7 @@ ioctl_iow_nr!(KVM_GET_DIRTY_LOG, KVMIO, 0x42, kvm_dirty_log); + ioctl_iowr_nr!(KVM_CREATE_DEVICE, KVMIO, 0xe0, kvm_create_device); + ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00); + ioctl_ior_nr!(KVM_GET_MP_STATE, KVMIO, 0x98, kvm_mp_state); ++#[cfg(not(target_arch = "riscv64"))] + ioctl_ior_nr!(KVM_GET_VCPU_EVENTS, KVMIO, 0x9f, kvm_vcpu_events); + ioctl_ior_nr!(KVM_GET_CLOCK, KVMIO, 0x7c, kvm_clock_data); + ioctl_ior_nr!(KVM_GET_REGS, KVMIO, 0x81, kvm_regs); +@@ -98,13 +107,8 @@ ioctl_iow_nr!(KVM_IRQFD, KVMIO, 0x76, kvm_irqfd); + ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip); + ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level); + ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state); ++#[cfg(not(target_arch = "riscv64"))] + ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events); +-#[cfg(target_arch = "x86_64")] +-ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2); +-#[cfg(target_arch = "x86_64")] +-ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data); +-#[cfg(target_arch = "x86_64")] +-ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip); + + #[allow(clippy::upper_case_acronyms)] + #[derive(Default)] +@@ -112,7 +116,7 @@ pub struct KvmHypervisor { + pub fd: Option, + pub vm_fd: Option>, + pub mem_slots: Arc>>, +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub irq_chip: Option>, + } + +@@ -131,7 +135,7 @@ impl KvmHypervisor { + fd: Some(kvm_fd), + vm_fd, + mem_slots: Arc::new(Mutex::new(HashMap::new())), +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + irq_chip: None, + }) + } +@@ -219,6 +223,24 @@ impl HypervisorOps for KvmHypervisor { + } + } + ++ #[cfg(target_arch = "riscv64")] ++ fn create_interrupt_controller( ++ &mut self, ++ aia_conf: &AIAConfig, ++ ) -> Result> { ++ aia_conf.check_sanity()?; ++ ++ let create_aia = || { ++ let hypervisor_aia = KvmAIA::new(self.vm_fd.clone().unwrap(), aia_conf.vcpu_count)?; ++ let aia = Arc::new(AIA::new(Arc::new(hypervisor_aia), aia_conf)?); ++ // Need register AIA to MigrationManager here ++ ++ Ok(Arc::new(InterruptController::new(aia))) ++ }; ++ ++ create_aia() ++ } ++ + #[cfg(target_arch = "x86_64")] + fn create_interrupt_controller(&mut self) -> Result<()> { + self.vm_fd +@@ -242,7 +264,7 @@ impl HypervisorOps for KvmHypervisor { + .with_context(|| "Create vcpu failed")?; + Ok(Arc::new(KvmCpu::new( + vcpu_id, +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + self.vm_fd.clone(), + vcpu_fd, + ))) +@@ -253,7 +275,7 @@ impl HypervisorOps for KvmHypervisor { + let irqfd_enable = kvm.check_extension(Cap::Irqfd); + let irq_route_table = Mutex::new(IrqRouteTable::new(self.fd.as_ref().unwrap())); + let irq_manager = Arc::new(KVMInterruptManager::new( +- irqfd_enable, ++ false, + self.vm_fd.clone().unwrap(), + irq_route_table, + )); +@@ -372,8 +394,11 @@ impl MigrateOps for KvmHypervisor { + + pub struct KvmCpu { + id: u8, +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + vm_fd: Option>, ++ #[cfg(target_arch = "riscv64")] ++ fd: Arc>, ++ #[cfg(not(target_arch = "riscv64"))] + fd: Arc, + /// The capability of VCPU. + caps: CPUCaps, +@@ -385,13 +410,16 @@ pub struct KvmCpu { + impl KvmCpu { + pub fn new( + id: u8, +- #[cfg(target_arch = "aarch64")] vm_fd: Option>, ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] vm_fd: Option>, + vcpu_fd: VcpuFd, + ) -> Self { + Self { + id, +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + vm_fd, ++ #[cfg(target_arch = "riscv64")] ++ fd: Arc::new(Mutex::new(vcpu_fd)), ++ #[cfg(not(target_arch = "riscv64"))] + fd: Arc::new(vcpu_fd), + caps: CPUCaps::init_capabilities(), + #[cfg(target_arch = "aarch64")] +@@ -422,6 +450,7 @@ impl KvmCpu { + .upgrade() + .with_context(|| CpuError::NoMachineInterface)?; + ++ #[cfg(not(target_arch = "riscv64"))] + match self.fd.run() { + Ok(run) => { + trace::kvm_vcpu_run_exit(cpu.id, &run); +@@ -458,7 +487,7 @@ impl KvmCpu { + + return Ok(false); + } +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + VcpuExit::SystemEvent(event, flags) => { + if event == kvm_bindings::KVM_SYSTEM_EVENT_SHUTDOWN { + info!( +@@ -517,6 +546,108 @@ impl KvmCpu { + }; + } + } ++ ++ #[cfg(target_arch = "riscv64")] ++ { ++ let mut vcpu_fd = self.fd.lock().unwrap(); ++ let res = vcpu_fd.run(); ++ match res { ++ Ok(run) => { ++ trace::kvm_vcpu_run_exit(cpu.id, &run); ++ match run { ++ #[cfg(target_arch = "x86_64")] ++ VcpuExit::IoIn(addr, data) => { ++ vm.lock().unwrap().pio_in(u64::from(addr), data); ++ } ++ #[cfg(target_arch = "x86_64")] ++ VcpuExit::IoOut(addr, data) => { ++ #[cfg(feature = "boot_time")] ++ capture_boot_signal(addr as u64, data); ++ ++ vm.lock().unwrap().pio_out(u64::from(addr), data); ++ } ++ VcpuExit::MmioRead(addr, data) => { ++ vm.lock().unwrap().mmio_read(addr, data); ++ } ++ VcpuExit::MmioWrite(addr, data) => { ++ #[cfg(all(target_arch = "aarch64", feature = "boot_time"))] ++ capture_boot_signal(addr, data); ++ ++ vm.lock().unwrap().mmio_write(addr, data); ++ } ++ #[cfg(target_arch = "x86_64")] ++ VcpuExit::Hlt => { ++ info!("Vcpu{} received KVM_EXIT_HLT signal", cpu.id); ++ return Err(anyhow!(CpuError::VcpuHltEvent(cpu.id))); ++ } ++ #[cfg(target_arch = "x86_64")] ++ VcpuExit::Shutdown => { ++ info!("Vcpu{} received an KVM_EXIT_SHUTDOWN signal", cpu.id); ++ cpu.guest_shutdown()?; ++ ++ return Ok(false); ++ } ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] ++ VcpuExit::SystemEvent(event, flags) => { ++ if event == kvm_bindings::KVM_SYSTEM_EVENT_SHUTDOWN { ++ info!( ++ "Vcpu{} received an KVM_SYSTEM_EVENT_SHUTDOWN signal", ++ cpu.id() ++ ); ++ cpu.guest_shutdown() ++ .with_context(|| "Some error occurred in guest shutdown")?; ++ return Ok(true); ++ } else if event == kvm_bindings::KVM_SYSTEM_EVENT_RESET { ++ info!("Vcpu{} received an KVM_SYSTEM_EVENT_RESET signal", cpu.id()); ++ cpu.guest_reset() ++ .with_context(|| "Some error occurred in guest reset")?; ++ return Ok(true); ++ } else { ++ error!( ++ "Vcpu{} received unexpected system event with type 0x{:x}, flags 0x{:?}", ++ cpu.id(), ++ event, ++ flags ++ ); ++ } ++ return Ok(false); ++ } ++ VcpuExit::FailEntry(reason, cpuid) => { ++ info!( ++ "Vcpu{} received KVM_EXIT_FAIL_ENTRY signal. the vcpu could not be run due to unknown reasons({})", ++ cpuid, reason ++ ); ++ return Ok(false); ++ } ++ VcpuExit::InternalError => { ++ info!("Vcpu{} received KVM_EXIT_INTERNAL_ERROR signal", cpu.id()); ++ return Ok(false); ++ } ++ r => { ++ return Err(anyhow!(CpuError::VcpuExitReason( ++ cpu.id(), ++ format!("{:?}", r) ++ ))); ++ } ++ } ++ } ++ Err(ref e) => { ++ match e.errno() { ++ libc::EAGAIN => {} ++ libc::EINTR => { ++ self.fd.lock().unwrap().set_kvm_immediate_exit(0); ++ } ++ _ => { ++ return Err(anyhow!(CpuError::UnhandledHypervisorExit( ++ cpu.id(), ++ e.errno() ++ ))); ++ } ++ }; ++ } ++ } ++ } ++ + Ok(true) + } + +@@ -550,13 +681,20 @@ impl CPUHypervisorOps for KvmCpu { + fn set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &Option, ++ boot_config: &CPUBootConfig, + #[cfg(target_arch = "aarch64")] vcpu_config: &CPUFeatures, + ) -> Result<()> { ++ #[cfg(target_arch = "riscv64")] ++ { ++ arch_cpu.lock().unwrap().timer_regs = self.get_timer_regs()?; ++ arch_cpu.lock().unwrap().config_regs = self.get_config_regs()?; ++ } + #[cfg(target_arch = "aarch64")] + return self.arch_set_boot_config(arch_cpu, boot_config, vcpu_config); + #[cfg(target_arch = "x86_64")] + return self.arch_set_boot_config(arch_cpu, boot_config); ++ #[cfg(target_arch = "riscv64")] ++ return self.arch_set_boot_config(arch_cpu, boot_config); + } + + fn get_one_reg(&self, reg_id: u64) -> Result { +@@ -610,10 +748,6 @@ impl CPUHypervisorOps for KvmCpu { + while let Ok(true) = cpu_thread_worker.ready_for_running() { + #[cfg(not(test))] + { +- if is_test_enabled() { +- thread::sleep(Duration::from_millis(5)); +- continue; +- } + if !self + .kvm_vcpu_exec(cpu_thread_worker.thread_cpu.clone()) + .with_context(|| { +@@ -641,6 +775,13 @@ impl CPUHypervisorOps for KvmCpu { + Ok(()) + } + ++ #[cfg(target_arch = "riscv64")] ++ fn set_hypervisor_exit(&self) -> Result<()> { ++ self.fd.lock().unwrap().set_kvm_immediate_exit(1); ++ Ok(()) ++ } ++ ++ #[cfg(not(target_arch = "riscv64"))] + fn set_hypervisor_exit(&self) -> Result<()> { + self.fd.set_kvm_immediate_exit(1); + Ok(()) +@@ -763,6 +904,11 @@ impl KVMInterruptManager { + let irqtype = KVM_ARM_IRQ_TYPE_SPI; + irqtype << KVM_ARM_IRQ_TYPE_SHIFT | irq + } ++ ++ #[cfg(target_arch = "riscv64")] ++ pub fn arch_map_irq(&self, gsi: u32) -> u32 { ++ gsi ++ } + } + + impl LineIrqManager for KVMInterruptManager { +@@ -829,6 +975,10 @@ impl LineIrqManager for KVMInterruptManager { + } + + impl MsiIrqManager for KVMInterruptManager { ++ fn irqfd_enable(&self) -> bool { ++ self.irqfd_cap ++ } ++ + fn allocate_irq(&self, vector: MsiVector) -> Result { + let mut locked_irq_route_table = self.irq_route_table.lock().unwrap(); + let gsi = locked_irq_route_table.allocate_gsi().map_err(|e| { +@@ -888,7 +1038,7 @@ impl MsiIrqManager for KVMInterruptManager { + trace::kvm_trigger_irqfd(irq_fd.as_ref().unwrap()); + irq_fd.unwrap().write(1)?; + } else { +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + let flags: u32 = kvm_bindings::KVM_MSI_VALID_DEVID; + #[cfg(target_arch = "x86_64")] + let flags: u32 = 0; +@@ -984,7 +1134,7 @@ mod test { + } + + fn mmio_read(&self, addr: u64, data: &mut [u8]) -> bool { +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + data[3] = 0x0; + data[2] = 0x0; +@@ -1073,7 +1223,7 @@ mod test { + let cpu = CPU::new(hypervisor_cpu.clone(), 0, x86_cpu, vm.clone()); + // test `set_boot_config` function + assert!(hypervisor_cpu +- .set_boot_config(cpu.arch().clone(), &Some(cpu_config)) ++ .set_boot_config(cpu.arch().clone(), &cpu_config) + .is_ok()); + + // test setup special registers +@@ -1122,7 +1272,7 @@ mod test { + let vcpu_fd = kvm_hyp.vm_fd.as_ref().unwrap().create_vcpu(0).unwrap(); + let hypervisor_cpu = Arc::new(KvmCpu::new( + 0, +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + kvm_hyp.vm_fd.clone(), + vcpu_fd, + )); +diff --git a/hypervisor/src/kvm/riscv64/aia.rs b/hypervisor/src/kvm/riscv64/aia.rs +new file mode 100644 +index 0000000..3c56c2a +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/aia.rs +@@ -0,0 +1,150 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::sync::Arc; ++ ++use anyhow::{Context, Ok, Result}; ++use kvm_ioctls::{DeviceFd, VmFd}; ++ ++use super::KvmDevice; ++use devices::AIAAccess; ++ ++pub struct KvmAIA { ++ fd: DeviceFd, ++ vcpu_count: u32, ++} ++ ++impl KvmAIA { ++ pub fn new(vm_fd: Arc, vcpu_count: u32) -> Result { ++ let mut aia_device = kvm_bindings::kvm_create_device { ++ type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_RISCV_AIA, ++ fd: 0, ++ flags: 0, ++ }; ++ ++ let aia_fd = vm_fd ++ .create_device(&mut aia_device) ++ .expect("Cannot create AIA device, is SSAIA ext. enabled?"); ++ ++ Ok(Self { ++ fd: aia_fd, ++ vcpu_count, ++ }) ++ } ++} ++ ++impl AIAAccess for KvmAIA { ++ fn init_aia(&self, nr_irqs: u32, aia_addr: u64) -> Result<()> { ++ use kvm_bindings::{ ++ KVM_DEV_RISCV_AIA_ADDR_APLIC, KVM_DEV_RISCV_AIA_CONFIG_HART_BITS, ++ KVM_DEV_RISCV_AIA_CONFIG_IDS, KVM_DEV_RISCV_AIA_CONFIG_MODE, ++ KVM_DEV_RISCV_AIA_CONFIG_SRCS, KVM_DEV_RISCV_AIA_CTRL_INIT, KVM_DEV_RISCV_AIA_GRP_ADDR, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, KVM_DEV_RISCV_AIA_GRP_CTRL, ++ }; ++ ++ // Get AIA mode, variants: EMUL, HW_ACCL, AUTO ++ KvmDevice::kvm_device_check( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ KVM_DEV_RISCV_AIA_CONFIG_MODE as u64, ++ ) ++ .unwrap(); ++ ++ // Get number of interrupt IDs ++ KvmDevice::kvm_device_check( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ KVM_DEV_RISCV_AIA_CONFIG_IDS as u64, ++ ) ++ .unwrap(); ++ ++ // Calculate number of interrupt sources, or allocated lines ++ ++ // Set number of interrupt sources ++ KvmDevice::kvm_device_check( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ KVM_DEV_RISCV_AIA_CONFIG_SRCS as u64, ++ ) ++ .unwrap(); ++ ++ KvmDevice::kvm_device_access( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ KVM_DEV_RISCV_AIA_CONFIG_SRCS as u64, ++ &nr_irqs as *const u32 as u64, ++ true, ++ ) ++ .with_context(|| "Failed to set number of irq sources of APLIC")?; ++ ++ // Calculate AIA hart bits ++ ++ // Set AIA hart bits ++ KvmDevice::kvm_device_check( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ KVM_DEV_RISCV_AIA_CONFIG_HART_BITS as u64, ++ ) ++ .unwrap(); ++ ++ // Need complete logic here ++ let max_hart_index = self.vcpu_count as u64 - 1; ++ let hart_bits = std::cmp::max(64 - max_hart_index.leading_zeros(), 1); ++ KvmDevice::kvm_device_access( ++ &self.fd, ++ kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG, ++ u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_HART_BITS), ++ &hart_bits as *const u32 as u64, ++ true, ++ ) ++ .with_context(|| "Failed to set HART index bits for IMSIC")?; ++ ++ // Set AIA device addresses ++ let aplic_addr = ++ aia_addr + (self.vcpu_count * kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE) as u64; ++ KvmDevice::kvm_device_access( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_ADDR, ++ KVM_DEV_RISCV_AIA_ADDR_APLIC as u64, ++ &aplic_addr as *const u64 as u64, ++ true, ++ ) ++ .with_context(|| "Failed to set APLIC base address")?; ++ ++ for i in 0..self.vcpu_count { ++ let imsic = aia_addr + (i * kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE) as u64; ++ KvmDevice::kvm_device_access( ++ &self.fd, ++ kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR, ++ u64::from(i + 1), ++ &imsic as *const u64 as u64, ++ true, ++ ) ++ .with_context(|| "Failed to set IMSIC addr")?; ++ } ++ ++ // Finalize AIA. ++ KvmDevice::kvm_device_access( ++ &self.fd, ++ KVM_DEV_RISCV_AIA_GRP_CTRL, ++ KVM_DEV_RISCV_AIA_CTRL_INIT as u64, ++ 0, ++ true, ++ ) ++ .with_context(|| "KVM failed to finalize AIA") ++ } ++ ++ fn pause(&self) -> Result<()> { ++ // TODO ++ Ok(()) ++ } ++} +diff --git a/hypervisor/src/kvm/riscv64/config_regs.rs b/hypervisor/src/kvm/riscv64/config_regs.rs +new file mode 100644 +index 0000000..37eacd3 +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/config_regs.rs +@@ -0,0 +1,37 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::mem::size_of; ++ ++use kvm_bindings::{kvm_riscv_config, KVM_REG_RISCV, KVM_REG_RISCV_CONFIG, KVM_REG_SIZE_U64}; ++use util::offset_of; ++ ++/// RISCV cpu config register. ++/// See: https://elixir.bootlin.com/linux/v6.0/source/arch/riscv/include/uapi/asm/kvm.h#L49 ++pub enum RISCVConfigRegs { ++ ISA, ++} ++ ++impl Into for RISCVConfigRegs { ++ fn into(self) -> u64 { ++ let reg_offset = match self { ++ RISCVConfigRegs::ISA => { ++ offset_of!(kvm_riscv_config, isa) ++ } ++ }; ++ // calculate reg_id ++ KVM_REG_RISCV as u64 ++ | KVM_REG_SIZE_U64 as u64 ++ | u64::from(KVM_REG_RISCV_CONFIG) ++ | (reg_offset / size_of::()) as u64 ++ } ++} +diff --git a/hypervisor/src/kvm/riscv64/core_regs.rs b/hypervisor/src/kvm/riscv64/core_regs.rs +new file mode 100644 +index 0000000..409c026 +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/core_regs.rs +@@ -0,0 +1,171 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::mem::size_of; ++ ++use kvm_bindings::{ ++ kvm_riscv_core, user_regs_struct, KVM_REG_RISCV, KVM_REG_RISCV_CORE, KVM_REG_SIZE_U64, ++}; ++use util::offset_of; ++ ++/// RISCV cpu core register. ++/// See: https://elixir.bootlin.com/linux/v6.0/source/arch/riscv/include/uapi/asm/kvm.h#L54 ++/// User-mode register state for core dumps, ptrace, sigcontext ++/// See: https://elixir.bootlin.com/linux/v6.0/source/arch/riscv/include/uapi/asm/ptrace.h#L19 ++#[allow(dead_code)] ++pub enum RISCVCoreRegs { ++ PC, ++ RA, ++ SP, ++ GP, ++ TP, ++ T0, ++ T1, ++ T2, ++ S0, ++ S1, ++ A0, ++ A1, ++ A2, ++ A3, ++ A4, ++ A5, ++ A6, ++ A7, ++ S2, ++ S3, ++ S4, ++ S5, ++ S6, ++ S7, ++ S8, ++ S9, ++ S10, ++ S11, ++ T3, ++ T4, ++ T5, ++ T6, ++ MODE, ++} ++ ++impl Into for RISCVCoreRegs { ++ fn into(self) -> u64 { ++ let reg_offset = match self { ++ RISCVCoreRegs::PC => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, pc) ++ } ++ RISCVCoreRegs::RA => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, ra) ++ } ++ RISCVCoreRegs::SP => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, sp) ++ } ++ RISCVCoreRegs::GP => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, gp) ++ } ++ RISCVCoreRegs::TP => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, tp) ++ } ++ RISCVCoreRegs::T0 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t0) ++ } ++ RISCVCoreRegs::T1 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t1) ++ } ++ RISCVCoreRegs::T2 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t2) ++ } ++ RISCVCoreRegs::S0 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s0) ++ } ++ RISCVCoreRegs::S1 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s1) ++ } ++ RISCVCoreRegs::A0 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a0) ++ } ++ RISCVCoreRegs::A1 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a1) ++ } ++ RISCVCoreRegs::A2 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a2) ++ } ++ RISCVCoreRegs::A3 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a3) ++ } ++ RISCVCoreRegs::A4 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a4) ++ } ++ RISCVCoreRegs::A5 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a5) ++ } ++ RISCVCoreRegs::A6 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a6) ++ } ++ RISCVCoreRegs::A7 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, a7) ++ } ++ RISCVCoreRegs::S2 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s2) ++ } ++ RISCVCoreRegs::S3 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s3) ++ } ++ RISCVCoreRegs::S4 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s4) ++ } ++ RISCVCoreRegs::S5 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s5) ++ } ++ RISCVCoreRegs::S6 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s6) ++ } ++ RISCVCoreRegs::S7 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s7) ++ } ++ RISCVCoreRegs::S8 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s8) ++ } ++ RISCVCoreRegs::S9 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s9) ++ } ++ RISCVCoreRegs::S10 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s10) ++ } ++ RISCVCoreRegs::S11 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, s11) ++ } ++ RISCVCoreRegs::T3 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t3) ++ } ++ RISCVCoreRegs::T4 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t4) ++ } ++ RISCVCoreRegs::T5 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t5) ++ } ++ RISCVCoreRegs::T6 => { ++ offset_of!(kvm_riscv_core, regs, user_regs_struct, t6) ++ } ++ RISCVCoreRegs::MODE => { ++ offset_of!(kvm_riscv_core, mode) ++ } ++ }; ++ ++ // calculate reg_id ++ KVM_REG_RISCV as u64 ++ | KVM_REG_SIZE_U64 as u64 ++ | u64::from(KVM_REG_RISCV_CORE) ++ | (reg_offset / size_of::()) as u64 ++ } ++} +diff --git a/hypervisor/src/kvm/riscv64/cpu_caps.rs b/hypervisor/src/kvm/riscv64/cpu_caps.rs +new file mode 100644 +index 0000000..56bad05 +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/cpu_caps.rs +@@ -0,0 +1,38 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use kvm_ioctls::Cap; ++use kvm_ioctls::Kvm; ++ ++// Capabilities for RISC-V cpu. ++#[derive(Debug, Clone)] ++pub struct RISCVCPUCaps { ++ pub irq_chip: bool, ++ pub ioevent_fd: bool, ++ pub irq_fd: bool, ++ pub user_mem: bool, ++ pub mp_state: bool, ++} ++ ++impl RISCVCPUCaps { ++ /// Initialize ArmCPUCaps instance. ++ pub fn init_capabilities() -> Self { ++ let kvm = Kvm::new().unwrap(); ++ RISCVCPUCaps { ++ irq_chip: kvm.check_extension(Cap::Irqchip), ++ ioevent_fd: kvm.check_extension(Cap::Ioeventfd), ++ irq_fd: kvm.check_extension(Cap::Irqfd), ++ user_mem: kvm.check_extension(Cap::UserMemory), ++ mp_state: kvm.check_extension(Cap::MpState), ++ } ++ } ++} +diff --git a/hypervisor/src/kvm/riscv64/mod.rs b/hypervisor/src/kvm/riscv64/mod.rs +new file mode 100644 +index 0000000..c14b6f2 +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/mod.rs +@@ -0,0 +1,404 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++// mod aia_csrs; ++mod config_regs; ++mod core_regs; ++pub mod cpu_caps; ++// mod csrs; ++pub mod aia; ++mod timer_regs; ++ ++use std::sync::{Arc, Mutex}; ++ ++use anyhow::{Context, Result}; ++use kvm_bindings::*; ++use kvm_ioctls::DeviceFd; ++use vmm_sys_util::{ioctl_ioc_nr, ioctl_iow_nr, ioctl_iowr_nr}; ++ ++use self::config_regs::RISCVConfigRegs; ++use self::core_regs::RISCVCoreRegs; ++use self::timer_regs::RISCVTimerRegs; ++use crate::kvm::{KvmCpu, KvmHypervisor}; ++use cpu::{ArchCPU, CPUBootConfig, RegsIndex, CPU}; ++ ++pub const KVM_MAX_CPREG_ENTRIES: usize = 500; ++ ++ioctl_iow_nr!(KVM_GET_DEVICE_ATTR, KVMIO, 0xe2, kvm_device_attr); ++ioctl_iow_nr!(KVM_GET_ONE_REG, KVMIO, 0xab, kvm_one_reg); ++ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg); ++ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list); ++// ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init); ++ ++/// A wrapper for kvm_based device check and access. ++pub struct KvmDevice; ++impl KvmDevice { ++ fn kvm_device_check(fd: &DeviceFd, group: u32, attr: u64) -> Result<()> { ++ let attr = kvm_bindings::kvm_device_attr { ++ group, ++ attr, ++ addr: 0, ++ flags: 0, ++ }; ++ fd.has_device_attr(&attr) ++ .with_context(|| "Failed to check device attributes.")?; ++ Ok(()) ++ } ++ ++ pub fn kvm_device_access( ++ fd: &DeviceFd, ++ group: u32, ++ attr: u64, ++ addr: u64, ++ write: bool, ++ ) -> Result<()> { ++ let attr = kvm_bindings::kvm_device_attr { ++ group, ++ attr, ++ addr, ++ flags: 0, ++ }; ++ ++ if write { ++ fd.set_device_attr(&attr) ++ .with_context(|| "Failed to set device attributes.")?; ++ } else { ++ let mut attr = attr; ++ unsafe { fd.get_device_attr(&mut attr) } ++ .with_context(|| "Failed to get device attributes.")?; ++ }; ++ ++ Ok(()) ++ } ++} ++ ++impl KvmHypervisor { ++ pub fn arch_init(&self) -> Result<()> { ++ Ok(()) ++ } ++} ++ ++impl KvmCpu { ++ pub fn arch_init_pmu(&self) -> Result<()> { ++ // let pmu_attr = kvm_device_attr { ++ // group: KVM_ARM_VCPU_PMU_V3_CTRL, ++ // attr: KVM_ARM_VCPU_PMU_V3_INIT as u64, ++ // addr: 0, ++ // flags: 0, ++ // }; ++ // // SAFETY: The fd can be guaranteed to be legal during creation. ++ // let vcpu_device = unsafe { DeviceFd::from_raw_fd(self.fd.as_raw_fd()) }; ++ // vcpu_device ++ // .has_device_attr(&pmu_attr) ++ // .with_context(|| "Kernel does not support PMU for vCPU")?; ++ // // Set IRQ 23, PPI 7 for PMU. ++ // let irq = PMU_INTR + PPI_BASE; ++ // let pmu_irq_attr = kvm_device_attr { ++ // group: KVM_ARM_VCPU_PMU_V3_CTRL, ++ // attr: KVM_ARM_VCPU_PMU_V3_IRQ as u64, ++ // addr: &irq as *const u32 as u64, ++ // flags: 0, ++ // }; ++ ++ // vcpu_device ++ // .set_device_attr(&pmu_irq_attr) ++ // .with_context(|| "Failed to set IRQ for PMU")?; ++ // // Init PMU after setting IRQ. ++ // vcpu_device ++ // .set_device_attr(&pmu_attr) ++ // .with_context(|| "Failed to enable PMU for vCPU")?; ++ // // forget `vcpu_device` to avoid fd close on exit, as DeviceFd is backed by File. ++ // forget(vcpu_device); ++ ++ // TODO ++ ++ Ok(()) ++ } ++ ++ pub fn arch_vcpu_init(&self) -> Result<()> { ++ // self.fd ++ // .vcpu_init(&self.kvi.lock().unwrap()) ++ // .with_context(|| "Failed to init kvm vcpu") ++ Ok(()) ++ } ++ ++ pub fn arch_set_boot_config( ++ &self, ++ arch_cpu: Arc>, ++ boot_config: &CPUBootConfig, ++ ) -> Result<()> { ++ arch_cpu.lock().unwrap().set_core_reg(boot_config); ++ ++ self.arch_vcpu_init()?; ++ ++ Ok(()) ++ } ++ ++ fn get_one_reg(&self, reg_id: u64) -> Result { ++ let mut val = [0_u8; 16]; ++ self.fd.lock().unwrap().get_one_reg(reg_id, &mut val)?; ++ Ok(u128::from_le_bytes(val)) ++ } ++ ++ fn set_one_reg(&self, reg_id: u64, val: u128) -> Result<()> { ++ self.fd ++ .lock() ++ .unwrap() ++ .set_one_reg(reg_id, &val.to_le_bytes())?; ++ Ok(()) ++ } ++ ++ pub fn arch_get_one_reg(&self, reg_id: u64) -> Result { ++ self.get_one_reg(reg_id) ++ } ++ ++ pub fn arch_get_regs( ++ &self, ++ arch_cpu: Arc>, ++ regs_index: RegsIndex, ++ ) -> Result<()> { ++ let mut locked_arch_cpu = arch_cpu.lock().unwrap(); ++ ++ match regs_index { ++ RegsIndex::CoreRegs => { ++ locked_arch_cpu.core_regs = self.get_core_regs()?; ++ } ++ RegsIndex::TimerRegs => { ++ locked_arch_cpu.timer_regs = self.get_timer_regs()?; ++ } ++ RegsIndex::ConfigRegs => { ++ locked_arch_cpu.config_regs = self.get_config_regs()?; ++ } ++ RegsIndex::MpState => { ++ if self.caps.mp_state { ++ let mut mp_state = self.fd.lock().unwrap().get_mp_state()?; ++ if mp_state.mp_state != KVM_MP_STATE_STOPPED { ++ mp_state.mp_state = KVM_MP_STATE_RUNNABLE; ++ } ++ locked_arch_cpu.mp_state = mp_state; ++ } ++ } ++ RegsIndex::AiaCsrs | RegsIndex::Csrs => {} ++ } ++ ++ Ok(()) ++ } ++ ++ pub fn arch_set_regs( ++ &self, ++ arch_cpu: Arc>, ++ regs_index: RegsIndex, ++ ) -> Result<()> { ++ let locked_arch_cpu = arch_cpu.lock().unwrap(); ++ let apic_id = locked_arch_cpu.apic_id; ++ match regs_index { ++ RegsIndex::CoreRegs => { ++ self.set_core_regs(locked_arch_cpu.core_regs) ++ .with_context(|| format!("Failed to set core register for CPU {}", apic_id))?; ++ } ++ RegsIndex::TimerRegs => { ++ self.set_timer_regs(locked_arch_cpu.timer_regs) ++ .with_context(|| format!("Failed to set timer register for CPU {}", apic_id))?; ++ } ++ RegsIndex::ConfigRegs => { ++ self.set_config_regs(locked_arch_cpu.config_regs) ++ .with_context(|| { ++ format!("Failed to set config register for CPU {}", apic_id) ++ })?; ++ } ++ RegsIndex::MpState => { ++ if self.caps.mp_state { ++ self.fd ++ .lock() ++ .unwrap() ++ .set_mp_state(locked_arch_cpu.mp_state) ++ .with_context(|| format!("Failed to set mpstate for CPU {}", apic_id))?; ++ } ++ } ++ RegsIndex::AiaCsrs | RegsIndex::Csrs => {} ++ } ++ ++ Ok(()) ++ } ++ ++ /// Returns the vcpu's current `core_register`. ++ /// ++ /// The register state is gotten from `KVM_GET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ fn get_core_regs(&self) -> Result { ++ // vcpu_fd.set_one_reg(RISCVCoreRegs::PC.into(), core_regs.regs.pc as u128)?; ++ // vcpu_fd.set_one_reg(RISCVCoreRegs::A0.into(), core_regs.regs.a0 as u128)?; ++ // vcpu_fd.set_one_reg(RISCVCoreRegs::A1.into(), core_regs.regs.a1 as u128)?; ++ let mut core_regs = kvm_riscv_core::default(); ++ ++ core_regs.regs.pc = self.get_one_reg(RISCVCoreRegs::PC.into())? as u64; ++ core_regs.regs.ra = self.get_one_reg(RISCVCoreRegs::RA.into())? as u64; ++ core_regs.regs.sp = self.get_one_reg(RISCVCoreRegs::SP.into())? as u64; ++ core_regs.regs.gp = self.get_one_reg(RISCVCoreRegs::GP.into())? as u64; ++ core_regs.regs.tp = self.get_one_reg(RISCVCoreRegs::TP.into())? as u64; ++ core_regs.regs.t0 = self.get_one_reg(RISCVCoreRegs::T0.into())? as u64; ++ core_regs.regs.t1 = self.get_one_reg(RISCVCoreRegs::T1.into())? as u64; ++ core_regs.regs.t2 = self.get_one_reg(RISCVCoreRegs::T2.into())? as u64; ++ core_regs.regs.t3 = self.get_one_reg(RISCVCoreRegs::T3.into())? as u64; ++ core_regs.regs.t4 = self.get_one_reg(RISCVCoreRegs::T4.into())? as u64; ++ core_regs.regs.t5 = self.get_one_reg(RISCVCoreRegs::T5.into())? as u64; ++ core_regs.regs.t6 = self.get_one_reg(RISCVCoreRegs::T6.into())? as u64; ++ core_regs.regs.a0 = self.get_one_reg(RISCVCoreRegs::A0.into())? as u64; ++ core_regs.regs.a1 = self.get_one_reg(RISCVCoreRegs::A1.into())? as u64; ++ core_regs.regs.a2 = self.get_one_reg(RISCVCoreRegs::A2.into())? as u64; ++ core_regs.regs.a3 = self.get_one_reg(RISCVCoreRegs::A3.into())? as u64; ++ core_regs.regs.a4 = self.get_one_reg(RISCVCoreRegs::A4.into())? as u64; ++ core_regs.regs.a5 = self.get_one_reg(RISCVCoreRegs::A5.into())? as u64; ++ core_regs.regs.a6 = self.get_one_reg(RISCVCoreRegs::A6.into())? as u64; ++ core_regs.regs.a7 = self.get_one_reg(RISCVCoreRegs::A7.into())? as u64; ++ core_regs.regs.s0 = self.get_one_reg(RISCVCoreRegs::S0.into())? as u64; ++ core_regs.regs.s1 = self.get_one_reg(RISCVCoreRegs::S1.into())? as u64; ++ core_regs.regs.s2 = self.get_one_reg(RISCVCoreRegs::S2.into())? as u64; ++ core_regs.regs.s3 = self.get_one_reg(RISCVCoreRegs::S3.into())? as u64; ++ core_regs.regs.s4 = self.get_one_reg(RISCVCoreRegs::S4.into())? as u64; ++ core_regs.regs.s5 = self.get_one_reg(RISCVCoreRegs::S5.into())? as u64; ++ core_regs.regs.s6 = self.get_one_reg(RISCVCoreRegs::S6.into())? as u64; ++ core_regs.regs.s7 = self.get_one_reg(RISCVCoreRegs::S7.into())? as u64; ++ core_regs.regs.s8 = self.get_one_reg(RISCVCoreRegs::S8.into())? as u64; ++ core_regs.regs.s9 = self.get_one_reg(RISCVCoreRegs::S9.into())? as u64; ++ core_regs.regs.s10 = self.get_one_reg(RISCVCoreRegs::S10.into())? as u64; ++ core_regs.regs.s11 = self.get_one_reg(RISCVCoreRegs::S11.into())? as u64; ++ ++ Ok(core_regs) ++ } ++ ++ /// Sets the vcpu's current "core_register" ++ /// ++ /// The register state is gotten from `KVM_SET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ /// * `core_regs` - kvm_regs state to be written. ++ fn set_core_regs(&self, core_regs: kvm_riscv_core) -> Result<()> { ++ self.set_one_reg(RISCVCoreRegs::PC.into(), core_regs.regs.pc as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::RA.into(), core_regs.regs.ra as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::SP.into(), core_regs.regs.sp as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::GP.into(), core_regs.regs.gp as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::TP.into(), core_regs.regs.tp as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T0.into(), core_regs.regs.t0 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T1.into(), core_regs.regs.t1 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T2.into(), core_regs.regs.t2 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T3.into(), core_regs.regs.t3 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T4.into(), core_regs.regs.t4 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T5.into(), core_regs.regs.t5 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::T6.into(), core_regs.regs.t6 as u128)?; ++ self.set_one_reg(RISCVCoreRegs::A0.into(), core_regs.regs.a0 as u128)?; ++ self.set_one_reg(RISCVCoreRegs::A1.into(), core_regs.regs.a1 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A2.into(), core_regs.regs.a2 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A3.into(), core_regs.regs.a3 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A4.into(), core_regs.regs.a4 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A5.into(), core_regs.regs.a5 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A6.into(), core_regs.regs.a6 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::A7.into(), core_regs.regs.a7 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S0.into(), core_regs.regs.s0 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S1.into(), core_regs.regs.s1 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S2.into(), core_regs.regs.s2 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S3.into(), core_regs.regs.s3 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S4.into(), core_regs.regs.s4 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S5.into(), core_regs.regs.s5 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S6.into(), core_regs.regs.s6 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S7.into(), core_regs.regs.s7 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S8.into(), core_regs.regs.s8 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S9.into(), core_regs.regs.s9 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S10.into(), core_regs.regs.s10 as u128)?; ++ //self.set_one_reg(RISCVCoreRegs::S11.into(), core_regs.regs.s11 as u128)?; ++ ++ Ok(()) ++ } ++ ++ /// Returns the vcpu's current `config_register`. ++ /// ++ /// The register state is gotten from `KVM_GET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ pub fn get_config_regs(&self) -> Result { ++ let mut config_regs = kvm_riscv_config::default(); ++ config_regs.isa = self.get_one_reg(RISCVConfigRegs::ISA.into())? as u64; ++ ++ Ok(config_regs) ++ } ++ ++ /// Sets the vcpu's current "config_register" ++ /// ++ /// The register state is gotten from `KVM_SET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ /// * `config_regs` - kvm_regs state to be written. ++ pub fn set_config_regs(&self, config_regs: kvm_riscv_config) -> Result<()> { ++ self.set_one_reg(RISCVConfigRegs::ISA.into(), config_regs.isa as u128)?; ++ Ok(()) ++ } ++ ++ /// Returns the vcpu's current `timer_register`. ++ /// ++ /// The register state is gotten from `KVM_GET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ pub fn get_timer_regs(&self) -> Result { ++ let mut timer_regs = kvm_riscv_timer::default(); ++ timer_regs.frequency = self.get_one_reg(RISCVTimerRegs::FREQUENCY.into())? as u64; ++ timer_regs.time = self.get_one_reg(RISCVTimerRegs::TIME.into())? as u64; ++ timer_regs.compare = self.get_one_reg(RISCVTimerRegs::COMPARE.into())? as u64; ++ timer_regs.state = self.get_one_reg(RISCVTimerRegs::STATE.into())? as u64; ++ ++ Ok(timer_regs) ++ } ++ ++ /// Sets the vcpu's current "timer_register" ++ /// ++ /// The register state is gotten from `KVM_SET_ONE_REG` api in KVM. ++ /// ++ /// # Arguments ++ /// ++ /// * `vcpu_fd` - the VcpuFd in KVM mod. ++ /// * `timer_regs` - kvm_regs state to be written. ++ pub fn set_timer_regs(&self, timer_regs: kvm_riscv_timer) -> Result<()> { ++ self.set_one_reg( ++ RISCVTimerRegs::FREQUENCY.into(), ++ timer_regs.frequency as u128, ++ )?; ++ self.set_one_reg(RISCVTimerRegs::TIME.into(), timer_regs.time as u128)?; ++ self.set_one_reg(RISCVTimerRegs::COMPARE.into(), timer_regs.compare as u128)?; ++ self.set_one_reg(RISCVTimerRegs::STATE.into(), timer_regs.state as u128)?; ++ Ok(()) ++ } ++ ++ pub fn arch_put_register(&self, cpu: Arc) -> Result<()> { ++ let arch_cpu = &cpu.arch_cpu; ++ self.arch_set_regs(arch_cpu.clone(), RegsIndex::CoreRegs)?; ++ //self.arch_set_regs(arch_cpu.clone(), RegsIndex::TimerRegs)?; ++ //self.arch_set_regs(arch_cpu.clone(), RegsIndex::ConfigRegs)?; ++ self.arch_set_regs(arch_cpu.clone(), RegsIndex::MpState)?; ++ // Put AIA and CSR ++ Ok(()) ++ } ++ ++ pub fn arch_reset_vcpu(&self, cpu: Arc) -> Result<()> { ++ cpu.arch_cpu.lock().unwrap().set(&cpu.boot_state()); ++ self.arch_put_register(cpu) ++ } ++} +diff --git a/hypervisor/src/kvm/riscv64/timer_regs.rs b/hypervisor/src/kvm/riscv64/timer_regs.rs +new file mode 100644 +index 0000000..c0a2944 +--- /dev/null ++++ b/hypervisor/src/kvm/riscv64/timer_regs.rs +@@ -0,0 +1,50 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::mem::size_of; ++ ++use kvm_bindings::{kvm_riscv_timer, KVM_REG_RISCV, KVM_REG_RISCV_TIMER, KVM_REG_SIZE_U64}; ++use util::offset_of; ++ ++/// RISCV cpu time register. ++/// See: https://elixir.bootlin.com/linux/v6.0/source/arch/riscv/include/uapi/asm/kvm.h#L78 ++pub enum RISCVTimerRegs { ++ FREQUENCY, ++ TIME, ++ COMPARE, ++ STATE, ++} ++ ++impl Into for RISCVTimerRegs { ++ fn into(self) -> u64 { ++ let reg_offset = match self { ++ RISCVTimerRegs::FREQUENCY => { ++ offset_of!(kvm_riscv_timer, frequency) ++ } ++ RISCVTimerRegs::TIME => { ++ offset_of!(kvm_riscv_timer, time) ++ } ++ RISCVTimerRegs::COMPARE => { ++ offset_of!(kvm_riscv_timer, compare) ++ } ++ RISCVTimerRegs::STATE => { ++ offset_of!(kvm_riscv_timer, state) ++ } ++ }; ++ ++ // calculate reg_id ++ KVM_REG_RISCV as u64 ++ | KVM_REG_SIZE_U64 as u64 ++ | u64::from(KVM_REG_RISCV_TIMER) ++ | (reg_offset / size_of::()) as u64 ++ } ++} +diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs +index e7d08ef..7d7e7b5 100644 +--- a/hypervisor/src/kvm/x86_64/mod.rs ++++ b/hypervisor/src/kvm/x86_64/mod.rs +@@ -84,7 +84,7 @@ impl KvmCpu { + pub fn arch_set_boot_config( + &self, + arch_cpu: Arc>, +- boot_config: &Option, ++ boot_config: &CPUBootConfig, + ) -> Result<()> { + let mut locked_arch_cpu = arch_cpu.lock().unwrap(); + let apic_id = locked_arch_cpu.apic_id; +@@ -93,14 +93,12 @@ impl KvmCpu { + .get_lapic() + .with_context(|| format!("Failed to get lapic for CPU {}/KVM", apic_id))?; + locked_arch_cpu.setup_lapic(lapic)?; ++ locked_arch_cpu.setup_regs(boot_config); + let sregs = self + .fd + .get_sregs() + .with_context(|| format!("Failed to get sregs for CPU {}/KVM", apic_id))?; +- if let Some(cfg) = boot_config { +- locked_arch_cpu.setup_regs(cfg); +- locked_arch_cpu.setup_sregs(sregs, cfg)?; +- } ++ locked_arch_cpu.setup_sregs(sregs, boot_config)?; + locked_arch_cpu.setup_fpu(); + locked_arch_cpu.setup_msrs(); + +diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs +index f53f232..84e5b18 100644 +--- a/hypervisor/src/lib.rs ++++ b/hypervisor/src/lib.rs +@@ -14,6 +14,8 @@ + + pub mod error; + pub mod kvm; ++#[cfg(not(target_arch = "riscv64"))] ++pub mod test; + + pub use error::HypervisorError; + +@@ -26,6 +28,8 @@ use kvm_ioctls::DeviceFd; + use address_space::AddressSpace; + use cpu::CPUHypervisorOps; + use devices::IrqManager; ++#[cfg(target_arch = "riscv64")] ++use devices::{AIAConfig, InterruptController}; + #[cfg(target_arch = "aarch64")] + use devices::{ICGICConfig, InterruptController}; + use machine_manager::machine::HypervisorType; +@@ -50,6 +54,12 @@ pub trait HypervisorOps: Send + Sync + Any { + #[cfg(target_arch = "x86_64")] + fn create_interrupt_controller(&mut self) -> Result<()>; + ++ #[cfg(target_arch = "riscv64")] ++ fn create_interrupt_controller( ++ &mut self, ++ aia_conf: &AIAConfig, ++ ) -> Result>; ++ + fn create_hypervisor_cpu(&self, vcpu_id: u8) + -> Result>; + +diff --git a/machine_manager/src/config/ramfb.rs b/hypervisor/src/test/aarch64/mod.rs +similarity index 55% +rename from machine_manager/src/config/ramfb.rs +rename to hypervisor/src/test/aarch64/mod.rs +index 8473c1d..0b5317a 100644 +--- a/machine_manager/src/config/ramfb.rs ++++ b/hypervisor/src/test/aarch64/mod.rs +@@ -1,4 +1,4 @@ +-// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. + // + // StratoVirt is licensed under Mulan PSL v2. + // You can use this software according to the terms and conditions of the Mulan +@@ -10,15 +10,14 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use anyhow::Result; ++use devices::{GICv3Access, GICv3ItsAccess}; + +-use crate::config::CmdParser; ++#[derive(Default)] ++pub struct TestGicv3 {} + +-pub fn parse_ramfb(cfg_args: &str) -> Result { +- let mut cmd_parser = CmdParser::new("ramfb"); +- cmd_parser.push("").push("install").push("id"); +- cmd_parser.parse(cfg_args)?; ++impl GICv3Access for TestGicv3 {} + +- let install = cmd_parser.get_value::("install")?.unwrap_or(false); +- Ok(install) +-} ++#[derive(Default)] ++pub struct TestGicv3Its {} ++ ++impl GICv3ItsAccess for TestGicv3Its {} +diff --git a/hypervisor/src/test/listener.rs b/hypervisor/src/test/listener.rs +new file mode 100644 +index 0000000..15a65dd +--- /dev/null ++++ b/hypervisor/src/test/listener.rs +@@ -0,0 +1,40 @@ ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use address_space::Listener; ++ ++#[derive(Default, Clone)] ++pub struct TestMemoryListener { ++ enabled: bool, ++} ++ ++impl Listener for TestMemoryListener { ++ /// Get default priority. ++ fn priority(&self) -> i32 { ++ 10_i32 ++ } ++ ++ /// Is this listener enabled to call. ++ fn enabled(&self) -> bool { ++ self.enabled ++ } ++ ++ /// Enable listener for address space. ++ fn enable(&mut self) { ++ self.enabled = true; ++ } ++ ++ /// Disable listener for address space. ++ fn disable(&mut self) { ++ self.enabled = false; ++ } ++} +diff --git a/hypervisor/src/test/mod.rs b/hypervisor/src/test/mod.rs +new file mode 100644 +index 0000000..8e4697a +--- /dev/null ++++ b/hypervisor/src/test/mod.rs +@@ -0,0 +1,417 @@ ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++#[cfg(target_arch = "aarch64")] ++mod aarch64; ++mod listener; ++ ++use std::collections::HashMap; ++use std::sync::atomic::AtomicBool; ++use std::sync::{Arc, Barrier, Condvar, Mutex}; ++use std::thread; ++use std::time::Duration; ++ ++use anyhow::{anyhow, Context, Result}; ++use kvm_ioctls::DeviceFd; ++use log::info; ++use vmm_sys_util::eventfd::EventFd; ++ ++#[cfg(target_arch = "aarch64")] ++use self::aarch64::{TestGicv3, TestGicv3Its}; ++use self::listener::TestMemoryListener; ++use super::HypervisorOps; ++use address_space::{AddressSpace, Listener}; ++#[cfg(target_arch = "aarch64")] ++use cpu::CPUFeatures; ++use cpu::{ ++ ArchCPU, CPUBootConfig, CPUHypervisorOps, CPUThreadWorker, CpuError, CpuLifecycleState, ++ RegsIndex, CPU, ++}; ++use devices::{pci::MsiVector, IrqManager, LineIrqManager, MsiIrqManager, TriggerMode}; ++#[cfg(target_arch = "aarch64")] ++use devices::{GICVersion, GICv3, ICGICConfig, InterruptController, GIC_IRQ_INTERNAL}; ++use machine_manager::machine::HypervisorType; ++use migration::{MigrateMemSlot, MigrateOps}; ++use util::test_helper::{IntxInfo, MsixMsg, TEST_INTX_LIST, TEST_MSIX_LIST}; ++ ++pub struct TestHypervisor {} ++ ++impl TestHypervisor { ++ pub fn new() -> Result { ++ Ok(TestHypervisor {}) ++ } ++ ++ fn create_memory_listener(&self) -> Arc> { ++ Arc::new(Mutex::new(TestMemoryListener::default())) ++ } ++} ++ ++impl HypervisorOps for TestHypervisor { ++ fn get_hypervisor_type(&self) -> HypervisorType { ++ HypervisorType::Test ++ } ++ ++ fn init_machine( ++ &self, ++ #[cfg(target_arch = "x86_64")] _sys_io: &Arc, ++ sys_mem: &Arc, ++ ) -> Result<()> { ++ sys_mem ++ .register_listener(self.create_memory_listener()) ++ .with_context(|| "Failed to register hypervisor listener for memory space.") ++ } ++ ++ #[cfg(target_arch = "aarch64")] ++ fn create_interrupt_controller( ++ &mut self, ++ gic_conf: &ICGICConfig, ++ ) -> Result> { ++ gic_conf.check_sanity()?; ++ ++ let create_gicv3 = || { ++ let gicv3 = Arc::new(GICv3::new( ++ Arc::new(TestGicv3::default()), ++ Arc::new(TestGicv3Its::default()), ++ gic_conf, ++ )?); ++ ++ Ok(Arc::new(InterruptController::new(gicv3))) ++ }; ++ ++ match &gic_conf.version { ++ Some(GICVersion::GICv3) => create_gicv3(), ++ Some(GICVersion::GICv2) => Err(anyhow!("MST doesn't support Gicv2.")), ++ // Try v3 by default if no version specified. ++ None => create_gicv3(), ++ } ++ } ++ ++ #[cfg(target_arch = "x86_64")] ++ fn create_interrupt_controller(&mut self) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn create_hypervisor_cpu( ++ &self, ++ vcpu_id: u8, ++ ) -> Result> { ++ Ok(Arc::new(TestCpu::new(vcpu_id))) ++ } ++ ++ fn create_irq_manager(&mut self) -> Result { ++ let test_irq_manager = Arc::new(TestInterruptManager {}); ++ Ok(IrqManager { ++ line_irq_manager: Some(test_irq_manager.clone()), ++ msi_irq_manager: Some(test_irq_manager), ++ }) ++ } ++ ++ fn create_vfio_device(&self) -> Option { ++ None ++ } ++} ++ ++pub struct TestCpu { ++ #[allow(unused)] ++ id: u8, ++} ++ ++impl TestCpu { ++ pub fn new(vcpu_id: u8) -> Self { ++ Self { id: vcpu_id } ++ } ++} ++ ++impl CPUHypervisorOps for TestCpu { ++ fn get_hypervisor_type(&self) -> HypervisorType { ++ HypervisorType::Test ++ } ++ ++ fn init_pmu(&self) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn vcpu_init(&self) -> Result<()> { ++ Ok(()) ++ } ++ ++ #[allow(unused)] ++ fn set_boot_config( ++ &self, ++ arch_cpu: Arc>, ++ boot_config: &CPUBootConfig, ++ #[cfg(target_arch = "aarch64")] _vcpu_config: &CPUFeatures, ++ ) -> Result<()> { ++ #[cfg(target_arch = "aarch64")] ++ { ++ arch_cpu.lock().unwrap().mpidr = self.id as u64; ++ arch_cpu.lock().unwrap().set_core_reg(boot_config); ++ } ++ Ok(()) ++ } ++ ++ fn get_one_reg(&self, _reg_id: u64) -> Result { ++ Err(anyhow!("MST does not support getting one reg.")) ++ } ++ ++ fn get_regs(&self, _arch_cpu: Arc>, _regs_index: RegsIndex) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn set_regs(&self, _arch_cpu: Arc>, _regs_index: RegsIndex) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn put_register(&self, _cpu: Arc) -> Result<()> { ++ Err(anyhow!("Test does not support putting register.")) ++ } ++ ++ fn reset_vcpu(&self, cpu: Arc) -> Result<()> { ++ cpu.arch_cpu.lock().unwrap().set(&cpu.boot_state()); ++ Ok(()) ++ } ++ ++ fn vcpu_exec( ++ &self, ++ cpu_thread_worker: CPUThreadWorker, ++ thread_barrier: Arc, ++ ) -> Result<()> { ++ cpu_thread_worker.init_local_thread_vcpu(); ++ cpu_thread_worker.thread_cpu.set_tid(None); ++ ++ // Wait for all vcpu to complete the running ++ // environment initialization. ++ thread_barrier.wait(); ++ ++ info!("Test vcpu{} start running", cpu_thread_worker.thread_cpu.id); ++ while let Ok(true) = cpu_thread_worker.ready_for_running() { ++ thread::sleep(Duration::from_millis(5)); ++ continue; ++ } ++ ++ // The vcpu thread is about to exit, marking the state ++ // of the CPU state as Stopped. ++ let (cpu_state, cvar) = &*cpu_thread_worker.thread_cpu.state; ++ *cpu_state.lock().unwrap() = CpuLifecycleState::Stopped; ++ cvar.notify_one(); ++ ++ Ok(()) ++ } ++ ++ fn set_hypervisor_exit(&self) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn pause( ++ &self, ++ _task: Arc>>>, ++ _state: Arc<(Mutex, Condvar)>, ++ _pause_signal: Arc, ++ ) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn resume( ++ &self, ++ _state: Arc<(Mutex, Condvar)>, ++ _pause_signal: Arc, ++ ) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn destroy( ++ &self, ++ _task: Arc>>>, ++ state: Arc<(Mutex, Condvar)>, ++ ) -> Result<()> { ++ let (cpu_state, cvar) = &*state; ++ let mut locked_cpu_state = cpu_state.lock().unwrap(); ++ if *locked_cpu_state == CpuLifecycleState::Running { ++ *locked_cpu_state = CpuLifecycleState::Stopping; ++ } else if *locked_cpu_state == CpuLifecycleState::Stopped ++ || *locked_cpu_state == CpuLifecycleState::Paused ++ { ++ return Ok(()); ++ } ++ drop(locked_cpu_state); ++ ++ let mut locked_cpu_state = cpu_state.lock().unwrap(); ++ locked_cpu_state = cvar ++ .wait_timeout(locked_cpu_state, Duration::from_millis(10)) ++ .unwrap() ++ .0; ++ ++ if *locked_cpu_state == CpuLifecycleState::Stopped { ++ Ok(()) ++ } else { ++ Err(anyhow!(CpuError::DestroyVcpu(format!( ++ "VCPU still in {:?} state", ++ *locked_cpu_state ++ )))) ++ } ++ } ++} ++ ++impl MigrateOps for TestHypervisor { ++ fn get_mem_slots(&self) -> Arc>> { ++ Arc::new(Mutex::new(HashMap::new())) ++ } ++ ++ fn get_dirty_log(&self, _slot: u32, _mem_size: u64) -> Result> { ++ Err(anyhow!( ++ "Failed to get dirty log, mst doesn't support migration feature." ++ )) ++ } ++ ++ fn start_dirty_log(&self) -> Result<()> { ++ Err(anyhow!( ++ "Failed to start dirty log, mst doesn't support migration feature." ++ )) ++ } ++ ++ fn stop_dirty_log(&self) -> Result<()> { ++ Err(anyhow!( ++ "Failed to stop dirty log, mst doesn't support migration feature." ++ )) ++ } ++ ++ fn register_instance(&self) -> Result<()> { ++ Ok(()) ++ } ++} ++ ++struct TestInterruptManager {} ++ ++impl TestInterruptManager { ++ #[cfg(target_arch = "x86_64")] ++ pub fn arch_map_irq(&self, gsi: u32) -> u32 { ++ gsi ++ } ++ ++ #[cfg(target_arch = "aarch64")] ++ pub fn arch_map_irq(&self, gsi: u32) -> u32 { ++ gsi + GIC_IRQ_INTERNAL ++ } ++ ++ pub fn add_msix_msg(addr: u64, data: u32) { ++ let new_msg = MsixMsg::new(addr, data); ++ let mut msix_list_lock = TEST_MSIX_LIST.lock().unwrap(); ++ ++ for msg in msix_list_lock.iter() { ++ if new_msg.addr == msg.addr && new_msg.data == msg.data { ++ return; ++ } ++ } ++ ++ msix_list_lock.push(new_msg); ++ } ++} ++ ++impl LineIrqManager for TestInterruptManager { ++ fn irqfd_enable(&self) -> bool { ++ false ++ } ++ ++ fn register_irqfd( ++ &self, ++ _irq_fd: Arc, ++ _irq: u32, ++ _trigger_mode: TriggerMode, ++ ) -> Result<()> { ++ Err(anyhow!( ++ "Failed to register irqfd, mst doesn't support irqfd feature." ++ )) ++ } ++ ++ fn unregister_irqfd(&self, _irq_fd: Arc, _irq: u32) -> Result<()> { ++ Err(anyhow!( ++ "Failed to unregister irqfd, mst doesn't support irqfd feature." ++ )) ++ } ++ ++ fn set_level_irq(&self, gsi: u32, level: bool) -> Result<()> { ++ let physical_irq = self.arch_map_irq(gsi); ++ let level: i8 = if level { 1 } else { 0 }; ++ ++ let mut intx_list_lock = TEST_INTX_LIST.lock().unwrap(); ++ ++ for intx in intx_list_lock.iter_mut() { ++ if intx.irq == physical_irq { ++ intx.level = level; ++ return Ok(()); ++ } ++ } ++ ++ let new_intx = IntxInfo::new(physical_irq, level); ++ intx_list_lock.push(new_intx); ++ Ok(()) ++ } ++ ++ fn set_edge_irq(&self, _gsi: u32) -> Result<()> { ++ Ok(()) ++ } ++ ++ fn write_irqfd(&self, _irq_fd: Arc) -> Result<()> { ++ Err(anyhow!( ++ "Failed to write irqfd, mst doesn't support irqfd feature." ++ )) ++ } ++} ++ ++impl MsiIrqManager for TestInterruptManager { ++ fn irqfd_enable(&self) -> bool { ++ false ++ } ++ ++ fn allocate_irq(&self, _vector: MsiVector) -> Result { ++ Err(anyhow!( ++ "Failed to allocate irq, mst doesn't support irq routing feature." ++ )) ++ } ++ ++ fn release_irq(&self, _irq: u32) -> Result<()> { ++ Err(anyhow!( ++ "Failed to release irq, mst doesn't support irq routing feature." ++ )) ++ } ++ ++ fn register_irqfd(&self, _irq_fd: Arc, _irq: u32) -> Result<()> { ++ Err(anyhow!( ++ "Failed to register msi irqfd, mst doesn't support irqfd feature." ++ )) ++ } ++ ++ fn unregister_irqfd(&self, _irq_fd: Arc, _irq: u32) -> Result<()> { ++ Err(anyhow!( ++ "Failed to unregister msi irqfd, mst doesn't support irqfd feature." ++ )) ++ } ++ ++ fn trigger( ++ &self, ++ _irq_fd: Option>, ++ vector: MsiVector, ++ _dev_id: u32, ++ ) -> Result<()> { ++ let data = vector.msg_data; ++ let mut addr: u64 = vector.msg_addr_hi as u64; ++ addr = (addr << 32) + vector.msg_addr_lo as u64; ++ TestInterruptManager::add_msix_msg(addr, data); ++ Ok(()) ++ } ++ ++ fn update_route_table(&self, _gsi: u32, _vector: MsiVector) -> Result<()> { ++ Err(anyhow!( ++ "Failed to update route table, mst doesn't support irq routing feature." ++ )) ++ } ++} +diff --git a/image/src/img.rs b/image/src/img.rs +index 7f21220..e106b70 100644 +--- a/image/src/img.rs ++++ b/image/src/img.rs +@@ -23,8 +23,8 @@ use crate::{cmdline::ArgsParse, BINARY_NAME}; + use block_backend::{ + qcow2::{header::QcowHeader, InternalSnapshotOps, Qcow2Driver, SyncAioInfo}, + raw::RawDriver, +- BlockDriverOps, BlockProperty, CheckResult, CreateOptions, FIX_ERRORS, FIX_LEAKS, NO_FIX, +- SECTOR_SIZE, ++ BlockDriverOps, BlockProperty, CheckResult, CreateOptions, ImageInfo, FIX_ERRORS, FIX_LEAKS, ++ NO_FIX, SECTOR_SIZE, + }; + use machine_manager::config::{memory_unit_conversion, DiskFormat}; + use util::{ +@@ -169,6 +169,7 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { + .read(true) + .write(true) + .custom_flags(libc::O_CREAT | libc::O_TRUNC) ++ .mode(0o660) + .open(path.clone())?; + + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; +@@ -189,6 +190,52 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { + Ok(()) + } + ++pub(crate) fn image_info(args: Vec) -> Result<()> { ++ if args.len() < 1 { ++ bail!("Not enough arguments"); ++ } ++ let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec![], vec![]); ++ arg_parser.parse(args)?; ++ ++ if arg_parser.opt_present("h") || arg_parser.opt_present("help") { ++ print_help(); ++ return Ok(()); ++ } ++ ++ // Parse the image path. ++ let len = arg_parser.free.len(); ++ let img_path = match len { ++ 0 => bail!("Image path is needed"), ++ 1 => arg_parser.free[0].clone(), ++ _ => { ++ let param = arg_parser.free[1].clone(); ++ bail!("Unexpected argument: {}", param); ++ } ++ }; ++ ++ let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; ++ let image_file = ImageFile::create(&img_path, false)?; ++ let detect_fmt = image_file.detect_img_format()?; ++ ++ let mut conf = BlockProperty::default(); ++ conf.format = detect_fmt; ++ let mut driver: Box> = match detect_fmt { ++ DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), ++ DiskFormat::Qcow2 => { ++ let mut qocw2_driver = ++ Qcow2Driver::new(image_file.file.try_clone()?, aio, conf.clone())?; ++ qocw2_driver.load_metadata(conf)?; ++ Box::new(qocw2_driver) ++ } ++ }; ++ ++ let mut image_info = ImageInfo::default(); ++ image_info.path = img_path; ++ driver.query_image(&mut image_info)?; ++ print!("{}", image_info); ++ Ok(()) ++} ++ + pub(crate) fn image_check(args: Vec) -> Result<()> { + let mut arg_parser = + ArgsParse::create(vec!["no_print_error", "h", "help"], vec!["f", "r"], vec![]); +@@ -473,6 +520,7 @@ Stratovirt disk image utility + + Command syntax: + create [-f fmt] [-o options] filename [size] ++info filename + check [-r [leaks | all]] [-no_print_error] [-f fmt] filename + resize [-f fmt] filename [+]size + snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename +@@ -759,6 +807,55 @@ mod test { + assert!(remove_file(path).is_ok()); + } + ++ /// Test the function of query image. ++ /// TestStep: ++ /// 2. Query image info with different type. ++ /// Expect: ++ /// 1. Ihe invalid args will result in failure. ++ #[test] ++ fn test_args_parse_of_image_info() { ++ let path = "/tmp/test_args_parse_of_image_info.qcow2"; ++ let test_case = vec![ ++ ("img_path", true), ++ ("-f qcow2", false), ++ ("invalid_args", false), ++ ("img_path +1G", false), ++ ("-h", true), ++ ("--help", true), ++ ]; ++ ++ for case in test_case { ++ let cmd_str = case.0.replace("img_path", path); ++ let args: Vec = cmd_str ++ .split(' ') ++ .into_iter() ++ .map(|str| str.to_string()) ++ .collect(); ++ ++ // Query image info with type of qcow2. ++ assert!(image_create(vec![ ++ "-f".to_string(), ++ "qcow2".to_string(), ++ path.to_string(), ++ "+10M".to_string() ++ ]) ++ .is_ok()); ++ assert_eq!(image_info(args.clone()).is_ok(), case.1); ++ ++ // Query image info with type of raw. ++ assert!(image_create(vec![ ++ "-f".to_string(), ++ "raw".to_string(), ++ path.to_string(), ++ "+10M".to_string() ++ ]) ++ .is_ok()); ++ assert_eq!(image_info(args).is_ok(), case.1); ++ } ++ ++ assert!(remove_file(path).is_ok()); ++ } ++ + /// Test the function of creating image. + /// TestStep: + /// 1. Create image with different cluster bits, image size and refcount bits. +diff --git a/image/src/main.rs b/image/src/main.rs +index 055ac21..b9c7aef 100644 +--- a/image/src/main.rs ++++ b/image/src/main.rs +@@ -21,7 +21,7 @@ use std::{ + use anyhow::{bail, Result}; + + use crate::img::{ +- image_check, image_create, image_resize, image_snapshot, print_help, print_version, ++ image_check, image_create, image_info, image_resize, image_snapshot, print_help, print_version, + }; + + const BINARY_NAME: &str = "stratovirt-img"; +@@ -83,6 +83,7 @@ fn run(args: Vec) -> Result<()> { + image_operation_matches!( + opt.as_str(); + ("create", image_create, cmd_args), ++ ("info", image_info, cmd_args), + ("check", image_check, cmd_args), + ("resize", image_resize, cmd_args), + ("snapshot", image_snapshot, cmd_args); +diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs +index 3e7cf38..40c8baf 100644 +--- a/machine/src/aarch64/micro.rs ++++ b/machine/src/aarch64/micro.rs +@@ -20,13 +20,13 @@ use address_space::{AddressSpace, GuestAddress, Region}; + use cpu::CPUTopology; + use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; + use hypervisor::kvm::aarch64::*; +-use machine_manager::config::{MigrateMode, SerialConfig, VmConfig}; ++use machine_manager::config::{SerialConfig, VmConfig}; + use migration::{MigrationManager, MigrationStatus}; + use util::{ + device_tree::{self, CompileFDT, FdtBuilder}, + seccomp::{BpfRule, SeccompCmpOpt}, + }; +-use virtio::VirtioMmioDevice; ++use virtio::{VirtioDevice, VirtioMmioDevice}; + + #[repr(usize)] + pub enum LayoutEntryType { +@@ -160,12 +160,8 @@ impl MachineOps for LightMachine { + vm_config.machine_config.nr_cpus, + )?; + +- let migrate_info = locked_vm.get_migrate_info(); +- let boot_config = if migrate_info.0 == MigrateMode::Unknown { +- Some(locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?) +- } else { +- None +- }; ++ let boot_config = ++ locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; + let cpu_config = locked_vm.load_cpu_features(vm_config)?; + + let hypervisor = locked_vm.base.hypervisor.clone(); +@@ -190,22 +186,20 @@ impl MachineOps for LightMachine { + locked_vm.add_devices(vm_config)?; + trace::replaceable_info(&locked_vm.replaceable_info); + +- if let Some(boot_cfg) = boot_config { +- let mut fdt_helper = FdtBuilder::new(); +- locked_vm +- .generate_fdt_node(&mut fdt_helper) +- .with_context(|| MachineError::GenFdtErr)?; +- let fdt_vec = fdt_helper.finish()?; +- locked_vm +- .base +- .sys_mem +- .write( +- &mut fdt_vec.as_slice(), +- GuestAddress(boot_cfg.fdt_addr), +- fdt_vec.len() as u64, +- ) +- .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; +- } ++ let mut fdt_helper = FdtBuilder::new(); ++ locked_vm ++ .generate_fdt_node(&mut fdt_helper) ++ .with_context(|| MachineError::GenFdtErr)?; ++ let fdt_vec = fdt_helper.finish()?; ++ locked_vm ++ .base ++ .sys_mem ++ .write( ++ &mut fdt_vec.as_slice(), ++ GuestAddress(boot_config.fdt_addr), ++ fdt_vec.len() as u64, ++ ) ++ .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; + + MigrationManager::register_vm_instance(vm.clone()); + MigrationManager::register_migration_instance(locked_vm.base.migration_hypervisor.clone()); +@@ -224,11 +218,12 @@ impl MachineOps for LightMachine { + self.add_virtio_mmio_block(vm_config, cfg_args) + } + +- fn realize_virtio_mmio_device( ++ fn add_virtio_mmio_device( + &mut self, +- dev: VirtioMmioDevice, ++ name: String, ++ device: Arc>, + ) -> Result>> { +- self.realize_virtio_mmio_device(dev) ++ self.add_virtio_mmio_device(name, device) + } + + fn syscall_whitelist(&self) -> Vec { +@@ -241,7 +236,6 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_ONE_REG() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DEVICE_ATTR() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_REG_LIST() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_ONE_REG() as u32) + } + + pub(crate) fn arch_syscall_whitelist() -> Vec { +diff --git a/machine/src/aarch64/mod.rs b/machine/src/aarch64/mod.rs +index ee107ad..3ffe949 100644 +--- a/machine/src/aarch64/mod.rs ++++ b/machine/src/aarch64/mod.rs +@@ -11,7 +11,7 @@ + // See the Mulan PSL v2 for more details. + + pub mod micro; ++pub mod pci_host_root; + pub mod standard; + + mod fdt; +-mod pci_host_root; +diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs +index 416298a..4b6eebd 100644 +--- a/machine/src/aarch64/standard.rs ++++ b/machine/src/aarch64/standard.rs +@@ -19,6 +19,8 @@ use std::sync::RwLock; + use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, bail, Context, Result}; ++#[cfg(feature = "ramfb")] ++use clap::Parser; + use log::{error, info, warn}; + use vmm_sys_util::eventfd::EventFd; + +@@ -45,25 +47,26 @@ use super::pci_host_root::PciHostRoot; + use crate::standard_common::syscall::syscall_whitelist; + use devices::acpi::ged::{acpi_dsdt_add_power_button, Ged, GedEvent}; + use devices::acpi::power::PowerDev; +-#[cfg(feature = "ramfb")] +-use devices::legacy::Ramfb; + use devices::legacy::{ + FwCfgEntryType, FwCfgMem, FwCfgOps, LegacyError as DevErrorKind, PFlash, PL011, PL031, + }; ++#[cfg(feature = "ramfb")] ++use devices::legacy::{Ramfb, RamfbConfig}; + use devices::pci::{PciDevOps, PciHost, PciIntxState}; + use devices::sysbus::SysBusDevType; + use devices::{ICGICConfig, ICGICv3Config, GIC_IRQ_MAX}; + use hypervisor::kvm::aarch64::*; + use hypervisor::kvm::*; + #[cfg(feature = "ramfb")] +-use machine_manager::config::parse_ramfb; ++use machine_manager::config::str_slip_to_clap; + use machine_manager::config::ShutdownAction; + #[cfg(feature = "gtk")] + use machine_manager::config::UiContext; + use machine_manager::config::{ +- parse_incoming_uri, BootIndexInfo, MigrateMode, NumaNode, PFlashConfig, SerialConfig, VmConfig, ++ parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, + }; + use machine_manager::event; ++use machine_manager::event_loop::EventLoop; + use machine_manager::machine::{ + MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, + MigrateInterface, VmState, +@@ -78,7 +81,7 @@ use ui::ohui_srv::{ohui_init, OhUiServer}; + use ui::vnc::vnc_init; + use util::byte_code::ByteCode; + use util::device_tree::{self, CompileFDT, FdtBuilder}; +-use util::loop_context::EventLoopManager; ++use util::loop_context::{create_new_eventfd, EventLoopManager}; + use util::seccomp::{BpfRule, SeccompCmpOpt}; + use util::set_termi_canon_mode; + +@@ -183,23 +186,23 @@ impl StdMachine { + IRQ_MAP[IrqEntryType::Pcie as usize].0, + ))), + power_button: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("power_button".to_string()))?, + ), + shutdown_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("shutdown_req".to_string()))?, + ), + reset_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("reset_req".to_string()))?, + ), + pause_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("pause_req".to_string()))?, + ), + resume_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("resume_req".to_string()))?, + ), + dtb_vec: Vec::new(), +@@ -255,7 +258,7 @@ impl StdMachine { + Ok(()) + } + +- pub fn handle_destroy_request(vm: &Arc>) -> Result<()> { ++ pub fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.lock().unwrap(); + let vmstate = { + let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); +@@ -267,11 +270,13 @@ impl StdMachine { + if locked_vm.shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request.") + } ++ return false; + } + ++ EventLoop::kick_all(); + info!("vm destroy"); + +- Ok(()) ++ true + } + + fn build_pptt_cores(&self, pptt: &mut AcpiTable, cluster_offset: u32, uid: &mut u32) { +@@ -357,7 +362,7 @@ impl StdMachine { + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + fn add_ohui_server(&mut self, vm_config: &VmConfig) -> Result<()> { + if let Some(dpy) = vm_config.display.as_ref() { +- if !dpy.ohui_config.ohui { ++ if dpy.display_type != "ohui" { + return Ok(()); + } + self.ohui_server = Some(Arc::new(OhUiServer::new(dpy.get_ui_path())?)); +@@ -606,16 +611,8 @@ impl MachineOps for StdMachine { + .with_context(|| MachineError::InitPCIeHostErr)?; + let fwcfg = locked_vm.add_fwcfg_device(nr_cpus)?; + +- let migrate = locked_vm.get_migrate_info(); +- let boot_config = +- if migrate.0 == MigrateMode::Unknown { +- Some(locked_vm.load_boot_source( +- fwcfg.as_ref(), +- MEM_LAYOUT[LayoutEntryType::Mem as usize].0, +- )?) +- } else { +- None +- }; ++ let boot_config = locked_vm ++ .load_boot_source(fwcfg.as_ref(), MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; + let cpu_config = locked_vm.load_cpu_features(vm_config)?; + + let hypervisor = locked_vm.base.hypervisor.clone(); +@@ -640,23 +637,21 @@ impl MachineOps for StdMachine { + .add_devices(vm_config) + .with_context(|| "Failed to add devices")?; + +- if let Some(boot_cfg) = boot_config { +- let mut fdt_helper = FdtBuilder::new(); +- locked_vm +- .generate_fdt_node(&mut fdt_helper) +- .with_context(|| MachineError::GenFdtErr)?; +- let fdt_vec = fdt_helper.finish()?; +- locked_vm.dtb_vec = fdt_vec.clone(); +- locked_vm +- .base +- .sys_mem +- .write( +- &mut fdt_vec.as_slice(), +- GuestAddress(boot_cfg.fdt_addr), +- fdt_vec.len() as u64, +- ) +- .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; +- } ++ let mut fdt_helper = FdtBuilder::new(); ++ locked_vm ++ .generate_fdt_node(&mut fdt_helper) ++ .with_context(|| MachineError::GenFdtErr)?; ++ let fdt_vec = fdt_helper.finish()?; ++ locked_vm.dtb_vec = fdt_vec.clone(); ++ locked_vm ++ .base ++ .sys_mem ++ .write( ++ &mut fdt_vec.as_slice(), ++ GuestAddress(boot_config.fdt_addr), ++ fdt_vec.len() as u64, ++ ) ++ .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; + + // If it is direct kernel boot mode, the ACPI can not be enabled. + if let Some(fw_cfg) = fwcfg { +@@ -695,16 +690,16 @@ impl MachineOps for StdMachine { + Ok(()) + } + +- fn add_pflash_device(&mut self, configs: &[PFlashConfig]) -> Result<()> { ++ fn add_pflash_device(&mut self, configs: &[DriveConfig]) -> Result<()> { + let mut configs_vec = configs.to_vec(); +- configs_vec.sort_by_key(|c| c.unit); ++ configs_vec.sort_by_key(|c| c.unit.unwrap()); + let sector_len: u32 = 1024 * 256; + let mut flash_base: u64 = MEM_LAYOUT[LayoutEntryType::Flash as usize].0; + let flash_size: u64 = MEM_LAYOUT[LayoutEntryType::Flash as usize].1 / 2; + for i in 0..=1 { + let (fd, read_only) = if i < configs_vec.len() { + let path = &configs_vec[i].path_on_host; +- let read_only = configs_vec[i].read_only; ++ let read_only = configs_vec[i].readonly; + let fd = self.fetch_drive_file(path)?; + (Some(fd), read_only) + } else { +@@ -728,7 +723,7 @@ impl MachineOps for StdMachine { + #[cfg(any(feature = "gtk", all(target_env = "ohos", feature = "ohui_srv")))] + match vm_config.display { + #[cfg(feature = "gtk")] +- Some(ref ds_cfg) if ds_cfg.gtk => { ++ Some(ref ds_cfg) if ds_cfg.display_type == "gtk" => { + let ui_context = UiContext { + vm_name: vm_config.guest_name.clone(), + power_button: Some(self.power_button.clone()), +@@ -741,7 +736,7 @@ impl MachineOps for StdMachine { + } + // OHUI server init. + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +- Some(ref ds_cfg) if ds_cfg.ohui_config.ohui => { ++ Some(ref ds_cfg) if ds_cfg.display_type == "ohui" => { + ohui_init(self.ohui_server.as_ref().unwrap().clone(), ds_cfg) + .with_context(|| "Failed to init OH UI server!")?; + } +@@ -757,12 +752,12 @@ impl MachineOps for StdMachine { + + #[cfg(feature = "ramfb")] + fn add_ramfb(&mut self, cfg_args: &str) -> Result<()> { +- let install = parse_ramfb(cfg_args)?; ++ let config = RamfbConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let fwcfg_dev = self + .get_fwcfg_dev() + .with_context(|| "Ramfb device must be used UEFI to boot, please add pflash devices")?; + let sys_mem = self.get_sys_mem(); +- let mut ramfb = Ramfb::new(sys_mem.clone(), install); ++ let mut ramfb = Ramfb::new(sys_mem.clone(), config.install); + + ramfb.ramfb_state.setup(&fwcfg_dev)?; + ramfb.realize(&mut self.base.sysbus) +@@ -797,7 +792,6 @@ pub(crate) fn arch_syscall_whitelist() -> Vec { + BpfRule::new(libc::SYS_epoll_pwait), + BpfRule::new(libc::SYS_mkdirat), + BpfRule::new(libc::SYS_unlinkat), +- BpfRule::new(libc::SYS_clone), + BpfRule::new(libc::SYS_rt_sigaction), + #[cfg(target_env = "gnu")] + BpfRule::new(libc::SYS_rseq), +diff --git a/machine/src/error.rs b/machine/src/error.rs +index c8fb8ee..f502b8f 100644 +--- a/machine/src/error.rs ++++ b/machine/src/error.rs +@@ -94,10 +94,10 @@ pub enum MachineError { + #[cfg(target_arch = "x86_64")] + CrtPitErr, + #[error("Failed to generate FDT.")] +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + GenFdtErr, + #[error("Failed to write FDT: addr={0}, size={1}")] +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + WrtFdtErr(u64, usize), + #[error("Failed to register event notifier.")] + RegNotifierErr, +diff --git a/machine/src/lib.rs b/machine/src/lib.rs +index c1c0c22..e3ba141 100644 +--- a/machine/src/lib.rs ++++ b/machine/src/lib.rs +@@ -13,6 +13,9 @@ + #[cfg(target_arch = "aarch64")] + pub mod aarch64; + pub mod error; ++#[cfg(target_arch = "riscv64")] ++pub mod riscv64; ++#[cfg(not(target_arch = "riscv64"))] + pub mod standard_common; + #[cfg(target_arch = "x86_64")] + pub mod x86_64; +@@ -21,6 +24,7 @@ mod micro_common; + + pub use crate::error::MachineError; + pub use micro_common::LightMachine; ++#[cfg(not(target_arch = "riscv64"))] + pub use standard_common::StdMachine; + + use std::collections::{BTreeMap, HashMap}; +@@ -47,47 +51,46 @@ use cpu::CPUFeatures; + use cpu::{ArchCPU, CPUBootConfig, CPUHypervisorOps, CPUInterface, CPUTopology, CpuTopology, CPU}; + use devices::legacy::FwCfgOps; + #[cfg(feature = "pvpanic")] +-use devices::misc::pvpanic::PvPanicPci; ++use devices::misc::pvpanic::{PvPanicPci, PvpanicDevConfig}; + #[cfg(feature = "scream")] + use devices::misc::scream::{Scream, ScreamConfig}; + #[cfg(feature = "demo_device")] +-use devices::pci::demo_device::DemoDev; +-use devices::pci::{PciBus, PciDevOps, PciHost, RootPort}; ++use devices::pci::demo_device::{DemoDev, DemoDevConfig}; ++use devices::pci::{ ++ devices_register_pcidevops_type, register_pcidevops_type, PciBus, PciDevOps, PciHost, RootPort, ++ RootPortConfig, ++}; + use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; + use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; +-use devices::sysbus::{SysBus, SysBusDevOps, SysBusDevType}; ++use devices::sysbus::{devices_register_sysbusdevops_type, SysBus, SysBusDevOps, SysBusDevType}; + #[cfg(feature = "usb_camera")] + use devices::usb::camera::{UsbCamera, UsbCameraConfig}; + use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; ++use devices::usb::storage::{UsbStorage, UsbStorageConfig}; + use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; ++use devices::usb::uas::{UsbUas, UsbUasConfig}; + #[cfg(feature = "usb_host")] + use devices::usb::usbhost::{UsbHost, UsbHostConfig}; + use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; +-use devices::usb::{storage::UsbStorage, UsbDevice}; +-#[cfg(target_arch = "aarch64")] ++use devices::usb::UsbDevice; ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + use devices::InterruptController; +-use devices::ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}; ++use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; ++#[cfg(not(target_arch = "riscv64"))] ++use hypervisor::test::TestHypervisor; + use hypervisor::{kvm::KvmHypervisor, HypervisorOps}; + #[cfg(feature = "usb_camera")] + use machine_manager::config::get_cameradev_by_id; +-#[cfg(feature = "demo_device")] +-use machine_manager::config::parse_demo_dev; +-#[cfg(feature = "virtio_gpu")] +-use machine_manager::config::parse_gpu; +-#[cfg(feature = "pvpanic")] +-use machine_manager::config::parse_pvpanic; +-use machine_manager::config::parse_usb_storage; + use machine_manager::config::{ +- complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, +- parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, +- parse_root_port, parse_scsi_controller, parse_scsi_device, parse_vfio, parse_vhost_user_blk, +- parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, +- BootSource, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, +- NumaNode, NumaNodes, PFlashConfig, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, +- MAX_VIRTIO_QUEUE, ++ complete_numa_node, get_chardev_socket_path, get_class_type, get_pci_bdf, ++ get_value_of_parameter, parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, ++ BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, ++ NetworkInterfaceConfig, NumaNode, NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, ++ VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + }; + use machine_manager::event_loop::EventLoop; +-use machine_manager::machine::{MachineInterface, VmState}; ++use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; ++use machine_manager::{check_arg_exist, check_arg_nonexist}; + use migration::{MigrateOps, MigrationManager}; + #[cfg(feature = "windows_emu_pid")] + use ui::console::{get_run_stage, VmRunningStage}; +@@ -96,18 +99,26 @@ use util::{ + arg_parser, + seccomp::{BpfRule, SeccompOpt, SyscallFilter}, + }; +-use vfio::{VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; +-#[cfg(feature = "virtio_gpu")] +-use virtio::Gpu; ++use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + use virtio::VirtioDeviceQuirk; + use virtio::{ +- balloon_allow_list, find_port_by_nr, get_max_nr, vhost, Balloon, BalloonConfig, Block, +- BlockState, Rng, RngState, +- ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr}, +- Serial, SerialPort, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, +- VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, ++ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, ++ virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Rng, RngConfig, ++ RngState, ++ ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, ++ Serial, SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, ++ VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, + }; ++#[cfg(feature = "virtio_gpu")] ++use virtio::{Gpu, GpuDevConfig}; ++ ++#[cfg(feature = "windows_emu_pid")] ++const WINDOWS_EMU_PID_DEFAULT_INTERVAL: u64 = 4000; ++#[cfg(feature = "windows_emu_pid")] ++const WINDOWS_EMU_PID_SHUTDOWN_INTERVAL: u64 = 1000; ++#[cfg(feature = "windows_emu_pid")] ++const WINDOWS_EMU_PID_POWERDOWN_INTERVAL: u64 = 30000; + + /// Machine structure include base members. + pub struct MachineBase { +@@ -116,7 +127,7 @@ pub struct MachineBase { + /// `vCPU` devices. + cpus: Vec>, + /// Interrupt controller device. +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + irq_chip: Option>, + /// Memory address space. + sys_mem: Arc, +@@ -186,12 +197,26 @@ impl MachineBase { + mmio_region, + ); + +- let hypervisor = Arc::new(Mutex::new(KvmHypervisor::new()?)); ++ let hypervisor: Arc>; ++ let migration_hypervisor: Arc>; ++ match vm_config.machine_config.hypervisor { ++ HypervisorType::Kvm => { ++ let kvm_hypervisor = Arc::new(Mutex::new(KvmHypervisor::new()?)); ++ hypervisor = kvm_hypervisor.clone(); ++ migration_hypervisor = kvm_hypervisor; ++ } ++ #[cfg(not(target_arch = "riscv64"))] ++ HypervisorType::Test => { ++ let test_hypervisor = Arc::new(Mutex::new(TestHypervisor::new()?)); ++ hypervisor = test_hypervisor.clone(); ++ migration_hypervisor = test_hypervisor; ++ } ++ }; + + Ok(MachineBase { + cpu_topo, + cpus: Vec::new(), +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + irq_chip: None, + sys_mem, + #[cfg(target_arch = "x86_64")] +@@ -204,8 +229,8 @@ impl MachineBase { + drive_files: Arc::new(Mutex::new(vm_config.init_drive_files()?)), + fwcfg_dev: None, + machine_ram, +- hypervisor: hypervisor.clone(), +- migration_hypervisor: hypervisor, ++ hypervisor, ++ migration_hypervisor, + }) + } + +@@ -269,13 +294,13 @@ macro_rules! create_device_add_matches { + match $command { + $( + $($driver_name)|+ => { +- $controller.$function_name($($arg),*)?; ++ $controller.$function_name($($arg),*).with_context(|| format!("add {} fail.", $command))?; + }, + )* + $( + #[cfg($($features)*)] + $driver_name1 => { +- $controller.$function_name1($($arg1),*)?; ++ $controller.$function_name1($($arg1),*).with_context(|| format!("add {} fail.", $command))?; + }, + )* + _ => bail!("Unsupported device: {:?}", $command), +@@ -318,7 +343,7 @@ pub trait MachineOps { + #[cfg(target_arch = "x86_64")] + fn load_boot_source(&self, fwcfg: Option<&Arc>>) -> Result; + +- #[cfg(target_arch = "aarch64")] ++ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + fn load_boot_source( + &self, + fwcfg: Option<&Arc>>, +@@ -396,6 +421,7 @@ pub trait MachineOps { + sys_mem: &Arc, + nr_cpus: u8, + ) -> Result<()> { ++ trace::trace_scope_start!(init_memory); + let migrate_info = self.get_migrate_info(); + if migrate_info.0 != MigrateMode::File { + self.create_machine_ram(mem_config, nr_cpus)?; +@@ -439,6 +465,8 @@ pub trait MachineOps { + + #[cfg(target_arch = "aarch64")] + let arch_cpu = ArchCPU::new(u32::from(vcpu_id)); ++ #[cfg(target_arch = "riscv64")] ++ let arch_cpu = ArchCPU::new(u32::from(vcpu_id)); + #[cfg(target_arch = "x86_64")] + let arch_cpu = ArchCPU::new(u32::from(vcpu_id), u32::from(max_cpus)); + +@@ -465,7 +493,7 @@ pub trait MachineOps { + nr_cpus: u8, + #[cfg(target_arch = "x86_64")] max_cpus: u8, + topology: &CPUTopology, +- boot_cfg: &Option, ++ boot_cfg: &CPUBootConfig, + #[cfg(target_arch = "aarch64")] vcpu_cfg: &CPUFeatures, + ) -> Result>> + where +@@ -559,34 +587,31 @@ pub trait MachineOps { + /// + /// * `cfg_args` - Device configuration. + fn add_virtio_vsock(&mut self, cfg_args: &str) -> Result<()> { +- let device_cfg = parse_vsock(cfg_args)?; ++ let device_cfg = ++ VhostKern::VsockConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let sys_mem = self.get_sys_mem().clone(); + let vsock = Arc::new(Mutex::new(VhostKern::Vsock::new(&device_cfg, &sys_mem))); +- match parse_device_type(cfg_args)?.as_str() { ++ match device_cfg.classtype.as_str() { + "vhost-vsock-device" => { +- let device = VirtioMmioDevice::new(&sys_mem, vsock.clone()); ++ check_arg_nonexist!( ++ ("bus", device_cfg.bus), ++ ("addr", device_cfg.addr), ++ ("multifunction", device_cfg.multifunction) ++ ); ++ let device = self ++ .add_virtio_mmio_device(device_cfg.id.clone(), vsock.clone()) ++ .with_context(|| MachineError::RlzVirtioMmioErr)?; + MigrationManager::register_device_instance( + VirtioMmioState::descriptor(), +- self.realize_virtio_mmio_device(device) +- .with_context(|| MachineError::RlzVirtioMmioErr)?, ++ device, + &device_cfg.id, + ); + } + _ => { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let mut virtio_pci_device = VirtioPciDevice::new( +- device_cfg.id.clone(), +- devfn, +- sys_mem, +- vsock.clone(), +- parent_bus, +- multi_func, +- ); +- virtio_pci_device.enable_need_irqfd(); +- virtio_pci_device +- .realize() ++ check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); ++ let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); ++ let multi_func = device_cfg.multifunction.unwrap_or_default(); ++ self.add_virtio_pci_device(&device_cfg.id, &bdf, vsock.clone(), multi_func, true) + .with_context(|| "Failed to add virtio pci vsock device")?; + } + } +@@ -600,9 +625,10 @@ pub trait MachineOps { + Ok(()) + } + +- fn realize_virtio_mmio_device( ++ fn add_virtio_mmio_device( + &mut self, +- _dev: VirtioMmioDevice, ++ _name: String, ++ _device: Arc>, + ) -> Result>> { + bail!("Virtio mmio devices not supported"); + } +@@ -663,36 +689,26 @@ pub trait MachineOps { + if vm_config.dev_name.get("balloon").is_some() { + bail!("Only one balloon device is supported for each vm."); + } +- let config = BalloonConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = BalloonConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + vm_config.dev_name.insert("balloon".to_string(), 1); + + let sys_mem = self.get_sys_mem(); + let balloon = Arc::new(Mutex::new(Balloon::new(config.clone(), sys_mem.clone()))); + Balloon::object_init(balloon.clone()); +- match parse_device_type(cfg_args)?.as_str() { ++ match config.classtype.as_str() { + "virtio-balloon-device" => { +- if config.addr.is_some() || config.bus.is_some() || config.multifunction.is_some() { +- bail!("virtio balloon device config is error!"); +- } +- let device = VirtioMmioDevice::new(sys_mem, balloon); +- self.realize_virtio_mmio_device(device)?; ++ check_arg_nonexist!( ++ ("bus", config.bus), ++ ("addr", config.addr), ++ ("multifunction", config.multifunction) ++ ); ++ self.add_virtio_mmio_device(config.id.clone(), balloon)?; + } + _ => { +- if config.addr.is_none() || config.bus.is_none() { +- bail!("virtio balloon pci config is error!"); +- } +- let bdf = PciBdf { +- bus: config.bus.unwrap(), +- addr: config.addr.unwrap(), +- }; ++ check_arg_exist!(("bus", config.bus), ("addr", config.addr)); ++ let bdf = PciBdf::new(config.bus.unwrap(), config.addr.unwrap()); + let multi_func = config.multifunction.unwrap_or_default(); +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let sys_mem = self.get_sys_mem().clone(); +- let virtio_pci_device = VirtioPciDevice::new( +- config.id, devfn, sys_mem, balloon, parent_bus, multi_func, +- ); +- virtio_pci_device +- .realize() ++ self.add_virtio_pci_device(&config.id, &bdf, balloon, multi_func, false) + .with_context(|| "Failed to add virtio pci balloon device")?; + } + } +@@ -707,34 +723,35 @@ pub trait MachineOps { + /// * `vm_config` - VM configuration. + /// * `cfg_args` - Device configuration args. + fn add_virtio_serial(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let serial_cfg = parse_virtio_serial(vm_config, cfg_args)?; +- let sys_mem = self.get_sys_mem().clone(); ++ if vm_config.virtio_serial.is_some() { ++ bail!("Only one virtio serial device is supported"); ++ } ++ let mut serial_cfg = ++ VirtioSerialInfo::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ serial_cfg.auto_max_ports(); + let serial = Arc::new(Mutex::new(Serial::new(serial_cfg.clone()))); + +- match parse_device_type(cfg_args)?.as_str() { ++ match serial_cfg.classtype.as_str() { + "virtio-serial-device" => { +- let device = VirtioMmioDevice::new(&sys_mem, serial.clone()); ++ check_arg_nonexist!( ++ ("bus", serial_cfg.bus), ++ ("addr", serial_cfg.addr), ++ ("multifunction", serial_cfg.multifunction) ++ ); ++ let device = self ++ .add_virtio_mmio_device(serial_cfg.id.clone(), serial.clone()) ++ .with_context(|| MachineError::RlzVirtioMmioErr)?; + MigrationManager::register_device_instance( + VirtioMmioState::descriptor(), +- self.realize_virtio_mmio_device(device) +- .with_context(|| MachineError::RlzVirtioMmioErr)?, ++ device, + &serial_cfg.id, + ); + } + _ => { +- let bdf = serial_cfg.pci_bdf.unwrap(); +- let multi_func = serial_cfg.multifunction; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let virtio_pci_device = VirtioPciDevice::new( +- serial_cfg.id.clone(), +- devfn, +- sys_mem, +- serial.clone(), +- parent_bus, +- multi_func, +- ); +- virtio_pci_device +- .realize() ++ check_arg_exist!(("bus", serial_cfg.bus), ("addr", serial_cfg.addr)); ++ let bdf = PciBdf::new(serial_cfg.bus.clone().unwrap(), serial_cfg.addr.unwrap()); ++ let multi_func = serial_cfg.multifunction.unwrap_or_default(); ++ self.add_virtio_pci_device(&serial_cfg.id, &bdf, serial.clone(), multi_func, false) + .with_context(|| "Failed to add virtio pci serial device")?; + } + } +@@ -745,6 +762,7 @@ pub trait MachineOps { + &serial_cfg.id, + ); + ++ vm_config.virtio_serial = Some(serial_cfg); + Ok(()) + } + +@@ -761,7 +779,7 @@ pub trait MachineOps { + .with_context(|| "No virtio serial device specified")?; + + let mut virtio_device = None; +- if serial_cfg.pci_bdf.is_none() { ++ if serial_cfg.bus.is_none() { + // Micro_vm. + for dev in self.get_sys_bus().devices.iter() { + let locked_busdev = dev.lock().unwrap(); +@@ -798,24 +816,31 @@ pub trait MachineOps { + let mut virtio_dev_h = virtio_dev.lock().unwrap(); + let serial = virtio_dev_h.as_any_mut().downcast_mut::().unwrap(); + +- let is_console = matches!(parse_device_type(cfg_args)?.as_str(), "virtconsole"); ++ let mut serialport_cfg = ++ VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let free_port0 = find_port_by_nr(&serial.ports, 0).is_none(); + // Note: port 0 is reserved for a virtconsole. + let free_nr = get_max_nr(&serial.ports) + 1; +- let serialport_cfg = +- parse_virtserialport(vm_config, cfg_args, is_console, free_nr, free_port0)?; +- if serialport_cfg.nr >= serial.max_nr_ports { ++ serialport_cfg.auto_nr(free_port0, free_nr, serial.max_nr_ports)?; ++ serialport_cfg.check()?; ++ if find_port_by_nr(&serial.ports, serialport_cfg.nr.unwrap()).is_some() { + bail!( +- "virtio serial port nr {} should be less than virtio serial's max_nr_ports {}", +- serialport_cfg.nr, +- serial.max_nr_ports ++ "Repetitive virtio serial port nr {}.", ++ serialport_cfg.nr.unwrap() + ); + } +- if find_port_by_nr(&serial.ports, serialport_cfg.nr).is_some() { +- bail!("Repetitive virtio serial port nr {}.", serialport_cfg.nr,); +- } ++ let is_console = matches!(serialport_cfg.classtype.as_str(), "virtconsole"); ++ let chardev_cfg = vm_config ++ .chardev ++ .remove(&serialport_cfg.chardev) ++ .with_context(|| { ++ format!( ++ "Chardev {:?} not found or is in use", ++ &serialport_cfg.chardev ++ ) ++ })?; + +- let mut serial_port = SerialPort::new(serialport_cfg); ++ let mut serial_port = SerialPort::new(serialport_cfg, chardev_cfg); + let port = Arc::new(Mutex::new(serial_port.clone())); + serial_port.realize()?; + if !is_console { +@@ -833,36 +858,35 @@ pub trait MachineOps { + /// * `vm_config` - VM configuration. + /// * `cfg_args` - Device configuration arguments. + fn add_virtio_rng(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let device_cfg = parse_rng_dev(vm_config, cfg_args)?; +- let sys_mem = self.get_sys_mem(); +- let rng_dev = Arc::new(Mutex::new(Rng::new(device_cfg.clone()))); ++ let rng_cfg = RngConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ rng_cfg.bytes_per_sec()?; ++ let rngobj_cfg = vm_config ++ .object ++ .rng_object ++ .remove(&rng_cfg.rng) ++ .with_context(|| "Object for rng-random device not found")?; ++ let rng_dev = Arc::new(Mutex::new(Rng::new(rng_cfg.clone(), rngobj_cfg))); + +- match parse_device_type(cfg_args)?.as_str() { ++ match rng_cfg.classtype.as_str() { + "virtio-rng-device" => { +- let device = VirtioMmioDevice::new(sys_mem, rng_dev.clone()); +- self.realize_virtio_mmio_device(device) ++ check_arg_nonexist!( ++ ("bus", rng_cfg.bus), ++ ("addr", rng_cfg.addr), ++ ("multifunction", rng_cfg.multifunction) ++ ); ++ self.add_virtio_mmio_device(rng_cfg.id.clone(), rng_dev.clone()) + .with_context(|| "Failed to add virtio mmio rng device")?; + } + _ => { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let sys_mem = self.get_sys_mem().clone(); +- let vitio_pci_device = VirtioPciDevice::new( +- device_cfg.id.clone(), +- devfn, +- sys_mem, +- rng_dev.clone(), +- parent_bus, +- multi_func, +- ); +- vitio_pci_device +- .realize() ++ check_arg_exist!(("bus", rng_cfg.bus), ("addr", rng_cfg.addr)); ++ let bdf = PciBdf::new(rng_cfg.bus.clone().unwrap(), rng_cfg.addr.unwrap()); ++ let multi_func = rng_cfg.multifunction.unwrap_or_default(); ++ self.add_virtio_pci_device(&rng_cfg.id, &bdf, rng_dev.clone(), multi_func, false) + .with_context(|| "Failed to add pci rng device")?; + } + } + +- MigrationManager::register_device_instance(RngState::descriptor(), rng_dev, &device_cfg.id); ++ MigrationManager::register_device_instance(RngState::descriptor(), rng_dev, &rng_cfg.id); + Ok(()) + } + +@@ -877,32 +901,41 @@ pub trait MachineOps { + /// * 'vm_config' - VM configuration. + /// * 'cfg_args' - Device configuration arguments. + fn add_virtio_fs(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let dev_cfg = parse_fs(vm_config, cfg_args)?; +- let id_clone = dev_cfg.id.clone(); ++ let dev_cfg = ++ vhost::user::FsConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let char_dev = vm_config ++ .chardev ++ .remove(&dev_cfg.chardev) ++ .with_context(|| format!("Chardev {:?} not found or is in use", &dev_cfg.chardev))?; + let sys_mem = self.get_sys_mem().clone(); + + if !vm_config.machine_config.mem_config.mem_share { + bail!("When configuring the vhost-user-fs-device or vhost-user-fs-pci device, the memory must be shared."); + } + +- match parse_device_type(cfg_args)?.as_str() { ++ let device = Arc::new(Mutex::new(vhost::user::Fs::new( ++ dev_cfg.clone(), ++ char_dev, ++ sys_mem, ++ ))); ++ match dev_cfg.classtype.as_str() { + "vhost-user-fs-device" => { +- let device = Arc::new(Mutex::new(vhost::user::Fs::new(dev_cfg, sys_mem.clone()))); +- let virtio_mmio_device = VirtioMmioDevice::new(&sys_mem, device); +- self.realize_virtio_mmio_device(virtio_mmio_device) ++ check_arg_nonexist!( ++ ("bus", dev_cfg.bus), ++ ("addr", dev_cfg.addr), ++ ("multifunction", dev_cfg.multifunction) ++ ); ++ self.add_virtio_mmio_device(dev_cfg.id.clone(), device) + .with_context(|| "Failed to add vhost user fs device")?; + } + _ => { +- let device = Arc::new(Mutex::new(vhost::user::Fs::new(dev_cfg, sys_mem.clone()))); +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- +- let mut vitio_pci_device = +- VirtioPciDevice::new(id_clone, devfn, sys_mem, device, parent_bus, multi_func); +- vitio_pci_device.enable_need_irqfd(); +- vitio_pci_device +- .realize() ++ check_arg_exist!(("bus", dev_cfg.bus), ("addr", dev_cfg.addr)); ++ let bdf = PciBdf::new(dev_cfg.bus.clone().unwrap(), dev_cfg.addr.unwrap()); ++ let multi_func = dev_cfg.multifunction.unwrap_or_default(); ++ let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); ++ let msi_irq_manager = root_bus.lock().unwrap().msi_irq_manager.clone(); ++ let need_irqfd = msi_irq_manager.as_ref().unwrap().irqfd_enable(); ++ self.add_virtio_pci_device(&dev_cfg.id, &bdf, device, multi_func, need_irqfd) + .with_context(|| "Failed to add pci fs device")?; + } + } +@@ -1059,11 +1092,10 @@ pub trait MachineOps { + + #[cfg(feature = "pvpanic")] + fn add_pvpanic(&mut self, cfg_args: &str) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let device_cfg = parse_pvpanic(cfg_args)?; +- ++ let config = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let bdf = PciBdf::new(config.bus.clone(), config.addr); + let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let pcidev = PvPanicPci::new(&device_cfg, devfn, parent_bus); ++ let pcidev = PvPanicPci::new(&config, devfn, parent_bus); + pcidev + .realize() + .with_context(|| "Failed to realize pvpanic device")?; +@@ -1077,26 +1109,38 @@ pub trait MachineOps { + cfg_args: &str, + hotplug: bool, + ) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( +- 0, +- vm_config.machine_config.nr_cpus, +- MAX_VIRTIO_QUEUE, +- )); +- let device_cfg = parse_blk(vm_config, cfg_args, queues_auto)?; +- if let Some(bootindex) = device_cfg.boot_index { ++ let mut device_cfg = ++ VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); ++ let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); ++ let multi_func = device_cfg.multifunction.unwrap_or_default(); ++ if device_cfg.num_queues.is_none() { ++ let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( ++ 0, ++ vm_config.machine_config.nr_cpus, ++ MAX_VIRTIO_QUEUE, ++ ); ++ device_cfg.num_queues = Some(queues_auto); ++ } ++ if let Some(bootindex) = device_cfg.bootindex { + self.check_bootindex(bootindex) + .with_context(|| "Fail to add virtio pci blk device for invalid bootindex")?; + } ++ ++ let drive_cfg = vm_config ++ .drives ++ .remove(&device_cfg.drive) ++ .with_context(|| "No drive configured matched for blk device")?; ++ + let device = Arc::new(Mutex::new(Block::new( + device_cfg.clone(), ++ drive_cfg, + self.get_drive_files(), + ))); + let pci_dev = self + .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, false) + .with_context(|| "Failed to add virtio pci device")?; +- if let Some(bootindex) = device_cfg.boot_index { ++ if let Some(bootindex) = device_cfg.bootindex { + // Eg: OpenFirmware device path(virtio-blk disk): + // /pci@i0cf8/scsi@6[,3]/disk@0,0 + // | | | | | +@@ -1125,54 +1169,55 @@ pub trait MachineOps { + cfg_args: &str, + hotplug: bool, + ) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( +- 0, +- vm_config.machine_config.nr_cpus, +- MAX_VIRTIO_QUEUE, +- )); +- let device_cfg = parse_scsi_controller(cfg_args, queues_auto)?; ++ let mut device_cfg = ++ ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); ++ let multi_func = device_cfg.multifunction.unwrap_or_default(); ++ if device_cfg.num_queues.is_none() { ++ let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( ++ 0, ++ vm_config.machine_config.nr_cpus, ++ MAX_VIRTIO_QUEUE, ++ ); ++ device_cfg.num_queues = Some(queues_auto as u32); ++ } + let device = Arc::new(Mutex::new(ScsiCntlr::new(device_cfg.clone()))); + + let bus_name = format!("{}.0", device_cfg.id); + scsi_cntlr_create_scsi_bus(&bus_name, &device)?; + +- let pci_dev = self +- .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, false) ++ self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, false) + .with_context(|| "Failed to add virtio scsi controller")?; + if !hotplug { + self.reset_bus(&device_cfg.id)?; + } +- device.lock().unwrap().config.boot_prefix = pci_dev.lock().unwrap().get_dev_path(); + Ok(()) + } + + fn add_scsi_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let device_cfg = parse_scsi_device(vm_config, cfg_args)?; +- let scsi_type = match parse_device_type(cfg_args)?.as_str() { +- "scsi-hd" => SCSI_TYPE_DISK, +- _ => SCSI_TYPE_ROM, +- }; +- if let Some(bootindex) = device_cfg.boot_index { ++ let device_cfg = ScsiDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let drive_arg = vm_config ++ .drives ++ .remove(&device_cfg.drive) ++ .with_context(|| "No drive configured matched for scsi device")?; ++ ++ if let Some(bootindex) = device_cfg.bootindex { + self.check_bootindex(bootindex) + .with_context(|| "Failed to add scsi device for invalid bootindex")?; + } + let device = Arc::new(Mutex::new(ScsiDevice::new( + device_cfg.clone(), +- scsi_type, ++ drive_arg, + self.get_drive_files(), + ))); + ++ // Bus name `$parent_cntlr_name.0` is checked when parsing by clap. ++ let cntlr = device_cfg.bus.split('.').collect::>()[0].to_string(); + let pci_dev = self +- .get_pci_dev_by_id_and_type(vm_config, Some(&device_cfg.cntlr), "virtio-scsi-pci") +- .with_context(|| { +- format!( +- "Can not find scsi controller from pci bus {}", +- device_cfg.cntlr +- ) +- })?; ++ .get_pci_dev_by_id_and_type(vm_config, Some(&cntlr), "virtio-scsi-pci") ++ .with_context(|| format!("Can not find scsi controller from pci bus {}", cntlr))?; + let locked_pcidev = pci_dev.lock().unwrap(); ++ let prefix = locked_pcidev.get_dev_path().unwrap(); + let virtio_pcidev = locked_pcidev + .as_any() + .downcast_ref::() +@@ -1197,7 +1242,7 @@ pub trait MachineOps { + .insert((device_cfg.target, device_cfg.lun), device.clone()); + device.lock().unwrap().parent_bus = Arc::downgrade(bus); + +- if let Some(bootindex) = device_cfg.boot_index { ++ if let Some(bootindex) = device_cfg.bootindex { + // Eg: OpenFirmware device path(virtio-scsi disk): + // /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3 + // | | | | | | +@@ -1205,7 +1250,6 @@ pub trait MachineOps { + // | | | channel(unused, fixed 0). + // | PCI slot,[function] holding SCSI controller. + // PCI root as system bus port. +- let prefix = cntlr.config.boot_prefix.as_ref().unwrap(); + let dev_path = + format! {"{}/channel@0/disk@{:x},{:x}", prefix, device_cfg.target, device_cfg.lun}; + self.add_bootindex_devices(bootindex, &dev_path, &device_cfg.id); +@@ -1219,35 +1263,53 @@ pub trait MachineOps { + cfg_args: &str, + hotplug: bool, + ) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let device_cfg = parse_net(vm_config, cfg_args)?; ++ let net_cfg = ++ NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let netdev_cfg = vm_config ++ .netdevs ++ .remove(&net_cfg.netdev) ++ .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; ++ check_arg_exist!(("bus", net_cfg.bus), ("addr", net_cfg.addr)); ++ let bdf = PciBdf::new(net_cfg.bus.clone().unwrap(), net_cfg.addr.unwrap()); ++ let multi_func = net_cfg.multifunction.unwrap_or_default(); ++ + let mut need_irqfd = false; +- let device: Arc> = if device_cfg.vhost_type.is_some() { ++ let device: Arc> = if netdev_cfg.vhost_type().is_some() { + need_irqfd = true; +- if device_cfg.vhost_type == Some(String::from("vhost-kernel")) { ++ if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { + Arc::new(Mutex::new(VhostKern::Net::new( +- &device_cfg, ++ &net_cfg, ++ netdev_cfg, + self.get_sys_mem(), + ))) + } else { ++ let chardev = netdev_cfg.chardev.clone().with_context(|| { ++ format!("Chardev not configured for netdev {:?}", netdev_cfg.id) ++ })?; ++ let chardev_cfg = vm_config ++ .chardev ++ .remove(&chardev) ++ .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; ++ let sock_path = get_chardev_socket_path(chardev_cfg)?; + Arc::new(Mutex::new(VhostUser::Net::new( +- &device_cfg, ++ &net_cfg, ++ netdev_cfg, ++ sock_path, + self.get_sys_mem(), + ))) + } + } else { +- let device = Arc::new(Mutex::new(virtio::Net::new(device_cfg.clone()))); ++ let device = Arc::new(Mutex::new(virtio::Net::new(net_cfg.clone(), netdev_cfg))); + MigrationManager::register_device_instance( + VirtioNetState::descriptor(), + device.clone(), +- &device_cfg.id, ++ &net_cfg.id, + ); + device + }; +- self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, need_irqfd)?; ++ self.add_virtio_pci_device(&net_cfg.id, &bdf, device, multi_func, need_irqfd)?; + if !hotplug { +- self.reset_bus(&device_cfg.id)?; ++ self.reset_bus(&net_cfg.id)?; + } + Ok(()) + } +@@ -1258,27 +1320,43 @@ pub trait MachineOps { + cfg_args: &str, + hotplug: bool, + ) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( +- 0, +- vm_config.machine_config.nr_cpus, +- MAX_VIRTIO_QUEUE, +- )); +- let device_cfg = parse_vhost_user_blk(vm_config, cfg_args, queues_auto)?; ++ let mut device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( ++ cfg_args, true, false, ++ ))?; ++ check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); ++ let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); ++ if device_cfg.num_queues.is_none() { ++ let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( ++ 0, ++ vm_config.machine_config.nr_cpus, ++ MAX_VIRTIO_QUEUE, ++ ); ++ device_cfg.num_queues = Some(queues_auto); ++ } ++ let chardev_cfg = vm_config ++ .chardev ++ .remove(&device_cfg.chardev) ++ .with_context(|| { ++ format!( ++ "Chardev: {:?} not found for vhost user blk", ++ &device_cfg.chardev ++ ) ++ })?; ++ + let device: Arc> = Arc::new(Mutex::new(VhostUser::Block::new( + &device_cfg, ++ chardev_cfg, + self.get_sys_mem(), + ))); + let pci_dev = self +- .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, true) ++ .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), false, true) + .with_context(|| { + format!( + "Failed to add virtio pci device, device id: {}", + &device_cfg.id + ) + })?; +- if let Some(bootindex) = device_cfg.boot_index { ++ if let Some(bootindex) = device_cfg.bootindex { + if let Some(dev_path) = pci_dev.lock().unwrap().get_dev_path() { + self.add_bootindex_devices(bootindex, &dev_path, &device_cfg.id); + } +@@ -1294,60 +1372,55 @@ pub trait MachineOps { + vm_config: &mut VmConfig, + cfg_args: &str, + ) -> Result<()> { +- let device_cfg = parse_vhost_user_blk(vm_config, cfg_args, None)?; ++ let device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( ++ cfg_args, true, false, ++ ))?; ++ check_arg_nonexist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); ++ let chardev_cfg = vm_config ++ .chardev ++ .remove(&device_cfg.chardev) ++ .with_context(|| { ++ format!( ++ "Chardev: {:?} not found for vhost user blk", ++ &device_cfg.chardev ++ ) ++ })?; + let device: Arc> = Arc::new(Mutex::new(VhostUser::Block::new( + &device_cfg, ++ chardev_cfg, + self.get_sys_mem(), + ))); +- let virtio_mmio_device = VirtioMmioDevice::new(self.get_sys_mem(), device); +- self.realize_virtio_mmio_device(virtio_mmio_device) ++ self.add_virtio_mmio_device(device_cfg.id.clone(), device) + .with_context(|| "Failed to add vhost user block device")?; + Ok(()) + } + +- fn create_vfio_pci_device( +- &mut self, +- id: &str, +- bdf: &PciBdf, +- host: &str, +- sysfsdev: &str, +- multifunc: bool, +- ) -> Result<()> { +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?; +- let path = if !host.is_empty() { +- format!("/sys/bus/pci/devices/{}", host) ++ fn add_vfio_device(&mut self, cfg_args: &str, hotplug: bool) -> Result<()> { ++ let hypervisor = self.get_hypervisor(); ++ let locked_hypervisor = hypervisor.lock().unwrap(); ++ *KVM_DEVICE_FD.lock().unwrap() = locked_hypervisor.create_vfio_device(); ++ ++ let device_cfg = VfioConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); ++ let multi_func = device_cfg.multifunction.unwrap_or_default(); ++ let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; ++ let path = if device_cfg.host.is_some() { ++ format!("/sys/bus/pci/devices/{}", device_cfg.host.unwrap()) + } else { +- sysfsdev.to_string() ++ device_cfg.sysfsdev.unwrap() + }; + let device = VfioDevice::new(Path::new(&path), self.get_sys_mem()) + .with_context(|| "Failed to create vfio device.")?; + let vfio_pci = VfioPciDevice::new( + device, + devfn, +- id.to_string(), ++ device_cfg.id.to_string(), + parent_bus, +- multifunc, ++ multi_func, + self.get_sys_mem().clone(), + ); + VfioPciDevice::realize(vfio_pci).with_context(|| "Failed to realize vfio-pci device.")?; +- Ok(()) +- } + +- fn add_vfio_device(&mut self, cfg_args: &str, hotplug: bool) -> Result<()> { +- let hypervisor = self.get_hypervisor(); +- let locked_hypervisor = hypervisor.lock().unwrap(); +- *KVM_DEVICE_FD.lock().unwrap() = locked_hypervisor.create_vfio_device(); +- +- let device_cfg: VfioConfig = parse_vfio(cfg_args)?; +- let bdf = get_pci_bdf(cfg_args)?; +- let multifunc = get_multi_function(cfg_args)?; +- self.create_vfio_pci_device( +- &device_cfg.id, +- &bdf, +- &device_cfg.host, +- &device_cfg.sysfsdev, +- multifunc, +- )?; + if !hotplug { + self.reset_bus(&device_cfg.id)?; + } +@@ -1364,10 +1437,10 @@ pub trait MachineOps { + + #[cfg(feature = "virtio_gpu")] + fn add_virtio_pci_gpu(&mut self, cfg_args: &str) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let multi_func = get_multi_function(cfg_args)?; +- let device_cfg = parse_gpu(cfg_args)?; +- let device = Arc::new(Mutex::new(Gpu::new(device_cfg.clone()))); ++ let config = GpuDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ config.check(); ++ let bdf = PciBdf::new(config.bus.clone(), config.addr); ++ let device = Arc::new(Mutex::new(Gpu::new(config.clone()))); + + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + if device.lock().unwrap().device_quirk() == Some(VirtioDeviceQuirk::VirtioGpuEnableBar0) +@@ -1377,7 +1450,7 @@ pub trait MachineOps { + device.lock().unwrap().set_bar0_fb(self.get_ohui_fb()); + } + +- self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, false)?; ++ self.add_virtio_pci_device(&config.id, &bdf, device, false, false)?; + Ok(()) + } + +@@ -1394,21 +1467,15 @@ pub trait MachineOps { + } + + fn add_pci_root_port(&mut self, cfg_args: &str) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- let device_cfg = parse_root_port(cfg_args)?; ++ let dev_cfg = RootPortConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let bdf = PciBdf::new(dev_cfg.bus.clone(), dev_cfg.addr); ++ let (_, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; + let pci_host = self.get_pci_host()?; + let bus = pci_host.lock().unwrap().root_bus.clone(); +- if PciBus::find_bus_by_name(&bus, &device_cfg.id).is_some() { +- bail!("ID {} already exists.", &device_cfg.id); ++ if PciBus::find_bus_by_name(&bus, &dev_cfg.id).is_some() { ++ bail!("ID {} already exists.", &dev_cfg.id); + } +- let rootport = RootPort::new( +- device_cfg.id, +- devfn, +- device_cfg.port, +- parent_bus, +- device_cfg.multifunction, +- ); ++ let rootport = RootPort::new(dev_cfg, parent_bus); + rootport + .realize() + .with_context(|| "Failed to add pci root port")?; +@@ -1425,17 +1492,15 @@ pub trait MachineOps { + ) -> Result>> { + let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?; + let sys_mem = self.get_sys_mem(); +- let mut pcidev = VirtioPciDevice::new( ++ let pcidev = VirtioPciDevice::new( + id.to_string(), + devfn, + sys_mem.clone(), + device, + parent_bus, + multi_func, ++ need_irqfd, + ); +- if need_irqfd { +- pcidev.enable_need_irqfd(); +- } + let clone_pcidev = Arc::new(Mutex::new(pcidev.clone())); + pcidev + .realize() +@@ -1513,46 +1578,47 @@ pub trait MachineOps { + for numa in vm_config.numa_nodes.iter() { + match numa.0.as_str() { + "node" => { +- let numa_config: NumaConfig = parse_numa_mem(numa.1.as_str())?; +- if numa_nodes.contains_key(&numa_config.numa_id) { +- bail!("Numa node id is repeated {}", numa_config.numa_id); ++ let node_config = parse_numa_mem(numa.1.as_str())?; ++ if numa_nodes.contains_key(&node_config.numa_id) { ++ bail!("Numa node id is repeated {}", node_config.numa_id); + } + let mut numa_node = NumaNode { +- cpus: numa_config.cpus, +- mem_dev: numa_config.mem_dev.clone(), ++ cpus: node_config.cpus, ++ mem_dev: node_config.mem_dev.clone(), + ..Default::default() + }; + + numa_node.size = vm_config + .object + .mem_object +- .remove(&numa_config.mem_dev) ++ .remove(&node_config.mem_dev) + .map(|mem_conf| mem_conf.size) + .with_context(|| { + format!( + "Object for memory-backend {} config not found", +- numa_config.mem_dev ++ node_config.mem_dev + ) + })?; +- numa_nodes.insert(numa_config.numa_id, numa_node); ++ numa_nodes.insert(node_config.numa_id, numa_node); + } + "dist" => { +- let dist: (u32, NumaDistance) = parse_numa_distance(numa.1.as_str())?; +- if !numa_nodes.contains_key(&dist.0) { +- bail!("Numa node id is not found {}", dist.0); ++ let dist_config = parse_numa_distance(numa.1.as_str())?; ++ if !numa_nodes.contains_key(&dist_config.numa_id) { ++ bail!("Numa node id is not found {}", dist_config.numa_id); + } +- if !numa_nodes.contains_key(&dist.1.destination) { +- bail!("Numa node id is not found {}", dist.1.destination); ++ if !numa_nodes.contains_key(&dist_config.destination) { ++ bail!("Numa node id is not found {}", dist_config.destination); + } + +- if let Some(n) = numa_nodes.get_mut(&dist.0) { +- if n.distances.contains_key(&dist.1.destination) { ++ if let Some(n) = numa_nodes.get_mut(&dist_config.numa_id) { ++ if n.distances.contains_key(&dist_config.destination) { + bail!( + "Numa destination info {} repeat settings", +- dist.1.destination ++ dist_config.destination + ); + } +- n.distances.insert(dist.1.destination, dist.1.distance); ++ n.distances ++ .insert(dist_config.destination, dist_config.distance); + } + } + _ => { +@@ -1577,7 +1643,7 @@ pub trait MachineOps { + /// + /// * `cfg_args` - XHCI Configuration. + fn add_usb_xhci(&mut self, cfg_args: &str) -> Result<()> { +- let device_cfg = XhciConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let device_cfg = XhciConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); + let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; + +@@ -1601,7 +1667,7 @@ pub trait MachineOps { + cfg_args: &str, + token_id: Option>>, + ) -> Result<()> { +- let config = ScreamConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = ScreamConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf { + bus: config.bus.clone(), + addr: config.addr, +@@ -1722,16 +1788,18 @@ pub trait MachineOps { + /// * `driver` - USB device class. + /// * `cfg_args` - USB device Configuration. + fn add_usb_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let usb_device = match parse_device_type(cfg_args)?.as_str() { ++ let usb_device = match get_class_type(cfg_args)?.as_str() { + "usb-kbd" => { +- let config = UsbKeyboardConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = ++ UsbKeyboardConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let keyboard = UsbKeyboard::new(config); + keyboard + .realize() + .with_context(|| "Failed to realize usb keyboard device")? + } + "usb-tablet" => { +- let config = UsbTabletConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = ++ UsbTabletConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let tablet = UsbTablet::new(config); + tablet + .realize() +@@ -1739,7 +1807,8 @@ pub trait MachineOps { + } + #[cfg(feature = "usb_camera")] + "usb-camera" => { +- let config = UsbCameraConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = ++ UsbCameraConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let cameradev = get_cameradev_by_id(vm_config, config.cameradev.clone()) + .with_context(|| { + format!( +@@ -1754,15 +1823,32 @@ pub trait MachineOps { + .with_context(|| "Failed to realize usb camera device")? + } + "usb-storage" => { +- let device_cfg = parse_usb_storage(vm_config, cfg_args)?; +- let storage = UsbStorage::new(device_cfg, self.get_drive_files()); ++ let device_cfg = ++ UsbStorageConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let drive_cfg = vm_config ++ .drives ++ .remove(&device_cfg.drive) ++ .with_context(|| "No drive configured matched for usb storage device.")?; ++ let storage = UsbStorage::new(device_cfg, drive_cfg, self.get_drive_files())?; + storage + .realize() + .with_context(|| "Failed to realize usb storage device")? + } ++ "usb-uas" => { ++ let device_cfg = ++ UsbUasConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ let drive_cfg = vm_config ++ .drives ++ .remove(&device_cfg.drive) ++ .with_context(|| "No drive configured matched for usb uas device.")?; ++ let uas = UsbUas::new(device_cfg, drive_cfg, self.get_drive_files()); ++ uas.realize() ++ .with_context(|| "Failed to realize usb uas device")? ++ } + #[cfg(feature = "usb_host")] + "usb-host" => { +- let config = UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args))?; ++ let config = ++ UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let usbhost = UsbHost::new(config)?; + usbhost + .realize() +@@ -1804,7 +1890,7 @@ pub trait MachineOps { + for dev in &cloned_vm_config.devices { + let cfg_args = dev.1.as_str(); + // Check whether the device id exists to ensure device uniqueness. +- let id = parse_device_id(cfg_args)?; ++ let id = get_value_of_parameter("id", cfg_args)?; + self.check_device_id_existed(&id) + .with_context(|| format!("Failed to check device id: config {}", cfg_args))?; + #[cfg(feature = "scream")] +@@ -1829,13 +1915,13 @@ pub trait MachineOps { + ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), + ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), + ("nec-usb-xhci", add_usb_xhci, cfg_args), +- ("usb-kbd" | "usb-storage" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); ++ ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + #[cfg(feature = "virtio_gpu")] + ("virtio-gpu-pci", add_virtio_pci_gpu, cfg_args), + #[cfg(feature = "ramfb")] + ("ramfb", add_ramfb, cfg_args), + #[cfg(feature = "demo_device")] +- ("pcie-demo-dev", add_demo_dev, vm_config, cfg_args), ++ ("pcie-demo-dev", add_demo_dev, cfg_args), + #[cfg(feature = "scream")] + ("ivshmem-scream", add_ivshmem_scream, vm_config, cfg_args, token_id), + #[cfg(feature = "pvpanic")] +@@ -1850,7 +1936,7 @@ pub trait MachineOps { + None + } + +- fn add_pflash_device(&mut self, _configs: &[PFlashConfig]) -> Result<()> { ++ fn add_pflash_device(&mut self, _configs: &[DriveConfig]) -> Result<()> { + bail!("Pflash device is not supported!"); + } + +@@ -1863,22 +1949,22 @@ pub trait MachineOps { + } + + #[cfg(feature = "demo_device")] +- fn add_demo_dev(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { +- let bdf = get_pci_bdf(cfg_args)?; +- let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; +- +- let demo_cfg = parse_demo_dev(vm_config, cfg_args.to_string()) ++ fn add_demo_dev(&mut self, cfg_args: &str) -> Result<()> { ++ let config = DemoDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false)) + .with_context(|| "failed to parse cmdline for demo dev.")?; +- ++ let bdf = PciBdf::new(config.bus.clone(), config.addr); ++ let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; + let sys_mem = self.get_sys_mem().clone(); +- let demo_dev = DemoDev::new(demo_cfg, devfn, sys_mem, parent_bus); ++ let demo_dev = DemoDev::new(config, devfn, sys_mem, parent_bus); + + demo_dev.realize() + } + ++ #[cfg(not(target_arch = "riscv64"))] + /// Return the syscall whitelist for seccomp. + fn syscall_whitelist(&self) -> Vec; + ++ #[cfg(not(target_arch = "riscv64"))] + /// Register seccomp rules in syscall whitelist to seccomp. + fn register_seccomp(&self, balloon_enable: bool) -> Result<()> { + let mut seccomp_filter = SyscallFilter::new(SeccompOpt::Trap); +@@ -2246,18 +2332,22 @@ fn check_windows_emu_pid( + powerdown_req: Arc, + shutdown_req: Arc, + ) { +- let mut check_delay = Duration::from_millis(4000); ++ let mut check_delay = Duration::from_millis(WINDOWS_EMU_PID_DEFAULT_INTERVAL); + if !Path::new(&pid_path).exists() { +- log::info!("Detect windows emu exited, let VM exits now"); ++ log::info!("Detect emulator exited, let VM exits now"); + if get_run_stage() == VmRunningStage::Os { ++ // Wait 30s for windows normal exit. ++ check_delay = Duration::from_millis(WINDOWS_EMU_PID_POWERDOWN_INTERVAL); + if let Err(e) = powerdown_req.write(1) { + log::error!("Failed to send powerdown request after emu exits: {:?}", e); + } +- } else if let Err(e) = shutdown_req.write(1) { +- log::error!("Failed to send shutdown request after emu exits: {:?}", e); ++ } else { ++ // Wait 1s for windows shutdown. ++ check_delay = Duration::from_millis(WINDOWS_EMU_PID_SHUTDOWN_INTERVAL); ++ if let Err(e) = shutdown_req.write(1) { ++ log::error!("Failed to send shutdown request after emu exits: {:?}", e); ++ } + } +- // Continue checking to prevent exit failed. +- check_delay = Duration::from_millis(1000); + } + + let check_emu_alive = Box::new(move || { +@@ -2271,3 +2361,31 @@ fn check_windows_emu_pid( + .unwrap() + .timer_add(check_emu_alive, check_delay); + } ++ ++fn machine_register_pcidevops_type() -> Result<()> { ++ #[cfg(target_arch = "x86_64")] ++ { ++ register_pcidevops_type::()?; ++ register_pcidevops_type::()?; ++ } ++ #[cfg(target_arch = "aarch64")] ++ { ++ register_pcidevops_type::()?; ++ } ++ ++ Ok(()) ++} ++ ++pub fn type_init() -> Result<()> { ++ // Register all sysbus devices type. ++ virtio_register_sysbusdevops_type()?; ++ devices_register_sysbusdevops_type()?; ++ ++ // Register all pci devices type. ++ machine_register_pcidevops_type()?; ++ vfio_register_pcidevops_type()?; ++ virtio_register_pcidevops_type()?; ++ devices_register_pcidevops_type()?; ++ ++ Ok(()) ++} +diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs +index b97f046..7fb530e 100644 +--- a/machine/src/micro_common/mod.rs ++++ b/machine/src/micro_common/mod.rs +@@ -27,7 +27,9 @@ + //! + //! - `x86_64` + //! - `aarch64` ++//! - `riscv64` + ++#[cfg(not(target_arch = "riscv64"))] + pub mod syscall; + + use std::fmt; +@@ -38,20 +40,22 @@ use std::sync::{Arc, Mutex}; + use std::vec::Vec; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use log::{error, info}; + + #[cfg(target_arch = "aarch64")] + use crate::aarch64::micro::{LayoutEntryType, MEM_LAYOUT}; ++#[cfg(target_arch = "riscv64")] ++use crate::riscv64::micro::{LayoutEntryType, MEM_LAYOUT}; + #[cfg(target_arch = "x86_64")] + use crate::x86_64::micro::{LayoutEntryType, MEM_LAYOUT}; + use crate::{MachineBase, MachineError, MachineOps}; + use cpu::CpuLifecycleState; + use devices::sysbus::{IRQ_BASE, IRQ_MAX}; + use machine_manager::config::{ +- parse_blk, parse_incoming_uri, parse_net, BlkDevConfig, ConfigCheck, DiskFormat, MigrateMode, +- NetworkInterfaceConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, ++ get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, ++ MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, + }; +-use machine_manager::event; + use machine_manager::event_loop::EventLoop; + use machine_manager::machine::{ + DeviceInterface, MachineAddressInterface, MachineExternalInterface, MachineInterface, +@@ -60,9 +64,10 @@ use machine_manager::machine::{ + use machine_manager::qmp::{ + qmp_channel::QmpChannel, qmp_response::Response, qmp_schema, qmp_schema::UpdateRegionArgument, + }; ++use machine_manager::{check_arg_nonexist, event}; + use migration::MigrationManager; +-use util::aio::WriteZeroesState; + use util::{loop_context::EventLoopManager, num_ops::str_to_num, set_termi_canon_mode}; ++use virtio::device::block::VirtioBlkDevConfig; + use virtio::{ + create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VhostUser, + VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, +@@ -78,8 +83,9 @@ const MMIO_REPLACEABLE_NET_NR: usize = 2; + struct MmioReplaceableConfig { + // Device id. + id: String, +- // The dev_config of the related backend device. +- dev_config: Arc, ++ // The config of the related backend device. ++ // Eg: Drive config of virtio mmio block. Netdev config of virtio mmio net. ++ back_config: Arc, + } + + // The device information of replaceable device. +@@ -155,69 +161,64 @@ impl LightMachine { + } + + pub(crate) fn create_replaceable_devices(&mut self) -> Result<()> { +- let mut rpl_devs: Vec = Vec::new(); + for id in 0..MMIO_REPLACEABLE_BLK_NR { + let block = Arc::new(Mutex::new(Block::new( +- BlkDevConfig::default(), ++ VirtioBlkDevConfig::default(), ++ DriveConfig::default(), + self.get_drive_files(), + ))); +- let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, block.clone()); +- rpl_devs.push(virtio_mmio); +- + MigrationManager::register_device_instance( + BlockState::descriptor(), +- block, ++ block.clone(), ++ &id.to_string(), ++ ); ++ ++ let blk_mmio = self.add_virtio_mmio_device(id.to_string(), block.clone())?; ++ let info = MmioReplaceableDevInfo { ++ device: block, ++ id: id.to_string(), ++ used: false, ++ }; ++ self.replaceable_info.devices.lock().unwrap().push(info); ++ MigrationManager::register_transport_instance( ++ VirtioMmioState::descriptor(), ++ blk_mmio, + &id.to_string(), + ); + } + for id in 0..MMIO_REPLACEABLE_NET_NR { +- let net = Arc::new(Mutex::new(Net::new(NetworkInterfaceConfig::default()))); +- let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, net.clone()); +- rpl_devs.push(virtio_mmio); +- ++ let total_id = id + MMIO_REPLACEABLE_BLK_NR; ++ let net = Arc::new(Mutex::new(Net::new( ++ NetworkInterfaceConfig::default(), ++ NetDevcfg::default(), ++ ))); + MigrationManager::register_device_instance( + VirtioNetState::descriptor(), +- net, +- &id.to_string(), ++ net.clone(), ++ &total_id.to_string(), + ); +- } +- +- let mut region_base = self.base.sysbus.min_free_base; +- let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; +- for (id, dev) in rpl_devs.into_iter().enumerate() { +- self.replaceable_info +- .devices +- .lock() +- .unwrap() +- .push(MmioReplaceableDevInfo { +- device: dev.device.clone(), +- id: id.to_string(), +- used: false, +- }); + ++ let net_mmio = self.add_virtio_mmio_device(total_id.to_string(), net.clone())?; ++ let info = MmioReplaceableDevInfo { ++ device: net, ++ id: total_id.to_string(), ++ used: false, ++ }; ++ self.replaceable_info.devices.lock().unwrap().push(info); + MigrationManager::register_transport_instance( + VirtioMmioState::descriptor(), +- VirtioMmioDevice::realize( +- dev, +- &mut self.base.sysbus, +- region_base, +- MEM_LAYOUT[LayoutEntryType::Mmio as usize].1, +- #[cfg(target_arch = "x86_64")] +- &self.base.boot_source, +- ) +- .with_context(|| MachineError::RlzVirtioMmioErr)?, +- &id.to_string(), ++ net_mmio, ++ &total_id.to_string(), + ); +- region_base += region_size; + } +- self.base.sysbus.min_free_base = region_base; ++ + Ok(()) + } + + pub(crate) fn fill_replaceable_device( + &mut self, + id: &str, +- dev_config: Arc, ++ dev_config: Vec>, + index: usize, + ) -> Result<()> { + let mut replaceable_devices = self.replaceable_info.devices.lock().unwrap(); +@@ -232,14 +233,14 @@ impl LightMachine { + .device + .lock() + .unwrap() +- .update_config(Some(dev_config.clone())) ++ .update_config(dev_config.clone()) + .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; + } + +- self.add_replaceable_config(id, dev_config) ++ self.add_replaceable_config(id, dev_config[0].clone()) + } + +- fn add_replaceable_config(&self, id: &str, dev_config: Arc) -> Result<()> { ++ fn add_replaceable_config(&self, id: &str, back_config: Arc) -> Result<()> { + let mut configs_lock = self.replaceable_info.configs.lock().unwrap(); + let limit = MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR; + if configs_lock.len() >= limit { +@@ -254,7 +255,7 @@ impl LightMachine { + + let config = MmioReplaceableConfig { + id: id.to_string(), +- dev_config, ++ back_config, + }; + + trace::mmio_replaceable_config(&config); +@@ -262,21 +263,28 @@ impl LightMachine { + Ok(()) + } + +- fn add_replaceable_device(&self, id: &str, driver: &str, slot: usize) -> Result<()> { ++ fn add_replaceable_device( ++ &self, ++ args: Box, ++ slot: usize, ++ ) -> Result<()> { ++ let id = args.id; ++ let driver = args.driver; ++ + // Find the configuration by id. + let configs_lock = self.replaceable_info.configs.lock().unwrap(); +- let mut dev_config = None; ++ let mut configs = Vec::new(); + for config in configs_lock.iter() { + if config.id == id { +- dev_config = Some(config.dev_config.clone()); ++ configs.push(config.back_config.clone()); + } + } +- if dev_config.is_none() { ++ if configs.is_empty() { + bail!("Failed to find device configuration."); + } + + // Sanity check for config, driver and slot. +- let cfg_any = dev_config.as_ref().unwrap().as_any(); ++ let cfg_any = configs[0].as_any(); + let index = if driver.contains("net") { + if slot >= MMIO_REPLACEABLE_NET_NR { + return Err(anyhow!(MachineError::RplDevLmtErr( +@@ -284,9 +292,18 @@ impl LightMachine { + MMIO_REPLACEABLE_NET_NR + ))); + } +- if cfg_any.downcast_ref::().is_none() { ++ if cfg_any.downcast_ref::().is_none() { + return Err(anyhow!(MachineError::DevTypeErr("net".to_string()))); + } ++ let net_config = NetworkInterfaceConfig { ++ classtype: driver, ++ id: id.clone(), ++ netdev: args.chardev.with_context(|| "No chardev set")?, ++ mac: args.mac, ++ iothread: args.iothread, ++ ..Default::default() ++ }; ++ configs.push(Arc::new(net_config)); + slot + MMIO_REPLACEABLE_BLK_NR + } else if driver.contains("blk") { + if slot >= MMIO_REPLACEABLE_BLK_NR { +@@ -295,9 +312,19 @@ impl LightMachine { + MMIO_REPLACEABLE_BLK_NR + ))); + } +- if cfg_any.downcast_ref::().is_none() { ++ if cfg_any.downcast_ref::().is_none() { + return Err(anyhow!(MachineError::DevTypeErr("blk".to_string()))); + } ++ let dev_config = VirtioBlkDevConfig { ++ classtype: driver, ++ id: id.clone(), ++ drive: args.drive.with_context(|| "No drive set")?, ++ bootindex: args.boot_index, ++ iothread: args.iothread, ++ serial: args.serial_num, ++ ..Default::default() ++ }; ++ configs.push(Arc::new(dev_config)); + slot + } else { + bail!("Unsupported replaceable device type."); +@@ -316,7 +343,7 @@ impl LightMachine { + .device + .lock() + .unwrap() +- .update_config(dev_config) ++ .update_config(configs) + .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; + } + Ok(()) +@@ -328,8 +355,10 @@ impl LightMachine { + let mut configs_lock = self.replaceable_info.configs.lock().unwrap(); + for (index, config) in configs_lock.iter().enumerate() { + if config.id == id { +- if let Some(blkconf) = config.dev_config.as_any().downcast_ref::() { +- self.unregister_drive_file(&blkconf.path_on_host)?; ++ if let Some(drive_config) = ++ config.back_config.as_any().downcast_ref::() ++ { ++ self.unregister_drive_file(&drive_config.path_on_host)?; + } + configs_lock.remove(index); + is_exist = true; +@@ -347,7 +376,7 @@ impl LightMachine { + .device + .lock() + .unwrap() +- .update_config(None) ++ .update_config(Vec::new()) + .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; + } + } +@@ -363,22 +392,42 @@ impl LightMachine { + vm_config: &mut VmConfig, + cfg_args: &str, + ) -> Result<()> { +- let device_cfg = parse_net(vm_config, cfg_args)?; +- if device_cfg.vhost_type.is_some() { +- let device = if device_cfg.vhost_type == Some(String::from("vhost-kernel")) { ++ let net_cfg = ++ NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ check_arg_nonexist!( ++ ("bus", net_cfg.bus), ++ ("addr", net_cfg.addr), ++ ("multifunction", net_cfg.multifunction) ++ ); ++ let netdev_cfg = vm_config ++ .netdevs ++ .remove(&net_cfg.netdev) ++ .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; ++ if netdev_cfg.vhost_type().is_some() { ++ if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { + let net = Arc::new(Mutex::new(VhostKern::Net::new( +- &device_cfg, ++ &net_cfg, ++ netdev_cfg, + &self.base.sys_mem, + ))); +- VirtioMmioDevice::new(&self.base.sys_mem, net) ++ self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + } else { ++ let chardev = netdev_cfg.chardev.clone().with_context(|| { ++ format!("Chardev not configured for netdev {:?}", netdev_cfg.id) ++ })?; ++ let chardev_cfg = vm_config ++ .chardev ++ .remove(&chardev) ++ .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; ++ let sock_path = get_chardev_socket_path(chardev_cfg)?; + let net = Arc::new(Mutex::new(VhostUser::Net::new( +- &device_cfg, ++ &net_cfg, ++ netdev_cfg, ++ sock_path, + &self.base.sys_mem, + ))); +- VirtioMmioDevice::new(&self.base.sys_mem, net) ++ self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + }; +- self.realize_virtio_mmio_device(device)?; + } else { + let index = MMIO_REPLACEABLE_BLK_NR + self.replaceable_info.net_count; + if index >= MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR { +@@ -387,7 +436,9 @@ impl LightMachine { + MMIO_REPLACEABLE_NET_NR + ); + } +- self.fill_replaceable_device(&device_cfg.id, Arc::new(device_cfg.clone()), index)?; ++ let configs: Vec> = ++ vec![Arc::new(netdev_cfg), Arc::new(net_cfg.clone())]; ++ self.fill_replaceable_device(&net_cfg.id, configs, index)?; + self.replaceable_info.net_count += 1; + } + Ok(()) +@@ -398,7 +449,17 @@ impl LightMachine { + vm_config: &mut VmConfig, + cfg_args: &str, + ) -> Result<()> { +- let device_cfg = parse_blk(vm_config, cfg_args, None)?; ++ let device_cfg = ++ VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; ++ check_arg_nonexist!( ++ ("bus", device_cfg.bus), ++ ("addr", device_cfg.addr), ++ ("multifunction", device_cfg.multifunction) ++ ); ++ let drive_cfg = vm_config ++ .drives ++ .remove(&device_cfg.drive) ++ .with_context(|| "No drive configured matched for blk device")?; + if self.replaceable_info.block_count >= MMIO_REPLACEABLE_BLK_NR { + bail!( + "A maximum of {} block replaceable devices are supported.", +@@ -406,15 +467,21 @@ impl LightMachine { + ); + } + let index = self.replaceable_info.block_count; +- self.fill_replaceable_device(&device_cfg.id, Arc::new(device_cfg.clone()), index)?; ++ let configs: Vec> = ++ vec![Arc::new(drive_cfg), Arc::new(device_cfg.clone())]; ++ self.fill_replaceable_device(&device_cfg.id, configs, index)?; + self.replaceable_info.block_count += 1; + Ok(()) + } + +- pub(crate) fn realize_virtio_mmio_device( ++ pub(crate) fn add_virtio_mmio_device( + &mut self, +- dev: VirtioMmioDevice, ++ name: String, ++ device: Arc>, + ) -> Result>> { ++ let sys_mem = self.get_sys_mem().clone(); ++ let dev = VirtioMmioDevice::new(&sys_mem, name, device); ++ + let region_base = self.base.sysbus.min_free_base; + let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; + let realized_virtio_mmio_device = VirtioMmioDevice::realize( +@@ -461,7 +528,7 @@ impl MachineLifecycle for LightMachine { + } + + info!("vm destroy"); +- EventLoop::get_ctx(None).unwrap().kick(); ++ EventLoop::kick_all(); + + true + } +@@ -583,6 +650,8 @@ impl DeviceInterface for LightMachine { + let cpu_type = String::from("host-x86-cpu"); + #[cfg(target_arch = "aarch64")] + let cpu_type = String::from("host-aarch64-cpu"); ++ #[cfg(target_arch = "riscv64")] ++ let cpu_type = String::from("host-riscv64-cpu"); + + for cpu_index in 0..self.base.cpu_topo.max_cpus { + if self.base.cpu_topo.get_mask(cpu_index as usize) == 0 { +@@ -668,7 +737,7 @@ impl DeviceInterface for LightMachine { + fn device_add(&mut self, args: Box) -> Response { + // get slot of bus by addr or lun + let mut slot = 0; +- if let Some(addr) = args.addr { ++ if let Some(addr) = args.addr.clone() { + if let Ok(num) = str_to_num::(&addr) { + slot = num; + } else { +@@ -684,7 +753,7 @@ impl DeviceInterface for LightMachine { + slot = lun + 1; + } + +- match self.add_replaceable_device(&args.id, &args.driver, slot) { ++ match self.add_replaceable_device(args.clone(), slot) { + Ok(()) => Response::create_empty_response(), + Err(ref e) => { + error!("{:?}", e); +@@ -719,32 +788,22 @@ impl DeviceInterface for LightMachine { + } + + fn blockdev_add(&self, args: Box) -> Response { +- let read_only = args.read_only.unwrap_or(false); ++ let readonly = args.read_only.unwrap_or(false); + let mut direct = true; + if args.cache.is_some() && !args.cache.unwrap().direct.unwrap_or(true) { + direct = false; + } + +- let config = BlkDevConfig { ++ let config = DriveConfig { + id: args.node_name.clone(), ++ drive_type: "none".to_string(), + path_on_host: args.file.filename.clone(), +- read_only, ++ readonly, + direct, +- serial_num: None, +- iothread: None, +- iops: None, +- queues: 1, +- boot_index: None, +- chardev: None, +- socket_path: None, + aio: args.file.aio, +- queue_size: DEFAULT_VIRTQUEUE_SIZE, +- discard: false, +- write_zeroes: WriteZeroesState::Off, +- format: DiskFormat::Raw, +- l2_cache_size: None, +- refcount_cache_size: None, ++ ..Default::default() + }; ++ + if let Err(e) = config.check() { + error!("{:?}", e); + return Response::create_error_response( +@@ -753,7 +812,7 @@ impl DeviceInterface for LightMachine { + ); + } + // Register drive backend file for hotplugged drive. +- if let Err(e) = self.register_drive_file(&config.id, &args.file.filename, read_only, direct) ++ if let Err(e) = self.register_drive_file(&config.id, &args.file.filename, readonly, direct) + { + error!("{:?}", e); + return Response::create_error_response( +@@ -783,18 +842,9 @@ impl DeviceInterface for LightMachine { + } + + fn netdev_add(&mut self, args: Box) -> Response { +- let mut config = NetworkInterfaceConfig { ++ let mut netdev_cfg = NetDevcfg { + id: args.id.clone(), +- host_dev_name: "".to_string(), +- mac: None, +- tap_fds: None, +- vhost_type: None, +- vhost_fds: None, +- iothread: None, +- queues: 2, +- mq: false, +- socket_path: None, +- queue_size: DEFAULT_VIRTQUEUE_SIZE, ++ ..Default::default() + }; + + if let Some(fds) = args.fds { +@@ -806,7 +856,7 @@ impl DeviceInterface for LightMachine { + }; + + if let Some(fd_num) = QmpChannel::get_fd(&netdev_fd) { +- config.tap_fds = Some(vec![fd_num]); ++ netdev_cfg.tap_fds = Some(vec![fd_num]); + } else { + // try to convert string to RawFd + let fd_num = match netdev_fd.parse::() { +@@ -824,10 +874,10 @@ impl DeviceInterface for LightMachine { + ); + } + }; +- config.tap_fds = Some(vec![fd_num]); ++ netdev_cfg.tap_fds = Some(vec![fd_num]); + } + } else if let Some(if_name) = args.if_name { +- config.host_dev_name = if_name.clone(); ++ netdev_cfg.ifname = if_name.clone(); + if create_tap(None, Some(&if_name), 1).is_err() { + return Response::create_error_response( + qmp_schema::QmpErrorClass::GenericError( +@@ -838,7 +888,7 @@ impl DeviceInterface for LightMachine { + } + } + +- match self.add_replaceable_config(&args.id, Arc::new(config)) { ++ match self.add_replaceable_config(&args.id, Arc::new(netdev_cfg)) { + Ok(()) => Response::create_empty_response(), + Err(ref e) => { + error!("{:?}", e); +diff --git a/machine/src/micro_common/syscall.rs b/machine/src/micro_common/syscall.rs +index ca8327f..f3acec1 100644 +--- a/machine/src/micro_common/syscall.rs ++++ b/machine/src/micro_common/syscall.rs +@@ -159,14 +159,7 @@ fn ioctl_allow_list() -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_API_VERSION() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_USER_MEMORY_REGION); +- #[cfg(target_arch = "x86_64")] +- let bpf_rule = bpf_rule +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_PIT2() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_CLOCK() as u32) +- .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_IRQCHIP() as u32); ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32); + arch_ioctl_allow_list(bpf_rule) + } + +diff --git a/machine/src/riscv64/fdt.rs b/machine/src/riscv64/fdt.rs +new file mode 100644 +index 0000000..05d00a3 +--- /dev/null ++++ b/machine/src/riscv64/fdt.rs +@@ -0,0 +1,217 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use anyhow::Result; ++ ++use crate::MachineBase; ++use devices::sysbus::{SysBusDevType, SysRes}; ++use util::device_tree::{self, FdtBuilder}; ++ ++/// Function that helps to generate arm pmu in device-tree. ++/// ++/// # Arguments ++/// ++/// * `fdt` - Flatted device-tree blob where node will be filled into. ++ ++/// Function that helps to generate serial node in device-tree. ++/// ++/// # Arguments ++/// ++/// * `dev_info` - Device resource info of serial device. ++/// * `fdt` - Flatted device-tree blob where serial node will be filled into. ++fn generate_serial_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> Result<()> { ++ let node = format!("serial@{:x}", res.region_base); ++ let serial_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("compatible", "ns16550a")?; ++ fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; ++ fdt.set_property_u32("clock-frequency", 3686400)?; ++ fdt.set_property_u32("interrupt-parent", device_tree::AIA_APLIC_PHANDLE)?; ++ let mut cells: Vec = Vec::new(); ++ cells.push(res.irq as u32); ++ cells.push(0x4); ++ fdt.set_property_array_u32("interrupts", &cells)?; ++ fdt.end_node(serial_node_dep) ++} ++ ++/// Function that helps to generate RTC node in device-tree. ++/// ++/// # Arguments ++/// ++/// * `dev_info` - Device resource info of RTC device. ++/// * `fdt` - Flatted device-tree blob where RTC node will be filled into. ++/// Function that helps to generate Virtio-Mmio device's node in device-tree. ++/// ++/// # Arguments ++/// ++/// * `dev_info` - Device resource info of Virtio-Mmio device. ++/// * `fdt` - Flatted device-tree blob where node will be filled into. ++fn generate_virtio_devices_node(fdt: &mut FdtBuilder, res: &SysRes) -> Result<()> { ++ let node = format!("virtio_mmio@{:x}", res.region_base); ++ let virtio_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("compatible", "virtio,mmio")?; ++ fdt.set_property_u32("interrupt-parent", device_tree::AIA_APLIC_PHANDLE)?; ++ fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; ++ let mut cells: Vec = Vec::new(); ++ cells.push(res.irq as u32); ++ cells.push(0x4); ++ fdt.set_property_array_u32("interrupts", &cells)?; ++ fdt.end_node(virtio_node_dep) ++} ++ ++/// Function that helps to generate fw-cfg node in device-tree. ++/// ++/// # Arguments ++/// ++/// * `dev_info` - Device resource info of fw-cfg device. ++/// * `fdt` - Flatted device-tree blob where fw-cfg node will be filled into. ++// fn generate_fwcfg_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> Result<()> { ++// TODO ++// } ++ ++/// Function that helps to generate flash node in device-tree. ++/// ++/// # Arguments ++/// ++/// * `dev_info` - Device resource info of fw-cfg device. ++/// * `flash` - Flatted device-tree blob where fw-cfg node will be filled into. ++// fn generate_flash_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> Result<()> { ++// TODO ++// } ++ ++/// Trait that helps to generate all nodes in device-tree. ++#[allow(clippy::upper_case_acronyms)] ++trait CompileFDTHelper { ++ /// Function that helps to generate cpu nodes. ++ fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> Result<()>; ++ /// Function that helps to generate Virtio-mmio devices' nodes. ++ fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> Result<()>; ++} ++ ++impl CompileFDTHelper for MachineBase { ++ fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let node = "cpus"; ++ ++ let cpus = &self.cpus; ++ let cpus_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_u32("#address-cells", 0x01)?; ++ fdt.set_property_u32("#size-cells", 0x0)?; ++ let frequency = cpus[0].arch().lock().unwrap().timer_regs().frequency; ++ fdt.set_property_u32("timebase-frequency", frequency as u32)?; ++ ++ let nr_vcpus = cpus.len(); ++ for cpu_index in 0..nr_vcpus { ++ let node = format!("cpu@{:x}", cpu_index); ++ let cpu_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_u32("phandle", cpu_index as u32 + device_tree::PHANDLE_CPU)?; ++ fdt.set_property_string("device_type", "cpu")?; ++ fdt.set_property_string("compatible", "riscv")?; ++ ++ let xlen = self.cpus[cpu_index] ++ .arch() ++ .lock() ++ .unwrap() ++ .get_xlen() ++ .to_string(); ++ let mut isa = format!("rv{}", xlen); ++ let valid_isa_order = String::from("IEMAFDQCLBJTPVNSUHKORWXYZG"); ++ for char in valid_isa_order.chars() { ++ let index = char as u32 - 'A' as u32; ++ let cpu_isa = self.cpus[cpu_index] ++ .arch() ++ .lock() ++ .unwrap() ++ .config_regs() ++ .isa; ++ if (cpu_isa & (1 << index) as u64) > 0 { ++ let tmp = char::from('a' as u8 + index as u8); ++ isa = format!("{}{}", isa, tmp); ++ } ++ } ++ isa = format!("{}_{}", isa, "ssaia_smaia"); ++ ++ fdt.set_property_string("riscv,isa", &isa)?; ++ ++ fdt.set_property_u32("reg", cpu_index as u32)?; ++ ++ let node = "interrupt-controller"; ++ let interrupt_controller = fdt.begin_node(node)?; ++ fdt.set_property_u32("#interrupt-cells", 1)?; ++ fdt.set_property_array_u32("interrupt-controller", &Vec::new())?; ++ fdt.set_property_string("compatible", "riscv,cpu-intc")?; ++ fdt.set_property_u32( ++ "phandle", ++ cpu_index as u32 + device_tree::INTC_PHANDLE_START, ++ )?; ++ fdt.end_node(interrupt_controller)?; ++ ++ fdt.end_node(cpu_node_dep)?; ++ } ++ ++ let cpu_map_node_dep = fdt.begin_node("cpu-map")?; ++ for cluster in 0..self.cpu_topo.clusters { ++ let cluster_name = format!("cluster{}", cluster); ++ let cluster_node_dep = fdt.begin_node(&cluster_name)?; ++ for core in 0..self.cpu_topo.cores { ++ let core_name = format!("core{}", core); ++ let core_node_dep = fdt.begin_node(&core_name)?; ++ let vcpuid = self.cpu_topo.cores * cluster + core; ++ fdt.set_property_u32("cpu", u32::from(vcpuid) + device_tree::PHANDLE_CPU)?; ++ fdt.end_node(core_node_dep)?; ++ } ++ fdt.end_node(cluster_node_dep)?; ++ } ++ fdt.end_node(cpu_map_node_dep)?; ++ ++ fdt.end_node(cpus_node_dep)?; ++ ++ Ok(()) ++ } ++ ++ fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let node = "soc"; ++ let smb_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "simple-bus")?; ++ fdt.set_property_u32("#address-cells", 0x02)?; ++ fdt.set_property_u32("#size-cells", 0x2)?; ++ fdt.set_property("ranges", &Vec::new())?; ++ ++ for dev in self.sysbus.devices.iter() { ++ let locked_dev = dev.lock().unwrap(); ++ match locked_dev.sysbusdev_base().dev_type { ++ SysBusDevType::Serial => { ++ generate_serial_device_node(fdt, &locked_dev.sysbusdev_base().res)? ++ } ++ SysBusDevType::VirtioMmio => { ++ generate_virtio_devices_node(fdt, &locked_dev.sysbusdev_base().res)? ++ } ++ _ => (), ++ } ++ } ++ ++ use util::device_tree::CompileFDT; ++ self.irq_chip.as_ref().unwrap().generate_fdt_node(fdt)?; ++ ++ fdt.end_node(smb_node_dep)?; ++ Ok(()) ++ } ++} ++ ++impl device_tree::CompileFDT for MachineBase { ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ fdt.set_property_string("compatible", "linux,dummy-virt")?; ++ fdt.set_property_u32("#address-cells", 0x2)?; ++ fdt.set_property_u32("#size-cells", 0x2)?; ++ ++ self.generate_cpu_nodes(fdt)?; ++ self.generate_devices_node(fdt) ++ } ++} +diff --git a/machine/src/riscv64/micro.rs b/machine/src/riscv64/micro.rs +new file mode 100644 +index 0000000..d0d059b +--- /dev/null ++++ b/machine/src/riscv64/micro.rs +@@ -0,0 +1,278 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::sync::{Arc, Mutex}; ++ ++use anyhow::{bail, Context, Result}; ++use devices::legacy::Serial; ++use log::info; ++ ++use crate::{LightMachine, MachineOps}; ++use crate::{MachineBase, MachineError}; ++use address_space::{AddressSpace, GuestAddress, Region}; ++use cpu::CPUTopology; ++// use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; ++use devices::AIAConfig as InterruptControllerConfig; ++use hypervisor::kvm::riscv64::*; ++use machine_manager::config::{SerialConfig, VmConfig}; ++use migration::{MigrationManager, MigrationStatus}; ++use util::{ ++ device_tree::{self, CompileFDT, FdtBuilder}, ++ seccomp::{BpfRule, SeccompCmpOpt}, ++}; ++use virtio::{VirtioDevice, VirtioMmioDevice}; ++ ++/// The type of memory layout entry on riscv64 ++#[repr(usize)] ++pub enum LayoutEntryType { ++ AIA, ++ Uart, ++ Mmio, ++ Mem, ++} ++/// Layout of riscv64 ++pub const MEM_LAYOUT: &[(u64, u64)] = &[ ++ (0x0c00_0000, 0x0400_0000), // AIA ++ (0x1000_0000, 0x0000_1000), // Uart ++ (0x1000_1000, 0x0000_1000), // Mmio ++ (0x8000_0000, 0x80_0000_0000), // Mem ++]; ++ ++impl MachineOps for LightMachine { ++ fn machine_base(&self) -> &MachineBase { ++ &self.base ++ } ++ ++ fn machine_base_mut(&mut self) -> &mut MachineBase { ++ &mut self.base ++ } ++ ++ fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { ++ let vm_ram = self.get_vm_ram(); ++ let layout_size = MEM_LAYOUT[LayoutEntryType::Mem as usize].1; ++ let ram = Region::init_alias_region( ++ vm_ram.clone(), ++ 0, ++ std::cmp::min(layout_size, mem_size), ++ "pc_ram", ++ ); ++ sys_mem ++ .root() ++ .add_subregion(ram, MEM_LAYOUT[LayoutEntryType::Mem as usize].0) ++ } ++ ++ fn init_interrupt_controller(&mut self, vcpu_count: u64) -> Result<()> { ++ let aia_conf = InterruptControllerConfig { ++ vcpu_count: vcpu_count as u32, ++ max_irq: 33, ++ region_range: ( ++ MEM_LAYOUT[LayoutEntryType::AIA as usize].0, ++ MEM_LAYOUT[LayoutEntryType::AIA as usize].1, ++ ), ++ }; ++ ++ let hypervisor = self.get_hypervisor(); ++ let mut locked_hypervisor = hypervisor.lock().unwrap(); ++ self.base.irq_chip = Some(locked_hypervisor.create_interrupt_controller(&aia_conf)?); ++ self.base.irq_chip.as_ref().unwrap().realize()?; ++ ++ let irq_manager = locked_hypervisor.create_irq_manager()?; ++ self.base.sysbus.irq_manager = irq_manager.line_irq_manager; ++ Ok(()) ++ } ++ ++ // fn add_rtc_device(&mut self) -> Result<()> { ++ // TODO ++ // } ++ ++ fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { ++ let region_base: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].0; ++ let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; ++ ++ let serial = Serial::new(config.clone()); ++ serial ++ .realize( ++ &mut self.base.sysbus, ++ region_base, ++ region_size, ++ &self.base.boot_source, ++ ) ++ .with_context(|| "Failed to realize Serial") ++ } ++ ++ fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { ++ let mut locked_vm = vm.lock().unwrap(); ++ ++ trace::sysbus(&locked_vm.base.sysbus); ++ trace::vm_state(&locked_vm.base.vm_state); ++ ++ let topology = CPUTopology::new().set_topology(( ++ vm_config.machine_config.nr_threads, ++ vm_config.machine_config.nr_cores, ++ vm_config.machine_config.nr_dies, ++ )); ++ trace::cpu_topo(&topology); ++ locked_vm.base.numa_nodes = locked_vm.add_numa_nodes(vm_config)?; ++ let locked_hypervisor = locked_vm.base.hypervisor.lock().unwrap(); ++ locked_hypervisor.init_machine(&locked_vm.base.sys_mem)?; ++ drop(locked_hypervisor); ++ locked_vm.init_memory( ++ &vm_config.machine_config.mem_config, ++ &locked_vm.base.sys_mem, ++ vm_config.machine_config.nr_cpus, ++ )?; ++ ++ let boot_config = ++ locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; ++ #[cfg(target_arch = "aarch64")] ++ let cpu_config = locked_vm.load_cpu_features(vm_config)?; ++ ++ let hypervisor = locked_vm.base.hypervisor.clone(); ++ // vCPUs init,and apply CPU features (for aarch64) ++ locked_vm.base.cpus.extend(::init_vcpu( ++ vm.clone(), ++ hypervisor, ++ vm_config.machine_config.nr_cpus, ++ &topology, ++ &boot_config, ++ )?); ++ ++ locked_vm.init_interrupt_controller(u64::from(vm_config.machine_config.nr_cpus))?; ++ ++ #[cfg(target_arch = "aarch64")] ++ locked_vm.cpu_post_init(&cpu_config)?; ++ ++ // Add mmio devices ++ locked_vm ++ .create_replaceable_devices() ++ .with_context(|| "Failed to create replaceable devices.")?; ++ locked_vm.add_devices(vm_config)?; ++ trace::replaceable_info(&locked_vm.replaceable_info); ++ ++ let mut fdt_helper = FdtBuilder::new(); ++ locked_vm ++ .generate_fdt_node(&mut fdt_helper) ++ .with_context(|| MachineError::GenFdtErr)?; ++ let fdt_vec = fdt_helper.finish()?; ++ ++ locked_vm ++ .base ++ .sys_mem ++ .write( ++ &mut fdt_vec.as_slice(), ++ GuestAddress(boot_config.fdt_addr), ++ fdt_vec.len() as u64, ++ ) ++ .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; ++ ++ MigrationManager::register_vm_instance(vm.clone()); ++ MigrationManager::register_migration_instance(locked_vm.base.migration_hypervisor.clone()); ++ if let Err(e) = MigrationManager::set_status(MigrationStatus::Setup) { ++ bail!("Failed to set migration status {}", e); ++ } ++ ++ Ok(()) ++ } ++ ++ fn add_virtio_mmio_net(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { ++ self.add_virtio_mmio_net(vm_config, cfg_args) ++ } ++ ++ fn add_virtio_mmio_block(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { ++ self.add_virtio_mmio_block(vm_config, cfg_args) ++ } ++ ++ fn add_virtio_mmio_device( ++ &mut self, ++ name: String, ++ device: Arc>, ++ ) -> Result>> { ++ self.add_virtio_mmio_device(name, device) ++ } ++ ++ #[cfg(not(target_arch = "riscv64"))] ++ fn syscall_whitelist(&self) -> Vec { ++ syscall_whitelist() ++ } ++} ++ ++pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { ++ bpf_rule ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_ONE_REG() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DEVICE_ATTR() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_REG_LIST() as u32) ++} ++ ++pub(crate) fn arch_syscall_whitelist() -> Vec { ++ vec![ ++ BpfRule::new(libc::SYS_epoll_pwait), ++ BpfRule::new(libc::SYS_newfstatat), ++ BpfRule::new(libc::SYS_unlinkat), ++ BpfRule::new(libc::SYS_mkdirat), ++ ] ++} ++ ++/// Trait that helps to generate all nodes in device-tree. ++#[allow(clippy::upper_case_acronyms)] ++trait CompileFDTHelper { ++ /// Function that helps to generate memory nodes. ++ fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> Result<()>; ++ /// Function that helps to generate the chosen node. ++ fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> Result<()>; ++} ++ ++impl CompileFDTHelper for LightMachine { ++ fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; ++ let mem_size = self.base.sys_mem.memory_end_address().raw_value() ++ - MEM_LAYOUT[LayoutEntryType::Mem as usize].0; ++ let node = format!("memory@{:x}", mem_base); ++ let memory_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("device_type", "memory")?; ++ fdt.set_property_array_u64("reg", &[mem_base, mem_size])?; ++ fdt.end_node(memory_node_dep) ++ } ++ ++ fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let node = "chosen"; ++ let boot_source = self.base.boot_source.lock().unwrap(); ++ ++ let chosen_node_dep = fdt.begin_node(node)?; ++ let cmdline = &boot_source.kernel_cmdline.to_string(); ++ fdt.set_property_string("bootargs", cmdline.as_str())?; ++ ++ let serial_property_string = format!( ++ "/soc/serial@{:x}", ++ MEM_LAYOUT[LayoutEntryType::Uart as usize].0 ++ ); ++ fdt.set_property_string("stdout-path", &serial_property_string)?; ++ ++ match &boot_source.initrd { ++ Some(initrd) => { ++ fdt.set_property_u64("linux,initrd-start", initrd.initrd_addr)?; ++ fdt.set_property_u64("linux,initrd-end", initrd.initrd_addr + initrd.initrd_size)?; ++ } ++ None => {} ++ } ++ fdt.end_node(chosen_node_dep) ++ } ++} ++ ++impl device_tree::CompileFDT for LightMachine { ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()> { ++ let node_dep = fdt.begin_node("")?; ++ self.base.generate_fdt_node(fdt)?; ++ self.generate_memory_node(fdt)?; ++ self.generate_chosen_node(fdt)?; ++ fdt.end_node(node_dep) ++ } ++} +diff --git a/machine/src/riscv64/mod.rs b/machine/src/riscv64/mod.rs +new file mode 100644 +index 0000000..2f40818 +--- /dev/null ++++ b/machine/src/riscv64/mod.rs +@@ -0,0 +1,14 @@ ++// Copyright (c) 2024 Institute of Software, CAS. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++mod fdt; ++pub mod micro; +diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs +index 1ab0be0..f18350a 100644 +--- a/machine/src/standard_common/mod.rs ++++ b/machine/src/standard_common/mod.rs +@@ -79,7 +79,9 @@ use ui::input::{input_button, input_move_abs, input_point_sync, key_event, Axis} + use ui::vnc::qmp_query_vnc; + use util::aio::{AioEngine, WriteZeroesState}; + use util::byte_code::ByteCode; +-use util::loop_context::{read_fd, EventNotifier, NotifierCallback, NotifierOperation}; ++use util::loop_context::{ ++ create_new_eventfd, read_fd, EventNotifier, NotifierCallback, NotifierOperation, ++}; + use virtio::{qmp_balloon, qmp_query_balloon}; + + const MAX_REGION_SIZE: u64 = 65536; +@@ -341,7 +343,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { + let shutdown_req_fd = shutdown_req.as_raw_fd(); + let shutdown_req_handler: Rc = Rc::new(move |_, _| { + let _ret = shutdown_req.read(); +- if StdMachine::handle_destroy_request(&clone_vm).is_ok() { ++ if StdMachine::handle_destroy_request(&clone_vm) { + Some(gen_delete_notifiers(&[shutdown_req_fd])) + } else { + None +@@ -882,11 +884,11 @@ impl StdMachine { + power_button: Arc, + shutdown_req: Arc, + ) { +- let emu_pid = vm_config.windows_emu_pid.as_ref(); ++ let emu_pid = vm_config.emulator_pid.as_ref(); + if emu_pid.is_none() { + return; + } +- log::info!("Watching on windows emu lifetime"); ++ log::info!("Watching on emulator lifetime"); + crate::check_windows_emu_pid( + "/proc/".to_owned() + emu_pid.unwrap(), + power_button, +@@ -1272,7 +1274,7 @@ impl DeviceInterface for StdMachine { + if let Err(e) = self.register_drive_file( + &config.id, + &args.file.filename, +- config.read_only, ++ config.readonly, + config.direct, + ) { + error!("{:?}", e); +@@ -1549,7 +1551,7 @@ impl DeviceInterface for StdMachine { + region = Region::init_io_region(args.size, dummy_dev_ops, "UpdateRegionTest"); + if args.ioeventfd.is_some() && args.ioeventfd.unwrap() { + let ioeventfds = vec![RegionIoEventFd { +- fd: Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()), ++ fd: Arc::new(create_new_eventfd().unwrap()), + addr_range: AddressRange::from(( + 0, + args.ioeventfd_size.unwrap_or_default(), +@@ -1672,12 +1674,7 @@ impl DeviceInterface for StdMachine { + None, + ); + } +- let drive_cfg = match self +- .get_vm_config() +- .lock() +- .unwrap() +- .add_block_drive(cmd_args[2]) +- { ++ let drive_cfg = match self.get_vm_config().lock().unwrap().add_drive(cmd_args[2]) { + Ok(cfg) => cfg, + Err(ref e) => { + return Response::create_error_response( +@@ -1689,7 +1686,7 @@ impl DeviceInterface for StdMachine { + if let Err(e) = self.register_drive_file( + &drive_cfg.id, + &drive_cfg.path_on_host, +- drive_cfg.read_only, ++ drive_cfg.readonly, + drive_cfg.direct, + ) { + error!("{:?}", e); +@@ -1915,8 +1912,10 @@ impl DeviceInterface for StdMachine { + fn parse_blockdev(args: &BlockDevAddArgument) -> Result { + let mut config = DriveConfig { + id: args.node_name.clone(), ++ drive_type: "none".to_string(), ++ unit: None, + path_on_host: args.file.filename.clone(), +- read_only: args.read_only.unwrap_or(false), ++ readonly: args.read_only.unwrap_or(false), + direct: true, + iops: args.iops, + aio: args.file.aio, +diff --git a/machine/src/standard_common/syscall.rs b/machine/src/standard_common/syscall.rs +index 0cfac2e..d665f31 100644 +--- a/machine/src/standard_common/syscall.rs ++++ b/machine/src/standard_common/syscall.rs +@@ -104,6 +104,7 @@ pub fn syscall_whitelist() -> Vec { + BpfRule::new(libc::SYS_accept4), + BpfRule::new(libc::SYS_lseek), + futex_rule(), ++ BpfRule::new(libc::SYS_clone), + BpfRule::new(libc::SYS_exit), + BpfRule::new(libc::SYS_exit_group), + BpfRule::new(libc::SYS_rt_sigreturn), +diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs +index 77ea440..e5d17ce 100644 +--- a/machine/src/x86_64/micro.rs ++++ b/machine/src/x86_64/micro.rs +@@ -22,10 +22,10 @@ use cpu::{CPUBootConfig, CPUTopology}; + use devices::legacy::FwCfgOps; + use hypervisor::kvm::x86_64::*; + use hypervisor::kvm::*; +-use machine_manager::config::{MigrateMode, SerialConfig, VmConfig}; ++use machine_manager::config::{SerialConfig, VmConfig}; + use migration::{MigrationManager, MigrationStatus}; + use util::seccomp::{BpfRule, SeccompCmpOpt}; +-use virtio::VirtioMmioDevice; ++use virtio::{VirtioDevice, VirtioMmioDevice}; + + #[repr(usize)] + pub enum LayoutEntryType { +@@ -174,12 +174,7 @@ impl MachineOps for LightMachine { + locked_vm.add_devices(vm_config)?; + trace::replaceable_info(&locked_vm.replaceable_info); + +- let migrate_info = locked_vm.get_migrate_info(); +- let boot_config = if migrate_info.0 == MigrateMode::Unknown { +- Some(locked_vm.load_boot_source(None)?) +- } else { +- None +- }; ++ let boot_config = locked_vm.load_boot_source(None)?; + let hypervisor = locked_vm.base.hypervisor.clone(); + locked_vm.base.cpus.extend(::init_vcpu( + vm.clone(), +@@ -209,11 +204,12 @@ impl MachineOps for LightMachine { + self.add_virtio_mmio_block(vm_config, cfg_args) + } + +- fn realize_virtio_mmio_device( ++ fn add_virtio_mmio_device( + &mut self, +- dev: VirtioMmioDevice, ++ name: String, ++ device: Arc>, + ) -> Result>> { +- self.realize_virtio_mmio_device(dev) ++ self.add_virtio_mmio_device(name, device) + } + + fn syscall_whitelist(&self) -> Vec { +@@ -243,6 +239,7 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_LAPIC() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MSRS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MSRS() as u32) ++ .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_CPUID2() as u32) + } + +diff --git a/machine/src/x86_64/mod.rs b/machine/src/x86_64/mod.rs +index 47b4ecb..b3227f9 100644 +--- a/machine/src/x86_64/mod.rs ++++ b/machine/src/x86_64/mod.rs +@@ -11,7 +11,6 @@ + // See the Mulan PSL v2 for more details. + + pub mod ich9_lpc; ++pub mod mch; + pub mod micro; + pub mod standard; +- +-mod mch; +diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs +index 3aac836..8dca2db 100644 +--- a/machine/src/x86_64/standard.rs ++++ b/machine/src/x86_64/standard.rs +@@ -45,9 +45,10 @@ use hypervisor::kvm::*; + #[cfg(feature = "gtk")] + use machine_manager::config::UiContext; + use machine_manager::config::{ +- parse_incoming_uri, BootIndexInfo, MigrateMode, NumaNode, PFlashConfig, SerialConfig, VmConfig, ++ parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, + }; + use machine_manager::event; ++use machine_manager::event_loop::EventLoop; + use machine_manager::machine::{ + MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, + MigrateInterface, VmState, +@@ -60,7 +61,10 @@ use ui::gtk::gtk_display_init; + use ui::vnc::vnc_init; + use util::seccomp::SeccompCmpOpt; + use util::{ +- byte_code::ByteCode, loop_context::EventLoopManager, seccomp::BpfRule, set_termi_canon_mode, ++ byte_code::ByteCode, ++ loop_context::{create_new_eventfd, EventLoopManager}, ++ seccomp::BpfRule, ++ set_termi_canon_mode, + }; + + pub(crate) const VENDOR_ID_INTEL: u16 = 0x8086; +@@ -155,20 +159,20 @@ impl StdMachine { + IRQ_MAP[IrqEntryType::Pcie as usize].0, + ))), + reset_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("reset request".to_string()))?, + ), + shutdown_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK).with_context(|| { ++ create_new_eventfd().with_context(|| { + MachineError::InitEventFdErr("shutdown request".to_string()) + })?, + ), + power_button: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("power button".to_string()))?, + ), + cpu_resize_req: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("cpu resize".to_string()))?, + ), + boot_order_list: Arc::new(Mutex::new(Vec::new())), +@@ -206,7 +210,7 @@ impl StdMachine { + Ok(()) + } + +- pub fn handle_destroy_request(vm: &Arc>) -> Result<()> { ++ pub fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.lock().unwrap(); + let vmstate = { + let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); +@@ -218,11 +222,13 @@ impl StdMachine { + if locked_vm.shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request.") + } ++ return false; + } + ++ EventLoop::kick_all(); + info!("vm destroy"); + +- Ok(()) ++ true + } + + fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { +@@ -262,7 +268,7 @@ impl StdMachine { + let region_size: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].1; + let cpu_config = CpuConfig::new(boot_config, cpu_topology); + let hotplug_cpu_req = Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) ++ create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("hotplug cpu".to_string()))?, + ); + +@@ -371,7 +377,7 @@ impl StdMachineOps for StdMachine { + hypervisor, + self.base.cpu_topo.max_cpus, + )?; +- vcpu.realize(&Some(boot_cfg), topology).with_context(|| { ++ vcpu.realize(boot_cfg, topology).with_context(|| { + format!( + "Failed to realize arch cpu register/features for CPU {}", + vcpu_id +@@ -559,12 +565,7 @@ impl MachineOps for StdMachine { + locked_vm.add_devices(vm_config)?; + + let fwcfg = locked_vm.add_fwcfg_device(nr_cpus, max_cpus)?; +- let migrate = locked_vm.get_migrate_info(); +- let boot_config = if migrate.0 == MigrateMode::Unknown { +- Some(locked_vm.load_boot_source(fwcfg.as_ref())?) +- } else { +- None +- }; ++ let boot_config = locked_vm.load_boot_source(fwcfg.as_ref())?; + let topology = CPUTopology::new().set_topology(( + vm_config.machine_config.nr_threads, + vm_config.machine_config.nr_cores, +@@ -580,9 +581,7 @@ impl MachineOps for StdMachine { + &boot_config, + )?); + +- if migrate.0 == MigrateMode::Unknown { +- locked_vm.init_cpu_controller(boot_config.unwrap(), topology, vm.clone())?; +- } ++ locked_vm.init_cpu_controller(boot_config, topology, vm.clone())?; + + if let Some(fw_cfg) = fwcfg { + locked_vm +@@ -635,9 +634,9 @@ impl MachineOps for StdMachine { + Ok(()) + } + +- fn add_pflash_device(&mut self, configs: &[PFlashConfig]) -> Result<()> { ++ fn add_pflash_device(&mut self, configs: &[DriveConfig]) -> Result<()> { + let mut configs_vec = configs.to_vec(); +- configs_vec.sort_by_key(|c| c.unit); ++ configs_vec.sort_by_key(|c| c.unit.unwrap()); + // The two PFlash devices locates below 4GB, this variable represents the end address + // of current PFlash device. + let mut flash_end: u64 = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; +@@ -645,7 +644,7 @@ impl MachineOps for StdMachine { + let mut fd = self.fetch_drive_file(&config.path_on_host)?; + let pfl_size = fd.metadata().unwrap().len(); + +- if config.unit == 0 { ++ if config.unit.unwrap() == 0 { + // According to the Linux/x86 boot protocol, the memory region of + // 0x000000 - 0x100000 (1 MiB) is for BIOS usage. And the top 128 + // KiB is for BIOS code which is stored in the first PFlash. +@@ -681,7 +680,7 @@ impl MachineOps for StdMachine { + sector_len, + 4_u32, + 1_u32, +- config.read_only, ++ config.readonly, + ) + .with_context(|| MachineError::InitPflashErr)?; + PFlash::realize( +@@ -704,7 +703,7 @@ impl MachineOps for StdMachine { + // GTK display init. + #[cfg(feature = "gtk")] + match vm_config.display { +- Some(ref ds_cfg) if ds_cfg.gtk => { ++ Some(ref ds_cfg) if ds_cfg.display_type == "gtk" => { + let ui_context = UiContext { + vm_name: vm_config.guest_name.clone(), + power_button: None, +@@ -769,8 +768,6 @@ pub(crate) fn arch_syscall_whitelist() -> Vec { + BpfRule::new(libc::SYS_mkdir), + BpfRule::new(libc::SYS_unlink), + BpfRule::new(libc::SYS_readlink), +- #[cfg(target_env = "musl")] +- BpfRule::new(libc::SYS_clone), + #[cfg(target_env = "gnu")] + BpfRule::new(libc::SYS_clone3), + #[cfg(target_env = "gnu")] +diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs +index 5b0d275..619a7c2 100644 +--- a/machine_manager/src/cmdline.rs ++++ b/machine_manager/src/cmdline.rs +@@ -11,9 +11,10 @@ + // See the Mulan PSL v2 for more details. + + use anyhow::{bail, Context, Result}; ++use clap::{ArgAction, Parser}; + + use crate::{ +- config::{parse_trace_options, ChardevType, CmdParser, MachineType, VmConfig}, ++ config::{add_trace, str_slip_to_clap, ChardevType, MachineType, SocketType, VmConfig}, + qmp::qmp_socket::QmpSocketPath, + temp_cleaner::TempCleaner, + }; +@@ -509,7 +510,7 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { + .multiple(false) + .long("windows_emu_pid") + .value_name("pid") +- .help("watch on the external windows emu pid") ++ .help("watch on the external emulator pid") + .takes_value(true), + ); + +@@ -587,7 +588,7 @@ pub fn create_vmconfig(args: &ArgMatches) -> Result { + add_args_to_config_multi!((args.values_of("cameradev")), vm_cfg, add_camera_backend); + add_args_to_config_multi!((args.values_of("smbios")), vm_cfg, add_smbios); + if let Some(opt) = args.value_of("trace") { +- parse_trace_options(&opt)?; ++ add_trace(&opt)?; + } + + // Check the mini-set for Vm to start is ok +@@ -599,6 +600,28 @@ pub fn create_vmconfig(args: &ArgMatches) -> Result { + Ok(vm_cfg) + } + ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct QmpConfig { ++ #[arg(long, alias = "classtype")] ++ uri: String, ++ #[arg(long, action = ArgAction::SetTrue, required = true)] ++ server: bool, ++ #[arg(long, action = ArgAction::SetTrue, required = true)] ++ nowait: bool, ++} ++ ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct MonConfig { ++ #[arg(long, default_value = "")] ++ id: String, ++ #[arg(long, value_parser = ["control"])] ++ mode: String, ++ #[arg(long)] ++ chardev: String, ++} ++ + /// This function is to parse qmp socket path and type. + /// + /// # Arguments +@@ -613,75 +636,34 @@ pub fn check_api_channel( + vm_config: &mut VmConfig, + ) -> Result> { + let mut sock_paths = Vec::new(); +- if let Some(qmp_config) = args.value_of("qmp") { +- let mut cmd_parser = CmdParser::new("qmp"); +- cmd_parser.push("").push("server").push("nowait"); +- +- cmd_parser.parse(&qmp_config)?; +- if let Some(uri) = cmd_parser.get_value::("")? { +- let sock_path = +- QmpSocketPath::new(uri).with_context(|| "Failed to parse qmp socket path")?; +- sock_paths.push(sock_path); +- } else { +- bail!("No uri found for qmp"); +- } +- if cmd_parser.get_value::("server")?.is_none() { +- bail!("Argument \'server\' is needed for qmp"); +- } +- if cmd_parser.get_value::("nowait")?.is_none() { +- bail!("Argument \'nowait\' is needed for qmp"); +- } ++ if let Some(qmp_args) = args.value_of("qmp") { ++ let qmp_cfg = QmpConfig::try_parse_from(str_slip_to_clap(&qmp_args, true, false))?; ++ let sock_path = ++ QmpSocketPath::new(qmp_cfg.uri).with_context(|| "Failed to parse qmp socket path")?; ++ sock_paths.push(sock_path); + } +- if let Some(mon_config) = args.value_of("mon") { +- let mut cmd_parser = CmdParser::new("monitor"); +- cmd_parser.push("id").push("mode").push("chardev"); +- cmd_parser.parse(&mon_config)?; +- +- let chardev = cmd_parser +- .get_value::("chardev")? +- .with_context(|| "Argument \'chardev\' is missing for \'mon\'")?; +- +- if let Some(mode) = cmd_parser.get_value::("mode")? { +- if mode != *"control" { +- bail!("Invalid \'mode\' parameter: {:?} for monitor", &mode); ++ if let Some(mon_args) = args.value_of("mon") { ++ let mon_cfg = MonConfig::try_parse_from(str_slip_to_clap(&mon_args, false, false))?; ++ let cfg = vm_config ++ .chardev ++ .remove(&mon_cfg.chardev) ++ .with_context(|| format!("No chardev found: {}", &mon_cfg.chardev))?; ++ let socket = cfg ++ .classtype ++ .socket_type() ++ .with_context(|| "Only chardev of unix-socket type can be used for monitor")?; ++ if let ChardevType::Socket { server, nowait, .. } = cfg.classtype { ++ if !server || !nowait { ++ bail!( ++ "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", ++ cfg.id() ++ ); + } +- } else { +- bail!("Argument \'mode\' of \'mon\' should be set to \'control\'."); + } +- +- if let Some(cfg) = vm_config.chardev.remove(&chardev) { +- if let ChardevType::UnixSocket { +- path, +- server, +- nowait, +- } = cfg.backend +- { +- if !server || !nowait { +- bail!( +- "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", +- path +- ); +- } +- sock_paths.push(QmpSocketPath::Unix { path }); +- } else if let ChardevType::TcpSocket { +- host, +- port, +- server, +- nowait, +- } = cfg.backend +- { +- if !server || !nowait { +- bail!( +- "Argument \'server\' and \'nowait\' are both required for chardev \'{}:{}\'", +- host, port +- ); +- } +- sock_paths.push(QmpSocketPath::Tcp { host, port }); +- } else { +- bail!("Only chardev of unix-socket type can be used for monitor"); +- } +- } else { +- bail!("No chardev found: {}", &chardev); ++ if let SocketType::Tcp { host, port } = socket { ++ sock_paths.push(QmpSocketPath::Tcp { host, port }); ++ } else if let SocketType::Unix { path } = socket { ++ sock_paths.push(QmpSocketPath::Unix { path }); + } + } + +diff --git a/machine_manager/src/config/camera.rs b/machine_manager/src/config/camera.rs +index 90872b4..43af312 100644 +--- a/machine_manager/src/config/camera.rs ++++ b/machine_manager/src/config/camera.rs +@@ -22,8 +22,10 @@ use crate::{ + }; + + #[derive(Parser, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +-#[command(name = "camera device")] ++#[command(no_binary_name(true))] + pub struct CameraDevConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] +@@ -38,7 +40,6 @@ pub enum CamBackendType { + V4l2, + #[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))] + OhCamera, +- #[cfg(not(target_env = "ohos"))] + Demo, + } + +@@ -51,7 +52,6 @@ impl FromStr for CamBackendType { + "v4l2" => Ok(CamBackendType::V4l2), + #[cfg(all(target_env = "ohos", feature = "usb_camera_oh"))] + "ohcamera" => Ok(CamBackendType::OhCamera), +- #[cfg(not(target_env = "ohos"))] + "demo" => Ok(CamBackendType::Demo), + _ => Err(anyhow!("Unknown camera backend type")), + } +@@ -61,7 +61,7 @@ impl FromStr for CamBackendType { + impl VmConfig { + pub fn add_camera_backend(&mut self, camera_config: &str) -> Result<()> { + let cfg = format!("cameradev,backend={}", camera_config); +- let config = CameraDevConfig::try_parse_from(str_slip_to_clap(&cfg))?; ++ let config = CameraDevConfig::try_parse_from(str_slip_to_clap(&cfg, true, false))?; + + self.add_cameradev_with_config(config) + } +@@ -105,6 +105,7 @@ impl VmConfig { + pub fn get_cameradev_config(args: qmp_schema::CameraDevAddArgument) -> Result { + let path = args.path.with_context(|| "cameradev config path is null")?; + let config = CameraDevConfig { ++ classtype: "cameradev".to_string(), + id: args.id, + path, + backend: CamBackendType::from_str(&args.driver)?, +diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs +index 943de72..0ea4d49 100644 +--- a/machine_manager/src/config/chardev.rs ++++ b/machine_manager/src/config/chardev.rs +@@ -14,248 +14,168 @@ use std::net::IpAddr; + use std::str::FromStr; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser, Subcommand}; + use log::error; + use serde::{Deserialize, Serialize}; + +-use super::{error::ConfigError, get_pci_bdf, pci_args_check, PciBdf}; +-use crate::config::{ +- check_arg_too_long, CmdParser, ConfigCheck, ExBool, VmConfig, MAX_PATH_LENGTH, +-}; ++use super::{error::ConfigError, str_slip_to_clap}; ++use super::{get_pci_df, parse_bool}; ++use crate::config::{valid_id, valid_path, valid_socket_path, ConfigCheck, VmConfig}; + use crate::qmp::qmp_schema; + +-const MAX_GUEST_CID: u64 = 4_294_967_295; +-const MIN_GUEST_CID: u64 = 3; +- + /// Default value of max ports for virtio-serial. + const DEFAULT_SERIAL_PORTS_NUMBER: u32 = 31; + +-/// Character device options. +-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +-pub enum ChardevType { +- Stdio, +- Pty, +- UnixSocket { +- path: String, +- server: bool, +- nowait: bool, +- }, +- TcpSocket { +- host: String, +- port: u16, +- server: bool, +- nowait: bool, +- }, +- File(String), +-} +- + /// Config structure for virtio-serial-port. +-#[derive(Debug, Clone)] +-pub struct VirtioSerialPort { ++#[derive(Parser, Debug, Clone)] ++#[command(no_binary_name(true))] ++pub struct VirtioSerialPortCfg { ++ #[arg(long, value_parser = ["virtconsole", "virtserialport"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, +- pub chardev: ChardevConfig, +- pub nr: u32, +- pub is_console: bool, ++ #[arg(long)] ++ pub chardev: String, ++ #[arg(long)] ++ pub nr: Option, + } + +-impl ConfigCheck for VirtioSerialPort { ++impl ConfigCheck for VirtioSerialPortCfg { + fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "chardev id") +- } +-} +- +-/// Config structure for character device. +-#[derive(Debug, Clone, Serialize, Deserialize)] +-pub struct ChardevConfig { +- pub id: String, +- pub backend: ChardevType, +-} +- +-impl ConfigCheck for ChardevConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "chardev id")?; +- match &self.backend { +- ChardevType::UnixSocket { path, .. } => { +- if path.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "unix-socket path".to_string(), +- MAX_PATH_LENGTH +- ))); +- } +- Ok(()) +- } +- ChardevType::TcpSocket { host, port, .. } => { +- if *port == 0u16 { +- return Err(anyhow!(ConfigError::InvalidParam( +- "port".to_string(), +- "tcp-socket".to_string() +- ))); +- } +- let ip_address = IpAddr::from_str(host); +- if ip_address.is_err() { +- return Err(anyhow!(ConfigError::InvalidParam( +- "host".to_string(), +- "tcp-socket".to_string() +- ))); +- } +- Ok(()) +- } +- ChardevType::File(path) => { +- if path.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "file path".to_string(), +- MAX_PATH_LENGTH +- ))); +- } +- Ok(()) +- } +- _ => Ok(()), ++ if self.classtype != "virtconsole" && self.nr.unwrap() == 0 { ++ bail!("Port number 0 on virtio-serial devices reserved for virtconsole device."); + } ++ ++ Ok(()) + } + } + +-fn check_chardev_fields( +- dev_type: &str, +- cmd_parser: &CmdParser, +- supported_fields: &[&str], +-) -> Result<()> { +- for (field, value) in &cmd_parser.params { +- let supported_field = supported_fields.contains(&field.as_str()); +- if !supported_field && value.is_some() { ++impl VirtioSerialPortCfg { ++ /// If nr is not set in command line. Configure incremental maximum value for virtconsole. ++ /// Configure incremental maximum value(except 0) for virtserialport. ++ pub fn auto_nr(&mut self, free_port0: bool, free_nr: u32, max_nr_ports: u32) -> Result<()> { ++ let free_console_nr = if free_port0 { 0 } else { free_nr }; ++ let auto_nr = match self.classtype.as_str() { ++ "virtconsole" => free_console_nr, ++ "virtserialport" => free_nr, ++ _ => bail!("Invalid classtype."), ++ }; ++ let nr = self.nr.unwrap_or(auto_nr); ++ if nr >= max_nr_ports { + bail!( +- "Chardev of type {} does not support \'{}\' argument", +- dev_type, +- field ++ "virtio serial port nr {} should be less than virtio serial's max_nr_ports {}", ++ nr, ++ max_nr_ports + ); + } +- } +- Ok(()) +-} +- +-fn parse_stdio_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { +- let supported_fields = ["", "id"]; +- check_chardev_fields("stdio", &cmd_parser, &supported_fields)?; +- Ok(ChardevConfig { +- id: chardev_id, +- backend: ChardevType::Stdio, +- }) +-} + +-fn parse_pty_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { +- let supported_fields = ["", "id"]; +- check_chardev_fields("pty", &cmd_parser, &supported_fields)?; +- Ok(ChardevConfig { +- id: chardev_id, +- backend: ChardevType::Pty, +- }) ++ self.nr = Some(nr); ++ Ok(()) ++ } + } + +-fn parse_file_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { +- let supported_fields = ["", "id", "path"]; +- check_chardev_fields("file", &cmd_parser, &supported_fields)?; +- +- let path = cmd_parser +- .get_value::("path")? +- .with_context(|| ConfigError::FieldIsMissing("path".to_string(), "chardev".to_string()))?; +- +- let default_value = path.clone(); +- let file_path = std::fs::canonicalize(path).map_or(default_value, |canonical_path| { +- String::from(canonical_path.to_str().unwrap()) +- }); +- +- Ok(ChardevConfig { +- id: chardev_id, +- backend: ChardevType::File(file_path), +- }) ++/// Config structure for character device. ++#[derive(Parser, Debug, Clone, Serialize, Deserialize)] ++#[command(no_binary_name(true))] ++pub struct ChardevConfig { ++ #[command(subcommand)] ++ pub classtype: ChardevType, + } + +-fn parse_socket_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { +- let mut server_enabled = false; +- let server = cmd_parser.get_value::("server")?; +- if let Some(server) = server { +- if server.ne("") { +- bail!("No parameter needed for server"); ++impl ChardevConfig { ++ pub fn id(&self) -> String { ++ match &self.classtype { ++ ChardevType::Stdio { id } => id, ++ ChardevType::Pty { id } => id, ++ ChardevType::Socket { id, .. } => id, ++ ChardevType::File { id, .. } => id, + } +- server_enabled = true; ++ .clone() + } ++} + +- let mut nowait_enabled = false; +- let nowait = cmd_parser.get_value::("nowait")?; +- if let Some(nowait) = nowait { +- if nowait.ne("") { +- bail!("No parameter needed for nowait"); ++impl ConfigCheck for ChardevConfig { ++ fn check(&self) -> Result<()> { ++ if let ChardevType::Socket { .. } = self.classtype { ++ self.classtype.socket_type()?; + } +- nowait_enabled = true; +- } +- +- let path = cmd_parser.get_value::("path")?; +- if let Some(path) = path { +- let supported_fields = ["", "id", "path", "server", "nowait"]; +- check_chardev_fields("unix-socket", &cmd_parser, &supported_fields)?; +- +- let default_value = path.clone(); +- let socket_path = std::fs::canonicalize(path).map_or(default_value, |canonical_path| { +- String::from(canonical_path.to_str().unwrap()) +- }); +- +- return Ok(ChardevConfig { +- id: chardev_id, +- backend: ChardevType::UnixSocket { +- path: socket_path, +- server: server_enabled, +- nowait: nowait_enabled, +- }, +- }); +- } + +- let port = cmd_parser.get_value::("port")?; +- if let Some(port) = port { +- let supported_fields = ["", "id", "host", "port", "server", "nowait"]; +- check_chardev_fields("tcp-socket", &cmd_parser, &supported_fields)?; +- +- let host = cmd_parser.get_value::("host")?; +- return Ok(ChardevConfig { +- id: chardev_id, +- backend: ChardevType::TcpSocket { +- host: host.unwrap_or_else(|| String::from("0.0.0.0")), +- port, +- server: server_enabled, +- nowait: nowait_enabled, +- }, +- }); ++ Ok(()) + } ++} + +- Err(anyhow!(ConfigError::InvalidParam( +- "backend".to_string(), +- "chardev".to_string() +- ))) ++/// Character device options. ++#[derive(Subcommand, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] ++pub enum ChardevType { ++ Stdio { ++ #[arg(long, value_parser = valid_id)] ++ id: String, ++ }, ++ Pty { ++ #[arg(long, value_parser = valid_id)] ++ id: String, ++ }, ++ // Unix Socket: use `path`. ++ // Tcp Socket: use `host` and `port`. ++ #[clap(group = clap::ArgGroup::new("unix-socket").args(&["host", "port"]).requires("port").multiple(true).conflicts_with("tcp-socket"))] ++ #[clap(group = clap::ArgGroup::new("tcp-socket").arg("path").conflicts_with("unix-socket"))] ++ Socket { ++ #[arg(long, value_parser = valid_id)] ++ id: String, ++ #[arg(long, value_parser = valid_socket_path)] ++ path: Option, ++ #[arg(long, value_parser = valid_host, default_value = "0.0.0.0")] ++ host: String, ++ #[arg(long, value_parser = clap::value_parser!(u16).range(1..))] ++ port: Option, ++ #[arg(long, action = ArgAction::SetTrue)] ++ server: bool, ++ #[arg(long, action = ArgAction::SetTrue)] ++ nowait: bool, ++ }, ++ File { ++ #[arg(long, value_parser = valid_id)] ++ id: String, ++ #[arg(long, value_parser = valid_path)] ++ path: String, ++ }, + } + +-pub fn parse_chardev(chardev_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("chardev"); +- for field in ["", "id", "path", "host", "port", "server", "nowait"] { +- cmd_parser.push(field); ++impl ChardevType { ++ pub fn socket_type(&self) -> Result { ++ if let ChardevType::Socket { ++ path, host, port, .. ++ } = self ++ { ++ if path.is_some() && port.is_none() { ++ return Ok(SocketType::Unix { ++ path: path.clone().unwrap(), ++ }); ++ } else if port.is_some() && path.is_none() { ++ return Ok(SocketType::Tcp { ++ host: host.clone(), ++ port: (*port).unwrap(), ++ }); ++ } ++ } ++ bail!("Not socket type or invalid socket type"); + } ++} + +- cmd_parser.parse(chardev_config)?; +- +- let chardev_id = cmd_parser +- .get_value::("id")? +- .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "chardev".to_string()))?; +- +- let backend = cmd_parser +- .get_value::("")? +- .with_context(|| ConfigError::InvalidParam("backend".to_string(), "chardev".to_string()))?; +- +- match backend.as_str() { +- "stdio" => parse_stdio_chardev(chardev_id, cmd_parser), +- "pty" => parse_pty_chardev(chardev_id, cmd_parser), +- "file" => parse_file_chardev(chardev_id, cmd_parser), +- "socket" => parse_socket_chardev(chardev_id, cmd_parser), +- _ => Err(anyhow!(ConfigError::InvalidParam( +- backend, +- "chardev".to_string() +- ))), ++pub enum SocketType { ++ Unix { path: String }, ++ Tcp { host: String, port: u16 }, ++} ++ ++fn valid_host(host: &str) -> Result { ++ let ip_address = IpAddr::from_str(host); ++ if ip_address.is_err() { ++ return Err(anyhow!(ConfigError::InvalidParam( ++ "host".to_string(), ++ "tcp-socket".to_string() ++ ))); + } ++ Ok(host.to_string()) + } + + /// Get chardev config from qmp arguments. +@@ -291,9 +211,11 @@ pub fn get_chardev_config(args: qmp_schema::CharDevAddArgument) -> Result Result Result { +- if let Some(char_dev) = vm_config.chardev.remove(chardev) { +- match char_dev.backend.clone() { +- ChardevType::UnixSocket { +- path, +- server, +- nowait, +- } => { +- if server || nowait { +- bail!( +- "Argument \'server\' or \'nowait\' is not need for chardev \'{}\'", +- path +- ); +- } +- Ok(path) +- } +- _ => { +- bail!( +- "Chardev {:?} backend should be unix-socket type.", +- &char_dev.id +- ); +- } ++pub fn get_chardev_socket_path(chardev: ChardevConfig) -> Result { ++ let id = chardev.id(); ++ if let ChardevType::Socket { ++ path, ++ server, ++ nowait, ++ .. ++ } = chardev.classtype ++ { ++ path.clone() ++ .with_context(|| format!("Chardev {:?} backend should be unix-socket type.", id))?; ++ if server || nowait { ++ bail!( ++ "Argument \'server\' or \'nowait\' is not need for chardev \'{}\'", ++ path.unwrap() ++ ); + } +- } else { +- bail!("Chardev: {:?} not found for character device", &chardev); ++ return Ok(path.unwrap()); + } +-} +- +-pub fn parse_virtserialport( +- vm_config: &mut VmConfig, +- config_args: &str, +- is_console: bool, +- free_nr: u32, +- free_port0: bool, +-) -> Result { +- let mut cmd_parser = CmdParser::new("virtserialport"); +- cmd_parser.push("").push("id").push("chardev").push("nr"); +- cmd_parser.parse(config_args)?; +- +- let chardev_name = cmd_parser +- .get_value::("chardev")? +- .with_context(|| { +- ConfigError::FieldIsMissing("chardev".to_string(), "virtserialport".to_string()) +- })?; +- let id = cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "virtserialport".to_string()) +- })?; +- +- let nr = cmd_parser +- .get_value::("nr")? +- .unwrap_or(if is_console && free_port0 { 0 } else { free_nr }); +- +- if nr == 0 && !is_console { +- bail!("Port number 0 on virtio-serial devices reserved for virtconsole device."); +- } +- +- if let Some(chardev) = vm_config.chardev.remove(&chardev_name) { +- let port_cfg = VirtioSerialPort { +- id, +- chardev, +- nr, +- is_console, +- }; +- port_cfg.check()?; +- return Ok(port_cfg); +- } +- bail!("Chardev {:?} not found or is in use", &chardev_name); ++ bail!("Chardev {:?} backend should be unix-socket type.", id); + } + + impl VmConfig { + /// Add chardev config to `VmConfig`. + pub fn add_chardev(&mut self, chardev_config: &str) -> Result<()> { +- let chardev = parse_chardev(chardev_config)?; ++ let chardev = ChardevConfig::try_parse_from(str_slip_to_clap(chardev_config, true, true))?; + chardev.check()?; +- let chardev_id = chardev.id.clone(); +- if self.chardev.get(&chardev_id).is_none() { +- self.chardev.insert(chardev_id, chardev); +- } else { +- bail!("Chardev {:?} has been added", &chardev_id); +- } ++ self.add_chardev_with_config(chardev)?; + Ok(()) + } + +@@ -395,16 +264,11 @@ impl VmConfig { + /// + /// * `conf` - The chardev config to be added to the vm. + pub fn add_chardev_with_config(&mut self, conf: ChardevConfig) -> Result<()> { +- if let Err(e) = conf.check() { +- bail!("Chardev config checking failed, {}", e.to_string()); +- } +- +- let chardev_id = conf.id.clone(); +- if self.chardev.get(&chardev_id).is_none() { +- self.chardev.insert(chardev_id, conf); +- } else { ++ let chardev_id = conf.id(); ++ if self.chardev.get(&chardev_id).is_some() { + bail!("Chardev {:?} has been added", chardev_id); + } ++ self.chardev.insert(chardev_id, conf); + Ok(()) + } + +@@ -414,11 +278,9 @@ impl VmConfig { + /// + /// * `id` - The chardev id which is used to delete chardev config. + pub fn del_chardev_by_id(&mut self, id: &str) -> Result<()> { +- if self.chardev.get(id).is_some() { +- self.chardev.remove(id); +- } else { +- bail!("Chardev {} not found", id); +- } ++ self.chardev ++ .remove(id) ++ .with_context(|| format!("Chardev {} not found", id))?; + Ok(()) + } + } +@@ -458,189 +320,74 @@ impl VmConfig { + } + } + +-/// Config structure for virtio-vsock. +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] +-pub struct VsockConfig { +- pub id: String, +- pub guest_cid: u64, +- pub vhost_fd: Option, +-} +- +-impl ConfigCheck for VsockConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "vsock id")?; +- +- if self.guest_cid < MIN_GUEST_CID || self.guest_cid >= MAX_GUEST_CID { +- return Err(anyhow!(ConfigError::IllegalValue( +- "Vsock guest-cid".to_string(), +- MIN_GUEST_CID, +- true, +- MAX_GUEST_CID, +- false, +- ))); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_vsock(vsock_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("vhost-vsock"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("guest-cid") +- .push("vhostfd"); +- cmd_parser.parse(vsock_config)?; +- pci_args_check(&cmd_parser)?; +- let id = cmd_parser +- .get_value::("id")? +- .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "vsock".to_string()))?; +- +- let guest_cid = cmd_parser.get_value::("guest-cid")?.with_context(|| { +- ConfigError::FieldIsMissing("guest-cid".to_string(), "vsock".to_string()) +- })?; +- +- let vhost_fd = cmd_parser.get_value::("vhostfd")?; +- let vsock = VsockConfig { +- id, +- guest_cid, +- vhost_fd, +- }; +- Ok(vsock) +-} +- +-#[derive(Clone, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct VirtioSerialInfo { ++ #[arg(long, value_parser = ["virtio-serial-pci", "virtio-serial-device"])] ++ pub classtype: String, ++ #[arg(long, default_value = "", value_parser = valid_id)] + pub id: String, +- pub pci_bdf: Option, +- pub multifunction: bool, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] ++ pub multifunction: Option, ++ #[arg(long, default_value = "31", value_parser = clap::value_parser!(u32).range(1..=DEFAULT_SERIAL_PORTS_NUMBER as i64))] + pub max_ports: u32, + } + +-impl ConfigCheck for VirtioSerialInfo { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "virtio-serial id")?; +- +- if self.max_ports < 1 || self.max_ports > DEFAULT_SERIAL_PORTS_NUMBER { +- return Err(anyhow!(ConfigError::IllegalValue( +- "Virtio-serial max_ports".to_string(), +- 1, +- true, +- DEFAULT_SERIAL_PORTS_NUMBER as u64, +- true +- ))); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_virtio_serial( +- vm_config: &mut VmConfig, +- serial_config: &str, +-) -> Result { +- let mut cmd_parser = CmdParser::new("virtio-serial"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("max_ports"); +- cmd_parser.parse(serial_config)?; +- pci_args_check(&cmd_parser)?; +- +- if vm_config.virtio_serial.is_some() { +- bail!("Only one virtio serial device is supported"); +- } +- +- let id = cmd_parser.get_value::("id")?.unwrap_or_default(); +- let multifunction = cmd_parser +- .get_value::("multifunction")? +- .map_or(false, |switch| switch.into()); +- let max_ports = cmd_parser +- .get_value::("max_ports")? +- .unwrap_or(DEFAULT_SERIAL_PORTS_NUMBER); +- let virtio_serial = if serial_config.contains("-pci") { +- let pci_bdf = get_pci_bdf(serial_config)?; +- VirtioSerialInfo { +- id, +- pci_bdf: Some(pci_bdf), +- multifunction, +- max_ports, +- } +- } else { +- VirtioSerialInfo { +- id, +- pci_bdf: None, +- multifunction, ++impl VirtioSerialInfo { ++ pub fn auto_max_ports(&mut self) { ++ if self.classtype == "virtio-serial-device" { + // Micro_vm does not support multi-ports in virtio-serial-device. +- max_ports: 1, ++ self.max_ports = 1; + } +- }; +- virtio_serial.check()?; +- vm_config.virtio_serial = Some(virtio_serial.clone()); +- +- Ok(virtio_serial) ++ } + } + + #[cfg(test)] + mod tests { + use super::*; +- use crate::config::parse_virtio_serial; + + fn test_mmio_console_config_cmdline_parser(chardev_cfg: &str, expected_chardev: ChardevType) { + let mut vm_config = VmConfig::default(); +- assert!(parse_virtio_serial(&mut vm_config, "virtio-serial-device").is_ok()); ++ let serial_cmd = "virtio-serial-device"; ++ let mut serial_cfg = ++ VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); ++ serial_cfg.auto_max_ports(); ++ vm_config.virtio_serial = Some(serial_cfg.clone()); + assert!(vm_config.add_chardev(chardev_cfg).is_ok()); + +- let virt_console = parse_virtserialport( +- &mut vm_config, +- "virtconsole,chardev=test_console,id=console1,nr=1", +- true, +- 0, +- true, +- ); +- assert!(virt_console.is_ok()); +- +- let console_cfg = virt_console.unwrap(); +- assert_eq!(console_cfg.id, "console1"); +- assert_eq!(console_cfg.chardev.backend, expected_chardev); ++ let port_cmd = "virtconsole,chardev=test_console,id=console1,nr=0"; ++ let mut port_cfg = ++ VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(port_cmd, true, false)).unwrap(); ++ assert!(port_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_ok()); ++ let chardev = vm_config.chardev.remove(&port_cfg.chardev).unwrap(); ++ assert_eq!(port_cfg.id, "console1"); ++ assert_eq!(port_cfg.nr.unwrap(), 0); ++ assert_eq!(chardev.classtype, expected_chardev); ++ ++ // Error: VirtioSerialPortCfg.nr >= VirtioSerialInfo.max_nr_ports. ++ let port_cmd = "virtconsole,chardev=test_console,id=console1,nr=1"; ++ let mut port_cfg = ++ VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(port_cmd, true, false)).unwrap(); ++ assert!(port_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_err()); + + let mut vm_config = VmConfig::default(); +- assert!( +- parse_virtio_serial(&mut vm_config, "virtio-serial-device,bus=pcie.0,addr=0x1") +- .is_err() +- ); + assert!(vm_config + .add_chardev("sock,id=test_console,path=/path/to/socket") + .is_err()); +- +- let mut vm_config = VmConfig::default(); +- assert!(parse_virtio_serial(&mut vm_config, "virtio-serial-device").is_ok()); +- assert!(vm_config +- .add_chardev("socket,id=test_console,path=/path/to/socket,server,nowait") +- .is_ok()); +- let virt_console = parse_virtserialport( +- &mut vm_config, +- "virtconsole,chardev=test_console1,id=console1,nr=1", +- true, +- 0, +- true, +- ); +- // test_console1 does not exist. +- assert!(virt_console.is_err()); + } + + #[test] + fn test_mmio_console_config_cmdline_parser_1() { + let chardev_cfg = "socket,id=test_console,path=/path/to/socket,server,nowait"; +- let expected_chardev = ChardevType::UnixSocket { +- path: "/path/to/socket".to_string(), ++ let expected_chardev = ChardevType::Socket { ++ id: "test_console".to_string(), ++ path: Some("/path/to/socket".to_string()), ++ host: "0.0.0.0".to_string(), ++ port: None, + server: true, + nowait: true, + }; +@@ -650,9 +397,11 @@ mod tests { + #[test] + fn test_mmio_console_config_cmdline_parser_2() { + let chardev_cfg = "socket,id=test_console,host=127.0.0.1,port=9090,server,nowait"; +- let expected_chardev = ChardevType::TcpSocket { ++ let expected_chardev = ChardevType::Socket { ++ id: "test_console".to_string(), ++ path: None, + host: "127.0.0.1".to_string(), +- port: 9090, ++ port: Some(9090), + server: true, + nowait: true, + }; +@@ -661,41 +410,34 @@ mod tests { + + fn test_pci_console_config_cmdline_parser(chardev_cfg: &str, expected_chardev: ChardevType) { + let mut vm_config = VmConfig::default(); +- let virtio_arg = "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2"; +- assert!(parse_virtio_serial(&mut vm_config, virtio_arg).is_ok()); ++ let serial_cmd = "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2,multifunction=on"; ++ let mut serial_cfg = ++ VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); ++ serial_cfg.auto_max_ports(); ++ vm_config.virtio_serial = Some(serial_cfg.clone()); + assert!(vm_config.add_chardev(chardev_cfg).is_ok()); + +- let virt_console = parse_virtserialport( +- &mut vm_config, +- "virtconsole,chardev=test_console,id=console1,nr=1", +- true, +- 0, +- true, +- ); +- assert!(virt_console.is_ok()); +- let console_cfg = virt_console.unwrap(); +- ++ let console_cmd = "virtconsole,chardev=test_console,id=console1,nr=1"; ++ let mut console_cfg = ++ VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(console_cmd, true, false)) ++ .unwrap(); ++ assert!(console_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_ok()); ++ let chardev = vm_config.chardev.remove(&console_cfg.chardev).unwrap(); + assert_eq!(console_cfg.id, "console1"); + let serial_info = vm_config.virtio_serial.clone().unwrap(); +- assert!(serial_info.pci_bdf.is_some()); +- let bdf = serial_info.pci_bdf.unwrap(); +- assert_eq!(bdf.bus, "pcie.0"); +- assert_eq!(bdf.addr, (1, 2)); +- assert_eq!(console_cfg.chardev.backend, expected_chardev); +- +- let mut vm_config = VmConfig::default(); +- assert!(parse_virtio_serial( +- &mut vm_config, +- "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2,multifunction=on" +- ) +- .is_ok()); ++ assert_eq!(serial_info.bus.unwrap(), "pcie.0"); ++ assert_eq!(serial_info.addr.unwrap(), (1, 2)); ++ assert_eq!(chardev.classtype, expected_chardev); + } + + #[test] + fn test_pci_console_config_cmdline_parser_1() { + let chardev_cfg = "socket,id=test_console,path=/path/to/socket,server,nowait"; +- let expected_chardev = ChardevType::UnixSocket { +- path: "/path/to/socket".to_string(), ++ let expected_chardev = ChardevType::Socket { ++ id: "test_console".to_string(), ++ path: Some("/path/to/socket".to_string()), ++ host: "0.0.0.0".to_string(), ++ port: None, + server: true, + nowait: true, + }; +@@ -705,36 +447,17 @@ mod tests { + #[test] + fn test_pci_console_config_cmdline_parser_2() { + let chardev_cfg = "socket,id=test_console,host=127.0.0.1,port=9090,server,nowait"; +- let expected_chardev = ChardevType::TcpSocket { ++ let expected_chardev = ChardevType::Socket { ++ id: "test_console".to_string(), ++ path: None, + host: "127.0.0.1".to_string(), +- port: 9090, ++ port: Some(9090), + server: true, + nowait: true, + }; + test_pci_console_config_cmdline_parser(chardev_cfg, expected_chardev) + } + +- #[test] +- fn test_vsock_config_cmdline_parser() { +- let vsock_cfg_op = parse_vsock("vhost-vsock-device,id=test_vsock,guest-cid=3"); +- assert!(vsock_cfg_op.is_ok()); +- +- let vsock_config = vsock_cfg_op.unwrap(); +- assert_eq!(vsock_config.id, "test_vsock"); +- assert_eq!(vsock_config.guest_cid, 3); +- assert_eq!(vsock_config.vhost_fd, None); +- assert!(vsock_config.check().is_ok()); +- +- let vsock_cfg_op = parse_vsock("vhost-vsock-device,id=test_vsock,guest-cid=3,vhostfd=4"); +- assert!(vsock_cfg_op.is_ok()); +- +- let vsock_config = vsock_cfg_op.unwrap(); +- assert_eq!(vsock_config.id, "test_vsock"); +- assert_eq!(vsock_config.guest_cid, 3); +- assert_eq!(vsock_config.vhost_fd, Some(4)); +- assert!(vsock_config.check().is_ok()); +- } +- + #[test] + fn test_chardev_config_cmdline_parser() { + let check_argument = |arg: String, expect: ChardevType| { +@@ -744,17 +467,30 @@ mod tests { + + let device_id = "test_id"; + if let Some(char_dev) = vm_config.chardev.remove(device_id) { +- assert_eq!(char_dev.backend, expect); ++ assert_eq!(char_dev.classtype, expect); + } else { + assert!(false); + } + }; + +- check_argument("stdio,id=test_id".to_string(), ChardevType::Stdio); +- check_argument("pty,id=test_id".to_string(), ChardevType::Pty); ++ check_argument( ++ "stdio,id=test_id".to_string(), ++ ChardevType::Stdio { ++ id: "test_id".to_string(), ++ }, ++ ); ++ check_argument( ++ "pty,id=test_id".to_string(), ++ ChardevType::Pty { ++ id: "test_id".to_string(), ++ }, ++ ); + check_argument( + "file,id=test_id,path=/some/file".to_string(), +- ChardevType::File("/some/file".to_string()), ++ ChardevType::File { ++ id: "test_id".to_string(), ++ path: "/some/file".to_string(), ++ }, + ); + + let extra_params = [ +@@ -767,17 +503,22 @@ mod tests { + for (param, server_state, nowait_state) in extra_params { + check_argument( + format!("{}{}", "socket,id=test_id,path=/path/to/socket", param), +- ChardevType::UnixSocket { +- path: "/path/to/socket".to_string(), ++ ChardevType::Socket { ++ id: "test_id".to_string(), ++ path: Some("/path/to/socket".to_string()), ++ host: "0.0.0.0".to_string(), ++ port: None, + server: server_state, + nowait: nowait_state, + }, + ); + check_argument( + format!("{}{}", "socket,id=test_id,port=9090", param), +- ChardevType::TcpSocket { ++ ChardevType::Socket { ++ id: "test_id".to_string(), ++ path: None, + host: "0.0.0.0".to_string(), +- port: 9090, ++ port: Some(9090), + server: server_state, + nowait: nowait_state, + }, +@@ -787,9 +528,11 @@ mod tests { + "{}{}", + "socket,id=test_id,host=172.56.16.12,port=7070", param + ), +- ChardevType::TcpSocket { ++ ChardevType::Socket { ++ id: "test_id".to_string(), ++ path: None, + host: "172.56.16.12".to_string(), +- port: 7070, ++ port: Some(7070), + server: server_state, + nowait: nowait_state, + }, +diff --git a/machine_manager/src/config/demo_dev.rs b/machine_manager/src/config/demo_dev.rs +deleted file mode 100644 +index 10d2199..0000000 +--- a/machine_manager/src/config/demo_dev.rs ++++ /dev/null +@@ -1,97 +0,0 @@ +-// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{bail, Result}; +- +-use super::{pci_args_check, CmdParser, VmConfig}; +- +-/// Config struct for `demo_dev`. +-/// Contains demo_dev device's attr. +-#[derive(Debug, Clone)] +-pub struct DemoDevConfig { +- pub id: String, +- // Different device implementations can be configured based on this parameter +- pub device_type: String, +- pub bar_num: u8, +- // Every bar has the same size just for simplification. +- pub bar_size: u64, +-} +- +-impl DemoDevConfig { +- pub fn new() -> Self { +- Self { +- id: "".to_string(), +- device_type: "".to_string(), +- bar_num: 0, +- bar_size: 0, +- } +- } +-} +- +-impl Default for DemoDevConfig { +- fn default() -> Self { +- Self::new() +- } +-} +- +-pub fn parse_demo_dev(_vm_config: &mut VmConfig, args_str: String) -> Result { +- let mut cmd_parser = CmdParser::new("demo-dev"); +- cmd_parser +- .push("") +- .push("id") +- .push("addr") +- .push("device_type") +- .push("bus") +- .push("bar_num") +- .push("bar_size"); +- cmd_parser.parse(&args_str)?; +- +- pci_args_check(&cmd_parser)?; +- +- let mut demo_dev_cfg = DemoDevConfig::new(); +- +- if let Some(id) = cmd_parser.get_value::("id")? { +- demo_dev_cfg.id = id; +- } else { +- bail!("No id configured for demo device"); +- } +- +- if let Some(device_type) = cmd_parser.get_value::("device_type")? { +- demo_dev_cfg.device_type = device_type; +- } +- +- if let Some(bar_num) = cmd_parser.get_value::("bar_num")? { +- demo_dev_cfg.bar_num = bar_num; +- } +- +- // todo: support parsing hex num "0x**". It just supports decimal number now. +- if let Some(bar_size) = cmd_parser.get_value::("bar_size")? { +- demo_dev_cfg.bar_size = bar_size; +- } +- +- Ok(demo_dev_cfg) +-} +- +-#[cfg(test)] +-mod tests { +- use super::*; +- #[test] +- fn test_parse_demo_dev() { +- let mut vm_config = VmConfig::default(); +- let config_line = "-device pcie-demo-dev,bus=pcie.0,addr=4.0,id=test_0,device_type=demo-gpu,bar_num=3,bar_size=4096"; +- let demo_cfg = parse_demo_dev(&mut vm_config, config_line.to_string()).unwrap(); +- assert_eq!(demo_cfg.id, "test_0".to_string()); +- assert_eq!(demo_cfg.device_type, "demo-gpu".to_string()); +- assert_eq!(demo_cfg.bar_num, 3); +- assert_eq!(demo_cfg.bar_size, 4096); +- } +-} +diff --git a/machine_manager/src/config/devices.rs b/machine_manager/src/config/devices.rs +index cf42739..e355b88 100644 +--- a/machine_manager/src/config/devices.rs ++++ b/machine_manager/src/config/devices.rs +@@ -13,7 +13,7 @@ + use anyhow::{Context, Result}; + use regex::Regex; + +-use super::{CmdParser, VmConfig}; ++use super::{get_class_type, VmConfig}; + use crate::qmp::qmp_schema; + + impl VmConfig { +@@ -117,7 +117,7 @@ impl VmConfig { + } + + pub fn add_device(&mut self, device_config: &str) -> Result<()> { +- let device_type = parse_device_type(device_config)?; ++ let device_type = get_class_type(device_config).with_context(|| "Missing driver field.")?; + self.devices.push((device_type, device_config.to_string())); + + Ok(()) +@@ -135,44 +135,3 @@ impl VmConfig { + } + } + } +- +-pub fn parse_device_type(device_config: &str) -> Result { +- let mut cmd_params = CmdParser::new("device"); +- cmd_params.push(""); +- cmd_params.get_parameters(device_config)?; +- cmd_params +- .get_value::("")? +- .with_context(|| "Missing driver field.") +-} +- +-pub fn parse_device_id(device_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("device"); +- cmd_parser.push("id"); +- +- cmd_parser.get_parameters(device_config)?; +- if let Some(id) = cmd_parser.get_value::("id")? { +- Ok(id) +- } else { +- Ok(String::new()) +- } +-} +- +-#[cfg(test)] +-mod tests { +- use super::*; +- +- #[test] +- fn test_parse_device_id() { +- let test_conf = "virtio-blk-device,drive=rootfs,id=blkid"; +- let ret = parse_device_id(test_conf); +- assert!(ret.is_ok()); +- let id = ret.unwrap(); +- assert_eq!("blkid", id); +- +- let test_conf = "virtio-blk-device,drive=rootfs"; +- let ret = parse_device_id(test_conf); +- assert!(ret.is_ok()); +- let id = ret.unwrap(); +- assert_eq!("", id); +- } +-} +diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs +index 8f1f2e0..d078285 100644 +--- a/machine_manager/src/config/display.rs ++++ b/machine_manager/src/config/display.rs +@@ -13,17 +13,15 @@ + #[cfg(feature = "gtk")] + use std::sync::Arc; + ++use anyhow::Result; + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +-use anyhow::Context; +-use anyhow::{bail, Result}; ++use anyhow::{bail, Context}; ++use clap::{ArgAction, Parser}; + use serde::{Deserialize, Serialize}; + #[cfg(feature = "gtk")] + use vmm_sys_util::eventfd::EventFd; + +-use crate::config::{CmdParser, ExBool, VmConfig}; +- +-#[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +-static DEFAULT_UI_PATH: &str = "/tmp/"; ++use crate::config::{parse_bool, str_slip_to_clap, VmConfig}; + + /// Event fd related to power button in gtk. + #[cfg(feature = "gtk")] +@@ -41,88 +39,59 @@ pub struct UiContext { + } + + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] +-pub struct OhuiConfig { +- /// Use OHUI. +- pub ohui: bool, +- /// Create the OHUI thread. +- pub iothread: Option, +- /// Confirm related files' path. +- pub path: String, ++fn get_sock_path(p: &str) -> Result { ++ let path = std::fs::canonicalize(p) ++ .with_context(|| format!("Failed to get real directory path: {:?}", p))?; ++ if !path.exists() { ++ bail!( ++ "The defined directory {:?} path doesn't exist", ++ path.as_os_str() ++ ); ++ } ++ if !path.is_dir() { ++ bail!( ++ "The defined socks-path {:?} is not directory", ++ path.as_os_str() ++ ); ++ } ++ ++ Ok(path.to_str().unwrap().to_string()) + } + + /// GTK and OHUI related configuration. +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] ++ + pub struct DisplayConfig { +- /// Create the GTK thread. +- pub gtk: bool, ++ #[arg(long, alias = "classtype", value_parser = ["gtk", "ohui"])] ++ pub display_type: String, + /// App name if configured. ++ #[arg(long)] + pub app_name: Option, + /// Keep the window fill the desktop. ++ #[arg(long, default_value = "off", action = ArgAction::Append, value_parser = parse_bool)] + pub full_screen: bool, +- /// Used for OHUI ++ /// Create the OHUI thread. + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +- pub ohui_config: OhuiConfig, ++ #[arg(long)] ++ pub iothread: Option, ++ /// Confirm related files' path. Default ui path is "/tmp". ++ #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] ++ #[arg(long, alias = "socks-path", default_value = "/tmp/", value_parser = get_sock_path)] ++ pub path: String, + } + + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + impl DisplayConfig { + pub fn get_ui_path(&self) -> String { +- self.ohui_config.path.clone() ++ self.path.clone() + } + } + + impl VmConfig { + pub fn add_display(&mut self, vm_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("display"); +- cmd_parser.push("").push("full-screen").push("app-name"); +- #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +- cmd_parser.push("iothread").push("socks-path"); +- cmd_parser.parse(vm_config)?; +- let mut display_config = DisplayConfig::default(); +- if let Some(str) = cmd_parser.get_value::("")? { +- match str.as_str() { +- "gtk" => display_config.gtk = true, +- #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +- "ohui" => display_config.ohui_config.ohui = true, +- _ => bail!("Unsupported device: {}", str), +- } +- } +- if let Some(name) = cmd_parser.get_value::("app-name")? { +- display_config.app_name = Some(name); +- } +- if let Some(default) = cmd_parser.get_value::("full-screen")? { +- display_config.full_screen = default.into(); +- } +- +- #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +- if display_config.ohui_config.ohui { +- if let Some(iothread) = cmd_parser.get_value::("iothread")? { +- display_config.ohui_config.iothread = Some(iothread); +- } +- +- if let Some(path) = cmd_parser.get_value::("socks-path")? { +- let path = std::fs::canonicalize(path.clone()).with_context(|| { +- format!("Failed to get real directory path: {:?}", path.clone()) +- })?; +- if !path.exists() { +- bail!( +- "The defined directory {:?} path doesn't exist", +- path.as_os_str() +- ); +- } +- if !path.is_dir() { +- bail!( +- "The defined socks-path {:?} is not directory", +- path.as_os_str() +- ); +- } +- display_config.ohui_config.path = path.to_str().unwrap().to_string(); +- } else { +- display_config.ohui_config.path = DEFAULT_UI_PATH.to_string(); +- } +- } +- ++ let display_config = ++ DisplayConfig::try_parse_from(str_slip_to_clap(vm_config, true, false))?; + self.display = Some(display_config); + Ok(()) + } +@@ -141,28 +110,28 @@ mod tests { + let config_line = "gtk"; + assert!(vm_config.add_display(config_line).is_ok()); + let display_config = vm_config.display.unwrap(); +- assert_eq!(display_config.gtk, true); ++ assert_eq!(display_config.display_type, "gtk"); + assert_eq!(display_config.full_screen, false); + + let mut vm_config = VmConfig::default(); + let config_line = "gtk,full-screen=on"; + assert!(vm_config.add_display(config_line).is_ok()); + let display_config = vm_config.display.unwrap(); +- assert_eq!(display_config.gtk, true); ++ assert_eq!(display_config.display_type, "gtk"); + assert_eq!(display_config.full_screen, true); + + let mut vm_config = VmConfig::default(); + let config_line = "gtk,full-screen=off"; + assert!(vm_config.add_display(config_line).is_ok()); + let display_config = vm_config.display.unwrap(); +- assert_eq!(display_config.gtk, true); ++ assert_eq!(display_config.display_type, "gtk"); + assert_eq!(display_config.full_screen, false); + + let mut vm_config = VmConfig::default(); + let config_line = "gtk,app-name=desktopappengine"; + assert!(vm_config.add_display(config_line).is_ok()); + let display_config = vm_config.display.unwrap(); +- assert_eq!(display_config.gtk, true); ++ assert_eq!(display_config.display_type, "gtk"); + assert_eq!(display_config.full_screen, false); + assert_eq!( + display_config.app_name, +diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs +index e88826a..e8e1a60 100644 +--- a/machine_manager/src/config/drive.rs ++++ b/machine_manager/src/config/drive.rs +@@ -16,25 +16,17 @@ use std::path::Path; + use std::str::FromStr; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser}; + use log::error; + use serde::{Deserialize, Serialize}; + +-use super::{error::ConfigError, pci_args_check, M}; +-use crate::config::{ +- check_arg_too_long, get_chardev_socket_path, memory_unit_conversion, CmdParser, ConfigCheck, +- ExBool, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_PATH_LENGTH, MAX_STRING_LENGTH, MAX_VIRTIO_QUEUE, +-}; ++use super::{error::ConfigError, parse_size, valid_id, valid_path}; ++use crate::config::{parse_bool, str_slip_to_clap, ConfigCheck, VmConfig, MAX_STRING_LENGTH}; + use util::aio::{aio_probe, AioEngine, WriteZeroesState}; + +-const MAX_SERIAL_NUM: usize = 20; + const MAX_IOPS: u64 = 1_000_000; + const MAX_UNIT_ID: usize = 2; + +-// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-blk should be larger than 2. +-const MIN_QUEUE_SIZE_BLK: u16 = 2; +-// Max size of each virtqueue for virtio-blk. +-const MAX_QUEUE_SIZE_BLK: u16 = 1024; +- + // L2 Cache max size is 32M. + pub const MAX_L2_CACHE_SIZE: u64 = 32 * (1 << 20); + // Refcount table cache max size is 32M. +@@ -60,29 +52,6 @@ pub struct DriveFile { + pub buf_align: u32, + } + +-#[derive(Debug, Clone, Serialize, Deserialize)] +-#[serde(deny_unknown_fields)] +-pub struct BlkDevConfig { +- pub id: String, +- pub path_on_host: String, +- pub read_only: bool, +- pub direct: bool, +- pub serial_num: Option, +- pub iothread: Option, +- pub iops: Option, +- pub queues: u16, +- pub boot_index: Option, +- pub chardev: Option, +- pub socket_path: Option, +- pub aio: AioEngine, +- pub queue_size: u16, +- pub discard: bool, +- pub write_zeroes: WriteZeroesState, +- pub format: DiskFormat, +- pub l2_cache_size: Option, +- pub refcount_cache_size: Option, +-} +- + #[derive(Debug, Clone)] + pub struct BootIndexInfo { + pub boot_index: u8, +@@ -90,33 +59,9 @@ pub struct BootIndexInfo { + pub dev_path: String, + } + +-impl Default for BlkDevConfig { +- fn default() -> Self { +- BlkDevConfig { +- id: "".to_string(), +- path_on_host: "".to_string(), +- read_only: false, +- direct: true, +- serial_num: None, +- iothread: None, +- iops: None, +- queues: 1, +- boot_index: None, +- chardev: None, +- socket_path: None, +- aio: AioEngine::Native, +- queue_size: DEFAULT_VIRTQUEUE_SIZE, +- discard: false, +- write_zeroes: WriteZeroesState::Off, +- format: DiskFormat::Raw, +- l2_cache_size: None, +- refcount_cache_size: None, +- } +- } +-} +- +-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] ++#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] + pub enum DiskFormat { ++ #[default] + Raw, + Qcow2, + } +@@ -142,44 +87,73 @@ impl ToString for DiskFormat { + } + } + +-/// Config struct for `drive`. +-/// Contains block device's attr. +-#[derive(Debug, Clone, Serialize, Deserialize)] +-#[serde(deny_unknown_fields)] ++fn valid_l2_cache_size(s: &str) -> Result { ++ let size = parse_size(s)?; ++ if size > MAX_L2_CACHE_SIZE { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "l2-cache-size".to_string(), ++ 0, ++ true, ++ MAX_L2_CACHE_SIZE, ++ true ++ ))); ++ } ++ Ok(size) ++} ++ ++fn valid_refcount_cache_size(s: &str) -> Result { ++ let size = parse_size(s)?; ++ if size > MAX_REFTABLE_CACHE_SIZE { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "refcount-cache-size".to_string(), ++ 0, ++ true, ++ MAX_REFTABLE_CACHE_SIZE, ++ true ++ ))); ++ } ++ Ok(size) ++} ++ ++/// Config struct for `drive`, including `block drive` and `pflash drive`. ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct DriveConfig { ++ #[arg(long, default_value = "")] + pub id: String, ++ #[arg(long, alias = "if", default_value = "none", value_parser = ["none", "pflash"])] ++ pub drive_type: String, ++ #[arg(long, value_parser = clap::value_parser!(u8).range(..MAX_UNIT_ID as i64))] ++ pub unit: Option, ++ #[arg(long, alias = "file", value_parser = valid_path)] + pub path_on_host: String, +- pub read_only: bool, ++ #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] ++ pub readonly: bool, ++ #[arg(long, default_value = "true", value_parser = parse_bool, action = ArgAction::Append)] + pub direct: bool, ++ #[arg(long, alias = "throttling.iops-total", value_parser = clap::value_parser!(u64).range(..=MAX_IOPS as u64))] + pub iops: Option, ++ #[arg( ++ long, ++ default_value = "native", ++ default_value_if("direct", "false", "off"), ++ default_value_if("direct", "off", "off") ++ )] + pub aio: AioEngine, ++ #[arg(long, default_value = "disk", value_parser = ["disk", "cdrom"])] + pub media: String, ++ #[arg(long, default_value = "ignore", value_parser = parse_bool, action = ArgAction::Append)] + pub discard: bool, ++ #[arg(long, alias = "detect-zeroes", default_value = "off")] + pub write_zeroes: WriteZeroesState, ++ #[arg(long, default_value = "raw")] + pub format: DiskFormat, ++ #[arg(long, value_parser = valid_l2_cache_size)] + pub l2_cache_size: Option, ++ #[arg(long, value_parser = valid_refcount_cache_size)] + pub refcount_cache_size: Option, + } + +-impl Default for DriveConfig { +- fn default() -> Self { +- DriveConfig { +- id: "".to_string(), +- path_on_host: "".to_string(), +- read_only: false, +- direct: true, +- iops: None, +- aio: AioEngine::Native, +- media: "disk".to_string(), +- discard: false, +- write_zeroes: WriteZeroesState::Off, +- format: DiskFormat::Raw, +- l2_cache_size: None, +- refcount_cache_size: None, +- } +- } +-} +- + impl DriveConfig { + /// Check whether the drive file path on the host is valid. + pub fn check_path(&self) -> Result<()> { +@@ -222,383 +196,90 @@ impl DriveConfig { + + impl ConfigCheck for DriveConfig { + fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "Drive id")?; ++ if self.drive_type == "pflash" { ++ self.unit.with_context(|| { ++ ConfigError::FieldIsMissing("unit".to_string(), "pflash".to_string()) ++ })?; ++ if self.format.to_string() != "raw" { ++ bail!("Only \'raw\' type of pflash is supported"); ++ } ++ } else { ++ if self.id.is_empty() { ++ return Err(anyhow!(ConfigError::FieldIsMissing( ++ "id".to_string(), ++ "blk".to_string() ++ ))); ++ } ++ valid_id(&self.id)?; ++ valid_path(&self.path_on_host)?; ++ if self.iops > Some(MAX_IOPS) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "iops of block device".to_string(), ++ 0, ++ true, ++ MAX_IOPS, ++ true, ++ ))); ++ } ++ if self.l2_cache_size > Some(MAX_L2_CACHE_SIZE) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "l2-cache-size".to_string(), ++ 0, ++ true, ++ MAX_L2_CACHE_SIZE, ++ true ++ ))); ++ } ++ if self.refcount_cache_size > Some(MAX_REFTABLE_CACHE_SIZE) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "refcount-cache-size".to_string(), ++ 0, ++ true, ++ MAX_REFTABLE_CACHE_SIZE, ++ true ++ ))); ++ } + +- if self.path_on_host.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "Drive device path".to_string(), +- MAX_PATH_LENGTH, +- ))); +- } +- if self.iops > Some(MAX_IOPS) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "iops of block device".to_string(), +- 0, +- true, +- MAX_IOPS, +- true, +- ))); +- } +- if self.aio != AioEngine::Off { +- if self.aio == AioEngine::Native && !self.direct { ++ if self.aio != AioEngine::Off { ++ if self.aio == AioEngine::Native && !self.direct { ++ return Err(anyhow!(ConfigError::InvalidParam( ++ "aio".to_string(), ++ "native aio type should be used with \"direct\" on".to_string(), ++ ))); ++ } ++ aio_probe(self.aio)?; ++ } else if self.direct { + return Err(anyhow!(ConfigError::InvalidParam( + "aio".to_string(), +- "native aio type should be used with \"direct\" on".to_string(), ++ "low performance expected when use sync io with \"direct\" on".to_string(), + ))); + } +- aio_probe(self.aio)?; +- } else if self.direct { +- return Err(anyhow!(ConfigError::InvalidParam( +- "aio".to_string(), +- "low performance expected when use sync io with \"direct\" on".to_string(), +- ))); +- } +- +- if !["disk", "cdrom"].contains(&self.media.as_str()) { +- return Err(anyhow!(ConfigError::InvalidParam( +- "media".to_string(), +- "media should be \"disk\" or \"cdrom\"".to_string(), +- ))); +- } +- +- if self.l2_cache_size > Some(MAX_L2_CACHE_SIZE) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "l2-cache-size".to_string(), +- 0, +- true, +- MAX_L2_CACHE_SIZE, +- true +- ))); +- } +- if self.refcount_cache_size > Some(MAX_REFTABLE_CACHE_SIZE) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "refcount-cache-size".to_string(), +- 0, +- true, +- MAX_REFTABLE_CACHE_SIZE, +- true +- ))); + } + +- Ok(()) +- } +-} +- +-impl ConfigCheck for BlkDevConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "drive device id")?; +- if self.serial_num.is_some() && self.serial_num.as_ref().unwrap().len() > MAX_SERIAL_NUM { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "drive serial number".to_string(), +- MAX_SERIAL_NUM, +- ))); +- } +- +- if self.iothread.is_some() && self.iothread.as_ref().unwrap().len() > MAX_STRING_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "iothread name".to_string(), +- MAX_STRING_LENGTH, +- ))); +- } +- +- if self.queues < 1 || self.queues > MAX_VIRTIO_QUEUE as u16 { +- return Err(anyhow!(ConfigError::IllegalValue( +- "number queues of block device".to_string(), +- 1, +- true, +- MAX_VIRTIO_QUEUE as u64, +- true, +- ))); +- } +- +- if self.queue_size <= MIN_QUEUE_SIZE_BLK || self.queue_size > MAX_QUEUE_SIZE_BLK { +- return Err(anyhow!(ConfigError::IllegalValue( +- "queue size of block device".to_string(), +- MIN_QUEUE_SIZE_BLK as u64, +- false, +- MAX_QUEUE_SIZE_BLK as u64, +- true +- ))); +- } +- +- if self.queue_size & (self.queue_size - 1) != 0 { +- bail!("Queue size should be power of 2!"); +- } +- +- let fake_drive = DriveConfig { +- path_on_host: self.path_on_host.clone(), +- direct: self.direct, +- iops: self.iops, +- aio: self.aio, +- ..Default::default() +- }; +- fake_drive.check()?; + #[cfg(not(test))] +- if self.chardev.is_none() { +- fake_drive.check_path()?; +- } +- +- Ok(()) +- } +-} +- +-fn parse_drive(cmd_parser: CmdParser) -> Result { +- let mut drive = DriveConfig::default(); +- if let Some(fmt) = cmd_parser.get_value::("format")? { +- drive.format = fmt; +- } +- +- drive.id = cmd_parser +- .get_value::("id")? +- .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "blk".to_string()))?; +- drive.path_on_host = cmd_parser +- .get_value::("file")? +- .with_context(|| ConfigError::FieldIsMissing("file".to_string(), "blk".to_string()))?; +- +- if let Some(read_only) = cmd_parser.get_value::("readonly")? { +- drive.read_only = read_only.into(); +- } +- if let Some(direct) = cmd_parser.get_value::("direct")? { +- drive.direct = direct.into(); +- } +- drive.iops = cmd_parser.get_value::("throttling.iops-total")?; +- drive.aio = cmd_parser.get_value::("aio")?.unwrap_or({ +- if drive.direct { +- AioEngine::Native +- } else { +- AioEngine::Off +- } +- }); +- drive.media = cmd_parser +- .get_value::("media")? +- .unwrap_or_else(|| "disk".to_string()); +- if let Some(discard) = cmd_parser.get_value::("discard")? { +- drive.discard = discard.into(); +- } +- drive.write_zeroes = cmd_parser +- .get_value::("detect-zeroes")? +- .unwrap_or(WriteZeroesState::Off); +- +- if let Some(l2_cache) = cmd_parser.get_value::("l2-cache-size")? { +- let sz = memory_unit_conversion(&l2_cache, M) +- .with_context(|| format!("Invalid l2 cache size: {}", l2_cache))?; +- drive.l2_cache_size = Some(sz); +- } +- if let Some(rc_cache) = cmd_parser.get_value::("refcount-cache-size")? { +- let sz = memory_unit_conversion(&rc_cache, M) +- .with_context(|| format!("Invalid refcount cache size: {}", rc_cache))?; +- drive.refcount_cache_size = Some(sz); +- } +- +- drive.check()?; +- #[cfg(not(test))] +- drive.check_path()?; +- Ok(drive) +-} +- +-pub fn parse_blk( +- vm_config: &mut VmConfig, +- drive_config: &str, +- queues_auto: Option, +-) -> Result { +- let mut cmd_parser = CmdParser::new("virtio-blk"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("drive") +- .push("bootindex") +- .push("serial") +- .push("iothread") +- .push("num-queues") +- .push("queue-size"); +- +- cmd_parser.parse(drive_config)?; +- +- pci_args_check(&cmd_parser)?; +- +- let mut blkdevcfg = BlkDevConfig::default(); +- if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { +- blkdevcfg.boot_index = Some(boot_index); +- } +- +- let blkdrive = cmd_parser +- .get_value::("drive")? +- .with_context(|| ConfigError::FieldIsMissing("drive".to_string(), "blk".to_string()))?; +- +- if let Some(iothread) = cmd_parser.get_value::("iothread")? { +- blkdevcfg.iothread = Some(iothread); +- } +- +- if let Some(serial) = cmd_parser.get_value::("serial")? { +- blkdevcfg.serial_num = Some(serial); +- } +- +- blkdevcfg.id = cmd_parser +- .get_value::("id")? +- .with_context(|| "No id configured for blk device")?; +- +- if let Some(queues) = cmd_parser.get_value::("num-queues")? { +- blkdevcfg.queues = queues; +- } else if let Some(queues) = queues_auto { +- blkdevcfg.queues = queues; +- } +- +- if let Some(queue_size) = cmd_parser.get_value::("queue-size")? { +- blkdevcfg.queue_size = queue_size; +- } +- +- let drive_arg = &vm_config +- .drives +- .remove(&blkdrive) +- .with_context(|| "No drive configured matched for blk device")?; +- blkdevcfg.path_on_host = drive_arg.path_on_host.clone(); +- blkdevcfg.read_only = drive_arg.read_only; +- blkdevcfg.direct = drive_arg.direct; +- blkdevcfg.iops = drive_arg.iops; +- blkdevcfg.aio = drive_arg.aio; +- blkdevcfg.discard = drive_arg.discard; +- blkdevcfg.write_zeroes = drive_arg.write_zeroes; +- blkdevcfg.format = drive_arg.format; +- blkdevcfg.l2_cache_size = drive_arg.l2_cache_size; +- blkdevcfg.refcount_cache_size = drive_arg.refcount_cache_size; +- blkdevcfg.check()?; +- Ok(blkdevcfg) +-} +- +-pub fn parse_vhost_user_blk( +- vm_config: &mut VmConfig, +- drive_config: &str, +- queues_auto: Option, +-) -> Result { +- let mut cmd_parser = CmdParser::new("vhost-user-blk-pci"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("num-queues") +- .push("chardev") +- .push("queue-size") +- .push("bootindex"); +- +- cmd_parser.parse(drive_config)?; +- +- pci_args_check(&cmd_parser)?; +- +- let mut blkdevcfg = BlkDevConfig::default(); +- +- if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { +- blkdevcfg.boot_index = Some(boot_index); +- } +- +- blkdevcfg.chardev = cmd_parser +- .get_value::("chardev")? +- .map(Some) +- .with_context(|| { +- ConfigError::FieldIsMissing("chardev".to_string(), "vhost-user-blk-pci".to_string()) +- })?; +- +- blkdevcfg.id = cmd_parser +- .get_value::("id")? +- .with_context(|| "No id configured for blk device")?; +- +- if let Some(queues) = cmd_parser.get_value::("num-queues")? { +- blkdevcfg.queues = queues; +- } else if let Some(queues) = queues_auto { +- blkdevcfg.queues = queues; +- } ++ self.check_path()?; + +- if let Some(size) = cmd_parser.get_value::("queue-size")? { +- blkdevcfg.queue_size = size; +- } +- +- if let Some(chardev) = &blkdevcfg.chardev { +- blkdevcfg.socket_path = Some(get_chardev_socket_path(chardev, vm_config)?); +- } +- blkdevcfg.check()?; +- Ok(blkdevcfg) +-} +- +-/// Config struct for `pflash`. +-/// Contains pflash device's attr. +-#[derive(Debug, Clone, Serialize, Deserialize, Default)] +-#[serde(deny_unknown_fields)] +-pub struct PFlashConfig { +- pub path_on_host: String, +- pub read_only: bool, +- pub unit: usize, +-} +- +-impl ConfigCheck for PFlashConfig { +- fn check(&self) -> Result<()> { +- if self.path_on_host.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "drive device path".to_string(), +- MAX_PATH_LENGTH, +- ))); +- } +- +- if self.unit >= MAX_UNIT_ID { +- return Err(anyhow!(ConfigError::UnitIdError( +- "PFlash unit id".to_string(), +- self.unit, +- MAX_UNIT_ID - 1 +- ))); +- } + Ok(()) + } + } + + impl VmConfig { +- /// Add '-drive ...' drive config to `VmConfig`. +- pub fn add_drive(&mut self, drive_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("drive"); +- cmd_parser.push("if"); +- +- cmd_parser.get_parameters(drive_config)?; +- let drive_type = cmd_parser +- .get_value::("if")? +- .unwrap_or_else(|| "none".to_string()); +- match drive_type.as_str() { ++ /// Add '-drive ...' drive config to `VmConfig`, including `block drive` and `pflash drive`. ++ pub fn add_drive(&mut self, drive_config: &str) -> Result { ++ let drive_cfg = DriveConfig::try_parse_from(str_slip_to_clap(drive_config, false, false))?; ++ drive_cfg.check()?; ++ match drive_cfg.drive_type.as_str() { + "none" => { +- self.add_block_drive(drive_config)?; ++ self.add_drive_with_config(drive_cfg.clone())?; + } + "pflash" => { +- self.add_pflash(drive_config)?; ++ self.add_flashdev(drive_cfg.clone())?; + } + _ => { +- bail!("Unknow 'if' argument: {:?}", drive_type.as_str()); ++ bail!("Unknow 'if' argument: {:?}", &drive_cfg.drive_type); + } + } + +- Ok(()) +- } +- +- /// Add block drive config to vm and return the added drive config. +- pub fn add_block_drive(&mut self, block_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("drive"); +- cmd_parser +- .push("file") +- .push("id") +- .push("readonly") +- .push("direct") +- .push("format") +- .push("if") +- .push("throttling.iops-total") +- .push("aio") +- .push("media") +- .push("discard") +- .push("detect-zeroes") +- .push("format") +- .push("l2-cache-size") +- .push("refcount-cache-size"); +- +- cmd_parser.parse(block_config)?; +- let drive_cfg = parse_drive(cmd_parser)?; +- self.add_drive_with_config(drive_cfg.clone())?; + Ok(drive_cfg) + } + +@@ -609,11 +290,10 @@ impl VmConfig { + /// * `drive_conf` - The drive config to be added to the vm. + pub fn add_drive_with_config(&mut self, drive_conf: DriveConfig) -> Result<()> { + let drive_id = drive_conf.id.clone(); +- if self.drives.get(&drive_id).is_none() { +- self.drives.insert(drive_id, drive_conf); +- } else { ++ if self.drives.get(&drive_id).is_some() { + bail!("Drive {} has been added", drive_id); + } ++ self.drives.insert(drive_id, drive_conf); + Ok(()) + } + +@@ -631,13 +311,13 @@ impl VmConfig { + } + + /// Add new flash device to `VmConfig`. +- fn add_flashdev(&mut self, pflash: PFlashConfig) -> Result<()> { ++ fn add_flashdev(&mut self, pflash: DriveConfig) -> Result<()> { + if self.pflashs.is_some() { + for pf in self.pflashs.as_ref().unwrap() { +- if pf.unit == pflash.unit { ++ if pf.unit.unwrap() == pflash.unit.unwrap() { + return Err(anyhow!(ConfigError::IdRepeat( + "pflash".to_string(), +- pf.unit.to_string() ++ pf.unit.unwrap().to_string() + ))); + } + } +@@ -647,147 +327,38 @@ impl VmConfig { + } + Ok(()) + } +- +- /// Add '-pflash ...' pflash config to `VmConfig`. +- pub fn add_pflash(&mut self, pflash_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("pflash"); +- cmd_parser +- .push("if") +- .push("file") +- .push("format") +- .push("readonly") +- .push("unit"); +- +- cmd_parser.parse(pflash_config)?; +- +- let mut pflash = PFlashConfig::default(); +- +- if let Some(format) = cmd_parser.get_value::("format")? { +- if format.ne("raw") { +- bail!("Only \'raw\' type of pflash is supported"); +- } +- } +- pflash.path_on_host = cmd_parser.get_value::("file")?.with_context(|| { +- ConfigError::FieldIsMissing("file".to_string(), "pflash".to_string()) +- })?; +- +- if let Some(read_only) = cmd_parser.get_value::("readonly")? { +- pflash.read_only = read_only.into(); +- } +- +- pflash.unit = cmd_parser.get_value::("unit")?.with_context(|| { +- ConfigError::FieldIsMissing("unit".to_string(), "pflash".to_string()) +- })? as usize; +- +- pflash.check()?; +- self.add_flashdev(pflash) +- } + } + + #[cfg(test)] + mod tests { + use super::*; +- use crate::config::get_pci_bdf; + + #[test] +- fn test_drive_config_cmdline_parser() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_drive( +- "id=rootfs,file=/path/to/rootfs,readonly=off,direct=on,throttling.iops-total=200" +- ) +- .is_ok()); +- let blk_cfg_res = parse_blk( +- &mut vm_config, +- "virtio-blk-device,drive=rootfs,id=rootfs,iothread=iothread1,serial=111111,num-queues=4", +- None, +- ); +- assert!(blk_cfg_res.is_ok()); +- let blk_device_config = blk_cfg_res.unwrap(); +- assert_eq!(blk_device_config.id, "rootfs"); +- assert_eq!(blk_device_config.path_on_host, "/path/to/rootfs"); +- assert_eq!(blk_device_config.direct, true); +- assert_eq!(blk_device_config.read_only, false); +- assert_eq!(blk_device_config.serial_num, Some(String::from("111111"))); +- assert_eq!(blk_device_config.queues, 4); +- ++ fn test_pflash_drive_config_cmdline_parser() { ++ // Test1: Right. + let mut vm_config = VmConfig::default(); + assert!(vm_config +- .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") +- .is_ok()); +- let blk_cfg_res = parse_blk( +- &mut vm_config, +- "virtio-blk-device,drive=rootfs1,id=rootfs1,iothread=iothread1,iops=200,serial=111111", +- None, +- ); +- assert!(blk_cfg_res.is_err()); // Can not find drive named "rootfs1". +- } +- +- #[test] +- fn test_pci_block_config_cmdline_parser() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") +- .is_ok()); +- let blk_cfg = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=4"; +- let blk_cfg_res = parse_blk(&mut vm_config, blk_cfg, None); +- assert!(blk_cfg_res.is_ok()); +- let drive_configs = blk_cfg_res.unwrap(); +- assert_eq!(drive_configs.id, "rootfs"); +- assert_eq!(drive_configs.path_on_host, "/path/to/rootfs"); +- assert_eq!(drive_configs.direct, true); +- assert_eq!(drive_configs.read_only, false); +- assert_eq!(drive_configs.serial_num, Some(String::from("111111"))); +- assert_eq!(drive_configs.queues, 4); +- +- let pci_bdf = get_pci_bdf(blk_cfg); +- assert!(pci_bdf.is_ok()); +- let pci = pci_bdf.unwrap(); +- assert_eq!(pci.bus, "pcie.0".to_string()); +- assert_eq!(pci.addr, (1, 2)); +- +- // drive "rootfs" has been removed. +- let blk_cfg_res = parse_blk(&mut vm_config, blk_cfg, None); +- assert!(blk_cfg_res.is_err()); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") +- .is_ok()); +- let blk_cfg = +- "virtio-blk-pci,id=blk1,bus=pcie.0,addr=0x1.0x2,drive=rootfs,multifunction=on"; +- assert!(parse_blk(&mut vm_config, blk_cfg, None).is_ok()); +- } +- +- #[test] +- fn test_pflash_config_cmdline_parser() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0") ++ .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0,format=raw") + .is_ok()); + assert!(vm_config.pflashs.is_some()); + let pflash = vm_config.pflashs.unwrap(); + assert!(pflash.len() == 1); + let pflash_cfg = &pflash[0]; +- assert_eq!(pflash_cfg.unit, 0); ++ assert_eq!(pflash_cfg.unit.unwrap(), 0); + assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); +- assert_eq!(pflash_cfg.read_only, true); ++ assert_eq!(pflash_cfg.readonly, true); + ++ // Test2: Change parameters sequence. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("readonly=on,file=flash0.fd,unit=0,if=pflash") + .is_ok()); +- + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("readonly=on,if=pflash,file=flash0.fd,unit=0") + .is_ok()); + +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=2") +- .is_err()); +- ++ // Test3: Add duplicate pflash. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0") +@@ -795,52 +366,103 @@ mod tests { + assert!(vm_config + .add_drive("if=pflash,file=flash1.fd,unit=1") + .is_ok()); ++ assert!(vm_config ++ .add_drive("if=pflash,file=flash1.fd,unit=1") ++ .is_err()); + assert!(vm_config.pflashs.is_some()); + let pflash = vm_config.pflashs.unwrap(); + assert!(pflash.len() == 2); + let pflash_cfg = &pflash[0]; +- assert_eq!(pflash_cfg.unit, 0); ++ assert_eq!(pflash_cfg.unit.unwrap(), 0); + assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); +- assert_eq!(pflash_cfg.read_only, true); ++ assert_eq!(pflash_cfg.readonly, true); + let pflash_cfg = &pflash[1]; +- assert_eq!(pflash_cfg.unit, 1); ++ assert_eq!(pflash_cfg.unit.unwrap(), 1); + assert_eq!(pflash_cfg.path_on_host, "flash1.fd".to_string()); +- assert_eq!(pflash_cfg.read_only, false); +- } ++ assert_eq!(pflash_cfg.readonly, false); + +- #[test] +- fn test_drive_config_check() { +- let mut drive_conf = DriveConfig::default(); +- for _ in 0..MAX_STRING_LENGTH { +- drive_conf.id += "A"; +- } +- assert!(drive_conf.check().is_ok()); ++ // Test4: Illegal parameters unit/format. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=2") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0,format=qcow2") ++ .is_err()); + +- // Overflow +- drive_conf.id += "A"; +- assert!(drive_conf.check().is_err()); ++ // Test5: Missing parameters file/unit. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config.add_drive("if=pflash,readonly=on,unit=2").is_err()); ++ assert!(vm_config ++ .add_drive("if=pflash,readonly=on,file=flash0.fd") ++ .is_err()); ++ } + +- let mut drive_conf = DriveConfig::default(); +- for _ in 0..MAX_PATH_LENGTH { +- drive_conf.path_on_host += "A"; +- } +- assert!(drive_conf.check().is_ok()); ++ #[test] ++ fn test_block_drive_config_cmdline_parser() { ++ // Test1: Right. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200,discard=unmap,detect-zeroes=unmap") ++ .is_ok()); ++ assert!(vm_config.drives.len() == 1); ++ let drive_cfg = &vm_config.drives.remove("rootfs").unwrap(); ++ ++ assert_eq!(drive_cfg.id, "rootfs"); ++ assert_eq!(drive_cfg.path_on_host, "/path/to/rootfs"); ++ assert_eq!(drive_cfg.format.to_string(), "qcow2"); ++ assert_eq!(drive_cfg.readonly, false); ++ assert_eq!(drive_cfg.direct, true); ++ assert_eq!(drive_cfg.iops.unwrap(), 200); ++ assert_eq!(drive_cfg.discard, true); ++ assert_eq!( ++ drive_cfg.write_zeroes, ++ WriteZeroesState::from_str("unmap").unwrap() ++ ); + +- // Overflow +- drive_conf.path_on_host += "A"; +- assert!(drive_conf.check().is_err()); ++ // Test2: Change parameters sequence. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("throttling.iops-total=200,file=/path/to/rootfs,format=qcow2,id=rootfs,readonly=off,direct=on,discard=unmap,detect-zeroes=unmap") ++ .is_ok()); + +- let mut drive_conf = DriveConfig::default(); +- drive_conf.iops = Some(MAX_IOPS); +- assert!(drive_conf.check().is_ok()); ++ // Test3: Add duplicate block drive config. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on") ++ .is_ok()); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on") ++ .is_err()); ++ let drive_cfg = &vm_config.drives.remove("rootfs"); ++ assert!(drive_cfg.is_some()); + +- let mut drive_conf = DriveConfig::default(); +- drive_conf.iops = None; +- assert!(drive_conf.check().is_ok()); ++ // Test4: Illegal parameters. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=vhdx") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("id=rootfs,if=illegal,file=/path/to/rootfs,format=vhdx") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,throttling.iops-total=1000001") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,media=illegal") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,detect-zeroes=illegal") ++ .is_err()); + +- // Overflow +- drive_conf.iops = Some(MAX_IOPS + 1); +- assert!(drive_conf.check().is_err()); ++ // Test5: Missing parameters id/file. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_drive("file=/path/to/rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200") ++ .is_err()); ++ assert!(vm_config ++ .add_drive("id=rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200") ++ .is_err()); + } + + #[test] +@@ -888,19 +510,19 @@ mod tests { + fn test_drive_config_discard() { + let mut vm_config = VmConfig::default(); + let drive_conf = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=ignore") ++ .add_drive("id=rootfs,file=/path/to/rootfs,discard=ignore") + .unwrap(); + assert_eq!(drive_conf.discard, false); + + let mut vm_config = VmConfig::default(); + let drive_conf = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=unmap") ++ .add_drive("id=rootfs,file=/path/to/rootfs,discard=unmap") + .unwrap(); + assert_eq!(drive_conf.discard, true); + + let mut vm_config = VmConfig::default(); + let ret = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=invalid") ++ .add_drive("id=rootfs,file=/path/to/rootfs,discard=invalid") + .is_err(); + assert_eq!(ret, true); + } +@@ -909,25 +531,25 @@ mod tests { + fn test_drive_config_write_zeroes() { + let mut vm_config = VmConfig::default(); + let drive_conf = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=off") ++ .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=off") + .unwrap(); + assert_eq!(drive_conf.write_zeroes, WriteZeroesState::Off); + + let mut vm_config = VmConfig::default(); + let drive_conf = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=on") ++ .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=on") + .unwrap(); + assert_eq!(drive_conf.write_zeroes, WriteZeroesState::On); + + let mut vm_config = VmConfig::default(); + let drive_conf = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=unmap") ++ .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=unmap") + .unwrap(); + assert_eq!(drive_conf.write_zeroes, WriteZeroesState::Unmap); + + let mut vm_config = VmConfig::default(); + let ret = vm_config +- .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=invalid") ++ .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=invalid") + .is_err(); + assert_eq!(ret, true); + } +diff --git a/machine_manager/src/config/fs.rs b/machine_manager/src/config/fs.rs +deleted file mode 100644 +index e1a16ab..0000000 +--- a/machine_manager/src/config/fs.rs ++++ /dev/null +@@ -1,115 +0,0 @@ +-// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{anyhow, bail, Context, Result}; +- +-use super::error::ConfigError; +-use crate::config::{ +- pci_args_check, ChardevType, CmdParser, ConfigCheck, VmConfig, MAX_SOCK_PATH_LENGTH, +- MAX_STRING_LENGTH, MAX_TAG_LENGTH, +-}; +- +-/// Config struct for `fs`. +-/// Contains fs device's attr. +-#[derive(Debug, Clone)] +-pub struct FsConfig { +- /// Device tag. +- pub tag: String, +- /// Device id. +- pub id: String, +- /// Char device sock path. +- pub sock: String, +-} +- +-impl Default for FsConfig { +- fn default() -> Self { +- FsConfig { +- tag: "".to_string(), +- id: "".to_string(), +- sock: "".to_string(), +- } +- } +-} +- +-impl ConfigCheck for FsConfig { +- fn check(&self) -> Result<()> { +- if self.tag.len() >= MAX_TAG_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "fs device tag".to_string(), +- MAX_TAG_LENGTH - 1, +- ))); +- } +- +- if self.id.len() >= MAX_STRING_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "fs device id".to_string(), +- MAX_STRING_LENGTH - 1, +- ))); +- } +- +- if self.sock.len() > MAX_SOCK_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "fs sock path".to_string(), +- MAX_SOCK_PATH_LENGTH, +- ))); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_fs(vm_config: &mut VmConfig, fs_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("fs"); +- cmd_parser +- .push("") +- .push("tag") +- .push("id") +- .push("chardev") +- .push("bus") +- .push("addr") +- .push("multifunction"); +- cmd_parser.parse(fs_config)?; +- pci_args_check(&cmd_parser)?; +- +- let mut fs_cfg = FsConfig { +- tag: cmd_parser.get_value::("tag")?.with_context(|| { +- ConfigError::FieldIsMissing("tag".to_string(), "virtio-fs".to_string()) +- })?, +- id: cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "virtio-fs".to_string()) +- })?, +- ..Default::default() +- }; +- +- if let Some(name) = cmd_parser.get_value::("chardev")? { +- if let Some(char_dev) = vm_config.chardev.remove(&name) { +- match &char_dev.backend { +- ChardevType::UnixSocket { path, .. } => { +- fs_cfg.sock = path.clone(); +- } +- _ => { +- bail!("Chardev {:?} backend should be unix-socket type.", &name); +- } +- } +- } else { +- bail!("Chardev {:?} not found or is in use", &name); +- } +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "chardev".to_string(), +- "virtio-fs".to_string() +- ))); +- } +- fs_cfg.check()?; +- +- Ok(fs_cfg) +-} +diff --git a/machine_manager/src/config/gpu.rs b/machine_manager/src/config/gpu.rs +deleted file mode 100644 +index 56ab284..0000000 +--- a/machine_manager/src/config/gpu.rs ++++ /dev/null +@@ -1,176 +0,0 @@ +-// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{anyhow, Result}; +-use log::warn; +- +-use super::{error::ConfigError, M}; +-use crate::config::{check_arg_too_long, CmdParser, ConfigCheck}; +- +-/// The maximum number of outputs. +-pub const VIRTIO_GPU_MAX_OUTPUTS: usize = 16; +- +-pub const VIRTIO_GPU_MAX_HOSTMEM: u64 = 256 * M; +- +-/// The bar0 size of enable_bar0 features +-pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; +- +-#[derive(Clone, Debug)] +-pub struct GpuDevConfig { +- pub id: String, +- pub max_outputs: u32, +- pub edid: bool, +- pub xres: u32, +- pub yres: u32, +- pub max_hostmem: u64, +- pub enable_bar0: bool, +-} +- +-impl Default for GpuDevConfig { +- fn default() -> Self { +- GpuDevConfig { +- id: "".to_string(), +- max_outputs: 1, +- edid: true, +- xres: 1024, +- yres: 768, +- max_hostmem: VIRTIO_GPU_MAX_HOSTMEM, +- enable_bar0: false, +- } +- } +-} +- +-impl ConfigCheck for GpuDevConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "id")?; +- if self.max_outputs > VIRTIO_GPU_MAX_OUTPUTS as u32 || self.max_outputs == 0 { +- return Err(anyhow!(ConfigError::IllegalValue( +- "max_outputs".to_string(), +- 0, +- false, +- VIRTIO_GPU_MAX_OUTPUTS as u64, +- true +- ))); +- } +- +- if self.max_hostmem == 0 { +- return Err(anyhow!(ConfigError::IllegalValueUnilateral( +- "max_hostmem".to_string(), +- true, +- false, +- 0 +- ))); +- } +- +- if self.max_hostmem < VIRTIO_GPU_MAX_HOSTMEM { +- warn!( +- "max_hostmem should >= {}, allocating less than it may cause \ +- the GPU to fail to start or refresh.", +- VIRTIO_GPU_MAX_HOSTMEM +- ); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_gpu(gpu_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("virtio-gpu-pci"); +- cmd_parser +- .push("") +- .push("id") +- .push("max_outputs") +- .push("edid") +- .push("xres") +- .push("yres") +- .push("max_hostmem") +- .push("bus") +- .push("addr") +- .push("enable_bar0"); +- cmd_parser.parse(gpu_config)?; +- +- let mut gpu_cfg: GpuDevConfig = GpuDevConfig::default(); +- if let Some(id) = cmd_parser.get_value::("id")? { +- gpu_cfg.id = id; +- } +- if let Some(max_outputs) = cmd_parser.get_value::("max_outputs")? { +- gpu_cfg.max_outputs = max_outputs; +- } +- if let Some(edid) = cmd_parser.get_value::("edid")? { +- gpu_cfg.edid = edid; +- } +- if let Some(xres) = cmd_parser.get_value::("xres")? { +- gpu_cfg.xres = xres; +- } +- if let Some(yres) = cmd_parser.get_value::("yres")? { +- gpu_cfg.yres = yres; +- } +- if let Some(max_hostmem) = cmd_parser.get_value::("max_hostmem")? { +- gpu_cfg.max_hostmem = max_hostmem; +- } +- if let Some(enable_bar0) = cmd_parser.get_value::("enable_bar0")? { +- gpu_cfg.enable_bar0 = enable_bar0; +- } +- gpu_cfg.check()?; +- +- Ok(gpu_cfg) +-} +- +-#[cfg(test)] +-mod tests { +- use super::*; +- +- #[test] +- fn test_parse_pci_gpu_config_cmdline_parser() { +- let max_hostmem = VIRTIO_GPU_MAX_HOSTMEM + 1; +- let gpu_cfg_cmdline = format!( +- "{}{}", +- "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ +- max_outputs=1,edid=true,xres=1024,yres=768,max_hostmem=", +- max_hostmem.to_string() +- ); +- let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); +- assert!(gpu_cfg_.is_ok()); +- let gpu_cfg = gpu_cfg_.unwrap(); +- assert_eq!(gpu_cfg.id, "gpu_1"); +- assert_eq!(gpu_cfg.max_outputs, 1); +- assert_eq!(gpu_cfg.edid, true); +- assert_eq!(gpu_cfg.xres, 1024); +- assert_eq!(gpu_cfg.yres, 768); +- assert_eq!(gpu_cfg.max_hostmem, max_hostmem); +- +- // max_outputs is illegal +- let gpu_cfg_cmdline = format!( +- "{}{}", +- "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ +- max_outputs=17,edid=true,xres=1024,yres=768,max_hostmem=", +- max_hostmem.to_string() +- ); +- let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); +- assert!(gpu_cfg_.is_err()); +- +- let gpu_cfg_cmdline = format!( +- "{}{}", +- "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ +- max_outputs=0,edid=true,xres=1024,yres=768,max_hostmem=", +- max_hostmem.to_string() +- ); +- let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); +- assert!(gpu_cfg_.is_err()); +- +- // max_hostmem is illegal +- let gpu_cfg_cmdline = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ +- max_outputs=1,edid=true,xres=1024,yres=768,max_hostmem=0"; +- let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); +- assert!(gpu_cfg_.is_err()); +- } +-} +diff --git a/machine_manager/src/config/iothread.rs b/machine_manager/src/config/iothread.rs +index ac3a0a9..029d658 100644 +--- a/machine_manager/src/config/iothread.rs ++++ b/machine_manager/src/config/iothread.rs +@@ -11,37 +11,29 @@ + // See the Mulan PSL v2 for more details. + + use anyhow::{anyhow, Result}; ++use clap::Parser; + use serde::{Deserialize, Serialize}; + +-use super::error::ConfigError; +-use crate::config::{check_arg_too_long, CmdParser, ConfigCheck, VmConfig}; ++use super::{error::ConfigError, str_slip_to_clap, valid_id}; ++use crate::config::VmConfig; + + const MAX_IOTHREAD_NUM: usize = 8; + + /// Config structure for iothread. +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct IothreadConfig { ++ #[arg(long, value_parser = ["iothread"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, + } + +-impl ConfigCheck for IothreadConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "iothread id") +- } +-} +- + impl VmConfig { + /// Add new iothread device to `VmConfig`. + pub fn add_iothread(&mut self, iothread_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("iothread"); +- cmd_parser.push("").push("id"); +- cmd_parser.parse(iothread_config)?; +- +- let mut iothread = IothreadConfig::default(); +- if let Some(id) = cmd_parser.get_value::("id")? { +- iothread.id = id; +- } +- iothread.check()?; ++ let iothread = ++ IothreadConfig::try_parse_from(str_slip_to_clap(iothread_config, true, false))?; + + if self.iothreads.is_some() { + if self.iothreads.as_ref().unwrap().len() >= MAX_IOTHREAD_NUM { +diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs +index c1a6fb7..b50cc3a 100644 +--- a/machine_manager/src/config/machine_config.rs ++++ b/machine_manager/src/config/machine_config.rs +@@ -13,13 +13,15 @@ + use std::str::FromStr; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser}; + use serde::{Deserialize, Serialize}; + + use super::error::ConfigError; +-use crate::config::{ +- check_arg_too_long, check_path_too_long, CmdParser, ConfigCheck, ExBool, IntegerList, VmConfig, +- MAX_NODES, ++use super::{ ++ get_value_of_parameter, parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path, + }; ++use crate::config::{ConfigCheck, IntegerList, VmConfig, MAX_NODES}; ++use crate::machine::HypervisorType; + + const DEFAULT_CPUS: u8 = 1; + const DEFAULT_THREADS: u8 = 1; +@@ -41,11 +43,12 @@ pub const G: u64 = 1024 * 1024 * 1024; + pub enum MachineType { + None, + MicroVm, ++ #[cfg(not(target_arch = "riscv64"))] + StandardVm, + } + + impl FromStr for MachineType { +- type Err = (); ++ type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + match s.to_lowercase().as_str() { +@@ -55,7 +58,7 @@ impl FromStr for MachineType { + "q35" => Ok(MachineType::StandardVm), + #[cfg(target_arch = "aarch64")] + "virt" => Ok(MachineType::StandardVm), +- _ => Err(()), ++ _ => Err(anyhow!("Invalid machine type.")), + } + } + } +@@ -82,32 +85,37 @@ impl From for HostMemPolicy { + } + } + +-#[derive(Clone, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct MemZoneConfig { ++ #[arg(long, alias = "classtype", value_parser = ["memory-backend-ram", "memory-backend-file", "memory-backend-memfd"])] ++ pub mem_type: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, ++ #[arg(long, value_parser = parse_size)] + pub size: u64, +- pub host_numa_nodes: Option>, ++ // Note: ++ // `Clap` will incorrectly assume that we're trying to get multiple arguments since we got ++ // a `Vec` from parser function `get_host_nodes`. Generally, we should use `Box` or a `new struct type` ++ // to encapsulate this `Vec`. And fortunately, there's a trick (using full qualified path of Vec) ++ // to avoid the new type wrapper. See: github.com/clap-rs/clap/issues/4626. ++ #[arg(long, alias = "host-nodes", value_parser = get_host_nodes)] ++ pub host_numa_nodes: Option<::std::vec::Vec>, ++ #[arg(long, default_value = "default", value_parser=["default", "preferred", "bind", "interleave"])] + pub policy: String, ++ #[arg(long, value_parser = valid_path)] + pub mem_path: Option, ++ #[arg(long, default_value = "true", value_parser = parse_bool, action = ArgAction::Append)] + pub dump_guest_core: bool, ++ #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] + pub share: bool, ++ #[arg(long, alias = "mem-prealloc", default_value = "false", value_parser = parse_bool, action = ArgAction::Append)] + pub prealloc: bool, +- pub memfd: bool, + } + +-impl Default for MemZoneConfig { +- fn default() -> Self { +- MemZoneConfig { +- id: String::new(), +- size: 0, +- host_numa_nodes: None, +- policy: String::from("bind"), +- mem_path: None, +- dump_guest_core: true, +- share: false, +- prealloc: false, +- memfd: false, +- } ++impl MemZoneConfig { ++ pub fn memfd(&self) -> bool { ++ self.mem_type.eq("memory-backend-memfd") + } + } + +@@ -135,9 +143,14 @@ impl Default for MachineMemConfig { + } + } + +-#[derive(Clone, Debug, Serialize, Deserialize, Default)] ++#[derive(Parser, Clone, Debug, Serialize, Deserialize, Default)] ++#[command(no_binary_name(true))] + pub struct CpuConfig { ++ #[arg(long, alias = "classtype", value_parser = ["host"])] ++ pub family: String, ++ #[arg(long, default_value = "off")] + pub pmu: PmuConfig, ++ #[arg(long, default_value = "off")] + pub sve: SveConfig, + } + +@@ -148,6 +161,20 @@ pub enum PmuConfig { + Off, + } + ++impl FromStr for PmuConfig { ++ type Err = anyhow::Error; ++ ++ fn from_str(s: &str) -> std::result::Result { ++ match s { ++ "on" => Ok(PmuConfig::On), ++ "off" => Ok(PmuConfig::Off), ++ _ => Err(anyhow!( ++ "Invalid PMU option,must be one of \'on\" or \"off\"." ++ )), ++ } ++ } ++} ++ + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)] + pub enum SveConfig { + On, +@@ -155,6 +182,20 @@ pub enum SveConfig { + Off, + } + ++impl FromStr for SveConfig { ++ type Err = anyhow::Error; ++ ++ fn from_str(s: &str) -> std::result::Result { ++ match s { ++ "on" => Ok(SveConfig::On), ++ "off" => Ok(SveConfig::Off), ++ _ => Err(anyhow!( ++ "Invalid SVE option, must be one of \"on\" or \"off\"." ++ )), ++ } ++ } ++} ++ + #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Default)] + pub enum ShutdownAction { + #[default] +@@ -167,6 +208,7 @@ pub enum ShutdownAction { + #[derive(Clone, Debug, Serialize, Deserialize)] + pub struct MachineConfig { + pub mach_type: MachineType, ++ pub hypervisor: HypervisorType, + pub nr_cpus: u8, + pub nr_threads: u8, + pub nr_cores: u8, +@@ -185,6 +227,7 @@ impl Default for MachineConfig { + fn default() -> Self { + MachineConfig { + mach_type: MachineType::MicroVm, ++ hypervisor: HypervisorType::Kvm, + nr_cpus: DEFAULT_CPUS, + nr_threads: DEFAULT_THREADS, + nr_cores: DEFAULT_CORES, +@@ -211,222 +254,190 @@ impl ConfigCheck for MachineConfig { + } + } + +-impl VmConfig { +- /// Add argument `name` to `VmConfig`. +- /// +- /// # Arguments +- /// +- /// * `name` - The name `String` added to `VmConfig`. +- pub fn add_machine(&mut self, mach_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("machine"); +- cmd_parser +- .push("") +- .push("type") +- .push("accel") +- .push("usb") +- .push("dump-guest-core") +- .push("mem-share"); +- #[cfg(target_arch = "aarch64")] +- cmd_parser.push("gic-version"); +- cmd_parser.parse(mach_config)?; ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct AccelConfig { ++ #[arg(long, alias = "classtype")] ++ hypervisor: HypervisorType, ++} + +- #[cfg(target_arch = "aarch64")] +- if let Some(gic_version) = cmd_parser.get_value::("gic-version")? { +- if gic_version != 3 { +- bail!("Unsupported gic version, only gicv3 is supported"); ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct MemSizeConfig { ++ #[arg(long, alias = "classtype", value_parser = parse_size)] ++ size: u64, ++} ++ ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct MachineCmdConfig { ++ #[arg(long, aliases = ["classtype", "type"])] ++ mach_type: MachineType, ++ #[arg(long, default_value = "on", action = ArgAction::Append, value_parser = parse_bool)] ++ dump_guest_core: bool, ++ #[arg(long, default_value = "off", action = ArgAction::Append, value_parser = parse_bool)] ++ mem_share: bool, ++ #[arg(long, default_value = "kvm")] ++ accel: HypervisorType, ++ // The "usb" member is added for compatibility with libvirt and is currently not in use. ++ // It only supports configuration as "off". Currently, a `String` type is used to verify incoming values. ++ // When it will be used, it needs to be changed to a `bool` type. ++ #[arg(long, default_value = "off", value_parser = ["off"])] ++ usb: String, ++ #[cfg(target_arch = "aarch64")] ++ #[arg(long, default_value = "3", value_parser = clap::value_parser!(u8).range(3..=3))] ++ gic_version: u8, ++} ++ ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct SmpConfig { ++ #[arg(long, alias = "classtype", value_parser = clap::value_parser!(u64).range(MIN_NR_CPUS..=MAX_NR_CPUS))] ++ cpus: u64, ++ #[arg(long, default_value = "0")] ++ maxcpus: u64, ++ #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] ++ sockets: u64, ++ #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] ++ dies: u64, ++ #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] ++ clusters: u64, ++ #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] ++ cores: u64, ++ #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] ++ threads: u64, ++} ++ ++impl SmpConfig { ++ fn auto_adjust_topology(&mut self) -> Result<()> { ++ let mut max_cpus = self.maxcpus; ++ let mut sockets = self.sockets; ++ let mut cores = self.cores; ++ let mut threads = self.threads; ++ ++ if max_cpus == 0 { ++ if sockets * self.dies * self.clusters * cores * threads > 0 { ++ max_cpus = sockets * self.dies * self.clusters * cores * threads; ++ } else { ++ max_cpus = self.cpus; + } + } + +- if let Some(accel) = cmd_parser.get_value::("accel")? { +- // Libvirt checks the parameter types of 'kvm', 'kvm:tcg' and 'tcg'. +- if accel.ne("kvm:tcg") && accel.ne("tcg") && accel.ne("kvm") { +- bail!("Only \'kvm\', \'kvm:tcg\' and \'tcg\' are supported for \'accel\' of \'machine\'"); ++ if cores == 0 { ++ if sockets == 0 { ++ sockets = 1; + } +- } +- if let Some(usb) = cmd_parser.get_value::("usb")? { +- if usb.into() { +- bail!("Argument \'usb\' should be set to \'off\'"); ++ if threads == 0 { ++ threads = 1; ++ } ++ cores = max_cpus / (sockets * self.dies * self.clusters * threads); ++ } else if sockets == 0 { ++ if threads == 0 { ++ threads = 1; + } ++ sockets = max_cpus / (self.dies * self.clusters * cores * threads); + } +- if let Some(mach_type) = cmd_parser +- .get_value::("") +- .with_context(|| "Unrecognized machine type")? +- { +- self.machine_config.mach_type = mach_type; ++ ++ if threads == 0 { ++ threads = max_cpus / (sockets * self.dies * self.clusters * cores); + } +- if let Some(mach_type) = cmd_parser +- .get_value::("type") +- .with_context(|| "Unrecognized machine type")? +- { +- self.machine_config.mach_type = mach_type; ++ ++ let min_max_cpus = std::cmp::max(self.cpus, MIN_NR_CPUS); ++ ++ if !(min_max_cpus..=MAX_NR_CPUS).contains(&max_cpus) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "MAX CPU number".to_string(), ++ min_max_cpus, ++ true, ++ MAX_NR_CPUS, ++ true, ++ ))); + } +- if let Some(dump_guest) = cmd_parser.get_value::("dump-guest-core")? { +- self.machine_config.mem_config.dump_guest_core = dump_guest.into(); ++ ++ if sockets * self.dies * self.clusters * cores * threads != max_cpus { ++ bail!("sockets * dies * clusters * cores * threads must be equal to max_cpus"); + } +- if let Some(mem_share) = cmd_parser.get_value::("mem-share")? { +- self.machine_config.mem_config.mem_share = mem_share.into(); ++ ++ self.maxcpus = max_cpus; ++ self.sockets = sockets; ++ self.cores = cores; ++ self.threads = threads; ++ ++ Ok(()) ++ } ++} ++ ++impl VmConfig { ++ /// Add argument `name` to `VmConfig`. ++ /// ++ /// # Arguments ++ /// ++ /// * `name` - The name `String` added to `VmConfig`. ++ pub fn add_machine(&mut self, mach_config: &str) -> Result<()> { ++ let mut has_type_label = false; ++ if get_value_of_parameter("type", mach_config).is_ok() { ++ has_type_label = true; + } ++ let mach_cfg = MachineCmdConfig::try_parse_from(str_slip_to_clap( ++ mach_config, ++ !has_type_label, ++ false, ++ ))?; ++ // TODO: The current "accel" configuration in "-machine" command line and "-accel" command line are not foolproof. ++ // Later parsing will overwrite first parsing. We will optimize this in the future. ++ self.machine_config.hypervisor = mach_cfg.accel; ++ self.machine_config.mach_type = mach_cfg.mach_type; ++ self.machine_config.mem_config.dump_guest_core = mach_cfg.dump_guest_core; ++ self.machine_config.mem_config.mem_share = mach_cfg.mem_share; + + Ok(()) + } + + /// Add '-accel' accelerator config to `VmConfig`. + pub fn add_accel(&mut self, accel_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("accel"); +- cmd_parser.push(""); +- cmd_parser.parse(accel_config)?; +- +- if let Some(accel) = cmd_parser.get_value::("")? { +- if accel.ne("kvm") { +- bail!("Only \'kvm\' is supported for \'accel\'"); +- } +- } +- ++ let accel_cfg = AccelConfig::try_parse_from(str_slip_to_clap(accel_config, true, false))?; ++ self.machine_config.hypervisor = accel_cfg.hypervisor; + Ok(()) + } + + /// Add '-m' memory config to `VmConfig`. + pub fn add_memory(&mut self, mem_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("m"); +- cmd_parser.push("").push("size"); +- +- cmd_parser.parse(mem_config)?; +- +- let mem = if let Some(mem_size) = cmd_parser.get_value::("")? { +- memory_unit_conversion(&mem_size, M)? +- } else if let Some(mem_size) = cmd_parser.get_value::("size")? { +- memory_unit_conversion(&mem_size, M)? +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "size".to_string(), +- "memory".to_string() +- ))); +- }; +- +- self.machine_config.mem_config.mem_size = mem; ++ // Is there a "size=" prefix tag in the command line. ++ let mut has_size_label = false; ++ if get_value_of_parameter("size", mem_config).is_ok() { ++ has_size_label = true; ++ } ++ let mem_cfg = ++ MemSizeConfig::try_parse_from(str_slip_to_clap(mem_config, !has_size_label, false))?; ++ self.machine_config.mem_config.mem_size = mem_cfg.size; + + Ok(()) + } + + /// Add '-smp' cpu config to `VmConfig`. + pub fn add_cpu(&mut self, cpu_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("smp"); +- cmd_parser +- .push("") +- .push("maxcpus") +- .push("sockets") +- .push("dies") +- .push("clusters") +- .push("cores") +- .push("threads") +- .push("cpus"); +- +- cmd_parser.parse(cpu_config)?; +- +- let cpu = if let Some(cpu) = cmd_parser.get_value::("")? { +- cpu +- } else if let Some(cpu) = cmd_parser.get_value::("cpus")? { +- if cpu == 0 { +- return Err(anyhow!(ConfigError::IllegalValue( +- "cpu".to_string(), +- 1, +- true, +- MAX_NR_CPUS, +- true +- ))); +- } +- cpu +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "cpus".to_string(), +- "smp".to_string() +- ))); +- }; +- +- let sockets = smp_read_and_check(&cmd_parser, "sockets", 0)?; +- +- let dies = smp_read_and_check(&cmd_parser, "dies", 1)?; +- +- let clusters = smp_read_and_check(&cmd_parser, "clusters", 1)?; +- +- let cores = smp_read_and_check(&cmd_parser, "cores", 0)?; +- +- let threads = smp_read_and_check(&cmd_parser, "threads", 0)?; +- +- let max_cpus = cmd_parser.get_value::("maxcpus")?.unwrap_or_default(); +- +- let (max_cpus, sockets, cores, threads) = +- adjust_topology(cpu, max_cpus, sockets, dies, clusters, cores, threads); +- +- // limit cpu count +- if !(MIN_NR_CPUS..=MAX_NR_CPUS).contains(&cpu) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "CPU number".to_string(), +- MIN_NR_CPUS, +- true, +- MAX_NR_CPUS, +- true, +- ))); ++ let mut has_cpus_label = false; ++ if get_value_of_parameter("cpus", cpu_config).is_ok() { ++ has_cpus_label = true; + } +- +- if !(MIN_NR_CPUS..=MAX_NR_CPUS).contains(&max_cpus) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "MAX CPU number".to_string(), +- MIN_NR_CPUS, +- true, +- MAX_NR_CPUS, +- true, +- ))); +- } +- +- if max_cpus < cpu { +- return Err(anyhow!(ConfigError::IllegalValue( +- "maxcpus".to_string(), +- cpu, +- true, +- MAX_NR_CPUS, +- true, +- ))); +- } +- +- if sockets * dies * clusters * cores * threads != max_cpus { +- bail!("sockets * dies * clusters * cores * threads must be equal to max_cpus"); +- } +- +- self.machine_config.nr_cpus = cpu as u8; +- self.machine_config.nr_threads = threads as u8; +- self.machine_config.nr_cores = cores as u8; +- self.machine_config.nr_dies = dies as u8; +- self.machine_config.nr_clusters = clusters as u8; +- self.machine_config.nr_sockets = sockets as u8; +- self.machine_config.max_cpus = max_cpus as u8; ++ let mut smp_cfg = ++ SmpConfig::try_parse_from(str_slip_to_clap(cpu_config, !has_cpus_label, false))?; ++ smp_cfg.auto_adjust_topology()?; ++ ++ self.machine_config.nr_cpus = smp_cfg.cpus as u8; ++ self.machine_config.nr_threads = smp_cfg.threads as u8; ++ self.machine_config.nr_cores = smp_cfg.cores as u8; ++ self.machine_config.nr_dies = smp_cfg.dies as u8; ++ self.machine_config.nr_clusters = smp_cfg.clusters as u8; ++ self.machine_config.nr_sockets = smp_cfg.sockets as u8; ++ self.machine_config.max_cpus = smp_cfg.maxcpus as u8; + + Ok(()) + } + + pub fn add_cpu_feature(&mut self, features: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("cpu"); +- cmd_parser.push(""); +- cmd_parser.push("pmu"); +- cmd_parser.push("sve"); +- cmd_parser.parse(features)?; +- +- // Check PMU when actually enabling PMU. +- if let Some(k) = cmd_parser.get_value::("pmu")? { +- self.machine_config.cpu_config.pmu = match k.as_ref() { +- "on" => PmuConfig::On, +- "off" => PmuConfig::Off, +- _ => bail!("Invalid PMU option,must be one of \'on\" or \"off\"."), +- } +- } +- +- if let Some(k) = cmd_parser.get_value::("sve")? { +- self.machine_config.cpu_config.sve = match k.as_ref() { +- "on" => SveConfig::On, +- "off" => SveConfig::Off, +- _ => bail!("Invalid SVE option, must be one of \"on\" or \"off\"."), +- } +- } ++ let cpu_config = CpuConfig::try_parse_from(str_slip_to_clap(features, true, false))?; ++ self.machine_config.cpu_config = cpu_config; + + Ok(()) + } +@@ -452,149 +463,26 @@ impl VmConfig { + } + + impl VmConfig { +- fn get_mem_zone_id(&self, cmd_parser: &CmdParser) -> Result { +- if let Some(id) = cmd_parser.get_value::("id")? { +- check_arg_too_long(&id, "id")?; +- Ok(id) +- } else { +- Err(anyhow!(ConfigError::FieldIsMissing( +- "id".to_string(), +- "memory-backend-ram".to_string() +- ))) +- } +- } +- +- fn get_mem_path(&self, cmd_parser: &CmdParser) -> Result> { +- if let Some(path) = cmd_parser.get_value::("mem-path")? { +- check_path_too_long(&path, "mem-path")?; +- return Ok(Some(path)); +- } +- Ok(None) +- } +- +- fn get_mem_zone_size(&self, cmd_parser: &CmdParser) -> Result { +- if let Some(mem) = cmd_parser.get_value::("size")? { +- let size = memory_unit_conversion(&mem, M)?; +- Ok(size) +- } else { +- Err(anyhow!(ConfigError::FieldIsMissing( +- "size".to_string(), +- "memory-backend-ram".to_string() +- ))) +- } +- } +- +- fn get_mem_zone_host_nodes(&self, cmd_parser: &CmdParser) -> Result>> { +- if let Some(mut host_nodes) = cmd_parser +- .get_value::("host-nodes") +- .with_context(|| { +- ConfigError::ConvertValueFailed(String::from("u32"), "host-nodes".to_string()) +- })? +- .map(|v| v.0.iter().map(|e| *e as u32).collect::>()) +- { +- host_nodes.sort_unstable(); +- if host_nodes[host_nodes.len() - 1] >= MAX_NODES { +- return Err(anyhow!(ConfigError::IllegalValue( +- "host_nodes".to_string(), +- 0, +- true, +- MAX_NODES as u64, +- false, +- ))); +- } +- Ok(Some(host_nodes)) +- } else { +- Ok(None) +- } +- } +- +- fn get_mem_zone_policy(&self, cmd_parser: &CmdParser) -> Result { +- let policy = cmd_parser +- .get_value::("policy")? +- .unwrap_or_else(|| "default".to_string()); +- if HostMemPolicy::from(policy.clone()) == HostMemPolicy::NotSupported { +- return Err(anyhow!(ConfigError::InvalidParam( +- "policy".to_string(), +- policy +- ))); +- } +- Ok(policy) +- } +- +- fn get_mem_share(&self, cmd_parser: &CmdParser) -> Result { +- let share = cmd_parser +- .get_value::("share")? +- .unwrap_or_else(|| "off".to_string()); +- +- if share.eq("on") || share.eq("off") { +- Ok(share.eq("on")) +- } else { +- Err(anyhow!(ConfigError::InvalidParam( +- "share".to_string(), +- share +- ))) +- } +- } +- +- fn get_mem_dump(&self, cmd_parser: &CmdParser) -> Result { +- if let Some(dump_guest) = cmd_parser.get_value::("dump-guest-core")? { +- return Ok(dump_guest.into()); +- } +- Ok(true) +- } +- +- fn get_mem_prealloc(&self, cmd_parser: &CmdParser) -> Result { +- if let Some(mem_prealloc) = cmd_parser.get_value::("mem-prealloc")? { +- return Ok(mem_prealloc.into()); +- } +- Ok(false) +- } +- + /// Convert memory zone cmdline to VM config + /// + /// # Arguments + /// + /// * `mem_zone` - The memory zone cmdline string. +- /// * `mem_type` - The memory zone type +- pub fn add_mem_zone(&mut self, mem_zone: &str, mem_type: String) -> Result { +- let mut cmd_parser = CmdParser::new("mem_zone"); +- cmd_parser +- .push("") +- .push("id") +- .push("size") +- .push("host-nodes") +- .push("policy") +- .push("share") +- .push("mem-path") +- .push("dump-guest-core") +- .push("mem-prealloc"); +- cmd_parser.parse(mem_zone)?; +- +- let zone_config = MemZoneConfig { +- id: self.get_mem_zone_id(&cmd_parser)?, +- size: self.get_mem_zone_size(&cmd_parser)?, +- host_numa_nodes: self.get_mem_zone_host_nodes(&cmd_parser)?, +- policy: self.get_mem_zone_policy(&cmd_parser)?, +- dump_guest_core: self.get_mem_dump(&cmd_parser)?, +- share: self.get_mem_share(&cmd_parser)?, +- mem_path: self.get_mem_path(&cmd_parser)?, +- prealloc: self.get_mem_prealloc(&cmd_parser)?, +- memfd: mem_type.eq("memory-backend-memfd"), +- }; ++ pub fn add_mem_zone(&mut self, mem_zone: &str) -> Result { ++ let zone_config = MemZoneConfig::try_parse_from(str_slip_to_clap(mem_zone, true, false))?; + +- if (zone_config.mem_path.is_none() && mem_type.eq("memory-backend-file")) +- || (zone_config.mem_path.is_some() && mem_type.ne("memory-backend-file")) ++ if (zone_config.mem_path.is_none() && zone_config.mem_type.eq("memory-backend-file")) ++ || (zone_config.mem_path.is_some() && zone_config.mem_type.ne("memory-backend-file")) + { +- bail!("Object type: {} config path err", mem_type); ++ bail!("Object type: {} config path err", zone_config.mem_type); + } + +- if self.object.mem_object.get(&zone_config.id).is_none() { +- self.object +- .mem_object +- .insert(zone_config.id.clone(), zone_config.clone()); +- } else { ++ if self.object.mem_object.get(&zone_config.id).is_some() { + bail!("Object: {} has been added", zone_config.id); + } ++ self.object ++ .mem_object ++ .insert(zone_config.id.clone(), zone_config.clone()); + + if zone_config.host_numa_nodes.is_none() { + return Ok(zone_config); +@@ -615,62 +503,6 @@ impl VmConfig { + } + } + +-fn smp_read_and_check(cmd_parser: &CmdParser, name: &str, default_val: u64) -> Result { +- if let Some(values) = cmd_parser.get_value::(name)? { +- if values == 0 { +- return Err(anyhow!(ConfigError::IllegalValue( +- name.to_string(), +- 1, +- true, +- u8::MAX as u64, +- false +- ))); +- } +- Ok(values) +- } else { +- Ok(default_val) +- } +-} +- +-fn adjust_topology( +- cpu: u64, +- mut max_cpus: u64, +- mut sockets: u64, +- dies: u64, +- clusters: u64, +- mut cores: u64, +- mut threads: u64, +-) -> (u64, u64, u64, u64) { +- if max_cpus == 0 { +- if sockets * dies * clusters * cores * threads > 0 { +- max_cpus = sockets * dies * clusters * cores * threads; +- } else { +- max_cpus = cpu; +- } +- } +- +- if cores == 0 { +- if sockets == 0 { +- sockets = 1; +- } +- if threads == 0 { +- threads = 1; +- } +- cores = max_cpus / (sockets * dies * clusters * threads); +- } else if sockets == 0 { +- if threads == 0 { +- threads = 1; +- } +- sockets = max_cpus / (dies * clusters * cores * threads); +- } +- +- if threads == 0 { +- threads = max_cpus / (sockets * dies * clusters * cores); +- } +- +- (max_cpus, sockets, cores, threads) +-} +- + /// Convert memory units from GiB, Mib to Byte. + /// + /// # Arguments +@@ -731,6 +563,34 @@ fn get_inner(outer: Option) -> Result { + outer.with_context(|| ConfigError::IntegerOverflow("-m".to_string())) + } + ++fn get_host_nodes(nodes: &str) -> Result> { ++ let mut host_nodes = IntegerList::from_str(nodes) ++ .with_context(|| { ++ ConfigError::ConvertValueFailed(String::from("u32"), "host-nodes".to_string()) ++ })? ++ .0 ++ .iter() ++ .map(|e| *e as u32) ++ .collect::>(); ++ ++ if host_nodes.is_empty() { ++ bail!("Got empty host nodes list!"); ++ } ++ ++ host_nodes.sort_unstable(); ++ if host_nodes[host_nodes.len() - 1] >= MAX_NODES { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "host_nodes".to_string(), ++ 0, ++ true, ++ MAX_NODES as u64, ++ false, ++ ))); ++ } ++ ++ Ok(host_nodes) ++} ++ + #[cfg(test)] + mod tests { + use super::*; +@@ -747,6 +607,7 @@ mod tests { + }; + let mut machine_config = MachineConfig { + mach_type: MachineType::MicroVm, ++ hypervisor: HypervisorType::Kvm, + nr_cpus: 1, + nr_cores: 1, + nr_threads: 1, +@@ -970,11 +831,12 @@ mod tests { + assert_eq!(machine_cfg.mem_config.mem_share, true); + + let mut vm_config = VmConfig::default(); +- let memory_cfg_str = "type=none,dump-guest-core=off,mem-share=off,accel=kvm,usb=off"; ++ let memory_cfg_str = "none,dump-guest-core=off,mem-share=off,accel=kvm,usb=off"; + let machine_cfg_ret = vm_config.add_machine(memory_cfg_str); + assert!(machine_cfg_ret.is_ok()); + let machine_cfg = vm_config.machine_config; + assert_eq!(machine_cfg.mach_type, MachineType::None); ++ assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); + assert_eq!(machine_cfg.mem_config.dump_guest_core, false); + assert_eq!(machine_cfg.mem_config.mem_share, false); + +@@ -1079,10 +941,7 @@ mod tests { + fn test_add_mem_zone() { + let mut vm_config = VmConfig::default(); + let zone_config_1 = vm_config +- .add_mem_zone( +- "-object memory-backend-ram,size=2G,id=mem1,host-nodes=1,policy=bind", +- String::from("memory-backend-ram"), +- ) ++ .add_mem_zone("memory-backend-ram,size=2G,id=mem1,host-nodes=1,policy=bind") + .unwrap(); + assert_eq!(zone_config_1.id, "mem1"); + assert_eq!(zone_config_1.size, 2147483648); +@@ -1090,38 +949,26 @@ mod tests { + assert_eq!(zone_config_1.policy, "bind"); + + let zone_config_2 = vm_config +- .add_mem_zone( +- "-object memory-backend-ram,size=2G,id=mem2,host-nodes=1-2,policy=default", +- String::from("memory-backend-ram"), +- ) ++ .add_mem_zone("memory-backend-ram,size=2G,id=mem2,host-nodes=1-2,policy=default") + .unwrap(); + assert_eq!(zone_config_2.host_numa_nodes, Some(vec![1, 2])); + + let zone_config_3 = vm_config +- .add_mem_zone( +- "-object memory-backend-ram,size=2M,id=mem3,share=on", +- String::from("memory-backend-ram"), +- ) ++ .add_mem_zone("memory-backend-ram,size=2M,id=mem3,share=on") + .unwrap(); + assert_eq!(zone_config_3.size, 2 * 1024 * 1024); + assert_eq!(zone_config_3.share, true); + + let zone_config_4 = vm_config +- .add_mem_zone( +- "-object memory-backend-ram,size=2M,id=mem4", +- String::from("memory-backend-ram"), +- ) ++ .add_mem_zone("memory-backend-ram,size=2M,id=mem4") + .unwrap(); + assert_eq!(zone_config_4.share, false); +- assert_eq!(zone_config_4.memfd, false); ++ assert_eq!(zone_config_4.memfd(), false); + + let zone_config_5 = vm_config +- .add_mem_zone( +- "-object memory-backend-memfd,size=2M,id=mem5", +- String::from("memory-backend-memfd"), +- ) ++ .add_mem_zone("memory-backend-memfd,size=2M,id=mem5") + .unwrap(); +- assert_eq!(zone_config_5.memfd, true); ++ assert_eq!(zone_config_5.memfd(), true); + } + + #[test] +@@ -1145,15 +992,44 @@ mod tests { + assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); + vm_config.add_cpu_feature("host,pmu=off").unwrap(); + assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); +- vm_config.add_cpu_feature("pmu=off").unwrap(); +- assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); + vm_config.add_cpu_feature("host,pmu=on").unwrap(); + assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::On); +- vm_config.add_cpu_feature("pmu=on").unwrap(); +- assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::On); +- vm_config.add_cpu_feature("sve=on").unwrap(); ++ vm_config.add_cpu_feature("host,sve=on").unwrap(); + assert!(vm_config.machine_config.cpu_config.sve == SveConfig::On); +- vm_config.add_cpu_feature("sve=off").unwrap(); ++ vm_config.add_cpu_feature("host,sve=off").unwrap(); + assert!(vm_config.machine_config.cpu_config.sve == SveConfig::Off); ++ ++ // Illegal cpu command lines: should set cpu family. ++ let result = vm_config.add_cpu_feature("pmu=off"); ++ assert!(result.is_err()); ++ let result = vm_config.add_cpu_feature("sve=on"); ++ assert!(result.is_err()); ++ ++ // Illegal parameters. ++ let result = vm_config.add_cpu_feature("host,sve1=on"); ++ assert!(result.is_err()); ++ ++ // Illegal values. ++ let result = vm_config.add_cpu_feature("host,sve=false"); ++ assert!(result.is_err()); ++ } ++ ++ #[test] ++ fn test_add_accel() { ++ let mut vm_config = VmConfig::default(); ++ let accel_cfg = "kvm"; ++ assert!(vm_config.add_accel(accel_cfg).is_ok()); ++ let machine_cfg = vm_config.machine_config; ++ assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); ++ ++ let mut vm_config = VmConfig::default(); ++ let accel_cfg = "kvm:tcg"; ++ assert!(vm_config.add_accel(accel_cfg).is_ok()); ++ let machine_cfg = vm_config.machine_config; ++ assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); ++ ++ let mut vm_config = VmConfig::default(); ++ let accel_cfg = "kvm1"; ++ assert!(vm_config.add_accel(accel_cfg).is_err()); + } + } +diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs +index 8b2944d..ca1281a 100644 +--- a/machine_manager/src/config/mod.rs ++++ b/machine_manager/src/config/mod.rs +@@ -20,75 +20,53 @@ pub mod vnc; + + mod boot_source; + mod chardev; +-#[cfg(feature = "demo_device")] +-mod demo_dev; + mod devices; + mod drive; +-mod fs; +-#[cfg(feature = "virtio_gpu")] +-mod gpu; + mod incoming; + mod iothread; + mod machine_config; + mod network; + mod numa; + mod pci; +-#[cfg(feature = "pvpanic")] +-mod pvpanic_pci; +-#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] +-mod ramfb; + mod rng; + #[cfg(feature = "vnc_auth")] + mod sasl_auth; +-mod scsi; + mod smbios; + #[cfg(feature = "vnc_auth")] + mod tls_creds; +-mod usb; +-mod vfio; + + pub use boot_source::*; + #[cfg(feature = "usb_camera")] + pub use camera::*; + pub use chardev::*; +-#[cfg(feature = "demo_device")] +-pub use demo_dev::*; + pub use devices::*; + #[cfg(any(feature = "gtk", feature = "ohui_srv"))] + pub use display::*; + pub use drive::*; + pub use error::ConfigError; +-pub use fs::*; +-#[cfg(feature = "virtio_gpu")] +-pub use gpu::*; + pub use incoming::*; + pub use iothread::*; + pub use machine_config::*; + pub use network::*; + pub use numa::*; + pub use pci::*; +-#[cfg(feature = "pvpanic")] +-pub use pvpanic_pci::*; +-#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] +-pub use ramfb::*; + pub use rng::*; + #[cfg(feature = "vnc_auth")] + pub use sasl_auth::*; +-pub use scsi::*; + pub use smbios::*; + #[cfg(feature = "vnc_auth")] + pub use tls_creds::*; +-pub use usb::*; +-pub use vfio::*; + #[cfg(feature = "vnc")] + pub use vnc::*; + + use std::collections::HashMap; +-use std::fs::File; ++use std::fs::{canonicalize, File}; + use std::io::Read; ++use std::path::Path; + use std::str::FromStr; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use log::error; + use serde::{Deserialize, Serialize}; + +@@ -110,10 +88,22 @@ pub const MAX_SOCK_PATH_LENGTH: usize = 108; + pub const MAX_VIRTIO_QUEUE: usize = 32; + pub const FAST_UNPLUG_ON: &str = "1"; + pub const FAST_UNPLUG_OFF: &str = "0"; +-pub const MAX_TAG_LENGTH: usize = 36; + pub const MAX_NODES: u32 = 128; + /// Default virtqueue size for virtio devices excepts virtio-fs. + pub const DEFAULT_VIRTQUEUE_SIZE: u16 = 256; ++// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi/virtio-blk should be larger than 2. ++pub const MIN_QUEUE_SIZE_BLOCK_DEVICE: u64 = 2; ++// Max size of each virtqueue for virtio-scsi/virtio-blk. ++pub const MAX_QUEUE_SIZE_BLOCK_DEVICE: u64 = 1024; ++/// The bar0 size of enable_bar0 features ++pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; ++ ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct GlobalConfig { ++ #[arg(long, alias = "pcie-root-port.fast-unplug", value_parser = ["0", "1"])] ++ fast_unplug: Option, ++} + + #[derive(Clone, Default, Debug, Serialize, Deserialize)] + pub struct ObjectConfig { +@@ -139,7 +129,7 @@ pub struct VmConfig { + pub serial: Option, + pub iothreads: Option>, + pub object: ObjectConfig, +- pub pflashs: Option>, ++ pub pflashs: Option>, + pub dev_name: HashMap, + pub global_config: HashMap, + pub numa_nodes: Vec<(String, String)>, +@@ -151,7 +141,7 @@ pub struct VmConfig { + #[cfg(feature = "usb_camera")] + pub camera_backend: HashMap, + #[cfg(feature = "windows_emu_pid")] +- pub windows_emu_pid: Option, ++ pub emulator_pid: Option, + pub smbios: SmbiosConfig, + } + +@@ -179,12 +169,12 @@ impl VmConfig { + + let mut stdio_count = 0; + if let Some(serial) = self.serial.as_ref() { +- if serial.chardev.backend == ChardevType::Stdio { ++ if let ChardevType::Stdio { .. } = serial.chardev.classtype { + stdio_count += 1; + } + } + for (_, char_dev) in self.chardev.clone() { +- if char_dev.backend == ChardevType::Stdio { ++ if let ChardevType::Stdio { .. } = char_dev.classtype { + stdio_count += 1; + } + } +@@ -214,29 +204,24 @@ impl VmConfig { + /// + /// * `object_args` - The args of object. + pub fn add_object(&mut self, object_args: &str) -> Result<()> { +- let mut cmd_params = CmdParser::new("object"); +- cmd_params.push(""); +- +- cmd_params.get_parameters(object_args)?; +- let device_type = cmd_params +- .get_value::("")? +- .with_context(|| "Object type not specified")?; +- match device_type.as_str() { ++ let object_type = ++ get_class_type(object_args).with_context(|| "Object type not specified")?; ++ match object_type.as_str() { + "iothread" => { + self.add_iothread(object_args) + .with_context(|| "Failed to add iothread")?; + } + "rng-random" => { +- let rng_cfg = parse_rng_obj(object_args)?; ++ let rng_cfg = ++ RngObjConfig::try_parse_from(str_slip_to_clap(object_args, true, false))?; + let id = rng_cfg.id.clone(); +- if self.object.rng_object.get(&id).is_none() { +- self.object.rng_object.insert(id, rng_cfg); +- } else { ++ if self.object.rng_object.get(&id).is_some() { + bail!("Object: {} has been added", id); + } ++ self.object.rng_object.insert(id, rng_cfg); + } + "memory-backend-ram" | "memory-backend-file" | "memory-backend-memfd" => { +- self.add_mem_zone(object_args, device_type)?; ++ self.add_mem_zone(object_args)?; + } + #[cfg(feature = "vnc_auth")] + "tls-creds-x509" => { +@@ -247,7 +232,7 @@ impl VmConfig { + self.add_saslauth(object_args)?; + } + _ => { +- bail!("Unknow object type: {:?}", &device_type); ++ bail!("Unknow object type: {:?}", &object_type); + } + } + +@@ -260,24 +245,18 @@ impl VmConfig { + /// + /// * `global_config` - The args of global config. + pub fn add_global_config(&mut self, global_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("global"); +- cmd_parser.push("pcie-root-port.fast-unplug"); +- cmd_parser.parse(global_config)?; ++ let global_config = ++ GlobalConfig::try_parse_from(str_slip_to_clap(global_config, false, false))?; + +- if let Some(fast_unplug_value) = +- cmd_parser.get_value::("pcie-root-port.fast-unplug")? +- { +- if fast_unplug_value != FAST_UNPLUG_ON && fast_unplug_value != FAST_UNPLUG_OFF { +- bail!("The value of fast-unplug is invalid: {}", fast_unplug_value); +- } ++ if let Some(fast_unplug_value) = global_config.fast_unplug { + let fast_unplug_key = String::from("pcie-root-port.fast-unplug"); +- if self.global_config.get(&fast_unplug_key).is_none() { +- self.global_config +- .insert(fast_unplug_key, fast_unplug_value); +- } else { ++ if self.global_config.get(&fast_unplug_key).is_some() { + bail!("Global config {} has been added", fast_unplug_key); + } ++ self.global_config ++ .insert(fast_unplug_key, fast_unplug_value); + } ++ + Ok(()) + } + +@@ -289,9 +268,9 @@ impl VmConfig { + #[cfg(feature = "windows_emu_pid")] + pub fn add_windows_emu_pid(&mut self, windows_emu_pid: &str) -> Result<()> { + if windows_emu_pid.is_empty() { +- bail!("The arg of windows_emu_pid is empty!"); ++ bail!("The arg of emulator_pid is empty!"); + } +- self.windows_emu_pid = Some(windows_emu_pid.to_string()); ++ self.emulator_pid = Some(windows_emu_pid.to_string()); + Ok(()) + } + +@@ -395,7 +374,7 @@ impl VmConfig { + &mut drive_files, + &drive.id, + &drive.path_on_host, +- drive.read_only, ++ drive.readonly, + drive.direct, + )?; + } +@@ -405,7 +384,7 @@ impl VmConfig { + &mut drive_files, + "", + &pflash.path_on_host, +- pflash.read_only, ++ pflash.readonly, + false, + )?; + } +@@ -436,163 +415,6 @@ pub trait ConfigCheck: AsAny + Send + Sync + std::fmt::Debug { + fn check(&self) -> Result<()>; + } + +-/// Struct `CmdParser` used to parse and check cmdline parameters to vm config. +-pub struct CmdParser { +- name: String, +- params: HashMap>, +-} +- +-impl CmdParser { +- /// Allocates an empty `CmdParser`. +- pub fn new(name: &str) -> Self { +- CmdParser { +- name: name.to_string(), +- params: HashMap::>::new(), +- } +- } +- +- /// Push a new param field into `params`. +- /// +- /// # Arguments +- /// +- /// * `param_field`: The cmdline parameter field name. +- pub fn push(&mut self, param_field: &str) -> &mut Self { +- self.params.insert(param_field.to_string(), None); +- +- self +- } +- +- /// Parse cmdline parameters string into `params`. +- /// +- /// # Arguments +- /// +- /// * `cmd_param`: The whole cmdline parameter string. +- pub fn parse(&mut self, cmd_param: &str) -> Result<()> { +- if cmd_param.starts_with(',') || cmd_param.ends_with(',') { +- return Err(anyhow!(ConfigError::InvalidParam( +- cmd_param.to_string(), +- self.name.clone() +- ))); +- } +- let param_items = cmd_param.split(',').collect::>(); +- for (i, param_item) in param_items.iter().enumerate() { +- if param_item.starts_with('=') || param_item.ends_with('=') { +- return Err(anyhow!(ConfigError::InvalidParam( +- param_item.to_string(), +- self.name.clone() +- ))); +- } +- let param = param_item.splitn(2, '=').collect::>(); +- let (param_key, param_value) = match param.len() { +- 1 => { +- if i == 0 { +- ("", param[0]) +- } else { +- (param[0], "") +- } +- } +- 2 => (param[0], param[1]), +- _ => { +- return Err(anyhow!(ConfigError::InvalidParam( +- param_item.to_string(), +- self.name.clone() +- ))); +- } +- }; +- +- if self.params.contains_key(param_key) { +- let field_value = self.params.get_mut(param_key).unwrap(); +- if field_value.is_none() { +- *field_value = Some(String::from(param_value)); +- } else { +- return Err(anyhow!(ConfigError::FieldRepeat( +- self.name.clone(), +- param_key.to_string() +- ))); +- } +- } else { +- return Err(anyhow!(ConfigError::InvalidParam( +- param[0].to_string(), +- self.name.clone() +- ))); +- } +- } +- +- Ok(()) +- } +- +- /// Parse all cmdline parameters string into `params`. +- /// +- /// # Arguments +- /// +- /// * `cmd_param`: The whole cmdline parameter string. +- fn get_parameters(&mut self, cmd_param: &str) -> Result<()> { +- if cmd_param.starts_with(',') || cmd_param.ends_with(',') { +- return Err(anyhow!(ConfigError::InvalidParam( +- cmd_param.to_string(), +- self.name.clone() +- ))); +- } +- let param_items = cmd_param.split(',').collect::>(); +- for param_item in param_items { +- let param = param_item.splitn(2, '=').collect::>(); +- let (param_key, param_value) = match param.len() { +- 1 => ("", param[0]), +- 2 => (param[0], param[1]), +- _ => { +- return Err(anyhow!(ConfigError::InvalidParam( +- param_item.to_string(), +- self.name.clone() +- ))); +- } +- }; +- +- if self.params.contains_key(param_key) { +- let field_value = self.params.get_mut(param_key).unwrap(); +- if field_value.is_none() { +- *field_value = Some(String::from(param_value)); +- } else { +- return Err(anyhow!(ConfigError::FieldRepeat( +- self.name.clone(), +- param_key.to_string() +- ))); +- } +- } +- } +- +- Ok(()) +- } +- +- /// Get cmdline parameters value from param field name. +- /// +- /// # Arguments +- /// +- /// * `param_field`: The cmdline parameter field name. +- pub fn get_value(&self, param_field: &str) -> Result> { +- match self.params.get(param_field) { +- Some(value) => { +- let field_msg = if param_field.is_empty() { +- &self.name +- } else { +- param_field +- }; +- +- if let Some(raw_value) = value { +- Ok(Some(raw_value.parse().map_err(|_| { +- anyhow!(ConfigError::ConvertValueFailed( +- field_msg.to_string(), +- raw_value.clone() +- )) +- })?)) +- } else { +- Ok(None) +- } +- } +- None => Ok(None), +- } +- } +-} +- + /// This struct is a wrapper for `bool`. + /// More switch string can be transferred to this structure. + pub struct ExBool { +@@ -619,8 +441,8 @@ impl From for bool { + + pub fn parse_bool(s: &str) -> Result { + match s { +- "on" => Ok(true), +- "off" => Ok(false), ++ "true" | "on" | "yes" | "unmap" => Ok(true), ++ "false" | "off" | "no" | "ignore" => Ok(false), + _ => Err(anyhow!("Unknow bool value {s}")), + } + } +@@ -644,15 +466,16 @@ fn enable_trace_state(path: &str) -> Result<()> { + Ok(()) + } + +-pub fn parse_trace_options(opt: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("trace"); +- cmd_parser.push("file"); +- cmd_parser.get_parameters(opt)?; ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++struct TraceConfig { ++ #[arg(long)] ++ file: String, ++} + +- let path = cmd_parser +- .get_value::("file")? +- .with_context(|| "trace: trace file must be set.")?; +- enable_trace_state(&path)?; ++pub fn add_trace(opt: &str) -> Result<()> { ++ let trace_cfg = TraceConfig::try_parse_from(str_slip_to_clap(opt, false, false))?; ++ enable_trace_state(&trace_cfg.file)?; + Ok(()) + } + +@@ -673,7 +496,7 @@ impl FromStr for UnsignedInteger { + pub struct IntegerList(pub Vec); + + impl FromStr for IntegerList { +- type Err = (); ++ type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + let mut integer_list = Vec::new(); +@@ -685,19 +508,22 @@ impl FromStr for IntegerList { + for list in lists.iter() { + let items: Vec<&str> = list.split('-').collect(); + if items.len() > 2 { +- return Err(()); ++ return Err(anyhow!( ++ "{} parameters connected by -, should be no more than 2.", ++ items.len() ++ )); + } + + let start = items[0] + .parse::() +- .map_err(|e| error!("Invalid value {}, error is {:?}", items[0], e))?; ++ .map_err(|e| anyhow!("Invalid value {}, error is {:?}", items[0], e))?; + integer_list.push(start); + if items.len() == 2 { + let end = items[1] + .parse::() +- .map_err(|e| error!("Invalid value {}, error is {:?}", items[1], e))?; ++ .map_err(|e| anyhow!("Invalid value {}, error is {:?}", items[1], e))?; + if start >= end { +- return Err(()); ++ return Err(anyhow!("start {} is bigger than end {}.", start, end)); + } + + for i in start..end { +@@ -730,128 +556,200 @@ pub fn check_path_too_long(arg: &str, name: &str) -> Result<()> { + Ok(()) + } + +-pub fn check_arg_nonexist(arg: Option, name: &str, device: &str) -> Result<()> { +- arg.with_context(|| ConfigError::FieldIsMissing(name.to_string(), device.to_string()))?; ++/// Make sure args are existed. ++/// ++/// arg_name: Name of arg. ++/// arg_value: Value of arg. Should be Option<> class. ++/// Eg: ++/// check_arg_exist!(("id", id)); ++/// check_arg_exist!(("bus", bus), ("addr", addr)); ++#[macro_export] ++macro_rules! check_arg_exist{ ++ ($(($arg_name:tt, $arg_value:expr)),*) => { ++ $($arg_value.clone().with_context(|| format!("Should set {}.", $arg_name))?;)* ++ } ++} + +- Ok(()) ++/// Make sure args are existed. ++/// ++/// arg_name: Name of arg. ++/// arg_value: Value of arg. Should be Option<> class. ++/// Eg: ++/// check_arg_nonexist!(("id", id)); ++/// check_arg_nonexist!(("bus", bus), ("addr", addr)); ++#[macro_export] ++macro_rules! check_arg_nonexist{ ++ ($(($arg_name:tt, $arg_value:expr)),*) => { ++ $($arg_value.clone().map_or(Some(0), |_| None).with_context(|| format!("Should not set {}", $arg_name))?;)* ++ } ++} ++ ++fn concat_classtype(args: &str, concat: bool) -> String { ++ if concat { ++ format!("classtype={}", args) ++ } else { ++ args.to_string() ++ } + } + + /// Configure StratoVirt parameters in clap format. +-pub fn str_slip_to_clap(args: &str) -> Vec { +- let args_vecs = args.split([',', '=']).collect::>(); +- let mut itr: Vec = Vec::with_capacity(args_vecs.len()); +- for (cnt, param) in args_vecs.iter().enumerate() { +- if cnt % 2 == 1 { +- itr.push(format!("--{}", param)); +- } else { +- itr.push(param.to_string()); ++/// ++/// The first parameter will be parsed as the `binary name` unless Command::no_binary_name is used when using `clap`. ++/// Stratovirt command line may use the first parameter as class type. ++/// Eg: ++/// 1. drive config: "-drive file=,if=pflash,unit=0" ++/// This cmdline has no class type. ++/// 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" ++/// This cmdline sets device type `virtio-balloon-pci` as the first parameter. ++/// ++/// Use first_pos_is_type to indicate whether the first parameter is a type class which needs a separate analysis. ++/// Eg: ++/// 1. drive config: "-drive file=,if=pflash,unit=0" ++/// Set first_pos_is_type false for this cmdline has no class type. ++/// 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" ++/// Set first_pos_is_type true for this cmdline has device type "virtio-balloon-pci" as the first parameter. ++/// ++/// Use first_pos_is_subcommand to indicate whether the first parameter is a subclass. ++/// Eg: ++/// Chardev has stdio/unix-socket/tcp-socket/pty/file classes. These classes have different configurations but will be stored ++/// in the same `ChardevConfig` structure by using `enum`. So, we will use class type as a subcommand to indicate which subtype ++/// will be used to store the configuration in enumeration type. Subcommand in `clap` doesn't need `--` in parameter. ++/// 1. -serial file,path= ++/// Set first_pos_is_subcommand true for first parameter `file` is the subclass type for chardev. ++pub fn str_slip_to_clap( ++ args: &str, ++ first_pos_is_type: bool, ++ first_pos_is_subcommand: bool, ++) -> Vec { ++ let mut subcommand = first_pos_is_subcommand; ++ let args_str = concat_classtype(args, first_pos_is_type && !subcommand); ++ let args_vecs = args_str.split([',']).collect::>(); ++ let mut itr: Vec = Vec::with_capacity(args_vecs.len() * 2); ++ for params in args_vecs { ++ let key_value = params.split(['=']).collect::>(); ++ // Command line like "key=value" will be converted to "--key value". ++ // Command line like "key" will be converted to "--key". ++ for (cnt, param) in key_value.iter().enumerate() { ++ if cnt % 2 == 0 { ++ if subcommand { ++ itr.push(param.to_string()); ++ subcommand = false; ++ } else { ++ itr.push(format!("--{}", param)); ++ } ++ } else { ++ itr.push(param.to_string()); ++ } + } + } + itr + } + ++/// Retrieve the value of the specified parameter from a string in the format "key=value". ++pub fn get_value_of_parameter(parameter: &str, args_str: &str) -> Result { ++ let args_vecs = args_str.split([',']).collect::>(); ++ ++ for args in args_vecs { ++ let key_value = args.split(['=']).collect::>(); ++ if key_value.len() != 2 || key_value[0] != parameter { ++ continue; ++ } ++ if key_value[1].is_empty() { ++ bail!("Find empty arg {} in string {}.", key_value[0], args_str); ++ } ++ return Ok(key_value[1].to_string()); ++ } ++ ++ bail!("Cannot find {}'s value from string {}", parameter, args_str); ++} ++ ++pub fn get_class_type(args: &str) -> Result { ++ let args_str = concat_classtype(args, true); ++ get_value_of_parameter("classtype", &args_str) ++} ++ + pub fn valid_id(id: &str) -> Result { + check_arg_too_long(id, "id")?; + Ok(id.to_string()) + } + ++// Virtio queue size must be power of 2 and in range [min_size, max_size]. ++pub fn valid_virtqueue_size(size: u64, min_size: u64, max_size: u64) -> Result<()> { ++ if size < min_size || size > max_size { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "virtqueue size".to_string(), ++ min_size, ++ true, ++ max_size, ++ true ++ ))); ++ } ++ ++ if size & (size - 1) != 0 { ++ bail!("Virtqueue size should be power of 2!"); ++ } ++ ++ Ok(()) ++} ++ ++pub fn valid_path(path: &str) -> Result { ++ if path.len() > MAX_PATH_LENGTH { ++ return Err(anyhow!(ConfigError::StringLengthTooLong( ++ "path".to_string(), ++ MAX_PATH_LENGTH, ++ ))); ++ } ++ ++ let canonical_path = canonicalize(path).map_or(path.to_string(), |pathbuf| { ++ String::from(pathbuf.to_str().unwrap()) ++ }); ++ ++ Ok(canonical_path) ++} ++ ++pub fn valid_socket_path(sock_path: &str) -> Result { ++ if sock_path.len() > MAX_SOCK_PATH_LENGTH { ++ return Err(anyhow!(ConfigError::StringLengthTooLong( ++ "socket path".to_string(), ++ MAX_SOCK_PATH_LENGTH, ++ ))); ++ } ++ valid_path(sock_path) ++} ++ ++pub fn valid_dir(d: &str) -> Result { ++ let dir = String::from(d); ++ if !Path::new(&dir).is_dir() { ++ return Err(anyhow!(ConfigError::DirNotExist(dir))); ++ } ++ Ok(dir) ++} ++ ++pub fn valid_block_device_virtqueue_size(s: &str) -> Result { ++ let size: u64 = s.parse()?; ++ valid_virtqueue_size( ++ size, ++ MIN_QUEUE_SIZE_BLOCK_DEVICE + 1, ++ MAX_QUEUE_SIZE_BLOCK_DEVICE, ++ )?; ++ ++ Ok(size as u16) ++} ++ ++pub fn parse_size(s: &str) -> Result { ++ let size = memory_unit_conversion(s, M).with_context(|| format!("Invalid size: {}", s))?; ++ Ok(size) ++} ++ + #[cfg(test)] + mod tests { + use super::*; + + #[test] +- fn test_cmd_parser() { +- let mut cmd_parser = CmdParser::new("test"); +- cmd_parser +- .push("") +- .push("id") +- .push("path") +- .push("num") +- .push("test1") +- .push("test2") +- .push("test3") +- .push("test4") +- .push("test5") +- .push("test6") +- .push("test7"); +- assert!(cmd_parser +- .parse("socket,id=charconsole0,path=/tmp/console.sock,num=1,test1=true,test2=on,test3=yes,test4=false,test5=off,test6=no,test7=random") +- .is_ok()); +- assert_eq!( +- cmd_parser.get_value::("").unwrap().unwrap(), +- "socket".to_string() +- ); +- assert_eq!( +- cmd_parser.get_value::("id").unwrap().unwrap(), +- "charconsole0".to_string() +- ); +- assert_eq!( +- cmd_parser.get_value::("path").unwrap().unwrap(), +- "/tmp/console.sock".to_string() +- ); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u64); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u32); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u16); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u8); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i64); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i32); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i16); +- assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i8); +- assert!(cmd_parser.get_value::("test1").unwrap().unwrap()); +- assert!( +- cmd_parser +- .get_value::("test1") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!( +- cmd_parser +- .get_value::("test2") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!( +- cmd_parser +- .get_value::("test3") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!(!cmd_parser.get_value::("test4").unwrap().unwrap()); +- assert!( +- !cmd_parser +- .get_value::("test4") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!( +- !cmd_parser +- .get_value::("test5") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!( +- !cmd_parser +- .get_value::("test6") +- .unwrap() +- .unwrap() +- .inner +- ); +- assert!(cmd_parser.get_value::("test7").is_err()); +- assert!(cmd_parser.get_value::("test7").is_err()); +- assert!(cmd_parser.get_value::("random").unwrap().is_none()); +- assert!(cmd_parser.parse("random=false").is_err()); +- } +- +- #[test] +- fn test_parse_trace_options() { +- assert!(parse_trace_options("fil=test_trace").is_err()); +- assert!(parse_trace_options("file").is_err()); +- assert!(parse_trace_options("file=test_trace").is_err()); ++ fn test_add_trace() { ++ assert!(add_trace("fil=test_trace").is_err()); ++ assert!(add_trace("file").is_err()); ++ assert!(add_trace("file=test_trace").is_err()); + } + + #[test] +@@ -886,4 +784,20 @@ mod tests { + let res = vm_config.add_global_config("pcie-root-port.fast-unplug=1"); + assert!(res.is_err()); + } ++ ++ #[test] ++ fn test_get_value_of_parameter() { ++ let cmd = "scsi-hd,id=disk1,drive=scsi-drive-0"; ++ let id = get_value_of_parameter("id", cmd).unwrap(); ++ assert_eq!(id, "disk1"); ++ ++ let cmd = "id="; ++ assert!(get_value_of_parameter("id", cmd).is_err()); ++ ++ let cmd = "id"; ++ assert!(get_value_of_parameter("id", cmd).is_err()); ++ ++ let cmd = "scsi-hd,idxxx=disk1"; ++ assert!(get_value_of_parameter("id", cmd).is_err()); ++ } + } +diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs +index f7d79a1..c9e5897 100644 +--- a/machine_manager/src/config/network.rs ++++ b/machine_manager/src/config/network.rs +@@ -13,40 +13,95 @@ + use std::os::unix::io::RawFd; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser}; + use serde::{Deserialize, Serialize}; + +-use super::{error::ConfigError, pci_args_check}; +-use crate::config::get_chardev_socket_path; +-use crate::config::{ +- check_arg_too_long, CmdParser, ConfigCheck, ExBool, VmConfig, DEFAULT_VIRTQUEUE_SIZE, +- MAX_PATH_LENGTH, MAX_VIRTIO_QUEUE, +-}; ++use super::error::ConfigError; ++use super::{get_pci_df, parse_bool, str_slip_to_clap, valid_id, valid_virtqueue_size}; ++use crate::config::{ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE}; + use crate::qmp::{qmp_channel::QmpChannel, qmp_schema}; + + const MAC_ADDRESS_LENGTH: usize = 17; + + /// Max virtqueue size of each virtqueue. +-pub const MAX_QUEUE_SIZE_NET: u16 = 4096; ++const MAX_QUEUE_SIZE_NET: u64 = 4096; + /// Max num of virtqueues. + const MAX_QUEUE_PAIRS: usize = MAX_VIRTIO_QUEUE / 2; + +-#[derive(Debug, Clone, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct NetDevcfg { ++ #[arg(long, alias="classtype", value_parser = ["tap", "vhost-user"])] ++ pub netdev_type: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, ++ #[arg(long, aliases = ["fds", "fd"], use_value_delimiter = true, value_delimiter = ':')] + pub tap_fds: Option>, +- pub vhost_type: Option, ++ #[arg(long, alias = "vhost", default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] ++ pub vhost_kernel: bool, ++ #[arg(long, aliases = ["vhostfds", "vhostfd"], use_value_delimiter = true, value_delimiter = ':')] + pub vhost_fds: Option>, ++ #[arg(long, default_value = "", value_parser = valid_id)] + pub ifname: String, ++ #[arg(long, default_value = "1", value_parser = parse_queues)] + pub queues: u16, ++ #[arg(long)] + pub chardev: Option, + } + ++impl NetDevcfg { ++ pub fn vhost_type(&self) -> Option { ++ if self.vhost_kernel { ++ return Some("vhost-kernel".to_string()); ++ } ++ if self.netdev_type == "vhost-user" { ++ return Some("vhost-user".to_string()); ++ } ++ // Default: virtio net. ++ None ++ } ++ ++ fn auto_queues(&mut self) -> Result<()> { ++ if let Some(fds) = &self.tap_fds { ++ let fds_num = fds ++ .len() ++ .checked_mul(2) ++ .with_context(|| format!("Invalid fds number {}", fds.len()))? ++ as u16; ++ if fds_num > self.queues { ++ self.queues = fds_num; ++ } ++ } ++ if let Some(fds) = &self.vhost_fds { ++ let fds_num = fds ++ .len() ++ .checked_mul(2) ++ .with_context(|| format!("Invalid vhostfds number {}", fds.len()))? ++ as u16; ++ if fds_num > self.queues { ++ self.queues = fds_num; ++ } ++ } ++ Ok(()) ++ } ++} ++ ++fn parse_queues(q: &str) -> Result { ++ let queues = q ++ .parse::()? ++ .checked_mul(2) ++ .with_context(|| "Invalid 'queues' value")?; ++ is_netdev_queues_valid(queues)?; ++ Ok(queues) ++} ++ + impl Default for NetDevcfg { + fn default() -> Self { + NetDevcfg { ++ netdev_type: "".to_string(), + id: "".to_string(), + tap_fds: None, +- vhost_type: None, ++ vhost_kernel: false, + vhost_fds: None, + ifname: "".to_string(), + queues: 2, +@@ -57,24 +112,18 @@ impl Default for NetDevcfg { + + impl ConfigCheck for NetDevcfg { + fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "id")?; +- check_arg_too_long(&self.ifname, "ifname")?; +- +- if let Some(vhost_type) = self.vhost_type.as_ref() { +- if vhost_type != "vhost-kernel" && vhost_type != "vhost-user" { +- return Err(anyhow!(ConfigError::UnknownVhostType)); +- } ++ if self.vhost_kernel && self.netdev_type == "vhost-user" { ++ bail!("vhost-user netdev does not support 'vhost' option"); + } + +- if !is_netdev_queues_valid(self.queues) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "number queues of net device".to_string(), +- 1, +- true, +- MAX_VIRTIO_QUEUE as u64 / 2, +- true, +- ))); ++ if self.vhost_fds.is_some() && self.vhost_type().is_none() { ++ bail!("Argument 'vhostfd' or 'vhostfds' are not needed for virtio-net device"); + } ++ if self.tap_fds.is_none() && self.ifname.eq("") && self.netdev_type.ne("vhost-user") { ++ bail!("Tap device is missing, use \'ifname\' or \'fd\' to configure a tap device"); ++ } ++ ++ is_netdev_queues_valid(self.queues)?; + + Ok(()) + } +@@ -82,227 +131,73 @@ impl ConfigCheck for NetDevcfg { + + /// Config struct for network + /// Contains network device config, such as `host_dev_name`, `mac`... +-#[derive(Debug, Clone, Serialize, Deserialize)] ++#[derive(Debug, Clone, Serialize, Deserialize, Parser)] + #[serde(deny_unknown_fields)] ++#[command(no_binary_name(true))] + pub struct NetworkInterfaceConfig { ++ #[arg(long, value_parser = ["virtio-net-pci", "virtio-net-device"])] ++ pub classtype: String, ++ #[arg(long, default_value = "", value_parser = valid_id)] + pub id: String, +- pub host_dev_name: String, ++ #[arg(long)] ++ pub netdev: String, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] ++ pub multifunction: Option, ++ #[arg(long, value_parser = valid_mac)] + pub mac: Option, +- pub tap_fds: Option>, +- pub vhost_type: Option, +- pub vhost_fds: Option>, ++ #[arg(long)] + pub iothread: Option, +- pub queues: u16, ++ #[arg(long, default_value="off", value_parser = parse_bool, action = ArgAction::Append)] + pub mq: bool, +- pub socket_path: Option, +- /// All queues of a net device have the same queue size now. ++ // All queues of a net device have the same queue size now. ++ #[arg(long, default_value = "256", alias = "queue-size", value_parser = valid_network_queue_size)] + pub queue_size: u16, ++ // MSI-X vectors the this network device has. This member isn't used now in stratovirt. ++ #[arg(long, default_value = "0")] ++ pub vectors: u16, + } + + impl Default for NetworkInterfaceConfig { + fn default() -> Self { + NetworkInterfaceConfig { ++ classtype: "".to_string(), + id: "".to_string(), +- host_dev_name: "".to_string(), ++ netdev: "".to_string(), ++ bus: None, ++ addr: None, ++ multifunction: None, + mac: None, +- tap_fds: None, +- vhost_type: None, +- vhost_fds: None, + iothread: None, +- queues: 2, + mq: false, +- socket_path: None, + queue_size: DEFAULT_VIRTQUEUE_SIZE, ++ vectors: 0, + } + } + } + ++fn valid_network_queue_size(s: &str) -> Result { ++ let size: u64 = s.parse()?; ++ valid_virtqueue_size(size, DEFAULT_VIRTQUEUE_SIZE as u64, MAX_QUEUE_SIZE_NET)?; ++ ++ Ok(size as u16) ++} ++ + impl ConfigCheck for NetworkInterfaceConfig { + fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "id")?; +- check_arg_too_long(&self.host_dev_name, "host dev name")?; +- + if self.mac.is_some() && !check_mac_address(self.mac.as_ref().unwrap()) { + return Err(anyhow!(ConfigError::MacFormatError)); + } + +- if self.iothread.is_some() { +- check_arg_too_long(self.iothread.as_ref().unwrap(), "iothread name")?; +- } +- +- if self.socket_path.is_some() && self.socket_path.as_ref().unwrap().len() > MAX_PATH_LENGTH +- { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "socket path".to_string(), +- MAX_PATH_LENGTH +- ))); +- } +- +- if self.queue_size < DEFAULT_VIRTQUEUE_SIZE || self.queue_size > MAX_QUEUE_SIZE_NET { +- return Err(anyhow!(ConfigError::IllegalValue( +- "queue size of net device".to_string(), +- DEFAULT_VIRTQUEUE_SIZE as u64, +- true, +- MAX_QUEUE_SIZE_NET as u64, +- true +- ))); +- } +- +- if self.queue_size & (self.queue_size - 1) != 0 { +- bail!("queue size of net device should be power of 2!"); +- } ++ valid_network_queue_size(&self.queue_size.to_string())?; + + Ok(()) + } + } + +-fn parse_fds(cmd_parser: &CmdParser, name: &str) -> Result>> { +- if let Some(fds) = cmd_parser.get_value::(name)? { +- let mut raw_fds = Vec::new(); +- for fd in fds.split(':').collect::>().iter() { +- raw_fds.push( +- (*fd) +- .parse::() +- .with_context(|| "Failed to parse fds")?, +- ); +- } +- Ok(Some(raw_fds)) +- } else { +- Ok(None) +- } +-} +- +-fn parse_netdev(cmd_parser: CmdParser) -> Result { +- let mut net = NetDevcfg::default(); +- let netdev_type = cmd_parser.get_value::("")?.unwrap_or_default(); +- if netdev_type.ne("tap") && netdev_type.ne("vhost-user") { +- bail!("Unsupported netdev type: {:?}", &netdev_type); +- } +- net.id = cmd_parser +- .get_value::("id")? +- .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "netdev".to_string()))?; +- if let Some(ifname) = cmd_parser.get_value::("ifname")? { +- net.ifname = ifname; +- } +- if let Some(queue_pairs) = cmd_parser.get_value::("queues")? { +- let queues = queue_pairs.checked_mul(2); +- if queues.is_none() || !is_netdev_queues_valid(queues.unwrap()) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "number queues of net device".to_string(), +- 1, +- true, +- MAX_VIRTIO_QUEUE as u64 / 2, +- true, +- ))); +- } +- +- net.queues = queues.unwrap(); +- } +- +- if let Some(tap_fd) = parse_fds(&cmd_parser, "fd")? { +- net.tap_fds = Some(tap_fd); +- } else if let Some(tap_fds) = parse_fds(&cmd_parser, "fds")? { +- net.tap_fds = Some(tap_fds); +- } +- if let Some(fds) = &net.tap_fds { +- let fds_num = +- fds.len() +- .checked_mul(2) +- .with_context(|| format!("Invalid fds number {}", fds.len()))? as u16; +- if fds_num > net.queues { +- net.queues = fds_num; +- } +- } +- +- if let Some(vhost) = cmd_parser.get_value::("vhost")? { +- if vhost.into() { +- net.vhost_type = Some(String::from("vhost-kernel")); +- } +- } else if netdev_type.eq("vhost-user") { +- net.vhost_type = Some(String::from("vhost-user")); +- } +- if let Some(chardev) = cmd_parser.get_value::("chardev")? { +- net.chardev = Some(chardev); +- } +- if let Some(vhost_fd) = parse_fds(&cmd_parser, "vhostfd")? { +- net.vhost_fds = Some(vhost_fd); +- } else if let Some(vhost_fds) = parse_fds(&cmd_parser, "vhostfds")? { +- net.vhost_fds = Some(vhost_fds); +- } +- if let Some(fds) = &net.vhost_fds { +- let fds_num = fds +- .len() +- .checked_mul(2) +- .with_context(|| format!("Invalid vhostfds number {}", fds.len()))? +- as u16; +- if fds_num > net.queues { +- net.queues = fds_num; +- } +- } +- +- if net.vhost_fds.is_some() && net.vhost_type.is_none() { +- bail!("Argument \'vhostfd\' is not needed for virtio-net device"); +- } +- if net.tap_fds.is_none() && net.ifname.eq("") && netdev_type.ne("vhost-user") { +- bail!("Tap device is missing, use \'ifname\' or \'fd\' to configure a tap device"); +- } +- +- net.check()?; +- +- Ok(net) +-} +- +-pub fn parse_net(vm_config: &mut VmConfig, net_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("virtio-net"); +- cmd_parser +- .push("") +- .push("id") +- .push("netdev") +- .push("mq") +- .push("vectors") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("mac") +- .push("iothread") +- .push("queue-size"); +- +- cmd_parser.parse(net_config)?; +- pci_args_check(&cmd_parser)?; +- let mut netdevinterfacecfg = NetworkInterfaceConfig::default(); +- +- let netdev = cmd_parser +- .get_value::("netdev")? +- .with_context(|| ConfigError::FieldIsMissing("netdev".to_string(), "net".to_string()))?; +- let netid = cmd_parser.get_value::("id")?.unwrap_or_default(); +- +- if let Some(mq) = cmd_parser.get_value::("mq")? { +- netdevinterfacecfg.mq = mq.inner; +- } +- netdevinterfacecfg.iothread = cmd_parser.get_value::("iothread")?; +- netdevinterfacecfg.mac = cmd_parser.get_value::("mac")?; +- if let Some(queue_size) = cmd_parser.get_value::("queue-size")? { +- netdevinterfacecfg.queue_size = queue_size; +- } +- +- let netcfg = &vm_config +- .netdevs +- .remove(&netdev) +- .with_context(|| format!("Netdev: {:?} not found for net device", &netdev))?; +- netdevinterfacecfg.id = netid; +- netdevinterfacecfg.host_dev_name = netcfg.ifname.clone(); +- netdevinterfacecfg.tap_fds = netcfg.tap_fds.clone(); +- netdevinterfacecfg.vhost_fds = netcfg.vhost_fds.clone(); +- netdevinterfacecfg.vhost_type = netcfg.vhost_type.clone(); +- netdevinterfacecfg.queues = netcfg.queues; +- if let Some(chardev) = &netcfg.chardev { +- netdevinterfacecfg.socket_path = Some(get_chardev_socket_path(chardev, vm_config)?); +- } +- +- netdevinterfacecfg.check()?; +- Ok(netdevinterfacecfg) +-} +- + fn get_netdev_fd(fd_name: &str) -> Result { + if let Some(fd) = QmpChannel::get_fd(fd_name) { + Ok(fd) +@@ -337,17 +232,12 @@ pub fn get_netdev_config(args: Box) -> Result) -> Result Result<()> { +- let mut cmd_parser = CmdParser::new("netdev"); +- cmd_parser +- .push("") +- .push("id") +- .push("fd") +- .push("fds") +- .push("vhost") +- .push("ifname") +- .push("vhostfd") +- .push("vhostfds") +- .push("queues") +- .push("chardev"); +- +- cmd_parser.parse(netdev_config)?; +- let drive_cfg = parse_netdev(cmd_parser)?; +- self.add_netdev_with_config(drive_cfg) ++ let mut netdev_cfg = ++ NetDevcfg::try_parse_from(str_slip_to_clap(netdev_config, true, false))?; ++ netdev_cfg.auto_queues()?; ++ netdev_cfg.check()?; ++ self.add_netdev_with_config(netdev_cfg) + } + + pub fn add_netdev_with_config(&mut self, conf: NetDevcfg) -> Result<()> { + let netdev_id = conf.id.clone(); +- if self.netdevs.get(&netdev_id).is_none() { +- self.netdevs.insert(netdev_id, conf); +- } else { ++ if self.netdevs.get(&netdev_id).is_some() { + bail!("Netdev {:?} has been added", netdev_id); + } ++ self.netdevs.insert(netdev_id, conf); + Ok(()) + } + + pub fn del_netdev_by_id(&mut self, id: &str) -> Result<()> { +- if self.netdevs.get(id).is_some() { +- self.netdevs.remove(id); +- } else { +- bail!("Netdev {} not found", id); +- } ++ self.netdevs ++ .remove(id) ++ .with_context(|| format!("Netdev {} not found", id))?; ++ + Ok(()) + } + } + ++fn valid_mac(mac: &str) -> Result { ++ if !check_mac_address(mac) { ++ return Err(anyhow!(ConfigError::MacFormatError)); ++ } ++ Ok(mac.to_string()) ++} ++ + fn check_mac_address(mac: &str) -> bool { + if mac.len() != MAC_ADDRESS_LENGTH { + return false; +@@ -485,207 +351,136 @@ fn check_mac_address(mac: &str) -> bool { + true + } + +-fn is_netdev_queues_valid(queues: u16) -> bool { +- queues >= 1 && queues <= MAX_VIRTIO_QUEUE as u16 ++fn is_netdev_queues_valid(queues: u16) -> Result<()> { ++ if !(queues >= 2 && queues <= MAX_VIRTIO_QUEUE as u16) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "number queues of net device".to_string(), ++ 1, ++ true, ++ MAX_QUEUE_PAIRS as u64, ++ true, ++ ))); ++ } ++ ++ Ok(()) + } + + #[cfg(test)] + mod tests { + use super::*; +- use crate::config::{get_pci_bdf, MAX_STRING_LENGTH}; + + #[test] +- fn test_network_config_cmdline_parser() { ++ fn test_netdev_config_cmdline_parser() { + let mut vm_config = VmConfig::default(); ++ ++ // Test1: Right. + assert!(vm_config.add_netdev("tap,id=eth0,ifname=tap0").is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0", +- ); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.id, "net0"); +- assert_eq!(network_configs.host_dev_name, "tap0"); +- assert_eq!(network_configs.iothread, Some("iothread0".to_string())); +- assert!(network_configs.mac.is_none()); +- assert!(network_configs.tap_fds.is_none()); +- assert!(network_configs.vhost_type.is_none()); +- assert!(network_configs.vhost_fds.is_none()); ++ assert!(vm_config.add_netdev("tap,id=eth0,ifname=tap0").is_err()); ++ let netdev_cfg = vm_config.netdevs.get("eth0").unwrap(); ++ assert_eq!(netdev_cfg.id, "eth0"); ++ assert_eq!(netdev_cfg.ifname, "tap0"); ++ assert!(netdev_cfg.tap_fds.is_none()); ++ assert_eq!(netdev_cfg.vhost_kernel, false); ++ assert!(netdev_cfg.vhost_fds.is_none()); ++ assert_eq!(netdev_cfg.queues, 2); ++ assert!(netdev_cfg.vhost_type().is_none()); + +- let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") + .is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net1,netdev=eth1,mac=12:34:56:78:9A:BC", +- ); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.id, "net1"); +- assert_eq!(network_configs.host_dev_name, "tap1"); +- assert_eq!(network_configs.mac, Some(String::from("12:34:56:78:9A:BC"))); +- assert!(network_configs.tap_fds.is_none()); +- assert_eq!( +- network_configs.vhost_type, +- Some(String::from("vhost-kernel")) +- ); +- assert_eq!(network_configs.vhost_fds, Some(vec![4])); ++ let netdev_cfg = vm_config.netdevs.get("eth1").unwrap(); ++ assert_eq!(netdev_cfg.ifname, "tap1"); ++ assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-kernel"); ++ assert_eq!(netdev_cfg.vhost_fds, Some(vec![4])); + +- let mut vm_config = VmConfig::default(); +- assert!(vm_config.add_netdev("tap,id=eth1,fd=35").is_ok()); +- let net_cfg_res = parse_net(&mut vm_config, "virtio-net-device,id=net1,netdev=eth1"); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.id, "net1"); +- assert_eq!(network_configs.host_dev_name, ""); +- assert_eq!(network_configs.tap_fds, Some(vec![35])); ++ assert!(vm_config.add_netdev("tap,id=eth2,fd=35").is_ok()); ++ let netdev_cfg = vm_config.netdevs.get("eth2").unwrap(); ++ assert_eq!(netdev_cfg.tap_fds, Some(vec![35])); + +- let mut vm_config = VmConfig::default(); + assert!(vm_config +- .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") ++ .add_netdev("tap,id=eth3,ifname=tap0,queues=4") + .is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net1,netdev=eth2,mac=12:34:56:78:9A:BC", +- ); +- assert!(net_cfg_res.is_err()); ++ let netdev_cfg = vm_config.netdevs.get("eth3").unwrap(); ++ assert_eq!(netdev_cfg.queues, 8); + +- let mut vm_config = VmConfig::default(); +- assert!(vm_config.add_netdev("tap,id=eth1,fd=35").is_ok()); +- let net_cfg_res = parse_net(&mut vm_config, "virtio-net-device,id=net1,netdev=eth3"); +- assert!(net_cfg_res.is_err()); +- +- // multi queue testcases +- let mut vm_config = VmConfig::default(); + assert!(vm_config +- .add_netdev("tap,id=eth0,ifname=tap0,queues=4") ++ .add_netdev("tap,id=eth4,fds=34:35:36:37:38") + .is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=on,vectors=6", +- ); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.queues, 8); +- assert_eq!(network_configs.mq, true); ++ let netdev_cfg = vm_config.netdevs.get("eth4").unwrap(); ++ assert_eq!(netdev_cfg.queues, 10); ++ assert_eq!(netdev_cfg.tap_fds, Some(vec![34, 35, 36, 37, 38])); + +- let mut vm_config = VmConfig::default(); + assert!(vm_config +- .add_netdev("tap,id=eth0,fds=34:35:36:37:38") ++ .add_netdev("tap,id=eth5,fds=34:35:36:37:38,vhost=on,vhostfds=39:40:41:42:43") + .is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=off,vectors=12", +- ); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.queues, 10); +- assert_eq!(network_configs.tap_fds, Some(vec![34, 35, 36, 37, 38])); +- assert_eq!(network_configs.mq, false); ++ let netdev_cfg = vm_config.netdevs.get("eth5").unwrap(); ++ assert_eq!(netdev_cfg.queues, 10); ++ assert_eq!(netdev_cfg.vhost_fds, Some(vec![39, 40, 41, 42, 43])); + +- let mut vm_config = VmConfig::default(); ++ // Test2: Missing values + assert!(vm_config +- .add_netdev("tap,id=eth0,fds=34:35:36:37:38,vhost=on,vhostfds=39:40:41:42:43") +- .is_ok()); +- let net_cfg_res = parse_net( +- &mut vm_config, +- "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=off,vectors=12", +- ); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.queues, 10); +- assert_eq!(network_configs.vhost_fds, Some(vec![39, 40, 41, 42, 43])); +- assert_eq!(network_configs.mq, false); ++ .add_netdev("tap,fds=34:35:36:37:38,vhost=on") ++ .is_err()); ++ ++ // Test3: Illegal values. ++ assert!(vm_config ++ .add_netdev("tap,id=eth10,fds=34:35:36:37:38,vhost=on,vhostfds=39,40,41,42,43") ++ .is_err()); ++ assert!(vm_config.add_netdev("tap,id=eth10,queues=0").is_err()); ++ assert!(vm_config.add_netdev("tap,id=eth10,queues=17").is_err()); + } + + #[test] +- fn test_pci_network_config_cmdline_parser() { ++ fn test_networkinterface_config_cmdline_parser() { ++ // Test1: Right. + let mut vm_config = VmConfig::default(); +- + assert!(vm_config + .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") + .is_ok()); ++ let net_cmd = ++ "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC,mq=on,vectors=6,queue-size=2048,multifunction=on"; + let net_cfg = +- "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC"; +- let net_cfg_res = parse_net(&mut vm_config, net_cfg); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.id, "net1"); +- assert_eq!(network_configs.host_dev_name, "tap1"); +- assert_eq!(network_configs.mac, Some(String::from("12:34:56:78:9A:BC"))); +- assert!(network_configs.tap_fds.is_none()); +- assert_eq!( +- network_configs.vhost_type, +- Some(String::from("vhost-kernel")) +- ); +- assert_eq!(network_configs.vhost_fds.unwrap()[0], 4); +- let pci_bdf = get_pci_bdf(net_cfg); +- assert!(pci_bdf.is_ok()); +- let pci = pci_bdf.unwrap(); +- assert_eq!(pci.bus, "pcie.0".to_string()); +- assert_eq!(pci.addr, (1, 2)); +- +- let net_cfg_res = parse_net(&mut vm_config, net_cfg); +- assert!(net_cfg_res.is_err()); +- ++ NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)).unwrap(); ++ assert_eq!(net_cfg.id, "net1"); ++ assert_eq!(net_cfg.netdev, "eth1"); ++ assert_eq!(net_cfg.bus.unwrap(), "pcie.0"); ++ assert_eq!(net_cfg.addr.unwrap(), (1, 2)); ++ assert_eq!(net_cfg.mac.unwrap(), "12:34:56:78:9A:BC"); ++ assert_eq!(net_cfg.vectors, 6); ++ assert_eq!(net_cfg.mq, true); ++ assert_eq!(net_cfg.queue_size, 2048); ++ assert_eq!(net_cfg.multifunction, Some(true)); ++ let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); ++ assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-kernel"); ++ ++ // Test2: Default values. + let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") +- .is_ok()); +- let net_cfg = +- "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC,multifunction=on"; +- assert!(parse_net(&mut vm_config, net_cfg).is_ok()); +- +- // For vhost-user net + assert!(vm_config.add_netdev("vhost-user,id=netdevid").is_ok()); +- let net_cfg = ++ let net_cmd = + "virtio-net-pci,id=netid,netdev=netdevid,bus=pcie.0,addr=0x2.0x0,mac=12:34:56:78:9A:BC"; +- let net_cfg_res = parse_net(&mut vm_config, net_cfg); +- assert!(net_cfg_res.is_ok()); +- let network_configs = net_cfg_res.unwrap(); +- assert_eq!(network_configs.id, "netid"); +- assert_eq!(network_configs.vhost_type, Some("vhost-user".to_string())); +- assert_eq!(network_configs.mac, Some("12:34:56:78:9A:BC".to_string())); +- +- assert!(vm_config +- .add_netdev("vhost-user,id=netdevid2,chardev=chardevid2") +- .is_ok()); + let net_cfg = +- "virtio-net-pci,id=netid2,netdev=netdevid2,bus=pcie.0,addr=0x2.0x0,mac=12:34:56:78:9A:BC"; +- let net_cfg_res = parse_net(&mut vm_config, net_cfg); +- assert!(net_cfg_res.is_err()); +- } +- +- #[test] +- fn test_netdev_config_check() { +- let mut netdev_conf = NetDevcfg::default(); +- for _ in 0..MAX_STRING_LENGTH { +- netdev_conf.id += "A"; +- } +- assert!(netdev_conf.check().is_ok()); +- +- // Overflow +- netdev_conf.id += "A"; +- assert!(netdev_conf.check().is_err()); +- +- let mut netdev_conf = NetDevcfg::default(); +- for _ in 0..MAX_STRING_LENGTH { +- netdev_conf.ifname += "A"; +- } +- assert!(netdev_conf.check().is_ok()); +- +- // Overflow +- netdev_conf.ifname += "A"; +- assert!(netdev_conf.check().is_err()); +- +- let mut netdev_conf = NetDevcfg::default(); +- netdev_conf.vhost_type = None; +- assert!(netdev_conf.check().is_ok()); +- netdev_conf.vhost_type = Some(String::from("vhost-kernel")); +- assert!(netdev_conf.check().is_ok()); +- netdev_conf.vhost_type = Some(String::from("vhost-")); +- assert!(netdev_conf.check().is_err()); ++ NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)).unwrap(); ++ assert_eq!(net_cfg.queue_size, 256); ++ assert_eq!(net_cfg.mq, false); ++ assert_eq!(net_cfg.vectors, 0); ++ let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); ++ assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-user"); ++ ++ // Test3: Missing Parameters. ++ let net_cmd = "virtio-net-pci,id=netid"; ++ let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); ++ assert!(result.is_err()); ++ ++ // Test4: Illegal Parameters. ++ let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,mac=1:1:1"; ++ let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); ++ assert!(result.is_err()); ++ let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,queue-size=128"; ++ let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); ++ assert!(result.is_err()); ++ let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,queue-size=10240"; ++ let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); ++ assert!(result.is_err()); + } + + #[test] +@@ -811,9 +606,9 @@ mod tests { + ..qmp_schema::NetDevAddArgument::default() + }); + let net_cfg = get_netdev_config(netdev).unwrap(); ++ assert_eq!(net_cfg.vhost_type().unwrap(), "vhost-kernel"); + assert_eq!(net_cfg.tap_fds.unwrap()[0], 11); + assert_eq!(net_cfg.vhost_fds.unwrap()[0], 21); +- assert_eq!(net_cfg.vhost_type.unwrap(), "vhost-kernel"); + } + + // Normal test with 'vhostfds'. +@@ -831,9 +626,9 @@ mod tests { + ..qmp_schema::NetDevAddArgument::default() + }); + let net_cfg = get_netdev_config(netdev).unwrap(); +- assert_eq!(net_cfg.tap_fds.unwrap(), [11, 12, 13, 14]); +- assert_eq!(net_cfg.vhost_fds.unwrap(), [21, 22, 23, 24]); +- assert_eq!(net_cfg.vhost_type.unwrap(), "vhost-kernel"); ++ assert_eq!(net_cfg.vhost_type().unwrap(), "vhost-kernel"); ++ assert_eq!(net_cfg.tap_fds.unwrap(), vec![11, 12, 13, 14]); ++ assert_eq!(net_cfg.vhost_fds.unwrap(), vec![21, 22, 23, 24]); + } + + let err_msgs = [ +@@ -859,8 +654,7 @@ mod tests { + ..qmp_schema::NetDevAddArgument::default() + }); + let err_msg = format!( +- "The 'queues' {} is bigger than max queue num {}", +- MAX_QUEUE_PAIRS + 1, ++ "number queues of net device must >= 1 and <= {}.", + MAX_QUEUE_PAIRS + ); + check_err_msg(netdev, &err_msg); +@@ -929,6 +723,7 @@ mod tests { + fds: Some(fds.to_string()), + ..qmp_schema::NetDevAddArgument::default() + }); ++ // number queues of net device + let err_msg = format!( + "The num of fd {} is bigger than max queue num {}", + MAX_QUEUE_PAIRS + 1, +diff --git a/machine_manager/src/config/numa.rs b/machine_manager/src/config/numa.rs +index a9a0bfa..664b180 100644 +--- a/machine_manager/src/config/numa.rs ++++ b/machine_manager/src/config/numa.rs +@@ -12,29 +12,17 @@ + + use std::cmp::max; + use std::collections::{BTreeMap, HashSet}; ++use std::str::FromStr; + +-use anyhow::{anyhow, bail, Context, Result}; ++use anyhow::{bail, Context, Result}; ++use clap::Parser; + + use super::error::ConfigError; +-use crate::config::{CmdParser, IntegerList, VmConfig, MAX_NODES}; ++use super::{get_class_type, str_slip_to_clap}; ++use crate::config::{IntegerList, VmConfig, MAX_NODES}; + + const MIN_NUMA_DISTANCE: u8 = 10; + +-#[derive(Default, Debug)] +-pub struct NumaDistance { +- pub destination: u32, +- pub distance: u8, +-} +- +-#[derive(Default, Debug)] +-pub struct NumaConfig { +- pub numa_id: u32, +- pub cpus: Vec, +- pub distances: Option>, +- pub size: u64, +- pub mem_dev: String, +-} +- + #[derive(Default)] + pub struct NumaNode { + pub cpus: Vec, +@@ -109,126 +97,83 @@ pub fn complete_numa_node(numa_nodes: &mut NumaNodes, nr_cpus: u8, mem_size: u64 + Ok(()) + } + +-/// Parse the NUMA node memory parameters. +-/// +-/// # Arguments +-/// +-/// * `numa_config` - The NUMA node configuration. +-pub fn parse_numa_mem(numa_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("numa"); +- cmd_parser +- .push("") +- .push("nodeid") +- .push("cpus") +- .push("memdev"); +- cmd_parser.parse(numa_config)?; +- +- let mut config: NumaConfig = NumaConfig::default(); +- if let Some(node_id) = cmd_parser.get_value::("nodeid")? { +- if node_id >= MAX_NODES { +- return Err(anyhow!(ConfigError::IllegalValue( +- "nodeid".to_string(), +- 0, +- true, +- MAX_NODES as u64, +- false, +- ))); +- } +- config.numa_id = node_id; +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "nodeid".to_string(), +- "numa".to_string() +- ))); +- } +- if let Some(mut cpus) = cmd_parser +- .get_value::("cpus") ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++pub struct NumaNodeConfig { ++ #[arg(long, value_parser = ["node"])] ++ pub classtype: String, ++ #[arg(long, alias = "nodeid", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] ++ pub numa_id: u32, ++ #[arg(long, value_parser = get_cpus)] ++ pub cpus: ::std::vec::Vec, ++ #[arg(long, alias = "memdev")] ++ pub mem_dev: String, ++} ++ ++fn get_cpus(cpus_str: &str) -> Result> { ++ let mut cpus = IntegerList::from_str(cpus_str) + .with_context(|| ConfigError::ConvertValueFailed(String::from("u8"), "cpus".to_string()))? +- .map(|v| v.0.iter().map(|e| *e as u8).collect::>()) +- { +- cpus.sort_unstable(); +- config.cpus = cpus; +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "cpus".to_string(), +- "numa".to_string() +- ))); ++ .0 ++ .iter() ++ .map(|e| *e as u8) ++ .collect::>(); ++ ++ if cpus.is_empty() { ++ bail!("Got empty cpus list!"); + } +- config.mem_dev = cmd_parser +- .get_value::("memdev")? +- .with_context(|| ConfigError::FieldIsMissing("memdev".to_string(), "numa".to_string()))?; + +- Ok(config) ++ cpus.sort_unstable(); ++ ++ Ok(cpus) + } + +-/// Parse the NUMA node distance parameters. ++/// Parse the NUMA node memory parameters. + /// + /// # Arguments + /// +-/// * `numa_dist` - The NUMA node distance configuration. +-pub fn parse_numa_distance(numa_dist: &str) -> Result<(u32, NumaDistance)> { +- let mut cmd_parser = CmdParser::new("numa"); +- cmd_parser.push("").push("src").push("dst").push("val"); +- cmd_parser.parse(numa_dist)?; +- +- let mut dist: NumaDistance = NumaDistance::default(); +- let numa_id = if let Some(src) = cmd_parser.get_value::("src")? { +- if src >= MAX_NODES { +- return Err(anyhow!(ConfigError::IllegalValue( +- "src".to_string(), +- 0, +- true, +- MAX_NODES as u64, +- false, +- ))); +- } +- src +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "src".to_string(), +- "numa".to_string() +- ))); +- }; +- if let Some(dst) = cmd_parser.get_value::("dst")? { +- if dst >= MAX_NODES { +- return Err(anyhow!(ConfigError::IllegalValue( +- "dst".to_string(), +- 0, +- true, +- MAX_NODES as u64, +- false, +- ))); +- } +- dist.destination = dst; +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "dst".to_string(), +- "numa".to_string() +- ))); +- } +- if let Some(val) = cmd_parser.get_value::("val")? { +- if val < MIN_NUMA_DISTANCE { +- bail!("NUMA distance shouldn't be less than 10"); +- } +- if numa_id == dist.destination && val != MIN_NUMA_DISTANCE { +- bail!("Local distance of node {} should be 10.", numa_id); ++/// * `numa_config` - The NUMA node configuration. ++pub fn parse_numa_mem(numa_config: &str) -> Result { ++ let config = NumaNodeConfig::try_parse_from(str_slip_to_clap(numa_config, true, false))?; ++ Ok(config) ++} ++ ++#[derive(Parser)] ++#[command(no_binary_name(true))] ++pub struct NumaDistConfig { ++ #[arg(long, value_parser = ["dist"])] ++ pub classtype: String, ++ #[arg(long, alias = "src", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] ++ pub numa_id: u32, ++ #[arg(long, alias = "dst", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] ++ pub destination: u32, ++ #[arg(long, alias = "val", value_parser = clap::value_parser!(u8).range(MIN_NUMA_DISTANCE as i64..))] ++ pub distance: u8, ++} ++ ++impl NumaDistConfig { ++ fn check(&self) -> Result<()> { ++ if self.numa_id == self.destination && self.distance != MIN_NUMA_DISTANCE { ++ bail!("Local distance of node {} should be 10.", self.numa_id); + } +- if numa_id != dist.destination && val == MIN_NUMA_DISTANCE { ++ if self.numa_id != self.destination && self.distance == MIN_NUMA_DISTANCE { + bail!( + "Remote distance of node {} should be more than 10.", +- numa_id ++ self.numa_id + ); + } +- +- dist.distance = val; +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "val".to_string(), +- "numa".to_string() +- ))); ++ Ok(()) + } ++} + +- Ok((numa_id, dist)) ++/// Parse the NUMA node distance parameters. ++/// ++/// # Arguments ++/// ++/// * `numa_dist` - The NUMA node distance configuration. ++pub fn parse_numa_distance(numa_dist: &str) -> Result { ++ let dist_cfg = NumaDistConfig::try_parse_from(str_slip_to_clap(numa_dist, true, false))?; ++ dist_cfg.check()?; ++ Ok(dist_cfg) + } + + impl VmConfig { +@@ -238,13 +183,8 @@ impl VmConfig { + /// + /// * `numa_config` - The NUMA node configuration. + pub fn add_numa(&mut self, numa_config: &str) -> Result<()> { +- let mut cmd_params = CmdParser::new("numa"); +- cmd_params.push(""); +- +- cmd_params.get_parameters(numa_config)?; +- if let Some(numa_type) = cmd_params.get_value::("")? { +- self.numa_nodes.push((numa_type, numa_config.to_string())); +- } ++ let numa_type = get_class_type(numa_config).with_context(|| "Numa type not specified")?; ++ self.numa_nodes.push((numa_type, numa_config.to_string())); + + Ok(()) + } +@@ -258,17 +198,15 @@ mod tests { + fn test_parse_numa_mem() { + let mut vm_config = VmConfig::default(); + assert!(vm_config +- .add_numa("-numa node,nodeid=0,cpus=0-1,memdev=mem0") +- .is_ok()); +- assert!(vm_config +- .add_numa("-numa node,nodeid=1,cpus=2-1,memdev=mem1") ++ .add_numa("node,nodeid=0,cpus=0-1,memdev=mem0") + .is_ok()); + assert!(vm_config +- .add_numa("-numa node,nodeid=2,memdev=mem2") ++ .add_numa("node,nodeid=1,cpus=2-1,memdev=mem1") + .is_ok()); +- assert!(vm_config.add_numa("-numa node,nodeid=3,cpus=3-4").is_ok()); ++ assert!(vm_config.add_numa("node,nodeid=2,memdev=mem2").is_ok()); ++ assert!(vm_config.add_numa("node,nodeid=3,cpus=3-4").is_ok()); + assert!(vm_config +- .add_numa("-numa node,nodeid=0,cpus=[0-1:3-5],memdev=mem0") ++ .add_numa("node,nodeid=0,cpus=[0-1:3-5],memdev=mem0") + .is_ok()); + + let numa = vm_config.numa_nodes.get(0).unwrap(); +@@ -291,17 +229,17 @@ mod tests { + #[test] + fn test_parse_numa_distance() { + let mut vm_config = VmConfig::default(); +- assert!(vm_config.add_numa("-numa dist,src=0,dst=1,val=15").is_ok()); +- assert!(vm_config.add_numa("-numa dist,dst=1,val=10").is_ok()); +- assert!(vm_config.add_numa("-numa dist,src=0,val=10").is_ok()); +- assert!(vm_config.add_numa("-numa dist,src=0,dst=1").is_ok()); +- assert!(vm_config.add_numa("-numa dist,src=0,dst=1,val=10").is_ok()); ++ assert!(vm_config.add_numa("dist,src=0,dst=1,val=15").is_ok()); ++ assert!(vm_config.add_numa("dist,dst=1,val=10").is_ok()); ++ assert!(vm_config.add_numa("dist,src=0,val=10").is_ok()); ++ assert!(vm_config.add_numa("dist,src=0,dst=1").is_ok()); ++ assert!(vm_config.add_numa("dist,src=0,dst=1,val=10").is_ok()); + + let numa = vm_config.numa_nodes.get(0).unwrap(); +- let dist = parse_numa_distance(numa.1.as_str()).unwrap(); +- assert_eq!(dist.0, 0); +- assert_eq!(dist.1.destination, 1); +- assert_eq!(dist.1.distance, 15); ++ let dist_cfg = parse_numa_distance(numa.1.as_str()).unwrap(); ++ assert_eq!(dist_cfg.numa_id, 0); ++ assert_eq!(dist_cfg.destination, 1); ++ assert_eq!(dist_cfg.distance, 15); + + let numa = vm_config.numa_nodes.get(1).unwrap(); + assert!(parse_numa_distance(numa.1.as_str()).is_err()); +diff --git a/machine_manager/src/config/pci.rs b/machine_manager/src/config/pci.rs +index e1ad498..6642f4f 100644 +--- a/machine_manager/src/config/pci.rs ++++ b/machine_manager/src/config/pci.rs +@@ -13,9 +13,7 @@ + use anyhow::{bail, Context, Result}; + use serde::{Deserialize, Serialize}; + +-use super::error::ConfigError; +-use super::{CmdParser, ConfigCheck, UnsignedInteger}; +-use crate::config::{check_arg_too_long, ExBool}; ++use super::get_value_of_parameter; + use util::num_ops::str_to_num; + + /// Basic information of pci devices such as bus number, +@@ -43,30 +41,6 @@ impl Default for PciBdf { + } + } + +-/// Basic information of RootPort like port number. +-#[derive(Debug, Clone)] +-pub struct RootPortConfig { +- pub port: u8, +- pub id: String, +- pub multifunction: bool, +-} +- +-impl ConfigCheck for RootPortConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "root_port id") +- } +-} +- +-impl Default for RootPortConfig { +- fn default() -> Self { +- RootPortConfig { +- port: 0, +- id: "".to_string(), +- multifunction: false, +- } +- } +-} +- + pub fn get_pci_df(addr: &str) -> Result<(u8, u8)> { + let addr_vec: Vec<&str> = addr.split('.').collect(); + if addr_vec.len() > 2 { +@@ -96,89 +70,15 @@ pub fn get_pci_df(addr: &str) -> Result<(u8, u8)> { + } + + pub fn get_pci_bdf(pci_cfg: &str) -> Result { +- let mut cmd_parser = CmdParser::new("bdf"); +- cmd_parser.push("").push("bus").push("addr"); +- cmd_parser.get_parameters(pci_cfg)?; +- +- let mut pci_bdf = PciBdf { +- bus: cmd_parser +- .get_value::("bus")? +- .with_context(|| "Bus not specified for pci device")?, +- ..Default::default() +- }; +- if let Some(addr) = cmd_parser.get_value::("addr")? { +- pci_bdf.addr = get_pci_df(&addr).with_context(|| "Failed to get addr")?; +- } else { +- bail!("No addr found for pci device"); ++ let bus = get_value_of_parameter("bus", pci_cfg)?; ++ let addr_str = get_value_of_parameter("addr", pci_cfg)?; ++ if addr_str.is_empty() { ++ bail!("Invalid addr."); + } +- Ok(pci_bdf) +-} +- +-pub fn get_multi_function(pci_cfg: &str) -> Result { +- let mut cmd_parser = CmdParser::new("multifunction"); +- cmd_parser.push("").push("multifunction"); +- cmd_parser.get_parameters(pci_cfg)?; +- +- if let Some(multi_func) = cmd_parser +- .get_value::("multifunction") +- .with_context(|| "Failed to get multifunction parameter, please set on or off (default).")? +- { +- return Ok(multi_func.inner); +- } +- +- Ok(false) +-} +- +-pub fn parse_root_port(rootport_cfg: &str) -> Result { +- let mut cmd_parser = CmdParser::new("pcie-root-port"); +- cmd_parser +- .push("") +- .push("bus") +- .push("addr") +- .push("port") +- .push("chassis") +- .push("multifunction") +- .push("id"); +- cmd_parser.parse(rootport_cfg)?; +- +- let root_port = RootPortConfig { +- port: cmd_parser +- .get_value::("port")? +- .with_context(|| { +- ConfigError::FieldIsMissing("port".to_string(), "rootport".to_string()) +- })? +- .0 as u8, +- id: cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "rootport".to_string()) +- })?, +- multifunction: cmd_parser +- .get_value::("multifunction")? +- .map_or(false, bool::from), +- }; +- +- let _ = cmd_parser.get_value::("chassis")?; ++ let addr = get_pci_df(&addr_str).with_context(|| "Failed to get addr")?; ++ let pci_bdf = PciBdf::new(bus, addr); + +- root_port.check()?; +- Ok(root_port) +-} +- +-pub fn pci_args_check(cmd_parser: &CmdParser) -> Result<()> { +- let device_type = cmd_parser.get_value::("")?; +- let dev_type = device_type.unwrap(); +- // Safe, because this function only be called when certain +- // devices type are added. +- if dev_type.ends_with("-device") { +- if cmd_parser.get_value::("bus")?.is_some() { +- bail!("virtio mmio device does not support bus arguments"); +- } +- if cmd_parser.get_value::("addr")?.is_some() { +- bail!("virtio mmio device does not support addr arguments"); +- } +- if cmd_parser.get_value::("multifunction")?.is_some() { +- bail!("virtio mmio device does not support multifunction arguments"); +- } +- } +- Ok(()) ++ Ok(pci_bdf) + } + + #[cfg(test)] +@@ -241,26 +141,4 @@ mod tests { + let pci_bdf = get_pci_bdf("virtio-balloon-device,addr=0x1.0x2"); + assert!(pci_bdf.is_err()); + } +- +- #[test] +- fn test_get_multi_function() { +- assert_eq!( +- get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2").unwrap(), +- false +- ); +- assert_eq!( +- get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=on") +- .unwrap(), +- true +- ); +- assert_eq!( +- get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=off") +- .unwrap(), +- false +- ); +- assert!(get_multi_function( +- "virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=close" +- ) +- .is_err()); +- } + } +diff --git a/machine_manager/src/config/pvpanic_pci.rs b/machine_manager/src/config/pvpanic_pci.rs +deleted file mode 100644 +index d0c3b87..0000000 +--- a/machine_manager/src/config/pvpanic_pci.rs ++++ /dev/null +@@ -1,66 +0,0 @@ +-// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use crate::config::{CmdParser, ConfigCheck}; +-use anyhow::{bail, Context, Result}; +-use serde::{Deserialize, Serialize}; +- +-pub const PVPANIC_PANICKED: u32 = 1 << 0; +-pub const PVPANIC_CRASHLOADED: u32 = 1 << 1; +- +-#[derive(Debug, Clone, Serialize, Deserialize)] +-pub struct PvpanicDevConfig { +- pub id: String, +- pub supported_features: u32, +-} +- +-impl Default for PvpanicDevConfig { +- fn default() -> Self { +- PvpanicDevConfig { +- id: "".to_string(), +- supported_features: PVPANIC_PANICKED | PVPANIC_CRASHLOADED, +- } +- } +-} +- +-impl ConfigCheck for PvpanicDevConfig { +- fn check(&self) -> Result<()> { +- Ok(()) +- } +-} +- +-pub fn parse_pvpanic(args_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("pvpanic"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("supported-features"); +- cmd_parser.parse(args_config)?; +- +- let mut pvpanicdevcfg = PvpanicDevConfig::default(); +- +- if let Some(features) = cmd_parser.get_value::("supported-features")? { +- pvpanicdevcfg.supported_features = +- match features & !(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) { +- 0 => features, +- _ => bail!("Unsupported pvpanic device features {}", features), +- } +- } +- +- pvpanicdevcfg.id = cmd_parser +- .get_value::("id")? +- .with_context(|| "No id configured for pvpanic device")?; +- +- Ok(pvpanicdevcfg) +-} +diff --git a/machine_manager/src/config/rng.rs b/machine_manager/src/config/rng.rs +index b153dcf..78c3ef7 100644 +--- a/machine_manager/src/config/rng.rs ++++ b/machine_manager/src/config/rng.rs +@@ -10,243 +10,18 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use serde::{Deserialize, Serialize}; + +-use super::error::ConfigError; +-use super::pci_args_check; +-use crate::config::{CmdParser, ConfigCheck, VmConfig, MAX_PATH_LENGTH}; ++use crate::config::{valid_id, valid_path}; + +-const MIN_BYTES_PER_SEC: u64 = 64; +-const MAX_BYTES_PER_SEC: u64 = 1_000_000_000; +- +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct RngObjConfig { ++ #[arg(long, value_parser = ["rng-random"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, ++ #[arg(long, value_parser = valid_path)] + pub filename: String, + } +- +-/// Config structure for virtio-rng. +-#[derive(Debug, Clone, Default)] +-pub struct RngConfig { +- pub id: String, +- pub random_file: String, +- pub bytes_per_sec: Option, +-} +- +-impl ConfigCheck for RngConfig { +- fn check(&self) -> Result<()> { +- if self.id.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "rng id".to_string(), +- MAX_PATH_LENGTH +- ))); +- } +- +- if self.random_file.len() > MAX_PATH_LENGTH { +- return Err(anyhow!(ConfigError::StringLengthTooLong( +- "rng random file".to_string(), +- MAX_PATH_LENGTH, +- ))); +- } +- +- if let Some(bytes_per_sec) = self.bytes_per_sec { +- if !(MIN_BYTES_PER_SEC..=MAX_BYTES_PER_SEC).contains(&bytes_per_sec) { +- return Err(anyhow!(ConfigError::IllegalValue( +- "The bytes per second of rng device".to_string(), +- MIN_BYTES_PER_SEC, +- true, +- MAX_BYTES_PER_SEC, +- true, +- ))); +- } +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_rng_dev(vm_config: &mut VmConfig, rng_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("rng"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("max-bytes") +- .push("period") +- .push("rng"); +- +- cmd_parser.parse(rng_config)?; +- pci_args_check(&cmd_parser)?; +- let mut rng_cfg = RngConfig::default(); +- let rng = cmd_parser +- .get_value::("rng")? +- .with_context(|| ConfigError::FieldIsMissing("rng".to_string(), "rng".to_string()))?; +- +- rng_cfg.id = cmd_parser.get_value::("id")?.unwrap_or_default(); +- +- if let Some(max) = cmd_parser.get_value::("max-bytes")? { +- if let Some(peri) = cmd_parser.get_value::("period")? { +- let mul = max +- .checked_mul(1000) +- .with_context(|| format!("Illegal max-bytes arguments: {:?}", max))?; +- let div = mul +- .checked_div(peri) +- .with_context(|| format!("Illegal period arguments: {:?}", peri))?; +- rng_cfg.bytes_per_sec = Some(div); +- } else { +- bail!("Argument 'period' is missing"); +- } +- } else if cmd_parser.get_value::("period")?.is_some() { +- bail!("Argument 'max-bytes' is missing"); +- } +- +- rng_cfg.random_file = vm_config +- .object +- .rng_object +- .remove(&rng) +- .map(|rng_object| rng_object.filename) +- .with_context(|| "Object for rng-random device not found")?; +- +- rng_cfg.check()?; +- Ok(rng_cfg) +-} +- +-pub fn parse_rng_obj(object_args: &str) -> Result { +- let mut cmd_params = CmdParser::new("rng-object"); +- cmd_params.push("").push("id").push("filename"); +- +- cmd_params.parse(object_args)?; +- let id = cmd_params +- .get_value::("id")? +- .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "rng-object".to_string()))?; +- let filename = cmd_params +- .get_value::("filename")? +- .with_context(|| { +- ConfigError::FieldIsMissing("filename".to_string(), "rng-object".to_string()) +- })?; +- let rng_obj_cfg = RngObjConfig { id, filename }; +- +- Ok(rng_obj_cfg) +-} +- +-#[cfg(test)] +-mod tests { +- use super::*; +- use crate::config::get_pci_bdf; +- +- #[test] +- fn test_rng_config_cmdline_parser_01() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev(&mut vm_config, "virtio-rng-device,rng=objrng0"); +- assert!(rng_config.is_ok()); +- let config = rng_config.unwrap(); +- assert_eq!(config.random_file, "/path/to/random_file"); +- assert_eq!(config.bytes_per_sec, None); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev( +- &mut vm_config, +- "virtio-rng-device,rng=objrng0,max-bytes=1234,period=1000", +- ); +- assert!(rng_config.is_ok()); +- let config = rng_config.unwrap(); +- assert_eq!(config.random_file, "/path/to/random_file"); +- assert_eq!(config.bytes_per_sec, Some(1234)); +- } +- +- #[test] +- fn test_rng_config_cmdline_parser_02() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev( +- &mut vm_config, +- "virtio-rng-device,rng=objrng0,max-bytes=63,period=1000", +- ); +- assert!(rng_config.is_err()); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev( +- &mut vm_config, +- "virtio-rng-device,rng=objrng0,max-bytes=64,period=1000", +- ); +- assert!(rng_config.is_ok()); +- let config = rng_config.unwrap(); +- assert_eq!(config.random_file, "/path/to/random_file"); +- assert_eq!(config.bytes_per_sec, Some(64)); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev( +- &mut vm_config, +- "virtio-rng-device,rng=objrng0,max-bytes=1000000000,period=1000", +- ); +- assert!(rng_config.is_ok()); +- let config = rng_config.unwrap(); +- assert_eq!(config.random_file, "/path/to/random_file"); +- assert_eq!(config.bytes_per_sec, Some(1000000000)); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_config = parse_rng_dev( +- &mut vm_config, +- "virtio-rng-device,rng=objrng0,max-bytes=1000000001,period=1000", +- ); +- assert!(rng_config.is_err()); +- } +- +- #[test] +- fn test_pci_rng_config_cmdline_parser() { +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_cfg = "virtio-rng-pci,rng=objrng0,bus=pcie.0,addr=0x1.0x3"; +- let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); +- assert!(rng_config.is_ok()); +- let config = rng_config.unwrap(); +- assert_eq!(config.random_file, "/path/to/random_file"); +- assert_eq!(config.bytes_per_sec, None); +- let pci_bdf = get_pci_bdf(rng_cfg); +- assert!(pci_bdf.is_ok()); +- let pci = pci_bdf.unwrap(); +- assert_eq!(pci.bus, "pcie.0".to_string()); +- assert_eq!(pci.addr, (1, 3)); +- +- // object "objrng0" has been removed. +- let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); +- assert!(rng_config.is_err()); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_cfg = "virtio-rng-device,rng=objrng0,bus=pcie.0,addr=0x1.0x3"; +- let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); +- assert!(rng_config.is_err()); +- +- let mut vm_config = VmConfig::default(); +- assert!(vm_config +- .add_object("rng-random,id=objrng0,filename=/path/to/random_file") +- .is_ok()); +- let rng_cfg = "virtio-rng-pci,rng=objrng0,bus=pcie.0,addr=0x1.0x3,multifunction=on"; +- assert!(parse_rng_dev(&mut vm_config, rng_cfg).is_ok()); +- } +-} +diff --git a/machine_manager/src/config/sasl_auth.rs b/machine_manager/src/config/sasl_auth.rs +index 506763a..37b47bc 100644 +--- a/machine_manager/src/config/sasl_auth.rs ++++ b/machine_manager/src/config/sasl_auth.rs +@@ -10,44 +10,33 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use anyhow::{anyhow, Context, Result}; ++use anyhow::{anyhow, Result}; ++use clap::Parser; + use serde::{Deserialize, Serialize}; + +-use crate::config::{ +- ConfigError, {CmdParser, VmConfig}, +-}; ++use crate::config::{str_slip_to_clap, valid_id, ConfigError, VmConfig}; + +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SaslAuthObjConfig { +- /// Object Id. ++ #[arg(long, value_parser = ["authz-simple"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, + /// Authentication User Name. ++ #[arg(long, default_value = "")] + pub identity: String, + } + + impl VmConfig { + pub fn add_saslauth(&mut self, saslauth_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("authz-simple"); +- cmd_parser.push("").push("id").push("identity"); +- cmd_parser.parse(saslauth_config)?; +- +- let mut saslauth = SaslAuthObjConfig { +- id: cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "vnc sasl_auth".to_string()) +- })?, +- ..Default::default() +- }; +- +- if let Some(identity) = cmd_parser.get_value::("identity")? { +- saslauth.identity = identity; +- } +- ++ let saslauth = ++ SaslAuthObjConfig::try_parse_from(str_slip_to_clap(saslauth_config, true, false))?; + let id = saslauth.id.clone(); +- if self.object.sasl_object.get(&id).is_none() { +- self.object.sasl_object.insert(id, saslauth); +- } else { ++ if self.object.sasl_object.get(&id).is_some() { + return Err(anyhow!(ConfigError::IdRepeat("saslauth".to_string(), id))); + } ++ self.object.sasl_object.insert(id, saslauth); + + Ok(()) + } +diff --git a/machine_manager/src/config/scsi.rs b/machine_manager/src/config/scsi.rs +deleted file mode 100644 +index b73833b..0000000 +--- a/machine_manager/src/config/scsi.rs ++++ /dev/null +@@ -1,279 +0,0 @@ +-// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{anyhow, bail, Context, Result}; +- +-use super::{error::ConfigError, pci_args_check, DiskFormat}; +-use crate::config::{ +- check_arg_too_long, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE, +-}; +-use util::aio::AioEngine; +- +-/// According to Virtio Spec. +-/// Max_channel should be 0. +-/// Max_target should be less than or equal to 255. +-pub const VIRTIO_SCSI_MAX_TARGET: u16 = 255; +-/// Max_lun should be less than or equal to 16383 (2^14 - 1). +-pub const VIRTIO_SCSI_MAX_LUN: u16 = 16383; +- +-/// Only support peripheral device addressing format(8 bits for lun) in stratovirt now. +-/// So, max lun id supported is 255 (2^8 - 1). +-const SUPPORT_SCSI_MAX_LUN: u16 = 255; +- +-// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi should be larger than 2. +-const MIN_QUEUE_SIZE_SCSI: u16 = 2; +-// Max size of each virtqueue for virtio-scsi. +-const MAX_QUEUE_SIZE_SCSI: u16 = 1024; +- +-#[derive(Debug, Clone)] +-pub struct ScsiCntlrConfig { +- /// Virtio-scsi-pci device id. +- pub id: String, +- /// Thread name of io handler. +- pub iothread: Option, +- /// Number of scsi cmd queues. +- pub queues: u32, +- /// Boot path of this scsi controller. It's prefix of scsi device's boot path. +- pub boot_prefix: Option, +- /// Virtqueue size for all queues. +- pub queue_size: u16, +-} +- +-impl Default for ScsiCntlrConfig { +- fn default() -> Self { +- ScsiCntlrConfig { +- id: "".to_string(), +- iothread: None, +- // At least 1 cmd queue. +- queues: 1, +- boot_prefix: None, +- queue_size: DEFAULT_VIRTQUEUE_SIZE, +- } +- } +-} +- +-impl ConfigCheck for ScsiCntlrConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.id, "virtio-scsi-pci device id")?; +- +- if self.iothread.is_some() { +- check_arg_too_long(self.iothread.as_ref().unwrap(), "iothread name")?; +- } +- +- if self.queues < 1 || self.queues > MAX_VIRTIO_QUEUE as u32 { +- return Err(anyhow!(ConfigError::IllegalValue( +- "queues number of scsi controller".to_string(), +- 1, +- true, +- MAX_VIRTIO_QUEUE as u64, +- true, +- ))); +- } +- +- if self.queue_size <= MIN_QUEUE_SIZE_SCSI || self.queue_size > MAX_QUEUE_SIZE_SCSI { +- return Err(anyhow!(ConfigError::IllegalValue( +- "virtqueue size of scsi controller".to_string(), +- MIN_QUEUE_SIZE_SCSI as u64, +- false, +- MAX_QUEUE_SIZE_SCSI as u64, +- true +- ))); +- } +- +- if self.queue_size & (self.queue_size - 1) != 0 { +- bail!("Virtqueue size should be power of 2!"); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_scsi_controller( +- drive_config: &str, +- queues_auto: Option, +-) -> Result { +- let mut cmd_parser = CmdParser::new("virtio-scsi-pci"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction") +- .push("iothread") +- .push("num-queues") +- .push("queue-size"); +- +- cmd_parser.parse(drive_config)?; +- +- pci_args_check(&cmd_parser)?; +- +- let mut cntlr_cfg = ScsiCntlrConfig::default(); +- +- if let Some(iothread) = cmd_parser.get_value::("iothread")? { +- cntlr_cfg.iothread = Some(iothread); +- } +- +- cntlr_cfg.id = cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "virtio scsi pci".to_string()) +- })?; +- +- if let Some(queues) = cmd_parser.get_value::("num-queues")? { +- cntlr_cfg.queues = queues; +- } else if let Some(queues) = queues_auto { +- cntlr_cfg.queues = queues as u32; +- } +- +- if let Some(size) = cmd_parser.get_value::("queue-size")? { +- cntlr_cfg.queue_size = size; +- } +- +- cntlr_cfg.check()?; +- Ok(cntlr_cfg) +-} +- +-#[derive(Clone, Debug)] +-pub struct ScsiDevConfig { +- /// Scsi Device id. +- pub id: String, +- /// The image file path. +- pub path_on_host: String, +- /// Serial number of the scsi device. +- pub serial: Option, +- /// Scsi controller which the scsi device attaches to. +- pub cntlr: String, +- /// Scsi device can not do write operation. +- pub read_only: bool, +- /// If true, use direct access io. +- pub direct: bool, +- /// Async IO type. +- pub aio_type: AioEngine, +- /// Boot order. +- pub boot_index: Option, +- /// Scsi four level hierarchical address(host, channel, target, lun). +- pub channel: u8, +- pub target: u8, +- pub lun: u16, +- pub format: DiskFormat, +- pub l2_cache_size: Option, +- pub refcount_cache_size: Option, +-} +- +-impl Default for ScsiDevConfig { +- fn default() -> Self { +- ScsiDevConfig { +- id: "".to_string(), +- path_on_host: "".to_string(), +- serial: None, +- cntlr: "".to_string(), +- read_only: false, +- direct: true, +- aio_type: AioEngine::Native, +- boot_index: None, +- channel: 0, +- target: 0, +- lun: 0, +- format: DiskFormat::Raw, +- l2_cache_size: None, +- refcount_cache_size: None, +- } +- } +-} +- +-pub fn parse_scsi_device(vm_config: &mut VmConfig, drive_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("scsi-device"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("scsi-id") +- .push("lun") +- .push("serial") +- .push("bootindex") +- .push("drive"); +- +- cmd_parser.parse(drive_config)?; +- +- let mut scsi_dev_cfg = ScsiDevConfig::default(); +- +- let scsi_drive = cmd_parser.get_value::("drive")?.with_context(|| { +- ConfigError::FieldIsMissing("drive".to_string(), "scsi device".to_string()) +- })?; +- +- if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { +- scsi_dev_cfg.boot_index = Some(boot_index); +- } +- +- if let Some(serial) = cmd_parser.get_value::("serial")? { +- scsi_dev_cfg.serial = Some(serial); +- } +- +- scsi_dev_cfg.id = cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "scsi device".to_string()) +- })?; +- +- if let Some(bus) = cmd_parser.get_value::("bus")? { +- // Format "$parent_cntlr_name.0" is required by scsi bus. +- let strs = bus.split('.').collect::>(); +- if strs.len() != 2 || strs[1] != "0" { +- bail!("Invalid scsi bus {}", bus); +- } +- scsi_dev_cfg.cntlr = strs[0].to_string(); +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "bus".to_string(), +- "scsi device".to_string() +- ))); +- } +- +- if let Some(target) = cmd_parser.get_value::("scsi-id")? { +- if target > VIRTIO_SCSI_MAX_TARGET as u8 { +- return Err(anyhow!(ConfigError::IllegalValue( +- "scsi-id of scsi device".to_string(), +- 0, +- true, +- VIRTIO_SCSI_MAX_TARGET as u64, +- true, +- ))); +- } +- scsi_dev_cfg.target = target; +- } +- +- if let Some(lun) = cmd_parser.get_value::("lun")? { +- // Do not support Flat space addressing format(14 bits for lun) in stratovirt now. +- // We now support peripheral device addressing format(8 bits for lun). +- // So, MAX_LUN should be less than 255(2^8 - 1) temporarily. +- if lun > SUPPORT_SCSI_MAX_LUN { +- return Err(anyhow!(ConfigError::IllegalValue( +- "lun of scsi device".to_string(), +- 0, +- true, +- SUPPORT_SCSI_MAX_LUN as u64, +- true, +- ))); +- } +- scsi_dev_cfg.lun = lun; +- } +- +- let drive_arg = &vm_config +- .drives +- .remove(&scsi_drive) +- .with_context(|| "No drive configured matched for scsi device")?; +- scsi_dev_cfg.path_on_host = drive_arg.path_on_host.clone(); +- scsi_dev_cfg.read_only = drive_arg.read_only; +- scsi_dev_cfg.direct = drive_arg.direct; +- scsi_dev_cfg.aio_type = drive_arg.aio; +- scsi_dev_cfg.format = drive_arg.format; +- scsi_dev_cfg.l2_cache_size = drive_arg.l2_cache_size; +- scsi_dev_cfg.refcount_cache_size = drive_arg.refcount_cache_size; +- +- Ok(scsi_dev_cfg) +-} +diff --git a/machine_manager/src/config/smbios.rs b/machine_manager/src/config/smbios.rs +index 2c8f0d9..75220f4 100644 +--- a/machine_manager/src/config/smbios.rs ++++ b/machine_manager/src/config/smbios.rs +@@ -12,74 +12,138 @@ + + use std::str::FromStr; + +-use anyhow::{bail, Context, Result}; ++use anyhow::{anyhow, bail, Result}; ++use clap::Parser; + use serde::{Deserialize, Serialize}; + +-use crate::config::{CmdParser, VmConfig}; ++use super::{get_value_of_parameter, str_slip_to_clap}; ++use crate::config::VmConfig; + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType0Config { +- pub vender: Option, ++ #[arg(long, alias = "type", value_parser = ["0"])] ++ pub smbios_type: String, ++ #[arg(long)] ++ pub vendor: Option, ++ #[arg(long)] + pub version: Option, ++ #[arg(long)] + pub date: Option, ++ // Note: we don't set `ArgAction::Append` for `added`, so it cannot be specified ++ // from the command line, as command line will parse errors. ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType1Config { ++ #[arg(long, alias = "type", value_parser = ["1"])] ++ pub smbios_type: String, ++ #[arg(long)] + pub manufacturer: Option, ++ #[arg(long)] + pub product: Option, ++ #[arg(long)] + pub version: Option, ++ #[arg(long)] + pub serial: Option, ++ #[arg(long)] + pub sku: Option, ++ #[arg(long)] + pub family: Option, ++ #[arg(long, value_parser = get_uuid)] + pub uuid: Option, ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType2Config { ++ #[arg(long, alias = "type", value_parser = ["2"])] ++ pub smbios_type: String, ++ #[arg(long)] + pub manufacturer: Option, ++ #[arg(long)] + pub product: Option, ++ #[arg(long)] + pub version: Option, ++ #[arg(long)] + pub serial: Option, ++ #[arg(long)] + pub asset: Option, ++ #[arg(long)] + pub location: Option, ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType3Config { ++ #[arg(long, alias = "type", value_parser = ["3"])] ++ pub smbios_type: String, ++ #[arg(long)] + pub manufacturer: Option, ++ #[arg(long)] + pub version: Option, ++ #[arg(long)] + pub serial: Option, ++ #[arg(long)] + pub sku: Option, ++ #[arg(long)] + pub asset: Option, ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType4Config { ++ #[arg(long, alias = "type", value_parser = ["4"])] ++ pub smbios_type: String, ++ #[arg(long)] + pub manufacturer: Option, ++ #[arg(long)] + pub version: Option, ++ #[arg(long)] + pub serial: Option, ++ #[arg(long)] + pub asset: Option, ++ #[arg(long, alias = "sock_pfx")] + pub sock_pfx: Option, ++ #[arg(long)] + pub part: Option, ++ #[arg(long)] + pub max_speed: Option, ++ #[arg(long)] + pub current_speed: Option, ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +-#[derive(Clone, Default, Debug, Serialize, Deserialize)] ++#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct SmbiosType17Config { ++ #[arg(long, alias = "type", value_parser = ["17"])] ++ pub smbios_type: String, ++ #[arg(long)] + pub manufacturer: Option, ++ #[arg(long)] + pub serial: Option, ++ #[arg(long)] + pub asset: Option, ++ #[arg(long, alias = "loc_pfx")] + pub loc_pfx: Option, ++ #[arg(long)] + pub part: Option, ++ #[arg(long, default_value = "0")] + pub speed: u16, ++ #[arg(long)] + pub bank: Option, ++ #[arg(long, default_value = "true")] + pub added: bool, + } + +@@ -124,13 +188,13 @@ pub struct Uuid { + } + + impl FromStr for Uuid { +- type Err = (); ++ type Err = anyhow::Error; + + fn from_str(str: &str) -> std::result::Result { + let name = str.to_string(); + + if !check_valid_uuid(&name) { +- return Err(()); ++ return Err(anyhow!("Invalid uuid {}", name)); + } + + let mut uuid_bytes = Vec::new(); +@@ -149,6 +213,11 @@ impl FromStr for Uuid { + } + } + ++fn get_uuid(s: &str) -> Result { ++ let uuid = Uuid::from_str(s)?; ++ Ok(uuid) ++} ++ + impl VmConfig { + /// # Arguments + /// +@@ -158,19 +227,8 @@ impl VmConfig { + bail!("smbios type0 has been added"); + } + +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("vendor") +- .push("version") +- .push("date"); +- cmd_parser.parse(type0)?; +- +- self.smbios.type0.vender = cmd_parser.get_value::("vendor")?; +- self.smbios.type0.version = cmd_parser.get_value::("version")?; +- self.smbios.type0.date = cmd_parser.get_value::("date")?; +- self.smbios.type0.added = true; ++ let type0_cfg = SmbiosType0Config::try_parse_from(str_slip_to_clap(type0, false, false))?; ++ self.smbios.type0 = type0_cfg; + + Ok(()) + } +@@ -183,27 +241,8 @@ impl VmConfig { + bail!("smbios type1 has been added"); + } + +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("manufacturer") +- .push("product") +- .push("version") +- .push("serial") +- .push("sku") +- .push("uuid") +- .push("family"); +- cmd_parser.parse(type1)?; +- +- self.smbios.type1.manufacturer = cmd_parser.get_value::("manufacturer")?; +- self.smbios.type1.product = cmd_parser.get_value::("product")?; +- self.smbios.type1.version = cmd_parser.get_value::("version")?; +- self.smbios.type1.serial = cmd_parser.get_value::("serial")?; +- self.smbios.type1.sku = cmd_parser.get_value::("sku")?; +- self.smbios.type1.family = cmd_parser.get_value::("family")?; +- self.smbios.type1.uuid = cmd_parser.get_value::("uuid")?; +- self.smbios.type1.added = true; ++ let type1_cfg = SmbiosType1Config::try_parse_from(str_slip_to_clap(type1, false, false))?; ++ self.smbios.type1 = type1_cfg; + + Ok(()) + } +@@ -215,26 +254,8 @@ impl VmConfig { + if self.smbios.type2.added { + bail!("smbios type2 has been added"); + } +- +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("manufacturer") +- .push("product") +- .push("version") +- .push("serial") +- .push("asset") +- .push("location"); +- cmd_parser.parse(type2)?; +- +- self.smbios.type2.manufacturer = cmd_parser.get_value::("manufacturer")?; +- self.smbios.type2.product = cmd_parser.get_value::("product")?; +- self.smbios.type2.version = cmd_parser.get_value::("version")?; +- self.smbios.type2.serial = cmd_parser.get_value::("serial")?; +- self.smbios.type2.asset = cmd_parser.get_value::("asset")?; +- self.smbios.type2.location = cmd_parser.get_value::("location")?; +- self.smbios.type2.added = true; ++ let type2_cfg = SmbiosType2Config::try_parse_from(str_slip_to_clap(type2, false, false))?; ++ self.smbios.type2 = type2_cfg; + + Ok(()) + } +@@ -247,23 +268,8 @@ impl VmConfig { + bail!("smbios type3 has been added"); + } + +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("manufacturer") +- .push("version") +- .push("serial") +- .push("sku") +- .push("asset"); +- cmd_parser.parse(type3)?; +- +- self.smbios.type3.manufacturer = cmd_parser.get_value::("manufacturer")?; +- self.smbios.type3.version = cmd_parser.get_value::("version")?; +- self.smbios.type3.serial = cmd_parser.get_value::("serial")?; +- self.smbios.type3.sku = cmd_parser.get_value::("sku")?; +- self.smbios.type3.asset = cmd_parser.get_value::("asset")?; +- self.smbios.type3.added = true; ++ let type3_cfg = SmbiosType3Config::try_parse_from(str_slip_to_clap(type3, false, false))?; ++ self.smbios.type3 = type3_cfg; + + Ok(()) + } +@@ -276,29 +282,8 @@ impl VmConfig { + bail!("smbios type4 has been added"); + } + +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("manufacturer") +- .push("version") +- .push("serial") +- .push("sock_pfx") +- .push("max-speed") +- .push("current-speed") +- .push("part") +- .push("asset"); +- cmd_parser.parse(type4)?; +- +- self.smbios.type4.manufacturer = cmd_parser.get_value::("manufacturer")?; +- self.smbios.type4.version = cmd_parser.get_value::("version")?; +- self.smbios.type4.serial = cmd_parser.get_value::("serial")?; +- self.smbios.type4.asset = cmd_parser.get_value::("asset")?; +- self.smbios.type4.part = cmd_parser.get_value::("part")?; +- self.smbios.type4.sock_pfx = cmd_parser.get_value::("sock_pfx")?; +- self.smbios.type4.max_speed = cmd_parser.get_value::("max-speed")?; +- self.smbios.type4.current_speed = cmd_parser.get_value::("current-speed")?; +- self.smbios.type4.added = true; ++ let type4_cfg = SmbiosType4Config::try_parse_from(str_slip_to_clap(type4, false, false))?; ++ self.smbios.type4 = type4_cfg; + + Ok(()) + } +@@ -311,31 +296,9 @@ impl VmConfig { + bail!("smbios type17 has been added"); + } + +- let mut cmd_parser = CmdParser::new("smbios"); +- cmd_parser +- .push("") +- .push("type") +- .push("loc_pfx") +- .push("bank") +- .push("manufacturer") +- .push("serial") +- .push("speed") +- .push("part") +- .push("asset"); +- cmd_parser.parse(type17)?; +- +- self.smbios.type17.manufacturer = cmd_parser.get_value::("manufacturer")?; +- self.smbios.type17.loc_pfx = cmd_parser.get_value::("loc_pfx")?; +- self.smbios.type17.serial = cmd_parser.get_value::("serial")?; +- self.smbios.type17.asset = cmd_parser.get_value::("asset")?; +- self.smbios.type17.part = cmd_parser.get_value::("part")?; +- self.smbios.type17.speed = if let Some(speed) = cmd_parser.get_value::("speed")? { +- speed +- } else { +- 0 +- }; +- self.smbios.type17.bank = cmd_parser.get_value::("bank")?; +- self.smbios.type17.added = true; ++ let type17_cfg = ++ SmbiosType17Config::try_parse_from(str_slip_to_clap(type17, false, false))?; ++ self.smbios.type17 = type17_cfg; + + Ok(()) + } +@@ -346,13 +309,7 @@ impl VmConfig { + /// + /// * `smbios_args` - The args of object. + pub fn add_smbios(&mut self, smbios_args: &str) -> Result<()> { +- let mut cmd_params = CmdParser::new("smbios"); +- cmd_params.push("").push("type"); +- +- cmd_params.get_parameters(smbios_args)?; +- let smbios_type = cmd_params +- .get_value::("type")? +- .with_context(|| "smbios type not specified")?; ++ let smbios_type = get_value_of_parameter("type", smbios_args)?; + match smbios_type.as_str() { + "0" => { + self.add_smbios_type0(smbios_args)?; +@@ -397,4 +354,24 @@ mod test { + ] + ); + } ++ ++ #[test] ++ fn test_add_smbios() { ++ let mut vm_config = VmConfig::default(); ++ ++ let smbios0 = "type=0,vendor=fake,version=fake,date=fake"; ++ let smbios1 = "type=1,manufacturer=fake,version=fake,product=fake,serial=fake,uuid=33DB4D5E-1FF7-401C-9657-7441C03DD766,sku=fake,family=fake"; ++ let smbios2 = "type=2,manufacturer=fake,product=fake,version=fake,serial=fake,asset=fake,location=fake"; ++ let smbios3 = "type=3,manufacturer=fake,version=fake,serial=fake,asset=fake,sku=fake"; ++ let smbios4 = "type=4,sock_pfx=fake,manufacturer=fake,version=fake,serial=fake,asset=fake,part=fake,max-speed=1,current-speed=1"; ++ let smbios17 = "type=17,loc_pfx=fake,bank=fake,manufacturer=fake,serial=fake,asset=fake,part=fake,speed=1"; ++ ++ assert!(vm_config.add_smbios(smbios0).is_ok()); ++ assert!(vm_config.add_smbios(smbios1).is_ok()); ++ assert!(vm_config.add_smbios(smbios2).is_ok()); ++ assert!(vm_config.add_smbios(smbios3).is_ok()); ++ assert!(vm_config.add_smbios(smbios4).is_ok()); ++ assert!(vm_config.add_smbios(smbios17).is_ok()); ++ assert!(vm_config.add_smbios(smbios0).is_err()); ++ } + } +diff --git a/machine_manager/src/config/tls_creds.rs b/machine_manager/src/config/tls_creds.rs +index 8803ea4..9290316 100644 +--- a/machine_manager/src/config/tls_creds.rs ++++ b/machine_manager/src/config/tls_creds.rs +@@ -10,64 +10,36 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use std::path::Path; +- +-use anyhow::{anyhow, Context, Result}; ++use anyhow::{anyhow, Result}; ++use clap::{ArgAction, Parser}; + use serde::{Deserialize, Serialize}; + +-use crate::config::{ +- ConfigError, {CmdParser, VmConfig}, +-}; ++use crate::config::{str_slip_to_clap, valid_dir, valid_id, ConfigError, VmConfig}; + +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct TlsCredObjConfig { ++ #[arg(long)] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] + pub id: String, ++ #[arg(long, value_parser = valid_dir)] + pub dir: String, +- pub cred_type: String, ++ #[arg(long)] + pub endpoint: Option, ++ #[arg(long, alias = "verify-peer", default_value= "false", action = ArgAction::Append)] + pub verifypeer: bool, + } + + impl VmConfig { + pub fn add_tlscred(&mut self, tlscred_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("tls-creds-x509"); +- cmd_parser +- .push("") +- .push("id") +- .push("dir") +- .push("endpoint") +- .push("verify-peer"); +- cmd_parser.parse(tlscred_config)?; +- +- let mut tlscred = TlsCredObjConfig { +- id: cmd_parser.get_value::("id")?.with_context(|| { +- ConfigError::FieldIsMissing("id".to_string(), "vnc tls_creds".to_string()) +- })?, +- ..Default::default() +- }; +- +- if let Some(dir) = cmd_parser.get_value::("dir")? { +- if Path::new(&dir).is_dir() { +- tlscred.dir = dir; +- } else { +- return Err(anyhow!(ConfigError::DirNotExist(dir))); +- } +- } +- if let Some(endpoint) = cmd_parser.get_value::("endpoint")? { +- tlscred.endpoint = Some(endpoint); +- } +- if let Some(verifypeer) = cmd_parser.get_value::("verify-peer")? { +- tlscred.verifypeer = verifypeer == *"true"; +- } +- tlscred.cred_type = "x509".to_string(); +- ++ let tlscred = ++ TlsCredObjConfig::try_parse_from(str_slip_to_clap(tlscred_config, true, false))?; + let id = tlscred.id.clone(); +- if self.object.tls_object.get(&id).is_none() { +- self.object.tls_object.insert(id, tlscred); +- } else { ++ if self.object.tls_object.get(&id).is_some() { + return Err(anyhow!(ConfigError::IdRepeat("tlscred".to_string(), id))); + } +- ++ self.object.tls_object.insert(id, tlscred); + Ok(()) + } + } +diff --git a/machine_manager/src/config/usb.rs b/machine_manager/src/config/usb.rs +deleted file mode 100644 +index da363b7..0000000 +--- a/machine_manager/src/config/usb.rs ++++ /dev/null +@@ -1,99 +0,0 @@ +-// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{bail, Context, Result}; +- +-use super::error::ConfigError; +-use crate::config::{ +- check_arg_nonexist, check_arg_too_long, CmdParser, ConfigCheck, ScsiDevConfig, VmConfig, +-}; +-use util::aio::AioEngine; +- +-pub fn check_id(id: Option, device: &str) -> Result<()> { +- check_arg_nonexist(id.clone(), "id", device)?; +- check_arg_too_long(&id.unwrap(), "id")?; +- +- Ok(()) +-} +- +-#[derive(Clone, Debug)] +-pub struct UsbStorageConfig { +- /// USB Storage device id. +- pub id: Option, +- /// The scsi backend config. +- pub scsi_cfg: ScsiDevConfig, +- /// The backend scsi device type(Disk or CD-ROM). +- pub media: String, +-} +- +-impl UsbStorageConfig { +- fn new() -> Self { +- Self { +- id: None, +- scsi_cfg: ScsiDevConfig::default(), +- media: "".to_string(), +- } +- } +-} +- +-impl Default for UsbStorageConfig { +- fn default() -> Self { +- Self::new() +- } +-} +- +-impl ConfigCheck for UsbStorageConfig { +- fn check(&self) -> Result<()> { +- check_id(self.id.clone(), "usb-storage")?; +- +- if self.scsi_cfg.aio_type != AioEngine::Off || self.scsi_cfg.direct { +- bail!("USB-storage: \"aio=off,direct=false\" must be configured."); +- } +- +- Ok(()) +- } +-} +- +-pub fn parse_usb_storage(vm_config: &mut VmConfig, drive_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("usb-storage"); +- cmd_parser +- .push("") +- .push("id") +- .push("bus") +- .push("port") +- .push("drive"); +- +- cmd_parser.parse(drive_config)?; +- +- let mut dev = UsbStorageConfig::new(); +- dev.id = cmd_parser.get_value::("id")?; +- +- let storage_drive = cmd_parser.get_value::("drive")?.with_context(|| { +- ConfigError::FieldIsMissing("drive".to_string(), "usb storage device".to_string()) +- })?; +- +- let drive_arg = &vm_config +- .drives +- .remove(&storage_drive) +- .with_context(|| "No drive configured matched for usb storage device.")?; +- dev.scsi_cfg.path_on_host = drive_arg.path_on_host.clone(); +- dev.scsi_cfg.read_only = drive_arg.read_only; +- dev.scsi_cfg.aio_type = drive_arg.aio; +- dev.scsi_cfg.direct = drive_arg.direct; +- dev.scsi_cfg.format = drive_arg.format; +- dev.scsi_cfg.l2_cache_size = drive_arg.l2_cache_size; +- dev.scsi_cfg.refcount_cache_size = drive_arg.refcount_cache_size; +- dev.media = drive_arg.media.clone(); +- +- dev.check()?; +- Ok(dev) +-} +diff --git a/machine_manager/src/config/vfio.rs b/machine_manager/src/config/vfio.rs +deleted file mode 100644 +index dddebde..0000000 +--- a/machine_manager/src/config/vfio.rs ++++ /dev/null +@@ -1,134 +0,0 @@ +-// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt is licensed under Mulan PSL v2. +-// You can use this software according to the terms and conditions of the Mulan +-// PSL v2. +-// You may obtain a copy of Mulan PSL v2 at: +-// http://license.coscl.org.cn/MulanPSL2 +-// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +-// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +-// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +-// See the Mulan PSL v2 for more details. +- +-use anyhow::{anyhow, Result}; +- +-use super::error::ConfigError; +-use crate::config::{check_arg_too_long, CmdParser, ConfigCheck}; +- +-#[derive(Default, Debug)] +-pub struct VfioConfig { +- pub sysfsdev: String, +- pub host: String, +- pub id: String, +-} +- +-impl ConfigCheck for VfioConfig { +- fn check(&self) -> Result<()> { +- check_arg_too_long(&self.host, "host")?; +- check_arg_too_long(&self.id, "id")?; +- +- Ok(()) +- } +-} +- +-pub fn parse_vfio(vfio_config: &str) -> Result { +- let mut cmd_parser = CmdParser::new("vfio-pci"); +- cmd_parser +- .push("") +- .push("host") +- .push("sysfsdev") +- .push("id") +- .push("bus") +- .push("addr") +- .push("multifunction"); +- cmd_parser.parse(vfio_config)?; +- +- let mut vfio: VfioConfig = VfioConfig::default(); +- if let Some(host) = cmd_parser.get_value::("host")? { +- vfio.host = host; +- } +- +- if let Some(sysfsdev) = cmd_parser.get_value::("sysfsdev")? { +- vfio.sysfsdev = sysfsdev; +- } +- +- if vfio.host.is_empty() && vfio.sysfsdev.is_empty() { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "host nor sysfsdev".to_string(), +- "vfio".to_string() +- ))); +- } +- +- if !vfio.host.is_empty() && !vfio.sysfsdev.is_empty() { +- return Err(anyhow!(ConfigError::InvalidParam( +- "host and sysfsdev".to_string(), +- "vfio".to_string() +- ))); +- } +- +- if let Some(id) = cmd_parser.get_value::("id")? { +- vfio.id = id; +- } +- vfio.check()?; +- +- Ok(vfio) +-} +- +-#[cfg(test)] +-mod tests { +- use super::*; +- use crate::config::get_pci_bdf; +- +- #[test] +- fn test_check_vfio_config() { +- let mut vfio_config = +- parse_vfio("vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2").unwrap(); +- assert!(vfio_config.check().is_ok()); +- +- vfio_config.host = "IYqUdAMXggoUMU28eBJCxQGUirYYSyW1cfGJI3ZpZAzMFCKnVPA5e7gnurLtXjCm\ +- YoG5pfqRDbN7M2dpSd8fzSbufAJaor8UY9xbH7BybZ7WDEFmkxgCQp6PWgaBSmLOCe1tEMs4RQ938ZLnh8ej\ +- Q81VovbrU7ecafacCn9AJQoidN3Seab3QOEd4SJbtd4hAPeYvsXLVa6xOZxtVjqjRxk9b36feF0C5JrucVcs\ +- QsusZZtVfUFUZxOoV8JltVsBmdasnic" +- .to_string(); +- assert!(vfio_config.check().is_err()); +- +- vfio_config.id = "LPwM1h4QUTCjL4fX2gFdCdPrF9S0kGHf0onpU6E4fyI6Jmzg0DCM9sffvEVjaVu1ilp\ +- 2OrgCWzvNBflYvUUihPj3ePPYs3erSHmSOmQZbnGEFsiBSTJHfPAsRtWJoipeIh9cgIR1tnU3OjwPPli4gmb6\ +- E6GgSyMd0oQtUGFyNf5pRHlYqlx3s7PMPVUtRJP0bBnNd5eDwWAotInu33h6UI0zfKgckAxeVdEROKAExx5xWK\ +- V3AgPhvvPzFx3chYymy" +- .to_string(); +- assert!(vfio_config.check().is_err()); +- } +- +- #[test] +- fn test_vfio_config_cmdline_parser() { +- let vfio_cfg = parse_vfio("vfio-pci,host=0000:1a:00.3,id=net"); +- assert!(vfio_cfg.is_ok()); +- let vfio_config = vfio_cfg.unwrap(); +- assert_eq!(vfio_config.host, "0000:1a:00.3"); +- assert_eq!(vfio_config.id, "net"); +- } +- +- #[test] +- fn test_pci_vfio_config_cmdline_parser() { +- let vfio_cfg1 = "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2"; +- let config1 = parse_vfio(vfio_cfg1); +- assert!(config1.is_ok()); +- let vfio_cfg2 = "vfio-pci,host=0000:1a:00.3,bus=pcie.0,addr=0x1.0x2"; +- let config2 = parse_vfio(vfio_cfg2); +- assert!(config2.is_ok()); +- let vfio_cfg3 = "vfio-pci,id=net,bus=pcie.0,addr=0x1.0x2"; +- let config3 = parse_vfio(vfio_cfg3); +- assert!(config3.is_err()); +- +- let pci_bdf = get_pci_bdf(vfio_cfg1); +- assert!(pci_bdf.is_ok()); +- let pci = pci_bdf.unwrap(); +- assert_eq!(pci.bus, "pcie.0".to_string()); +- assert_eq!(pci.addr, (1, 2)); +- +- let vfio_cfg1 = +- "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2,multifunction=on"; +- assert!(parse_vfio(vfio_cfg1).is_ok()); +- } +-} +diff --git a/machine_manager/src/config/vnc.rs b/machine_manager/src/config/vnc.rs +index b243d94..ca1fd10 100644 +--- a/machine_manager/src/config/vnc.rs ++++ b/machine_manager/src/config/vnc.rs +@@ -13,22 +13,26 @@ + use std::net::Ipv4Addr; + + use anyhow::{anyhow, Context, Result}; ++use clap::{ArgAction, Parser}; + use serde::{Deserialize, Serialize}; + +-use crate::config::{CmdParser, ConfigError, VmConfig}; ++use crate::config::{str_slip_to_clap, ConfigError, VmConfig}; + + /// Configuration of vnc. +-#[derive(Debug, Clone, Default, Serialize, Deserialize)] ++#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] ++#[command(no_binary_name(true))] + pub struct VncConfig { +- /// Listening ip. +- pub ip: String, +- /// Listening port. +- pub port: String, ++ /// Vnc listening addr (ip, port). ++ #[arg(long, alias = "classtype", value_parser = parse_ip_port)] ++ pub addr: (String, u16), + /// Configuration of encryption. ++ #[arg(long, alias = "tls-creds", default_value = "")] + pub tls_creds: String, + /// Authentication switch. ++ #[arg(long, default_value = "false", action = ArgAction::SetTrue)] + pub sasl: bool, + /// Configuration of authentication. ++ #[arg(long, alias = "sasl-authz", default_value = "")] + pub sasl_authz: String, + } + +@@ -38,45 +42,13 @@ const VNC_PORT_OFFSET: i32 = 5900; + impl VmConfig { + /// Make configuration for vnc: "chardev" -> "vnc". + pub fn add_vnc(&mut self, vnc_config: &str) -> Result<()> { +- let mut cmd_parser = CmdParser::new("vnc"); +- cmd_parser +- .push("") +- .push("tls-creds") +- .push("sasl") +- .push("sasl-authz"); +- cmd_parser.parse(vnc_config)?; +- +- let mut vnc_config = VncConfig::default(); +- // Parse Ip:Port. +- if let Some(addr) = cmd_parser.get_value::("")? { +- parse_port(&mut vnc_config, addr)?; +- } else { +- return Err(anyhow!(ConfigError::FieldIsMissing( +- "ip".to_string(), +- "port".to_string() +- ))); +- } +- +- // VNC Security Type. +- if let Some(tls_creds) = cmd_parser.get_value::("tls-creds")? { +- vnc_config.tls_creds = tls_creds +- } +- if let Some(_sasl) = cmd_parser.get_value::("sasl")? { +- vnc_config.sasl = true +- } else { +- vnc_config.sasl = false +- } +- if let Some(sasl_authz) = cmd_parser.get_value::("sasl-authz")? { +- vnc_config.sasl_authz = sasl_authz; +- } +- ++ let vnc_config = VncConfig::try_parse_from(str_slip_to_clap(vnc_config, true, false))?; + self.vnc = Some(vnc_config); + Ok(()) + } + } + +-/// Parse Ip:port. +-fn parse_port(vnc_config: &mut VncConfig, addr: String) -> Result<()> { ++fn parse_ip_port(addr: &str) -> Result<(String, u16)> { + let v: Vec<&str> = addr.split(':').collect(); + if v.len() != 2 { + return Err(anyhow!(ConfigError::FieldIsMissing( +@@ -97,10 +69,8 @@ fn parse_port(vnc_config: &mut VncConfig, addr: String) -> Result<()> { + "port".to_string() + ))); + } +- vnc_config.ip = ip.to_string(); +- vnc_config.port = ((base_port + VNC_PORT_OFFSET) as u16).to_string(); + +- Ok(()) ++ Ok((ip.to_string(), (base_port + VNC_PORT_OFFSET) as u16)) + } + + #[cfg(test)] +@@ -113,8 +83,8 @@ mod tests { + let config_line = "0.0.0.0:1,tls-creds=vnc-tls-creds0,sasl,sasl-authz=authz0"; + assert!(vm_config.add_vnc(config_line).is_ok()); + let vnc_config = vm_config.vnc.unwrap(); +- assert_eq!(vnc_config.ip, String::from("0.0.0.0")); +- assert_eq!(vnc_config.port, String::from("5901")); ++ assert_eq!(vnc_config.addr.0, String::from("0.0.0.0")); ++ assert_eq!(vnc_config.addr.1, 5901); + assert_eq!(vnc_config.tls_creds, String::from("vnc-tls-creds0")); + assert_eq!(vnc_config.sasl, true); + assert_eq!(vnc_config.sasl_authz, String::from("authz0")); +@@ -124,7 +94,7 @@ mod tests { + assert!(vm_config.add_vnc(config_line).is_ok()); + let vnc_config = vm_config.vnc.unwrap(); + assert_eq!(vnc_config.sasl, false); +- assert_eq!(vnc_config.port, String::from("11800")); ++ assert_eq!(vnc_config.addr.1, 11800); + + let mut vm_config = VmConfig::default(); + let config_line = "0.0.0.0:1,sasl,sasl-authz=authz0"; +diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs +index 7acaca8..79d7cf6 100644 +--- a/machine_manager/src/event_loop.rs ++++ b/machine_manager/src/event_loop.rs +@@ -12,7 +12,7 @@ + + use std::collections::HashMap; + use std::os::unix::prelude::RawFd; +-use std::sync::{Arc, Mutex}; ++use std::sync::{Arc, Barrier, Mutex}; + use std::{process, thread}; + + use anyhow::{bail, Result}; +@@ -49,9 +49,18 @@ impl EventLoop { + /// * `iothreads` - refer to `-iothread` params + pub fn object_init(iothreads: &Option>) -> Result<()> { + let mut io_threads = HashMap::new(); ++ let cnt = match iothreads { ++ Some(thrs) => thrs.len(), ++ None => 0, ++ }; ++ let thread_exit_barrier = Arc::new(Barrier::new(cnt + 1)); ++ + if let Some(thrs) = iothreads { + for thr in thrs { +- io_threads.insert(thr.id.clone(), EventLoopContext::new()); ++ io_threads.insert( ++ thr.id.clone(), ++ EventLoopContext::new(thread_exit_barrier.clone()), ++ ); + } + } + +@@ -60,7 +69,7 @@ impl EventLoop { + unsafe { + if GLOBAL_EVENT_LOOP.is_none() { + GLOBAL_EVENT_LOOP = Some(EventLoop { +- main_loop: EventLoopContext::new(), ++ main_loop: EventLoopContext::new(thread_exit_barrier), + io_threads, + }); + +@@ -76,10 +85,11 @@ impl EventLoop { + }; + IOTHREADS.lock().unwrap().push(iothread_info); + while let Ok(ret) = ctx.iothread_run() { +- if !ret { ++ if !ret || get_signal() != 0 { + break; + } + } ++ ctx.thread_exit_barrier.wait(); + })?; + } + } else { +@@ -115,11 +125,16 @@ impl EventLoop { + /// + /// # Arguments + /// +- /// * `manager` - The main part to manager the event loop specified by name. +- /// * `name` - specify which event loop to manage +- pub fn set_manager(manager: Arc>, name: Option<&String>) { +- if let Some(ctx) = Self::get_ctx(name) { +- ctx.set_manager(manager) ++ /// * `manager` - The main part to manager the event loop. ++ pub fn set_manager(manager: Arc>) { ++ // SAFETY: All concurrently accessed data of EventLoopContext is protected. ++ unsafe { ++ if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { ++ event_loop.main_loop.set_manager(manager.clone()); ++ for (_name, io_thread) in event_loop.io_threads.iter_mut() { ++ io_thread.set_manager(manager.clone()); ++ } ++ } + } + } + +@@ -152,10 +167,12 @@ impl EventLoop { + let sig_num = get_signal(); + if sig_num != 0 { + info!("MainLoop exits due to receive signal {}", sig_num); ++ event_loop.main_loop.thread_exit_barrier.wait(); + return Ok(()); + } + if !event_loop.main_loop.run()? { + info!("MainLoop exits due to guest internal operation."); ++ event_loop.main_loop.thread_exit_barrier.wait(); + return Ok(()); + } + } +@@ -172,6 +189,18 @@ impl EventLoop { + GLOBAL_EVENT_LOOP = None; + } + } ++ ++ pub fn kick_all() { ++ // SAFETY: All concurrently accessed data of EventLoopContext is protected. ++ unsafe { ++ if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { ++ for (_name, io_thread) in event_loop.io_threads.iter_mut() { ++ io_thread.kick(); ++ } ++ event_loop.main_loop.kick(); ++ } ++ } ++ } + } + + pub fn register_event_helper( +diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs +index f0f00aa..4579439 100644 +--- a/machine_manager/src/machine.rs ++++ b/machine_manager/src/machine.rs +@@ -11,9 +11,12 @@ + // See the Mulan PSL v2 for more details. + + use std::os::unix::io::RawFd; ++use std::str::FromStr; + use std::sync::Mutex; + ++use anyhow::anyhow; + use once_cell::sync::Lazy; ++use serde::{Deserialize, Serialize}; + use strum::VariantNames; + + use crate::config::ShutdownAction; +@@ -44,10 +47,26 @@ pub enum VmState { + } + + /// Type for Hypervisor. +-#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] ++#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] + pub enum HypervisorType { + #[default] + Kvm, ++ #[cfg(not(target_arch = "riscv64"))] ++ Test, ++} ++ ++impl FromStr for HypervisorType { ++ type Err = anyhow::Error; ++ ++ fn from_str(s: &str) -> std::result::Result { ++ match s { ++ // Note: "kvm:tcg" is a configuration compatible with libvirt. ++ "kvm" | "kvm:tcg" => Ok(HypervisorType::Kvm), ++ #[cfg(not(target_arch = "riscv64"))] ++ "test" => Ok(HypervisorType::Test), ++ _ => Err(anyhow!("Not supported or invalid hypervisor type {}.", s)), ++ } ++ } + } + + /// Trait to handle virtual machine lifecycle. +@@ -251,6 +270,10 @@ pub trait DeviceInterface { + let target = Target { + arch: "aarch64".to_string(), + }; ++ #[cfg(target_arch = "riscv64")] ++ let target = Target { ++ arch: "riscv64".to_string(), ++ }; + Response::create_response(serde_json::to_value(target).unwrap(), None) + } + +@@ -314,6 +337,16 @@ pub trait DeviceInterface { + }; + #[cfg(target_arch = "aarch64")] + vec_machine.push(machine_info); ++ #[cfg(target_arch = "riscv64")] ++ let machine_info = MachineInfo { ++ hotplug: false, ++ name: "virt".to_string(), ++ numa_mem_support: false, ++ cpu_max: 255, ++ deprecated: false, ++ }; ++ #[cfg(target_arch = "riscv64")] ++ vec_machine.push(machine_info); + Response::create_response(serde_json::to_value(&vec_machine).unwrap(), None) + } + +diff --git a/machine_manager/src/qmp/qmp_channel.rs b/machine_manager/src/qmp/qmp_channel.rs +index 42b0f44..a083950 100644 +--- a/machine_manager/src/qmp/qmp_channel.rs ++++ b/machine_manager/src/qmp/qmp_channel.rs +@@ -153,9 +153,10 @@ impl QmpChannel { + pub fn send_event(event: &schema::QmpEvent) { + if Self::is_connected() { + let mut event_str = serde_json::to_string(&event).unwrap(); +- let mut writer_unlocked = Self::inner().event_writer.write().unwrap(); +- let writer = writer_unlocked.as_mut().unwrap(); ++ let mut writer_locked = Self::inner().event_writer.write().unwrap(); ++ let writer = writer_locked.as_mut().unwrap(); + ++ info!("EVENT: --> {:?}", event); + if let Err(e) = writer.flush() { + error!("flush err, {:?}", e); + return; +@@ -163,9 +164,7 @@ impl QmpChannel { + event_str.push_str("\r\n"); + if let Err(e) = writer.write(event_str.as_bytes()) { + error!("write err, {:?}", e); +- return; + } +- info!("EVENT: --> {:?}", event); + } + } + +diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs +index 4281624..e1f9440 100644 +--- a/machine_manager/src/qmp/qmp_schema.rs ++++ b/machine_manager/src/qmp/qmp_schema.rs +@@ -843,6 +843,14 @@ pub enum CpuInfo { + #[serde(rename = "Arm")] + arm: CpuInfoArm, + }, ++ #[serde(rename = "riscv")] ++ RISCV { ++ #[serde(flatten)] ++ common: CpuInfoCommon, ++ #[serde(flatten)] ++ #[serde(rename = "RISCV")] ++ riscv: CpuInfoRISCV, ++ }, + } + + #[derive(Default, Debug, Clone, Serialize, Deserialize)] +@@ -851,6 +859,9 @@ pub struct CpuInfoX86 {} + #[derive(Default, Debug, Clone, Serialize, Deserialize)] + pub struct CpuInfoArm {} + ++#[derive(Default, Debug, Clone, Serialize, Deserialize)] ++pub struct CpuInfoRISCV {} ++ + /// query-status + /// + /// Query the run status of all VCPUs. +diff --git a/machine_manager/src/signal_handler.rs b/machine_manager/src/signal_handler.rs +index 2f1ba86..6d67919 100644 +--- a/machine_manager/src/signal_handler.rs ++++ b/machine_manager/src/signal_handler.rs +@@ -50,7 +50,7 @@ pub fn set_signal(num: c_int) { + unsafe { + RECEIVED_SIGNAL.store(num, Ordering::SeqCst); + } +- EventLoop::get_ctx(None).unwrap().kick(); ++ EventLoop::kick_all(); + } + } + +diff --git a/machine_manager/src/temp_cleaner.rs b/machine_manager/src/temp_cleaner.rs +index e63d273..cd5b2f4 100644 +--- a/machine_manager/src/temp_cleaner.rs ++++ b/machine_manager/src/temp_cleaner.rs +@@ -81,15 +81,12 @@ impl TempCleaner { + while let Some(path) = self.paths.pop() { + if Path::new(&path).exists() { + if let Err(ref e) = fs::remove_file(&path) { +- error!( +- "Failed to delete console / socket file:{} :{} \r\n", +- &path, e +- ); ++ error!("Failed to delete console / socket file:{} :{}", &path, e); + } else { +- info!("Delete file: {} successfully.\r\n", &path); ++ info!("Delete file: {} successfully", &path); + } + } else { +- info!("file: {} has been removed \r\n", &path); ++ info!("file: {} has been removed", &path); + } + } + } +diff --git a/migration/src/manager.rs b/migration/src/manager.rs +index d381ae3..96d9943 100644 +--- a/migration/src/manager.rs ++++ b/migration/src/manager.rs +@@ -175,6 +175,9 @@ pub struct Vmm { + #[cfg(target_arch = "aarch64")] + /// Trait to represent GIC devices(GICv3, GICv3 ITS). + pub gic_group: HashMap>, ++ #[cfg(target_arch = "riscv64")] ++ /// Trait to represent AIA devices(APLIC, IMSICs). ++ pub aia_group: HashMap>, + #[cfg(target_arch = "x86_64")] + /// Trait to represent kvm device. + pub kvm: Option>, +@@ -362,6 +365,23 @@ impl MigrationManager { + locked_vmm.gic_group.insert(translate_id(id), gic); + } + ++ /// Register AIA device instance to vmm. ++ /// ++ /// # Arguments ++ /// ++ /// * `aia_desc` - The `DeviceStateDesc` of AIA instance. ++ /// * `aia` - The AIA device instance with MigrationHook trait. ++ #[cfg(target_arch = "riscv64")] ++ pub fn register_aia_instance(aia_desc: DeviceStateDesc, aia: Arc, id: &str) ++ where ++ T: MigrationHook + Sync + Send + 'static, ++ { ++ Self::register_device_desc(aia_desc); ++ ++ let mut locked_vmm = MIGRATION_MANAGER.vmm.write().unwrap(); ++ locked_vmm.aia_group.insert(translate_id(id), aia); ++ } ++ + /// Register migration instance to vmm. + /// + /// # Arguments +diff --git a/migration/src/protocol.rs b/migration/src/protocol.rs +index 0d57220..0902eb0 100644 +--- a/migration/src/protocol.rs ++++ b/migration/src/protocol.rs +@@ -393,6 +393,8 @@ impl Default for MigrationHeader { + arch: [b'x', b'8', b'6', b'_', b'6', b'4', b'0', b'0'], + #[cfg(target_arch = "aarch64")] + arch: [b'a', b'a', b'r', b'c', b'h', b'6', b'4', b'0'], ++ #[cfg(target_arch = "riscv64")] ++ arch: [b'r', b'i', b's', b'c', b'v', b'6', b'4', b'0'], + desc_len: 0, + } + } +@@ -418,6 +420,8 @@ impl MigrationHeader { + let current_arch = [b'x', b'8', b'6', b'_', b'6', b'4', b'0', b'0']; + #[cfg(target_arch = "aarch64")] + let current_arch = [b'a', b'a', b'r', b'c', b'h', b'6', b'4', b'0']; ++ #[cfg(target_arch = "riscv64")] ++ let current_arch = [b'r', b'i', b's', b'c', b'v', b'6', b'4', b'0']; + if self.arch != current_arch { + return Err(anyhow!(MigrationError::HeaderItemNotFit( + "Arch".to_string() +diff --git a/migration/src/snapshot.rs b/migration/src/snapshot.rs +index 3a449ba..1126ff0 100644 +--- a/migration/src/snapshot.rs ++++ b/migration/src/snapshot.rs +@@ -25,6 +25,7 @@ use util::unix::host_page_size; + + pub const SERIAL_SNAPSHOT_ID: &str = "serial"; + pub const KVM_SNAPSHOT_ID: &str = "kvm"; ++pub const AIA_SNAPSHOT_ID: &str = "aia"; + pub const GICV3_SNAPSHOT_ID: &str = "gicv3"; + pub const GICV3_ITS_SNAPSHOT_ID: &str = "gicv3_its"; + pub const PL011_SNAPSHOT_ID: &str = "pl011"; +@@ -233,6 +234,16 @@ impl MigrationManager { + } + } + ++ #[cfg(target_arch = "riscv64")] ++ { ++ // Save AIA device state. ++ let aia_id = translate_id(AIA_SNAPSHOT_ID); ++ if let Some(aia) = locked_vmm.aia_group.get(&aia_id) { ++ aia.save_device(aia_id, fd) ++ .with_context(|| "Failed to save aia state")?; ++ } ++ } ++ + Ok(()) + } + +@@ -302,6 +313,18 @@ impl MigrationManager { + } + } + ++ #[cfg(target_arch = "riscv64")] ++ { ++ // Restore AIA group state. ++ for _ in 0..locked_vmm.aia_group.len() { ++ let (aia_data, id) = Self::check_vm_state(fd, &snap_desc_db)?; ++ if let Some(aia) = locked_vmm.aia_group.get(&id) { ++ aia.restore_device(&aia_data) ++ .with_context(|| "Failed to restore aia state")?; ++ } ++ } ++ } ++ + Ok(()) + } + } +diff --git a/src/main.rs b/src/main.rs +index 15eaefc..50807f8 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -18,7 +18,9 @@ use anyhow::{bail, Context, Result}; + use log::{error, info}; + use thiserror::Error; + +-use machine::{LightMachine, MachineOps, StdMachine}; ++#[cfg(not(target_arch = "riscv64"))] ++use machine::StdMachine; ++use machine::{type_init, LightMachine, MachineOps}; + use machine_manager::{ + cmdline::{check_api_channel, create_args_parser, create_vmconfig}, + config::MachineType, +@@ -71,9 +73,16 @@ fn main() -> ExitCode { + } + + fn run() -> Result<()> { ++ type_init()?; ++ + let cmd_args = create_args_parser().get_matches()?; + + if cmd_args.is_present("mod-test") { ++ let machine = cmd_args.value_of("machine").unwrap_or_default(); ++ let accel = cmd_args.value_of("accel").unwrap_or_default(); ++ if !machine.contains("accel=test") && accel.ne("test") { ++ bail!("MST can only use test accel!"); ++ } + set_test_enabled(); + } + +@@ -97,7 +106,6 @@ fn run() -> Result<()> { + })); + + let mut vm_config: VmConfig = create_vmconfig(&cmd_args)?; +- info!("VmConfig is {:?}", vm_config); + + match real_main(&cmd_args, &mut vm_config) { + Ok(()) => { +@@ -155,20 +163,21 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res + LightMachine::new(vm_config).with_context(|| "Failed to init MicroVM")?, + )); + MachineOps::realize(&vm, vm_config).with_context(|| "Failed to realize micro VM.")?; +- EventLoop::set_manager(vm.clone(), None); ++ EventLoop::set_manager(vm.clone()); + + for listener in listeners { + sockets.push(Socket::from_listener(listener, Some(vm.clone()))); + } + vm + } ++ #[cfg(not(target_arch = "riscv64"))] + MachineType::StandardVm => { + let vm = Arc::new(Mutex::new( + StdMachine::new(vm_config).with_context(|| "Failed to init StandardVM")?, + )); + MachineOps::realize(&vm, vm_config) + .with_context(|| "Failed to realize standard VM.")?; +- EventLoop::set_manager(vm.clone(), None); ++ EventLoop::set_manager(vm.clone()); + + if is_test_enabled() { + let sock_path = cmd_args.value_of("mod-test"); +@@ -188,27 +197,37 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res + vm + } + MachineType::None => { +- if is_test_enabled() { +- panic!("please specify machine type.") +- } +- let vm = Arc::new(Mutex::new( +- StdMachine::new(vm_config).with_context(|| "Failed to init NoneVM")?, +- )); +- EventLoop::set_manager(vm.clone(), None); ++ #[cfg(not(target_arch = "riscv64"))] ++ { ++ if is_test_enabled() { ++ panic!("please specify machine type.") ++ } ++ let vm = Arc::new(Mutex::new( ++ StdMachine::new(vm_config).with_context(|| "Failed to init NoneVM")?, ++ )); ++ EventLoop::set_manager(vm.clone()); + +- for listener in listeners { +- sockets.push(Socket::from_listener(listener, Some(vm.clone()))); ++ for listener in listeners { ++ sockets.push(Socket::from_listener(listener, Some(vm.clone()))); ++ } ++ vm ++ } ++ #[cfg(target_arch = "riscv64")] ++ { ++ panic!() + } +- vm + } + }; + +- let balloon_switch_on = vm_config.dev_name.get("balloon").is_some(); +- if !cmd_args.is_present("disable-seccomp") { +- vm.lock() +- .unwrap() +- .register_seccomp(balloon_switch_on) +- .with_context(|| "Failed to register seccomp rules.")?; ++ #[cfg(not(target_arch = "riscv64"))] ++ { ++ let balloon_switch_on = vm_config.dev_name.get("balloon").is_some(); ++ if !cmd_args.is_present("disable-seccomp") { ++ vm.lock() ++ .unwrap() ++ .register_seccomp(balloon_switch_on) ++ .with_context(|| "Failed to register seccomp rules.")?; ++ } + } + + for socket in sockets { +diff --git a/tests/mod_test/src/libtest.rs b/tests/mod_test/src/libtest.rs +index 9b1f6f6..ada68e0 100644 +--- a/tests/mod_test/src/libtest.rs ++++ b/tests/mod_test/src/libtest.rs +@@ -355,7 +355,13 @@ pub fn test_init(extra_arg: Vec<&str>) -> TestState { + + let listener = init_socket(&test_socket); + +- let child = Command::new(binary_path) ++ let mut cmd = Command::new(binary_path); ++ ++ #[cfg(target_env = "ohos")] ++ cmd.args(["-disable-seccomp"]); ++ ++ let child = cmd ++ .args(["-accel", "test"]) + .args(["-qmp", &format!("unix:{},server,nowait", qmp_socket)]) + .args(["-mod-test", &test_socket]) + .args(extra_arg) +diff --git a/tests/mod_test/tests/pvpanic_test.rs b/tests/mod_test/tests/pvpanic_test.rs +index 0445159..03dfc67 100644 +--- a/tests/mod_test/tests/pvpanic_test.rs ++++ b/tests/mod_test/tests/pvpanic_test.rs +@@ -15,11 +15,11 @@ use std::fs; + use std::path::Path; + use std::rc::Rc; + ++use devices::misc::pvpanic::{PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; + use devices::pci::config::{ + PCI_CLASS_SYSTEM_OTHER, PCI_DEVICE_ID_REDHAT_PVPANIC, PCI_SUBDEVICE_ID_QEMU, + PCI_VENDOR_ID_REDHAT, PCI_VENDOR_ID_REDHAT_QUMRANET, + }; +-use machine_manager::config::{PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; + use mod_test::{ + libdriver::{machine::TestStdMachine, pci::*}, + libtest::{test_init, TestState, MACHINE_TYPE_ARG}, +diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs +index 66d7598..b519e1c 100644 +--- a/tests/mod_test/tests/usb_camera_test.rs ++++ b/tests/mod_test/tests/usb_camera_test.rs +@@ -33,6 +33,7 @@ enum FmtType { + Yuy2 = 0, + Rgb565, + Mjpg, ++ Nv12, + } + + #[derive(Debug, Clone, Serialize, Deserialize)] +@@ -115,8 +116,10 @@ fn format_index_to_fmt(idx: u8) -> FmtType { + FmtType::Yuy2 + } else if idx == 2 { + FmtType::Mjpg +- } else { ++ } else if idx == 3 { + FmtType::Rgb565 ++ } else { ++ FmtType::Nv12 + } + } + +@@ -193,6 +196,16 @@ fn check_frame_data(fmt: &FmtType, data: &[u8]) { + let pos = data.len() - 2; + assert_eq!(data[pos..], [0xff, 0xf9]); + } ++ FmtType::Nv12 => { ++ let len = data.len(); ++ for i in 0..(len / 2) { ++ assert_eq!(data[i], 76); ++ } ++ for i in 0..(len / 4) { ++ let idx = len / 2 + i * 2; ++ assert_eq!(data[idx..idx + 2], [90, 255]); ++ } ++ } + } + } + +@@ -263,6 +276,8 @@ fn test_xhci_camera_basic() { + check_frame(&mut xhci, slot_id, 2, 2, 3); + // Rgb + check_frame(&mut xhci, slot_id, 3, 3, 3); ++ // Nv12 ++ check_frame(&mut xhci, slot_id, 4, 1, 3); + + test_state.borrow_mut().stop(); + } +diff --git a/trace/src/lib.rs b/trace/src/lib.rs +index 1501a50..32646d2 100644 +--- a/trace/src/lib.rs ++++ b/trace/src/lib.rs +@@ -19,7 +19,7 @@ pub(crate) mod hitrace; + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] +-pub(crate) mod trace_scope; ++pub mod trace_scope; + + use std::{ + fmt, +diff --git a/trace/src/trace_scope.rs b/trace/src/trace_scope.rs +index 4a02101..a860ef8 100644 +--- a/trace/src/trace_scope.rs ++++ b/trace/src/trace_scope.rs +@@ -20,12 +20,14 @@ use crate::ftrace::write_trace_marker; + + static mut TRACE_SCOPE_COUNTER: AtomicI32 = AtomicI32::new(i32::MIN); + ++#[derive(Clone)] + pub enum Scope { + Common(TraceScope), + Asyn(TraceScopeAsyn), + None, + } + ++#[derive(Clone)] + pub struct TraceScope {} + + impl TraceScope { +@@ -63,6 +65,7 @@ impl Drop for TraceScope { + } + } + ++#[derive(Clone)] + pub struct TraceScopeAsyn { + value: String, + id: i32, +diff --git a/trace/trace_generator/src/lib.rs b/trace/trace_generator/src/lib.rs +index 008263c..4d1a80a 100644 +--- a/trace/trace_generator/src/lib.rs ++++ b/trace/trace_generator/src/lib.rs +@@ -216,6 +216,11 @@ pub fn gen_trace_scope_func(_input: TokenStream) -> TokenStream { + } + }; + ++ let func_decl = match desc.enabled { ++ true => quote!(pub fn #func_name(asyn: bool, #func_args) -> trace_scope::Scope), ++ false => quote!(pub fn #func_name(asyn: bool, #func_args)), ++ }; ++ + let message_args = match desc.args.is_empty() { + true => quote!(), + false => { +@@ -258,7 +263,7 @@ pub fn gen_trace_scope_func(_input: TokenStream) -> TokenStream { + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + #[inline(always)] +- pub fn #func_name(asyn: bool, #func_args) -> trace_scope::Scope { ++ #func_decl { + #func_body + } + +diff --git a/trace/trace_info/acpi.toml b/trace/trace_info/acpi.toml +new file mode 100644 +index 0000000..9b4352a +--- /dev/null ++++ b/trace/trace_info/acpi.toml +@@ -0,0 +1,23 @@ ++[[events]] ++name = "ged_inject_acpi_event" ++args = "event: u32" ++message = "acpi_sevent {}" ++enabled = true ++ ++[[events]] ++name = "ged_read" ++args = "event: u32" ++message = "acpi_sevent {}" ++enabled = true ++ ++[[events]] ++name = "power_read" ++args = "reg_idx: u64, value: u32" ++message = "reg_idx {} value {}" ++enabled = true ++ ++[[events]] ++name = "power_status_read" ++args = "regs: &dyn fmt::Debug" ++message = "regs {:?}" ++enabled = true +diff --git a/trace/trace_info/camera.toml b/trace/trace_info/camera.toml +index 4e0ee65..e1f044f 100644 +--- a/trace/trace_info/camera.toml ++++ b/trace/trace_info/camera.toml +@@ -21,3 +21,15 @@ name = "camera_get_format_by_index" + args = "format_index: u8, frame_index: u8, out: &dyn fmt::Debug" + message = "V4l2 fmt {}, frm {}, info {:?}." + enabled = true ++ ++[[scopes]] ++name = "ohcam_get_frame" ++args = "offset: usize, len: usize" ++message = "ohcam get frame offset {} len {}" ++enabled = true ++ ++[[scopes]] ++name = "ohcam_next_frame" ++args = "frame_id: u64" ++message = "ohcam next frame {}" ++enabled = true +diff --git a/trace/trace_info/device_legacy.toml b/trace/trace_info/device_legacy.toml +index 14ed943..42bbae0 100644 +--- a/trace/trace_info/device_legacy.toml ++++ b/trace/trace_info/device_legacy.toml +@@ -201,3 +201,27 @@ name = "pflash_write_data" + args = "offset: u64, size: usize, value: &[u8], counter: u32" + message = "data offset: 0x{:04x}, size: {}, value: 0x{:x?}, counter: 0x{:04x}" + enabled = true ++ ++[[events]] ++name = "fwcfg_select_entry" ++args = "key: u16, key_name: &'static str, ret: i32" ++message = "key_value {} key_name {:?} ret {}" ++enabled = true ++ ++[[events]] ++name = "fwcfg_add_entry" ++args = "key: u16, key_name: &'static str, data: Vec" ++message = "key_value {} key_name {:?} data {:?}" ++enabled = true ++ ++[[events]] ++name = "fwcfg_read_data" ++args = "value: u64" ++message = "value {}" ++enabled = true ++ ++[[events]] ++name = "fwcfg_add_file" ++args = "index: usize, filename: &str, data_len: usize" ++message = "index {} filename {:?} data_len {}" ++enabled = true +diff --git a/trace/trace_info/memory.toml b/trace/trace_info/memory.toml +new file mode 100644 +index 0000000..4ff485a +--- /dev/null ++++ b/trace/trace_info/memory.toml +@@ -0,0 +1,41 @@ ++[[scopes]] ++name = "address_space_read" ++args = "addr: &dyn fmt::Debug, count: u64" ++message = "Memory: flatview_read addr {:?}, count {}" ++enabled = true ++ ++[[scopes]] ++name = "address_space_write" ++args = "addr: &dyn fmt::Debug, count: u64" ++message = "Memory: flatview_write addr {:?}, count {}" ++enabled = true ++ ++[[scopes]] ++name = "address_space_read_direct" ++args = "host_addr: u64, count: usize" ++message = "Memory: address_space_read_direct host_addr {}, count {}" ++enabled = true ++ ++[[scopes]] ++name = "address_space_write_direct" ++args = "host_addr: u64, count: usize" ++message = "Memory: address_space_write_direct host_addr {}, count {}" ++enabled = true ++ ++[[scopes]] ++name = "address_update_topology" ++args = "" ++message = "Memory: update opology" ++enabled = true ++ ++[[scopes]] ++name = "pre_alloc" ++args = "size: u64" ++message = "Memory: pre_alloc ram size is {}" ++enabled = true ++ ++[[scopes]] ++name = "init_memory" ++args = "" ++message = "Memory: init memory" ++enabled = true +diff --git a/trace/trace_info/misc.toml b/trace/trace_info/misc.toml +index 78ac9d1..897a6bc 100644 +--- a/trace/trace_info/misc.toml ++++ b/trace/trace_info/misc.toml +@@ -27,3 +27,63 @@ name = "scream_setup_alsa_hwp" + args = "name: &str, hwp: &dyn fmt::Debug" + message = "scream {} setup hardware parameters: {:?}" + enabled = true ++ ++[[events]] ++name = "oh_scream_render_init" ++args = "context: &dyn fmt::Debug" ++message = "context: {:?}" ++enabled = true ++ ++[[events]] ++name = "oh_scream_render_destroy" ++args = "" ++message = "" ++enabled = true ++ ++[[events]] ++name = "oh_scream_capture_init" ++args = "context: &dyn fmt::Debug" ++message = "context: {:?}" ++enabled = true ++ ++[[events]] ++name = "oh_scream_capture_destroy" ++args = "" ++message = "" ++enabled = true ++ ++[[events]] ++name = "oh_scream_on_write_data_cb" ++args = "len: usize" ++message = "len: {}" ++enabled = true ++ ++[[events]] ++name = "oh_scream_on_read_data_cb" ++args = "len: usize" ++message = "len: {}" ++enabled = true ++ ++[[scopes]] ++name = "ohaudio_render_process" ++args = "data: &dyn fmt::Debug" ++message = "audio data {:?} to render" ++enabled = true ++ ++[[scopes]] ++name = "ohaudio_capturer_process" ++args = "data: &dyn fmt::Debug" ++message = "audio data {:?} to capture" ++enabled = true ++ ++[[scopes]] ++name = "ohaudio_write_cb" ++args = "to_copy: i32, len: i32" ++message = "OH audio expect audio data {} bytes, we have {} bytes" ++enabled = true ++ ++[[scopes]] ++name = "ohaudio_read_cb" ++args = "len: i32" ++message = "OH audio captured {} bytes" ++enabled = true +diff --git a/trace/trace_info/ui.toml b/trace/trace_info/ui.toml +index 091c056..1df6455 100644 +--- a/trace/trace_info/ui.toml ++++ b/trace/trace_info/ui.toml +@@ -219,3 +219,63 @@ name = "console_select" + args = "con_id: &dyn fmt::Debug" + message = "console id={:?}" + enabled = true ++ ++[[events]] ++name = "oh_event_mouse_button" ++args = "msg_btn: u32, action: u32" ++message = "msg_btn={} action={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_mouse_motion" ++args = "x: f64, y: f64" ++message = "x={} y={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_keyboard" ++args = "keycode: u16, key_action: u16" ++message = "keycode={} key_action={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_windowinfo" ++args = "width: u32, height: u32" ++message = "width={} height={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_scroll" ++args = "direction: u32" ++message = "direction={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_ledstate" ++args = "state: u32" ++message = "state={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_focus" ++args = "state: u32" ++message = "state={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_greet" ++args = "id: u64" ++message = "token_id={}" ++enabled = true ++ ++[[events]] ++name = "oh_event_unsupported_type" ++args = "ty: &dyn fmt::Debug, size: u32" ++message = "type={:?} body_size={}" ++enabled = true ++ ++[[scopes]] ++name = "handle_msg" ++args = "opcode: &dyn fmt::Debug" ++message = "handle ohui {:?} message" ++enabled = true +diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml +index fc5699a..d94588e 100644 +--- a/trace/trace_info/usb.toml ++++ b/trace/trace_info/usb.toml +@@ -221,7 +221,7 @@ message = "status={:?}" + enabled = true + + [[events]] +-name = "usb_xhci_flush_ep_transfer" ++name = "usb_xhci_cancel_all_ep_transfers" + args = "slotid: &dyn fmt::Debug, epid: &dyn fmt::Debug" + message = "slotid={:?} epid={:?}" + enabled = true +@@ -465,3 +465,105 @@ name = "usb_host_req_complete" + args = "bus_num: u8, addr: u8, packet: u64, status: &dyn fmt::Debug, actual_length: usize" + message = "dev bus 0x{:X} addr 0x{:X}, packet 0x{:#X}, status {:?} actual length {}" + enabled = true ++ ++[[events]] ++name = "usb_uas_handle_control" ++args = "packet_id: u32, device_id: &str, req: &[u8]" ++message = "USB {} packet received on UAS {} device, the request is {:?}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_handle_iu_command" ++args = "device_id: &str, cdb: u8" ++message = "UAS {} device handling IU with cdb[0] {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_fill_sense" ++args = "status: u8, iu_len: usize, sense_len: usize" ++message = "UAS device is filling sense with status {:02} URB length {} sense length {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_fill_fake_sense" ++args = "status: u8, iu_len: usize, sense_len: usize" ++message = "UAS device is filling fake sense with status {:02} URB length {} sense length {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_fill_packet" ++args = "iovec_size: usize" ++message = "UAS device is filling USB packet with iovec of size {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_try_start_next_transfer" ++args = "device_id: &str, xfer_len: i32" ++message = "UAS {} device is trying to start next transfer of length {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_fill_data_ready" ++args = "device_id: &str, data_ready_sent: bool" ++message = "UAS {} device set data_ready_sent to {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_start_next_transfer" ++args = "device_id: &str, stream: usize" ++message = "UAS {} device starting a transfer on stream {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_handle_data" ++args = "device_id: &str, endpoint: u8, stream: usize" ++message = "UAS {} device handling data on endpoint {} and stream {}." ++enabled = true ++ ++[[events]] ++name = "usb_uas_command_received" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} command packet received on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_command_completed" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} command packet completed on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_status_received" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} status packet received on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_status_completed" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} status packet completed on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_status_queued_async" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} status packet queued async on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_data_received" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} data packet received on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_data_completed" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} data packet completed on UAS {} device." ++enabled = true ++ ++[[events]] ++name = "usb_uas_data_queued_async" ++args = "packet_id: u32, device_id: &str" ++message = "USB {} data packet queued async on UAS {} device." ++enabled = true +diff --git a/trace/trace_info/virtio.toml b/trace/trace_info/virtio.toml +index 1e7def4..1f8ea24 100644 +--- a/trace/trace_info/virtio.toml ++++ b/trace/trace_info/virtio.toml +@@ -196,12 +196,6 @@ args = "vring: u64, event_idx: u16" + message = "virtqueue {:#X} set avail event idx {}" + enabled = true + +-[[events]] +-name = "virtio_tpt_common" +-args = "func: &str, id: &str" +-message = "{} for device {}" +-enabled = true +- + [[events]] + name = "virtio_tpt_read_common_config" + args = "id: &str, offset: u64" +@@ -303,3 +297,21 @@ name = "vhost_delete_mem_range_failed" + args = "" + message = "Vhost: deleting mem region failed: not matched." + enabled = true ++ ++[[scopes]] ++name = "auto_msg_evt_handler" ++args = "" ++message = "Balloon: handle auto balloon message" ++enabled = true ++ ++[[scopes]] ++name = "reporting_evt_handler" ++args = "" ++message = "Balloon: handle fpr message" ++enabled = true ++ ++[[scopes]] ++name = "process_balloon_queue" ++args = "" ++message = "Balloon: handle normal balloon message" ++enabled = true +diff --git a/ui/src/input.rs b/ui/src/input.rs +index 59f2b93..d540c99 100644 +--- a/ui/src/input.rs ++++ b/ui/src/input.rs +@@ -252,6 +252,23 @@ impl KeyBoardState { + #[derive(Default)] + struct LedState { + kbd_led: u8, ++ sync: Option>, ++} ++ ++pub trait SyncLedstate: Send + Sync { ++ fn sync_to_host(&self, state: u8) { ++ debug!("ledstate in guest is {}", state); ++ } ++} ++ ++impl LedState { ++ fn register_led_sync(&mut self, sync: Arc) { ++ self.sync = Some(sync); ++ } ++ ++ fn unregister_led_sync(&mut self) { ++ self.sync = None; ++ } + } + + #[derive(Default)] +@@ -328,6 +345,14 @@ impl Inputs { + } + } + ++pub fn register_led_sync(sync: Arc) { ++ LED_STATE.lock().unwrap().register_led_sync(sync); ++} ++ ++pub fn unregister_led_sync() { ++ LED_STATE.lock().unwrap().unregister_led_sync(); ++} ++ + pub fn register_keyboard(device: &str, kbd: Arc>) { + INPUTS.lock().unwrap().register_kbd(device, kbd); + } +@@ -465,6 +490,9 @@ pub fn get_kbd_led_state() -> u8 { + + pub fn set_kbd_led_state(state: u8) { + LED_STATE.lock().unwrap().kbd_led = state; ++ if let Some(sync_cb) = LED_STATE.lock().unwrap().sync.as_ref() { ++ sync_cb.sync_to_host(state); ++ } + } + + pub fn keyboard_modifier_get(key_mod: KeyboardModifier) -> bool { +diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs +index 861a163..64d6e0a 100755 +--- a/ui/src/ohui_srv/channel.rs ++++ b/ui/src/ohui_srv/channel.rs +@@ -10,119 +10,98 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use std::os::raw::c_void; ++use std::io::{ErrorKind, Read, Write}; ++use std::os::fd::AsRawFd; + use std::os::unix::io::RawFd; +-use std::sync::RwLock; + +-use anyhow::Result; +-use libc::iovec; ++use anyhow::{bail, Result}; + use log::error; + + use util::byte_code::ByteCode; +-use util::unix::UnixSock; ++use util::socket::{SocketListener, SocketStream}; ++use util::unix::limit_permission; + + pub struct OhUiChannel { +- pub sock: RwLock, +- pub path: String, ++ listener: SocketListener, ++ stream: Option, + } + + impl OhUiChannel { +- pub fn new(path: &str) -> Self { +- OhUiChannel { +- sock: RwLock::new(UnixSock::new(path)), +- path: String::from(path), +- } +- } ++ pub fn new(path: &str) -> Result { ++ let listener = match SocketListener::bind_by_uds(path) { ++ Ok(l) => l, ++ Err(e) => bail!("Failed to create listener with path {}, {:?}", path, e), ++ }; ++ limit_permission(path).unwrap_or_else(|e| { ++ error!( ++ "Failed to limit permission for ohui-sock {}, err: {:?}", ++ path, e ++ ); ++ }); + +- pub fn bind(&self) -> Result<()> { +- self.sock.write().unwrap().bind(true) ++ Ok(OhUiChannel { ++ listener, ++ stream: None, ++ }) + } + + pub fn get_listener_raw_fd(&self) -> RawFd { +- self.sock.read().unwrap().get_listener_raw_fd() ++ self.listener.as_raw_fd() + } + +- pub fn get_stream_raw_fd(&self) -> RawFd { +- self.sock.read().unwrap().get_stream_raw_fd() ++ pub fn get_stream_raw_fd(&self) -> Option { ++ self.stream.as_ref().map(|s| s.as_raw_fd()) + } + +- pub fn set_nonblocking(&self, nb: bool) -> Result<()> { +- self.sock.read().unwrap().set_nonblocking(nb) +- } +- +- pub fn set_listener_nonblocking(&self, nb: bool) -> Result<()> { +- self.sock.read().unwrap().listen_set_nonblocking(nb) +- } +- +- pub fn accept(&self) -> Result<()> { +- self.sock.write().unwrap().accept() ++ pub fn accept(&mut self) -> Result<()> { ++ self.stream = Some(self.listener.accept()?); ++ Ok(()) + } + +- pub fn send(&self, data: *const u8, len: usize) -> Result { +- let mut iovs = Vec::with_capacity(1); +- iovs.push(iovec { +- iov_base: data as *mut c_void, +- iov_len: len, +- }); +- let ret = self.sock.read().unwrap().send_msg(&mut iovs, &[])?; +- Ok(ret) ++ pub fn disconnect(&mut self) { ++ self.stream = None; + } ++} + +- pub fn send_by_obj(&self, obj: &T) -> Result<()> { +- let slice = obj.as_bytes(); +- let mut left = slice.len(); +- let mut count = 0_usize; ++pub fn recv_slice(stream: &mut dyn Read, data: &mut [u8]) -> Result { ++ let len = data.len(); ++ let mut ret = 0; + +- while left > 0 { +- let buf = &slice[count..]; +- match self.send(buf.as_ptr(), left) { +- Ok(n) => { +- left -= n; +- count += n; +- } +- Err(e) => { +- if std::io::Error::last_os_error().raw_os_error().unwrap() == libc::EAGAIN { +- continue; +- } +- return Err(e); ++ while ret < len { ++ match stream.read(&mut data[ret..len]) { ++ Ok(0) => break, ++ Ok(n) => ret += n, ++ Err(e) => { ++ let ek = e.kind(); ++ if ek != ErrorKind::WouldBlock && ek != ErrorKind::Interrupted { ++ bail!("recv_slice: error occurred: {:?}", e); + } ++ break; + } + } +- Ok(()) + } ++ Ok(ret) ++} + +- pub fn recv_slice(&self, data: &mut [u8]) -> Result { +- let len = data.len(); +- if len == 0 { +- return Ok(0); +- } +- let ret = self.recv(data.as_mut_ptr(), len); +- match ret { +- Ok(n) => Ok(n), ++pub fn send_obj(stream: &mut dyn Write, obj: &T) -> Result<()> { ++ let slice = obj.as_bytes(); ++ let mut left = slice.len(); ++ let mut count = 0_usize; ++ ++ while left > 0 { ++ match stream.write(&slice[count..]) { ++ Ok(n) => { ++ left -= n; ++ count += n; ++ } + Err(e) => { +- if std::io::Error::last_os_error() +- .raw_os_error() +- .unwrap_or(libc::EIO) +- != libc::EAGAIN +- { +- error!("recv_slice(): error occurred: {}", e); ++ let ek = e.kind(); ++ if ek == ErrorKind::WouldBlock || ek == ErrorKind::Interrupted { ++ continue; + } +- Ok(0) ++ bail!(e); + } + } + } +- +- pub fn recv(&self, data: *mut u8, len: usize) -> Result { +- let mut iovs = Vec::with_capacity(1); +- iovs.push(iovec { +- iov_base: data as *mut c_void, +- iov_len: len, +- }); +- +- let ret = self.sock.read().unwrap().recv_msg(&mut iovs, &mut []); +- match ret { +- Ok((n, _)) => Ok(n), +- Err(e) => Err(e.into()), +- } +- } ++ Ok(()) + } +diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs +index 1907946..899d263 100755 +--- a/ui/src/ohui_srv/mod.rs ++++ b/ui/src/ohui_srv/mod.rs +@@ -35,6 +35,7 @@ use crate::{ + DisplayChangeListenerOperations, DisplayMouse, DisplaySurface, + DISPLAY_UPDATE_INTERVAL_DEFAULT, + }, ++ input::{register_led_sync, unregister_led_sync}, + pixman::{bytes_per_pixel, get_image_data, ref_pixman_image, unref_pixman_image}, + }; + use address_space::FileBackend; +@@ -51,7 +52,7 @@ use util::{ + NotifierOperation, + }, + pixman::{pixman_format_code_t, pixman_image_t}, +- unix::do_mmap, ++ unix::{do_mmap, limit_permission}, + }; + + #[derive(Debug, Clone)] +@@ -92,9 +93,9 @@ pub struct OhUiServer { + // guest surface for framebuffer + surface: RwLock, + // transfer channel via unix sock +- channel: Arc, ++ channel: Arc>, + // message handler +- msg_handler: OhUiMsgHandler, ++ msg_handler: Arc, + // connected or not + connected: AtomicBool, + // iothread processing unix socket +@@ -110,13 +111,13 @@ pub struct OhUiServer { + } + + impl OhUiServer { +- fn init_channel(path: &String) -> Result> { ++ fn init_channel(path: &String) -> Result>> { + let file_path = Path::new(path.as_str()).join("ohui.sock"); + let sock_file = file_path + .to_str() + .ok_or_else(|| anyhow!("init_channel: Failed to get str from {}", path))?; + TempCleaner::add_path(sock_file.to_string()); +- Ok(Arc::new(OhUiChannel::new(sock_file))) ++ Ok(Arc::new(Mutex::new(OhUiChannel::new(sock_file)?))) + } + + fn init_fb_file(path: &String) -> Result<(Option, u64)> { +@@ -126,6 +127,12 @@ impl OhUiServer { + .ok_or_else(|| anyhow!("init_fb_file: Failed to get str from {}", path))?; + let fb_backend = FileBackend::new_mem(fb_file, VIRTIO_GPU_ENABLE_BAR0_SIZE)?; + TempCleaner::add_path(fb_file.to_string()); ++ limit_permission(fb_file).unwrap_or_else(|e| { ++ error!( ++ "Failed to limit permission for ohui-fb {}, err: {:?}", ++ fb_file, e ++ ); ++ }); + + let host_addr = do_mmap( + &Some(fb_backend.file.as_ref()), +@@ -146,6 +153,12 @@ impl OhUiServer { + .ok_or_else(|| anyhow!("init_cursor_file: Failed to get str from {}", path))?; + let cursor_backend = FileBackend::new_mem(cursor_file, CURSOR_SIZE)?; + TempCleaner::add_path(cursor_file.to_string()); ++ limit_permission(cursor_file).unwrap_or_else(|e| { ++ error!( ++ "Failed to limit permission for ohui-cursor {}, err: {:?}", ++ cursor_file, e ++ ); ++ }); + + let cursorbuffer = do_mmap( + &Some(cursor_backend.file.as_ref()), +@@ -167,8 +180,8 @@ impl OhUiServer { + Ok(OhUiServer { + passthru: OnceCell::new(), + surface: RwLock::new(GuestSurface::new()), +- channel: channel.clone(), +- msg_handler: OhUiMsgHandler::new(channel), ++ channel, ++ msg_handler: Arc::new(OhUiMsgHandler::new()), + connected: AtomicBool::new(false), + iothread: OnceCell::new(), + cursorbuffer, +@@ -185,8 +198,8 @@ impl OhUiServer { + } + + #[inline(always)] +- fn get_channel(&self) -> &OhUiChannel { +- self.channel.as_ref() ++ fn get_channel(&self) -> Arc> { ++ self.channel.clone() + } + + #[inline(always)] +@@ -252,6 +265,14 @@ impl OhUiServer { + #[inline(always)] + fn set_connect(&self, conn: bool) { + self.connected.store(conn, Ordering::Relaxed); ++ if conn { ++ self.msg_handler.update_sock(self.channel.clone()); ++ register_led_sync(self.msg_handler.clone()); ++ } else { ++ unregister_led_sync(); ++ self.channel.lock().unwrap().disconnect(); ++ self.msg_handler.reset(); ++ } + } + + fn set_iothread(&self, iothread: Option) { +@@ -353,7 +374,7 @@ impl DisplayChangeListenerOperations for OhUiServer { + + pub fn ohui_init(ohui_srv: Arc, cfg: &DisplayConfig) -> Result<()> { + // set iothread +- ohui_srv.set_iothread(cfg.ohui_config.iothread.clone()); ++ ohui_srv.set_iothread(cfg.iothread.clone()); + // Register ohui interface + let dcl = Arc::new(Mutex::new(DisplayChangeListener::new( + None, +@@ -386,7 +407,12 @@ impl OhUiTrans { + } + + fn get_fd(&self) -> RawFd { +- self.server.get_channel().get_stream_raw_fd() ++ self.server ++ .get_channel() ++ .lock() ++ .unwrap() ++ .get_stream_raw_fd() ++ .unwrap() + } + } + +@@ -431,8 +457,6 @@ impl OhUiListener { + } + + fn handle_connection(&self) -> Result<()> { +- // Set stream sock with nonblocking +- self.server.get_channel().set_nonblocking(true)?; + // Register OhUiTrans read notifier + ohui_register_event(OhUiTrans::new(self.server.clone()), self.server.clone())?; + self.server.set_connect(true); +@@ -442,11 +466,15 @@ impl OhUiListener { + } + + fn accept(&self) -> Result<()> { +- self.server.get_channel().accept() ++ self.server.get_channel().lock().unwrap().accept() + } + + fn get_fd(&self) -> RawFd { +- self.server.get_channel().get_listener_raw_fd() ++ self.server ++ .get_channel() ++ .lock() ++ .unwrap() ++ .get_listener_raw_fd() + } + } + +@@ -493,11 +521,7 @@ fn ohui_register_event(e: T, srv: Arc) -> Re + } + + fn ohui_start_listener(server: Arc) -> Result<()> { +- // Bind and set listener nonblocking +- let channel = server.get_channel(); +- channel.bind()?; +- channel.set_listener_nonblocking(true)?; +- ohui_register_event(OhUiListener::new(server.clone()), server.clone())?; ++ ohui_register_event(OhUiListener::new(server.clone()), server)?; + info!("Successfully start listener."); + Ok(()) + } +diff --git a/ui/src/ohui_srv/msg.rs b/ui/src/ohui_srv/msg.rs +index ed217f5..c359d71 100755 +--- a/ui/src/ohui_srv/msg.rs ++++ b/ui/src/ohui_srv/msg.rs +@@ -132,6 +132,12 @@ pub struct LedstateEvent { + + impl ByteCode for LedstateEvent {} + ++impl LedstateEvent { ++ pub fn new(state: u32) -> Self { ++ LedstateEvent { state } ++ } ++} ++ + #[repr(C, packed)] + #[derive(Debug, Default, Copy, Clone)] + pub struct GreetEvent { +diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs +index f00853b..1e085e5 100755 +--- a/ui/src/ohui_srv/msg_handle.rs ++++ b/ui/src/ohui_srv/msg_handle.rs +@@ -11,21 +11,27 @@ + // See the Mulan PSL v2 for more details. + + use std::collections::HashMap; ++use std::os::fd::{FromRawFd, RawFd}; ++use std::os::unix::net::UnixStream; + use std::sync::{Arc, Mutex, RwLock}; + +-use anyhow::{anyhow, bail, Result}; +-use log::{error, warn}; ++use anyhow::{anyhow, bail, Context, Result}; ++use log::error; + use util::byte_code::ByteCode; + +-use super::{channel::OhUiChannel, msg::*}; ++use super::{ ++ channel::{recv_slice, send_obj, OhUiChannel}, ++ msg::*, ++}; + use crate::{ + console::{get_active_console, graphic_hardware_ui_info}, + input::{ + self, get_kbd_led_state, input_button, input_move_abs, input_point_sync, keyboard_update, +- release_all_key, trigger_key, Axis, ABS_MAX, CAPS_LOCK_LED, INPUT_BUTTON_WHEEL_DOWN, +- INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, +- INPUT_POINT_FORWARD, INPUT_POINT_LEFT, INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, +- KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, ++ release_all_key, trigger_key, Axis, SyncLedstate, ABS_MAX, CAPS_LOCK_LED, ++ INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, ++ INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, INPUT_POINT_LEFT, ++ INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, ++ KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, + }, + keycode::{DpyMod, KeyCode}, + }; +@@ -119,42 +125,54 @@ impl WindowState { + } + } + ++#[derive(Default)] + pub struct OhUiMsgHandler { + state: Mutex, + hmcode2svcode: HashMap, +- reader: Mutex, +- writer: Mutex, ++ reader: Mutex>, ++ writer: Mutex>, ++} ++ ++impl SyncLedstate for OhUiMsgHandler { ++ fn sync_to_host(&self, state: u8) { ++ if let Some(writer) = self.writer.lock().unwrap().as_mut() { ++ let body = LedstateEvent::new(state as u32); ++ if let Err(e) = writer.send_message(EventType::Ledstate, &body) { ++ error!("sync_to_host: failed to send message with error {e}"); ++ } ++ } ++ } + } + + impl OhUiMsgHandler { +- pub fn new(channel: Arc) -> Self { ++ pub fn new() -> Self { + OhUiMsgHandler { + state: Mutex::new(WindowState::default()), + hmcode2svcode: KeyCode::keysym_to_qkeycode(DpyMod::Ohui), +- reader: Mutex::new(MsgReader::new(channel.clone())), +- writer: Mutex::new(MsgWriter::new(channel)), ++ reader: Mutex::new(None), ++ writer: Mutex::new(None), + } + } + ++ pub fn update_sock(&self, channel: Arc>) { ++ let fd = channel.lock().unwrap().get_stream_raw_fd().unwrap(); ++ *self.reader.lock().unwrap() = Some(MsgReader::new(fd)); ++ *self.writer.lock().unwrap() = Some(MsgWriter::new(fd)); ++ } ++ + pub fn handle_msg(&self, token_id: Arc>) -> Result<()> { +- let mut reader = self.reader.lock().unwrap(); ++ let mut locked_reader = self.reader.lock().unwrap(); ++ let reader = locked_reader ++ .as_mut() ++ .with_context(|| "handle_msg: no connection established")?; + if !reader.recv()? { + return Ok(()); + } + + let hdr = &reader.header; +- let body_size = hdr.size as usize; + let event_type = hdr.event_type; +- if body_size != event_msg_data_len(hdr.event_type) { +- warn!( +- "{:?} data len is wrong, we want {}, but receive {}", +- event_type, +- event_msg_data_len(hdr.event_type), +- body_size +- ); +- reader.clear(); +- return Ok(()); +- } ++ let body_size = hdr.size as size; ++ trace::trace_scope_start!(handle_msg, args = (&event_type)); + + let body_bytes = reader.body.as_ref().unwrap(); + if let Err(e) = match event_type { +@@ -181,6 +199,7 @@ impl OhUiMsgHandler { + } + EventType::Focus => { + let body = FocusEvent::from_bytes(&body_bytes[..]).unwrap(); ++ trace::oh_event_focus(body.state); + if body.state == CLIENT_FOCUSOUT_EVENT { + reader.clear(); + release_all_key()?; +@@ -194,6 +213,7 @@ impl OhUiMsgHandler { + } + EventType::Greet => { + let body = GreetEvent::from_bytes(&body_bytes[..]).unwrap(); ++ trace::oh_event_greet(body.token_id); + *token_id.write().unwrap() = body.token_id; + Ok(()) + } +@@ -202,6 +222,7 @@ impl OhUiMsgHandler { + "unsupported type {:?} and body size {}", + event_type, body_size + ); ++ trace::oh_event_unsupported_type(&event_type, body_size.try_into().unwrap()); + Ok(()) + } + } { +@@ -213,6 +234,7 @@ impl OhUiMsgHandler { + + fn handle_mouse_button(&self, mb: &MouseButtonEvent) -> Result<()> { + let (msg_btn, action) = (mb.button, mb.btn_action); ++ trace::oh_event_mouse_button(msg_btn, action); + let btn = match msg_btn { + CLIENT_MOUSE_BUTTON_LEFT => INPUT_POINT_LEFT, + CLIENT_MOUSE_BUTTON_RIGHT => INPUT_POINT_RIGHT, +@@ -236,19 +258,17 @@ impl OhUiMsgHandler { + hot_y: u32, + size_per_pixel: u32, + ) { +- let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); +- if let Err(e) = self +- .writer +- .lock() +- .unwrap() +- .send_message(EventType::CursorDefine, &body) +- { +- error!("handle_cursor_define: failed to send message with error {e}"); ++ if let Some(writer) = self.writer.lock().unwrap().as_mut() { ++ let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); ++ if let Err(e) = writer.send_message(EventType::CursorDefine, &body) { ++ error!("handle_cursor_define: failed to send message with error {e}"); ++ } + } + } + + // NOTE: we only support absolute position info now, that means usb-mouse does not work. + fn handle_mouse_motion(&self, mm: &MouseMotionEvent) -> Result<()> { ++ trace::oh_event_mouse_motion(mm.x, mm.y); + self.state.lock().unwrap().move_pointer(mm.x, mm.y) + } + +@@ -263,6 +283,7 @@ impl OhUiMsgHandler { + bail!("not supported keycode {}", hmkey); + } + }; ++ trace::oh_event_keyboard(keycode, ke.key_action); + self.state + .lock() + .unwrap() +@@ -280,6 +301,7 @@ impl OhUiMsgHandler { + }; + self.state.lock().unwrap().press_btn(dir)?; + self.state.lock().unwrap().release_btn(dir)?; ++ trace::oh_event_scroll(dir); + Ok(()) + } + +@@ -295,6 +317,7 @@ impl OhUiMsgHandler { + error!("handle_windowinfo failed with error {e}"); + } + } ++ trace::oh_event_windowinfo(wi.width, wi.height); + } + + fn handle_ledstate(&self, led: &LedstateEvent) { +@@ -302,75 +325,95 @@ impl OhUiMsgHandler { + .lock() + .unwrap() + .update_host_ledstate(led.state as u8); ++ trace::oh_event_ledstate(led.state); + } + + pub fn send_windowinfo(&self, w: u32, h: u32) { + self.state.lock().unwrap().update_window_info(w, h); +- let body = WindowInfoEvent::new(w, h); +- self.writer +- .lock() +- .unwrap() +- .send_message(EventType::WindowInfo, &body) +- .unwrap(); ++ if let Some(writer) = self.writer.lock().unwrap().as_mut() { ++ let body = WindowInfoEvent::new(w, h); ++ if let Err(e) = writer.send_message(EventType::WindowInfo, &body) { ++ error!("send_windowinfo: failed to send message with error {e}"); ++ } ++ } + } + + pub fn handle_dirty_area(&self, x: u32, y: u32, w: u32, h: u32) { +- let body = FrameBufferDirtyEvent::new(x, y, w, h); +- if let Err(e) = self +- .writer +- .lock() +- .unwrap() +- .send_message(EventType::FrameBufferDirty, &body) +- { +- error!("handle_dirty_area: failed to send message with error {e}"); ++ if let Some(writer) = self.writer.lock().unwrap().as_mut() { ++ let body = FrameBufferDirtyEvent::new(x, y, w, h); ++ if let Err(e) = writer.send_message(EventType::FrameBufferDirty, &body) { ++ error!("handle_dirty_area: failed to send message with error {e}"); ++ } + } + } ++ ++ pub fn reset(&self) { ++ *self.reader.lock().unwrap() = None; ++ *self.writer.lock().unwrap() = None; ++ } + } + + struct MsgReader { +- /// socket to read +- channel: Arc, + /// cache for header +- pub header: EventMsgHdr, ++ header: EventMsgHdr, + /// received byte size of header +- pub header_ready: usize, ++ header_ready: usize, + /// cache of body +- pub body: Option>, ++ body: Option>, + /// received byte size of body +- pub body_ready: usize, ++ body_ready: usize, ++ /// UnixStream to read ++ sock: UnixStream, + } + + impl MsgReader { +- pub fn new(channel: Arc) -> Self { ++ pub fn new(fd: RawFd) -> Self { + MsgReader { +- channel, + header: EventMsgHdr::default(), + header_ready: 0, + body: None, + body_ready: 0, ++ // SAFETY: The fd is valid only when the new connection has been established ++ // and MsgReader instance would be destroyed when disconnected. ++ sock: unsafe { UnixStream::from_raw_fd(fd) }, + } + } + + pub fn recv(&mut self) -> Result { + if self.recv_header()? { ++ self.check_header()?; + return self.recv_body(); + } + Ok(false) + } + +- pub fn clear(&mut self) { ++ fn clear(&mut self) { + self.header_ready = 0; + self.body_ready = 0; + self.body = None; + } + ++ fn check_header(&mut self) -> Result<()> { ++ let expected_size = event_msg_data_len(self.header.event_type); ++ if expected_size != self.header.size as usize { ++ self.clear(); ++ bail!( ++ "{:?} data len is wrong, we want {}, but receive {}", ++ self.header.event_type as EventType, ++ expected_size, ++ self.header.size as usize, ++ ); ++ } ++ Ok(()) ++ } ++ + fn recv_header(&mut self) -> Result { + if self.header_ready == EVENT_MSG_HDR_SIZE as usize { + return Ok(true); + } + + let buf = self.header.as_mut_bytes(); +- self.header_ready += self.channel.recv_slice(&mut buf[self.header_ready..])?; ++ self.header_ready += recv_slice(&mut self.sock, &mut buf[self.header_ready..])?; + Ok(self.header_ready == EVENT_MSG_HDR_SIZE as usize) + } + +@@ -392,22 +435,32 @@ impl MsgReader { + unsafe { + buf.set_len(body_size); + } +- self.body_ready += self.channel.recv_slice(&mut buf[self.body_ready..])?; ++ self.body_ready += recv_slice(&mut self.sock, &mut buf[self.body_ready..])?; + + Ok(self.body_ready == body_size) + } + } + +-struct MsgWriter(Arc); ++struct MsgWriter { ++ sock: UnixStream, ++} + + impl MsgWriter { +- fn new(channel: Arc) -> Self { +- MsgWriter(channel) ++ fn new(fd: RawFd) -> Self { ++ Self { ++ // SAFETY: The fd is valid only when the new connection has been established ++ // and MsgWriter instance would be destroyed when disconnected. ++ sock: unsafe { UnixStream::from_raw_fd(fd) }, ++ } + } + +- fn send_message(&self, t: EventType, body: &T) -> Result<()> { ++ fn send_message( ++ &mut self, ++ t: EventType, ++ body: &T, ++ ) -> Result<()> { + let hdr = EventMsgHdr::new(t); +- self.0.send_by_obj(&hdr)?; +- self.0.send_by_obj(body) ++ send_obj(&mut self.sock, &hdr)?; ++ send_obj(&mut self.sock, body) + } + } +diff --git a/ui/src/vnc/client_io.rs b/ui/src/vnc/client_io.rs +index 347e7d5..b4fa905 100644 +--- a/ui/src/vnc/client_io.rs ++++ b/ui/src/vnc/client_io.rs +@@ -47,8 +47,8 @@ use crate::{ + use util::{ + bitmap::Bitmap, + loop_context::{ +- gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, +- NotifierOperation, ++ create_new_eventfd, gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, ++ NotifierCallback, NotifierOperation, + }, + }; + +@@ -392,8 +392,8 @@ impl ClientState { + pub fn new(addr: String) -> Self { + ClientState { + addr, +- disconn_evt: Arc::new(Mutex::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), +- write_fd: Arc::new(Mutex::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), ++ disconn_evt: Arc::new(Mutex::new(create_new_eventfd().unwrap())), ++ write_fd: Arc::new(Mutex::new(create_new_eventfd().unwrap())), + in_buffer: Arc::new(Mutex::new(BuffPool::new())), + out_buffer: Arc::new(Mutex::new(BuffPool::new())), + client_dpm: Arc::new(Mutex::new(DisplayMode::default())), +diff --git a/ui/src/vnc/mod.rs b/ui/src/vnc/mod.rs +index 9f0a7e9..ff2e48c 100644 +--- a/ui/src/vnc/mod.rs ++++ b/ui/src/vnc/mod.rs +@@ -290,7 +290,7 @@ pub fn vnc_init(vnc: &Option, object: &ObjectConfig) -> Result<()> { + None => return Ok(()), + }; + +- let addr = format!("{}:{}", vnc_cfg.ip, vnc_cfg.port); ++ let addr = format!("{}:{}", vnc_cfg.addr.0, vnc_cfg.addr.1); + let listener: TcpListener = match TcpListener::bind(addr.as_str()) { + Ok(l) => l, + Err(e) => { +diff --git a/ui/src/vnc/server_io.rs b/ui/src/vnc/server_io.rs +index 76af9e8..ac577df 100644 +--- a/ui/src/vnc/server_io.rs ++++ b/ui/src/vnc/server_io.rs +@@ -221,7 +221,7 @@ impl SecurityType { + // Tls configuration. + if let Some(tls_cred) = object.tls_object.get(&vnc_cfg.tls_creds) { + let tlscred = TlsCreds { +- cred_type: tls_cred.cred_type.clone(), ++ cred_type: "x509".to_string(), + dir: tls_cred.dir.clone(), + endpoint: tls_cred.endpoint.clone(), + verifypeer: tls_cred.verifypeer, +diff --git a/util/Cargo.toml b/util/Cargo.toml +index 5bf691e..8466ed4 100644 +--- a/util/Cargo.toml ++++ b/util/Cargo.toml +@@ -11,7 +11,7 @@ license = "Mulan PSL v2" + arc-swap = "1.6.0" + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + nix = { version = "0.26.2", default-features = false, features = ["poll", "term", "time", "signal", "fs", "feature"] } + libc = "0.2" + libloading = "0.7.4" +@@ -28,5 +28,6 @@ trace = {path = "../trace"} + default = [] + usb_camera_v4l2 = ["dep:v4l2-sys-mit"] + usb_camera_oh = [] ++usb_host = [] + scream_ohaudio = [] + pixman = [] +diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs +index d8d733d..a9427f6 100644 +--- a/util/src/aio/mod.rs ++++ b/util/src/aio/mod.rs +@@ -32,6 +32,7 @@ use uring::IoUringContext; + use vmm_sys_util::eventfd::EventFd; + + use super::link_list::{List, Node}; ++use crate::loop_context::create_new_eventfd; + use crate::num_ops::{round_down, round_up}; + use crate::thread_pool::ThreadPool; + use crate::unix::host_page_size; +@@ -66,7 +67,7 @@ pub enum AioEngine { + } + + impl FromStr for AioEngine { +- type Err = (); ++ type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + match s { +@@ -74,7 +75,7 @@ impl FromStr for AioEngine { + AIO_NATIVE => Ok(AioEngine::Native), + AIO_IOURING => Ok(AioEngine::IoUring), + AIO_THREADS => Ok(AioEngine::Threads), +- _ => Err(()), ++ _ => Err(anyhow!("Unknown aio type")), + } + } + } +@@ -90,8 +91,9 @@ impl ToString for AioEngine { + } + } + +-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] ++#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] + pub enum WriteZeroesState { ++ #[default] + Off, + On, + Unmap, +@@ -503,7 +505,7 @@ impl Aio { + thread_pool: Option>, + ) -> Result { + let max_events: usize = 128; +- let fd = EventFd::new(libc::EFD_NONBLOCK)?; ++ let fd = create_new_eventfd()?; + let ctx: Option>> = if let Some(pool) = thread_pool { + let threads_aio_ctx = ThreadsAioContext::new(max_events as u32, &fd, pool); + match engine { +@@ -812,8 +814,9 @@ fn iovec_is_zero(iovecs: &[Iovec]) -> bool { + } + + pub fn iovecs_split(iovecs: Vec, mut size: u64) -> (Vec, Vec) { +- let mut begin = Vec::new(); +- let mut end = Vec::new(); ++ let len = iovecs.len(); ++ let mut begin: Vec = Vec::with_capacity(len); ++ let mut end: Vec = Vec::with_capacity(len); + for iov in iovecs { + if size == 0 { + end.push(iov); +diff --git a/util/src/aio/raw.rs b/util/src/aio/raw.rs +index 69cb0ba..4654a7c 100644 +--- a/util/src/aio/raw.rs ++++ b/util/src/aio/raw.rs +@@ -37,7 +37,8 @@ pub fn raw_read(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { + } + if ret < 0 { + error!( +- "Failed to pread: buf{}, size{}, offset{}, errno{}.", ++ "Failed to pread: fd {} buf {:#x}, size {}, offset{:#x}, errno {}.", ++ fd, + buf, + size, + offset, +@@ -66,7 +67,8 @@ pub fn raw_readv(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { + } + if ret < 0 { + error!( +- "Failed to preadv: offset{}, errno{}.", ++ "Failed to preadv: fd {} offset {:#x}, errno {}.", ++ fd, + offset, + nix::errno::errno(), + ); +@@ -93,7 +95,8 @@ pub fn raw_write(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { + } + if ret < 0 { + error!( +- "Failed to pwrite: buf{}, size{}, offset{}, errno{}.", ++ "Failed to pwrite: fd {} buf {:#x}, size{}, offset {:#x}, errno {}.", ++ fd, + buf, + size, + offset, +@@ -122,7 +125,8 @@ pub fn raw_writev(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { + } + if ret < 0 { + error!( +- "Failed to pwritev: offset{}, errno{}.", ++ "Failed to pwritev: fd {} offset {:#x}, errno {}.", ++ fd, + offset, + nix::errno::errno(), + ); +@@ -134,7 +138,7 @@ pub fn raw_datasync(fd: RawFd) -> i64 { + // SAFETY: fd is valid. + let ret = unsafe { i64::from(fdatasync(fd)) }; + if ret < 0 { +- error!("Failed to fdatasync: errno{}.", nix::errno::errno()); ++ error!("Failed to fdatasync: errno {}.", nix::errno::errno()); + } + ret + } +@@ -143,7 +147,7 @@ pub fn raw_discard(fd: RawFd, offset: usize, size: u64) -> i32 { + let ret = do_fallocate(fd, FallocateMode::PunchHole, true, offset as u64, size); + + if ret < 0 && ret != -libc::ENOTSUP { +- error!("Failed to fallocate for {}, errno {}.", fd, ret); ++ error!("Failed to fallocate for fd {}, errno {}.", fd, ret); + } + ret + } +diff --git a/util/src/device_tree.rs b/util/src/device_tree.rs +index ebb50d0..b03cf14 100644 +--- a/util/src/device_tree.rs ++++ b/util/src/device_tree.rs +@@ -27,6 +27,12 @@ pub const GIC_FDT_IRQ_TYPE_PPI: u32 = 1; + pub const IRQ_TYPE_EDGE_RISING: u32 = 1; + pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; + ++// PHANDEL definitions for RISC-V ++pub const AIA_APLIC_PHANDLE: u32 = 1; ++pub const AIA_IMSIC_PHANDLE: u32 = 2; ++pub const PHANDLE_CPU: u32 = 3; ++pub const INTC_PHANDLE_START: u32 = 256 + PHANDLE_CPU; ++ + pub const FDT_MAX_SIZE: u32 = 0x1_0000; + + // Magic number in fdt header(big-endian). +diff --git a/util/src/leak_bucket.rs b/util/src/leak_bucket.rs +index 5dd65f2..cde308c 100644 +--- a/util/src/leak_bucket.rs ++++ b/util/src/leak_bucket.rs +@@ -20,7 +20,7 @@ use log::error; + use vmm_sys_util::eventfd::EventFd; + + use crate::clock::get_current_time; +-use crate::loop_context::EventLoopContext; ++use crate::loop_context::{create_new_eventfd, EventLoopContext}; + use crate::time::NANOSECONDS_PER_SECOND; + + /// Used to improve the accuracy of bucket level. +@@ -53,7 +53,7 @@ impl LeakBucket { + level: 0, + prev_time: get_current_time(), + timer_started: false, +- timer_wakeup: Arc::new(EventFd::new(libc::EFD_NONBLOCK)?), ++ timer_wakeup: Arc::new(create_new_eventfd()?), + }) + } + +diff --git a/util/src/lib.rs b/util/src/lib.rs +index f861d6f..37bb3fa 100644 +--- a/util/src/lib.rs ++++ b/util/src/lib.rs +@@ -17,7 +17,7 @@ pub mod byte_code; + pub mod checksum; + pub mod clock; + pub mod daemonize; +-#[cfg(target_arch = "aarch64")] ++#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + pub mod device_tree; + pub mod edid; + pub mod error; +diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs +index 10e4cf7..957fdb4 100644 +--- a/util/src/loop_context.rs ++++ b/util/src/loop_context.rs +@@ -13,14 +13,15 @@ + use std::collections::BTreeMap; + use std::fmt; + use std::fmt::Debug; ++use std::io::Error; + use std::os::unix::io::{AsRawFd, RawFd}; + use std::rc::Rc; + use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +-use std::sync::{Arc, Mutex, RwLock}; ++use std::sync::{Arc, Barrier, Mutex, RwLock}; + use std::time::{Duration, Instant}; + + use anyhow::{anyhow, Context, Result}; +-use libc::{c_void, read, EFD_NONBLOCK}; ++use libc::{c_void, read, EFD_CLOEXEC, EFD_NONBLOCK}; + use log::{error, warn}; + use nix::errno::Errno; + use nix::{ +@@ -54,6 +55,10 @@ pub enum NotifierOperation { + Park = 16, + /// Resume a file descriptor from the event table + Resume = 32, ++ /// Add events to current event table for a file descriptor ++ AddEvents = 64, ++ /// Delete events from current event table for a file descriptor ++ DeleteEvents = 128, + } + + #[derive(Debug, PartialEq)] +@@ -154,6 +159,10 @@ pub fn gen_delete_notifiers(fds: &[RawFd]) -> Vec { + notifiers + } + ++pub fn create_new_eventfd() -> Result { ++ EventFd::new(EFD_NONBLOCK | EFD_CLOEXEC) ++} ++ + /// EventLoop manager, advise continue running or stop running + pub trait EventLoopManager: Send + Sync { + fn loop_should_exit(&self) -> bool; +@@ -215,6 +224,8 @@ pub struct EventLoopContext { + pub thread_pool: Arc, + /// Record VM clock state. + pub clock_state: Arc>, ++ /// The io thread barrier. ++ pub thread_exit_barrier: Arc, + } + + impl Drop for EventLoopContext { +@@ -231,11 +242,11 @@ unsafe impl Send for EventLoopContext {} + + impl EventLoopContext { + /// Constructs a new `EventLoopContext`. +- pub fn new() -> Self { ++ pub fn new(thread_exit_barrier: Arc) -> Self { + let mut ctx = EventLoopContext { + epoll: Epoll::new().unwrap(), + manager: None, +- kick_event: EventFd::new(EFD_NONBLOCK).unwrap(), ++ kick_event: create_new_eventfd().unwrap(), + kick_me: AtomicBool::new(false), + kicked: AtomicBool::new(false), + events: Arc::new(RwLock::new(BTreeMap::new())), +@@ -245,6 +256,7 @@ impl EventLoopContext { + timer_next_id: AtomicU64::new(0), + thread_pool: Arc::new(ThreadPool::default()), + clock_state: Arc::new(Mutex::new(ClockState::default())), ++ thread_exit_barrier, + }; + ctx.init_kick(); + ctx +@@ -466,6 +478,35 @@ impl EventLoopContext { + Ok(()) + } + ++ fn update_events_for_fd(&mut self, event: &EventNotifier, add: bool) -> Result<()> { ++ let mut events_map = self.events.write().unwrap(); ++ match events_map.get_mut(&event.raw_fd) { ++ Some(notifier) => { ++ let new_events = if add { ++ event.event | notifier.event ++ } else { ++ !event.event & notifier.event ++ }; ++ if new_events != notifier.event { ++ self.epoll ++ .ctl( ++ ControlOperation::Modify, ++ notifier.raw_fd, ++ EpollEvent::new(new_events, &**notifier as *const _ as u64), ++ ) ++ .with_context(|| { ++ format!("Failed to add events, event fd: {}", notifier.raw_fd) ++ })?; ++ notifier.event = new_events; ++ } ++ } ++ _ => { ++ return Err(anyhow!(UtilError::NoRegisterFd(event.raw_fd))); ++ } ++ } ++ Ok(()) ++ } ++ + /// update fds registered to `EventLoop` according to the operation type. + /// + /// # Arguments +@@ -490,6 +531,12 @@ impl EventLoopContext { + NotifierOperation::Resume => { + self.resume_event(&en)?; + } ++ NotifierOperation::AddEvents => { ++ self.update_events_for_fd(&en, true)?; ++ } ++ NotifierOperation::DeleteEvents => { ++ self.update_events_for_fd(&en, false)?; ++ } + } + } + self.kick(); +@@ -677,12 +724,6 @@ impl EventLoopContext { + } + } + +-impl Default for EventLoopContext { +- fn default() -> Self { +- Self::new() +- } +-} +- + pub fn read_fd(fd: RawFd) -> u64 { + let mut value: u64 = 0; + +@@ -707,6 +748,7 @@ pub fn read_fd(fd: RawFd) -> u64 { + #[cfg(test)] + mod test { + use std::os::unix::io::{AsRawFd, RawFd}; ++ use std::sync::Barrier; + + use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; + +@@ -755,7 +797,7 @@ mod test { + + #[test] + fn basic_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let mut notifiers = Vec::new(); + let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); + let fd1_related = EventFd::new(EFD_NONBLOCK).unwrap(); +@@ -783,7 +825,7 @@ mod test { + + #[test] + fn parked_event_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let mut notifiers = Vec::new(); + let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); + let fd2 = EventFd::new(EFD_NONBLOCK).unwrap(); +@@ -830,7 +872,7 @@ mod test { + + #[test] + fn event_handler_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let mut notifiers = Vec::new(); + let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); + let fd1_related = EventFd::new(EFD_NONBLOCK).unwrap(); +@@ -869,7 +911,7 @@ mod test { + + #[test] + fn error_operation_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); + let leisure_fd = EventFd::new(EFD_NONBLOCK).unwrap(); + +@@ -906,7 +948,7 @@ mod test { + + #[test] + fn error_parked_operation_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); + let fd2 = EventFd::new(EFD_NONBLOCK).unwrap(); + +@@ -941,7 +983,7 @@ mod test { + + #[test] + fn fd_released_test() { +- let mut mainloop = EventLoopContext::new(); ++ let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); + let fd = mainloop.create_event(); + + // In this case, fd is already closed. But program was wrote to ignore the error. +diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs +index 7214e32..4dd7687 100755 +--- a/util/src/ohos_binding/audio/mod.rs ++++ b/util/src/ohos_binding/audio/mod.rs +@@ -197,6 +197,7 @@ pub enum AudioProcessCb { + ), + } + ++#[derive(Debug)] + pub struct AudioContext { + stream_type: AudioStreamType, + spec: AudioSpec, +@@ -300,6 +301,10 @@ impl AudioContext { + call_capi!(OH_AudioRenderer_Start(self.renderer)) + } + ++ pub fn flush_renderer(&self) -> Result<(), OAErr> { ++ call_capi!(OH_AudioRenderer_Flush(self.renderer)) ++ } ++ + pub fn new(stream_type: AudioStreamType) -> Self { + Self { + stream_type, +diff --git a/util/src/ohos_binding/camera.rs b/util/src/ohos_binding/camera.rs +index 16cb7a3..e481e88 100644 +--- a/util/src/ohos_binding/camera.rs ++++ b/util/src/ohos_binding/camera.rs +@@ -27,6 +27,8 @@ pub const CAMERA_FORMAT_YCBCR420: i32 = 2; + #[allow(unused)] + pub const CAMERA_FORMAT_RGB18888: i32 = 3; + pub const CAMERA_FORMAT_YUV420SP: i32 = 1003; ++pub const CAMERA_FORMAT_NV12: i32 = 1004; ++pub const CAMERA_FORMAT_YUYV422: i32 = 1005; + pub const CAMERA_FORMAT_MJPEG: i32 = 2000; + + #[derive(Clone)] +@@ -108,6 +110,9 @@ impl OhCamera { + ) -> Result<()> { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { ++ if (self.capi.create_session)(self.ctx) != 0 { ++ bail!("OH Camera: failed to create session"); ++ } + if (self.capi.pre_start)(self.ctx, buffer_proc, broken_proc) != 0 { + bail!("OH Camera: failed to prestart camera stream"); + } +@@ -121,7 +126,6 @@ impl OhCamera { + pub fn reset_camera(&self) { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { +- (self.capi.create_session)(self.ctx); + (self.capi.init_cameras)(self.ctx); + (self.capi.init_profiles)(self.ctx); + } +diff --git a/util/src/ohos_binding/hwf_adapter/mod.rs b/util/src/ohos_binding/hwf_adapter/mod.rs +index ffa1145..2709c81 100644 +--- a/util/src/ohos_binding/hwf_adapter/mod.rs ++++ b/util/src/ohos_binding/hwf_adapter/mod.rs +@@ -12,6 +12,8 @@ + + #[cfg(feature = "usb_camera_oh")] + pub mod camera; ++#[cfg(feature = "usb_host")] ++pub mod usb; + + use std::ffi::OsStr; + use std::sync::Arc; +@@ -23,6 +25,8 @@ use once_cell::sync::Lazy; + + #[cfg(feature = "usb_camera_oh")] + use camera::CamFuncTable; ++#[cfg(feature = "usb_host")] ++use usb::UsbFuncTable; + + static LIB_HWF_ADAPTER: Lazy = Lazy::new(|| + // SAFETY: The dynamic library should be always existing. +@@ -40,6 +44,8 @@ struct LibHwfAdapter { + library: Library, + #[cfg(feature = "usb_camera_oh")] + camera: Arc, ++ #[cfg(feature = "usb_host")] ++ usb: Arc, + } + + impl LibHwfAdapter { +@@ -52,10 +58,17 @@ impl LibHwfAdapter { + CamFuncTable::new(&library).with_context(|| "failed to init camera function table")?, + ); + ++ #[cfg(feature = "usb_host")] ++ let usb = Arc::new( ++ UsbFuncTable::new(&library).with_context(|| "failed to init usb function table")?, ++ ); ++ + Ok(Self { + library, + #[cfg(feature = "usb_camera_oh")] + camera, ++ #[cfg(feature = "usb_host")] ++ usb, + }) + } + +@@ -63,9 +76,19 @@ impl LibHwfAdapter { + fn get_camera_api(&self) -> Arc { + self.camera.clone() + } ++ ++ #[cfg(feature = "usb_host")] ++ fn get_usb_api(&self) -> Arc { ++ self.usb.clone() ++ } + } + + #[cfg(feature = "usb_camera_oh")] + pub fn hwf_adapter_camera_api() -> Arc { + LIB_HWF_ADAPTER.get_camera_api() + } ++ ++#[cfg(feature = "usb_host")] ++pub fn hwf_adapter_usb_api() -> Arc { ++ LIB_HWF_ADAPTER.get_usb_api() ++} +diff --git a/util/src/ohos_binding/hwf_adapter/usb.rs b/util/src/ohos_binding/hwf_adapter/usb.rs +new file mode 100644 +index 0000000..abb3cc7 +--- /dev/null ++++ b/util/src/ohos_binding/hwf_adapter/usb.rs +@@ -0,0 +1,45 @@ ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++use std::os::raw::c_int; ++ ++use anyhow::{Context, Result}; ++use libloading::os::unix::Symbol as RawSymbol; ++use libloading::Library; ++ ++use crate::get_libfn; ++ ++#[allow(non_snake_case)] ++#[repr(C)] ++#[derive(Eq, PartialEq, Clone, Copy, Debug)] ++pub struct OhusbDevice { ++ pub busNum: u8, ++ pub devAddr: u8, ++ pub fd: c_int, ++} ++ ++type OhusbOpenDeviceFn = unsafe extern "C" fn(*mut OhusbDevice) -> c_int; ++type OhusbCloseDeviceFn = unsafe extern "C" fn(*mut OhusbDevice) -> c_int; ++ ++pub struct UsbFuncTable { ++ pub open_device: RawSymbol, ++ pub close_device: RawSymbol, ++} ++ ++impl UsbFuncTable { ++ pub unsafe fn new(library: &Library) -> Result { ++ Ok(Self { ++ open_device: get_libfn!(library, OhusbOpenDeviceFn, OhusbOpenDevice), ++ close_device: get_libfn!(library, OhusbCloseDeviceFn, OhusbCloseDevice), ++ }) ++ } ++} +diff --git a/util/src/ohos_binding/mod.rs b/util/src/ohos_binding/mod.rs +index 5f876ba..2e6a3cf 100644 +--- a/util/src/ohos_binding/mod.rs ++++ b/util/src/ohos_binding/mod.rs +@@ -15,6 +15,8 @@ pub mod audio; + #[cfg(feature = "usb_camera_oh")] + pub mod camera; + pub mod misc; ++#[cfg(feature = "usb_host")] ++pub mod usb; + + #[cfg(feature = "usb_camera_oh")] + mod hwf_adapter; +diff --git a/util/src/ohos_binding/usb.rs b/util/src/ohos_binding/usb.rs +new file mode 100644 +index 0000000..a8d227b +--- /dev/null ++++ b/util/src/ohos_binding/usb.rs +@@ -0,0 +1,50 @@ ++// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt is licensed under Mulan PSL v2. ++// You can use this software according to the terms and conditions of the Mulan ++// PSL v2. ++// You may obtain a copy of Mulan PSL v2 at: ++// http://license.coscl.org.cn/MulanPSL2 ++// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++// See the Mulan PSL v2 for more details. ++ ++pub use super::hwf_adapter::usb::OhusbDevice; ++ ++use std::sync::Arc; ++ ++use anyhow::{bail, Result}; ++ ++use super::hwf_adapter::hwf_adapter_usb_api; ++use super::hwf_adapter::usb::UsbFuncTable; ++ ++#[derive(Clone)] ++pub struct OhUsb { ++ capi: Arc, ++} ++ ++impl OhUsb { ++ pub fn new() -> Result { ++ let capi = hwf_adapter_usb_api(); ++ Ok(Self { capi }) ++ } ++ ++ pub fn open_device(&self, dev_handle: *mut OhusbDevice) -> Result { ++ // SAFETY: We call related API sequentially for specified ctx. ++ let ret = unsafe { (self.capi.open_device)(dev_handle) }; ++ if ret < 0 { ++ bail!("OH USB: open device failed."); ++ } ++ Ok(ret) ++ } ++ ++ pub fn close_device(&self, dev_handle: *mut OhusbDevice) -> Result { ++ // SAFETY: We call related API sequentially for specified ctx. ++ let ret = unsafe { (self.capi.close_device)(dev_handle) }; ++ if ret < 0 { ++ bail!("OH USB: close device failed."); ++ } ++ Ok(ret) ++ } ++} +diff --git a/util/src/seccomp.rs b/util/src/seccomp.rs +index 41206a3..d3033d4 100644 +--- a/util/src/seccomp.rs ++++ b/util/src/seccomp.rs +@@ -24,6 +24,7 @@ + //! + //! - `x86_64` + //! - `aarch64` ++//! - `riscv64` + //! + //! ## Examples + //! +@@ -54,6 +55,8 @@ + //! let nr = libc::SYS_open; + //! #[cfg(target_arch = "aarch64")] + //! let nr = libc::SYS_openat; ++//! #[cfg(target_arch = "riscv64")] ++//! let nr = libc::SYS_openat; + //! nr + //! }; + //! +@@ -127,6 +130,8 @@ const SECCOMP_FILETER_FLAG_TSYNC: u32 = 1; + const EM_X86_64: u32 = 62; + #[cfg(target_arch = "aarch64")] + const EM_AARCH64: u32 = 183; ++#[cfg(target_arch = "riscv64")] ++const EM_RISCV64: u32 = 243; + const __AUDIT_ATCH_64BIT: u32 = 0x8000_0000; + const __AUDIT_ARCH_LE: u32 = 0x4000_0000; + #[cfg(target_arch = "x86_64")] +@@ -135,6 +140,9 @@ const AUDIT_ARCH_X86_64: u32 = EM_X86_64 | __AUDIT_ATCH_64BIT | __AUDIT_ARCH_LE; + #[cfg(target_arch = "aarch64")] + /// See: https://elixir.bootlin.com/linux/v4.19.123/source/include/uapi/linux/audit.h#L376 + const AUDIT_ARCH_AARCH64: u32 = EM_AARCH64 | __AUDIT_ATCH_64BIT | __AUDIT_ARCH_LE; ++#[cfg(target_arch = "riscv64")] ++/// See: https://elixir.bootlin.com/linux/v5.0/source/include/uapi/linux/audit.h#L376 ++const AUDIT_ARCH_RISCV64: u32 = EM_RISCV64 | __AUDIT_ATCH_64BIT | __AUDIT_ARCH_LE; + + /// Compared operator in bpf filter rule. + #[derive(Copy, Clone, PartialEq, Eq)] +@@ -270,6 +278,8 @@ fn validate_architecture() -> Vec { + bpf_jump(BPF_JMP + BPF_JEQ, AUDIT_ARCH_X86_64, 1, 0), + #[cfg(target_arch = "aarch64")] + bpf_jump(BPF_JMP + BPF_JEQ, AUDIT_ARCH_AARCH64, 1, 0), ++ #[cfg(target_arch = "riscv64")] ++ bpf_jump(BPF_JMP + BPF_JEQ, AUDIT_ARCH_RISCV64, 1, 0), + bpf_stmt(BPF_RET + BPF_K, SECCOMP_RET_KILL), + ] + } +@@ -494,6 +504,8 @@ mod tests { + k: 0xC000_003E, + #[cfg(target_arch = "aarch64")] + k: 0xC000_00B7, ++ #[cfg(target_arch = "riscv64")] ++ k: 0xC000_00F3, + }, + // Ret kill + SockFilter { +@@ -518,6 +530,8 @@ mod tests { + k: 0, + #[cfg(target_arch = "aarch64")] + k: 63, ++ #[cfg(target_arch = "riscv64")] ++ k: 63, + }, + // Ret allow + SockFilter { +@@ -555,6 +569,8 @@ mod tests { + k: 0xC000_003E, + #[cfg(target_arch = "aarch64")] + k: 0xC000_00B7, ++ #[cfg(target_arch = "riscv64")] ++ k: 0xC000_00F3, + }, + // Ret kill + SockFilter { +@@ -579,6 +595,8 @@ mod tests { + k: 0, + #[cfg(target_arch = "aarch64")] + k: 63, ++ #[cfg(target_arch = "riscv64")] ++ k: 63, + }, + // Load arg + SockFilter { +@@ -627,6 +645,8 @@ mod tests { + k: 0, + #[cfg(target_arch = "aarch64")] + k: 63, ++ #[cfg(target_arch = "riscv64")] ++ k: 63, + }, + // Load arg + SockFilter { +diff --git a/util/src/socket.rs b/util/src/socket.rs +index 3b1290b..573b7f4 100644 +--- a/util/src/socket.rs ++++ b/util/src/socket.rs +@@ -41,6 +41,13 @@ impl SocketStream { + } => link_description.clone(), + } + } ++ ++ pub fn set_nonblocking(&mut self, nonblocking: bool) -> IoResult<()> { ++ match self { ++ SocketStream::Tcp { stream, .. } => stream.set_nonblocking(nonblocking), ++ SocketStream::Unix { stream, .. } => stream.set_nonblocking(nonblocking), ++ } ++ } + } + + impl AsRawFd for SocketStream { +@@ -132,6 +139,7 @@ impl SocketListener { + match self { + SocketListener::Tcp { listener, address } => { + let (stream, sock_addr) = listener.accept()?; ++ stream.set_nonblocking(true)?; + let peer_address = sock_addr.to_string(); + let link_description = format!( + "{{ protocol: tcp, address: {}, peer: {} }}", +@@ -144,6 +152,7 @@ impl SocketListener { + } + SocketListener::Unix { listener, address } => { + let (stream, _) = listener.accept()?; ++ stream.set_nonblocking(true)?; + let link_description = format!("{{ protocol: unix, address: {} }}", address); + Ok(SocketStream::Unix { + link_description, +diff --git a/util/src/test_helper.rs b/util/src/test_helper.rs +index 7f69b42..47cb11b 100644 +--- a/util/src/test_helper.rs ++++ b/util/src/test_helper.rs +@@ -16,25 +16,25 @@ use std::time::{Duration, Instant}; + use once_cell::sync::{Lazy, OnceCell}; + + #[derive(Default, Clone, Copy)] +-struct MsixMsg { +- addr: u64, +- data: u32, ++pub struct MsixMsg { ++ pub addr: u64, ++ pub data: u32, + } + + impl MsixMsg { +- fn new(addr: u64, data: u32) -> Self { ++ pub fn new(addr: u64, data: u32) -> Self { + MsixMsg { addr, data } + } + } + + #[derive(Default, Clone, Copy, Debug)] +-struct IntxInfo { +- irq: u32, +- level: i8, ++pub struct IntxInfo { ++ pub irq: u32, ++ pub level: i8, + } + + impl IntxInfo { +- fn new(irq: u32, level: i8) -> Self { ++ pub fn new(irq: u32, level: i8) -> Self { + IntxInfo { irq, level } + } + } +@@ -42,8 +42,8 @@ impl IntxInfo { + static TEST_ENABLED: OnceCell = OnceCell::new(); + static TEST_BASE_TIME: OnceCell = OnceCell::new(); + static mut TEST_CLOCK: Option>> = None; +-static TEST_MSIX_LIST: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); +-static TEST_INTX_LIST: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); ++pub static TEST_MSIX_LIST: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); ++pub static TEST_INTX_LIST: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); + + pub fn set_test_enabled() { + if let Err(_e) = TEST_ENABLED.set(true) { +@@ -139,20 +139,6 @@ pub fn has_msix_msg(addr: u64, data: u32) -> bool { + } + } + +-pub fn trigger_intx(irq: u32, change: i8) { +- let new_intx = IntxInfo::new(irq, change); +- let mut intx_list_lock = TEST_INTX_LIST.lock().unwrap(); +- +- for intx in intx_list_lock.iter_mut() { +- if intx.irq == new_intx.irq { +- intx.level += new_intx.level; +- return; +- } +- } +- +- intx_list_lock.push(new_intx); +-} +- + pub fn query_intx(irq: u32) -> bool { + let mut intx_list_lock = TEST_INTX_LIST.lock().unwrap(); + for intx in intx_list_lock.iter_mut() { +diff --git a/util/src/unix.rs b/util/src/unix.rs +index d71e3c8..6a723ed 100644 +--- a/util/src/unix.rs ++++ b/util/src/unix.rs +@@ -187,10 +187,11 @@ impl UnixSock { + + /// The listener accepts incoming client connections. + pub fn accept(&mut self) -> Result<()> { +- let (sock, _addr) = self ++ let listener = self + .listener + .as_ref() +- .unwrap() ++ .with_context(|| "UnixSock is not bound")?; ++ let (sock, _addr) = listener + .accept() + .with_context(|| format!("Failed to accept the socket {}", self.path))?; + self.sock = Some(sock); +@@ -203,8 +204,12 @@ impl UnixSock { + } + + pub fn server_connection_refuse(&mut self) -> Result<()> { ++ let listener = self ++ .listener ++ .as_ref() ++ .with_context(|| "UnixSock is not bound")?; + // Refuse connection by finishing life cycle of stream fd from listener fd. +- self.listener.as_ref().unwrap().accept().with_context(|| { ++ listener.accept().with_context(|| { + format!( + "Failed to accept the socket for refused connection {}", + self.path +@@ -224,18 +229,21 @@ impl UnixSock { + } + + pub fn listen_set_nonblocking(&self, nonblocking: bool) -> Result<()> { +- self.listener ++ let listener = self ++ .listener + .as_ref() +- .unwrap() ++ .with_context(|| "UnixSock is not bound")?; ++ listener + .set_nonblocking(nonblocking) + .with_context(|| "couldn't set nonblocking for unix sock listener") + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> { +- self.sock ++ let sock = self ++ .sock + .as_ref() +- .unwrap() +- .set_nonblocking(nonblocking) ++ .with_context(|| "UnixSock is not connected")?; ++ sock.set_nonblocking(nonblocking) + .with_context(|| "couldn't set nonblocking") + } + +@@ -287,7 +295,7 @@ impl UnixSock { + /// # Errors + /// + /// The socket file descriptor is broken. +- pub fn send_msg(&self, iovecs: &mut [iovec], out_fds: &[RawFd]) -> std::io::Result { ++ pub fn send_msg(&self, iovecs: &mut [iovec], out_fds: &[RawFd]) -> Result { + // SAFETY: We checked the iovecs lens before. + let iovecs_len = iovecs.len(); + // SAFETY: We checked the out_fds lens before. +@@ -331,17 +339,17 @@ impl UnixSock { + msg.msg_controllen = cmsg_capacity as _; + } + +- let write_count = +- // SAFETY: msg parameters are valid. +- unsafe { sendmsg(self.sock.as_ref().unwrap().as_raw_fd(), &msg, MSG_NOSIGNAL) }; ++ let sock = self ++ .sock ++ .as_ref() ++ .with_context(|| "UnixSock is not connected")?; ++ // SAFETY: msg parameters are valid. ++ let write_count = unsafe { sendmsg(sock.as_raw_fd(), &msg, MSG_NOSIGNAL) }; + + if write_count == -1 { +- Err(std::io::Error::new( +- std::io::ErrorKind::InvalidData, +- format!( +- "Failed to send msg, err: {}", +- std::io::Error::last_os_error() +- ), ++ Err(anyhow!( ++ "Failed to send msg, err: {}", ++ std::io::Error::last_os_error() + )) + } else { + Ok(write_count as usize) +@@ -358,11 +366,7 @@ impl UnixSock { + /// # Errors + /// + /// The socket file descriptor is broken. +- pub fn recv_msg( +- &self, +- iovecs: &mut [iovec], +- in_fds: &mut [RawFd], +- ) -> std::io::Result<(usize, usize)> { ++ pub fn recv_msg(&self, iovecs: &mut [iovec], in_fds: &mut [RawFd]) -> Result<(usize, usize)> { + // SAFETY: We check the iovecs lens before. + let iovecs_len = iovecs.len(); + // SAFETY: We check the in_fds lens before. +@@ -386,33 +390,25 @@ impl UnixSock { + msg.msg_controllen = cmsg_capacity as _; + } + ++ let sock = self ++ .sock ++ .as_ref() ++ .with_context(|| "UnixSock is not connected")?; + // SAFETY: msg parameters are valid. +- let total_read = unsafe { +- recvmsg( +- self.sock.as_ref().unwrap().as_raw_fd(), +- &mut msg, +- MSG_WAITALL, +- ) +- }; ++ let total_read = unsafe { recvmsg(sock.as_raw_fd(), &mut msg, MSG_WAITALL) }; + + if total_read == -1 { +- return Err(std::io::Error::new( +- std::io::ErrorKind::InvalidData, +- format!( +- "Failed to recv msg, err: {}", +- std::io::Error::last_os_error() +- ), +- )); ++ bail!( ++ "Failed to recv msg, err: {}", ++ std::io::Error::last_os_error() ++ ); + } + if total_read == 0 && (msg.msg_controllen as u64) < size_of::() as u64 { +- return Err(std::io::Error::new( +- std::io::ErrorKind::InvalidData, +- format!( +- "The length of control message is invalid, {} {}", +- msg.msg_controllen, +- size_of::() +- ), +- )); ++ bail!( ++ "The length of control message is invalid, {} {}", ++ msg.msg_controllen, ++ size_of::() ++ ); + } + + let mut cmsg_ptr = msg.msg_control as *mut cmsghdr; +diff --git a/vendor/memoffset-0.7.1/.cargo-checksum.json b/vendor/memoffset-0.7.1/.cargo-checksum.json +deleted file mode 100644 +index 60f2c09..0000000 +--- a/vendor/memoffset-0.7.1/.cargo-checksum.json ++++ /dev/null +@@ -1 +0,0 @@ +-{"files":{"Cargo.toml":"2122b76e5dff09497c7edf7f184155e456e44209c05e4f8abb01632be7241b56","LICENSE":"3234ac55816264ee7b6c7ee27efd61cf0a1fe775806870e3d9b4c41ea73c5cb1","README.md":"7a7935d96a1a40b56afeadca391c742f7ac3a6e0f1deab1d43430553f71b6d23","build.rs":"6d677e33a1c98d588c97ec7985d4d5c3b954683e0a73c3dc53d79db4fbb5e638","src/lib.rs":"e7976d295371a3c1e0cf31b0d50210cd6b1135caba3a5111403a97ec6175c0a2","src/offset_of.rs":"ea04e76e3ab1fa192618fffb0c6a047795c275f1deaf6c6617245badaba8660c","src/raw_field.rs":"ef54087d5f507c2b639a4f61f2881eb1e41a46e22191ffd0e23b2fe9e3f17c25","src/span_of.rs":"b900faef2b852b52c37c55a172c05c9144bfff7d84dbc06e943fb0453d68adfc"},"package":"5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"} +\ No newline at end of file +diff --git a/vendor/memoffset-0.7.1/Cargo.toml b/vendor/memoffset-0.7.1/Cargo.toml +deleted file mode 100644 +index 1677446..0000000 +--- a/vendor/memoffset-0.7.1/Cargo.toml ++++ /dev/null +@@ -1,36 +0,0 @@ +-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +-# +-# When uploading crates to the registry Cargo will automatically +-# "normalize" Cargo.toml files for maximal compatibility +-# with all versions of Cargo and also rewrite `path` dependencies +-# to registry (e.g., crates.io) dependencies. +-# +-# If you are reading this file be aware that the original Cargo.toml +-# will likely look very different (and much more reasonable). +-# See Cargo.toml.orig for the original contents. +- +-[package] +-name = "memoffset" +-version = "0.7.1" +-authors = ["Gilad Naaman "] +-description = "offset_of functionality for Rust structs." +-readme = "README.md" +-keywords = [ +- "mem", +- "offset", +- "offset_of", +- "offsetof", +-] +-categories = ["no-std"] +-license = "MIT" +-repository = "https://github.com/Gilnaa/memoffset" +- +-[dev-dependencies.doc-comment] +-version = "0.3" +- +-[build-dependencies.autocfg] +-version = "1" +- +-[features] +-default = [] +-unstable_const = [] +diff --git a/vendor/memoffset-0.7.1/LICENSE b/vendor/memoffset-0.7.1/LICENSE +deleted file mode 100644 +index 61f6081..0000000 +--- a/vendor/memoffset-0.7.1/LICENSE ++++ /dev/null +@@ -1,19 +0,0 @@ +-Copyright (c) 2017 Gilad Naaman +- +-Permission is hereby granted, free of charge, to any person obtaining a copy +-of this software and associated documentation files (the "Software"), to deal +-in the Software without restriction, including without limitation the rights +-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-copies of the Software, and to permit persons to whom the Software is +-furnished to do so, subject to the following conditions: +- +-The above copyright notice and this permission notice shall be included in all +-copies or substantial portions of the Software. +- +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-SOFTWARE. +\ No newline at end of file +diff --git a/vendor/memoffset-0.7.1/README.md b/vendor/memoffset-0.7.1/README.md +deleted file mode 100644 +index e297b33..0000000 +--- a/vendor/memoffset-0.7.1/README.md ++++ /dev/null +@@ -1,65 +0,0 @@ +-# memoffset # +- +-[![](https://img.shields.io/crates/v/memoffset.svg)](https://crates.io/crates/memoffset) +- +-C-Like `offset_of` functionality for Rust structs. +- +-Introduces the following macros: +- * `offset_of!` for obtaining the offset of a member of a struct. +- * `offset_of_tuple!` for obtaining the offset of a member of a tuple. (Requires Rust 1.20+) +- * `span_of!` for obtaining the range that a field, or fields, span. +- +-`memoffset` works under `no_std` environments. +- +-## Usage ## +-Add the following dependency to your `Cargo.toml`: +- +-```toml +-[dependencies] +-memoffset = "0.7" +-``` +- +-These versions will compile fine with rustc versions greater or equal to 1.19. +- +-## Examples ## +-```rust +-use memoffset::{offset_of, span_of}; +- +-#[repr(C, packed)] +-struct Foo { +- a: u32, +- b: u32, +- c: [u8; 5], +- d: u32, +-} +- +-fn main() { +- assert_eq!(offset_of!(Foo, b), 4); +- assert_eq!(offset_of!(Foo, d), 4+4+5); +- +- assert_eq!(span_of!(Foo, a), 0..4); +- assert_eq!(span_of!(Foo, a .. c), 0..8); +- assert_eq!(span_of!(Foo, a ..= c), 0..13); +- assert_eq!(span_of!(Foo, ..= d), 0..17); +- assert_eq!(span_of!(Foo, b ..), 4..17); +-} +-``` +- +-## Feature flags ## +- +-### Usage in constants ### +-`memoffset` has **experimental** support for compile-time `offset_of!` on a nightly compiler. +- +-In order to use it, you must enable the `unstable_const` crate feature and several compiler features. +- +-Cargo.toml: +-```toml +-[dependencies.memoffset] +-version = "0.7" +-features = ["unstable_const"] +-``` +- +-Your crate root: (`lib.rs`/`main.rs`) +-```rust,ignore +-#![feature(const_ptr_offset_from, const_refs_to_cell)] +-``` +diff --git a/vendor/memoffset-0.7.1/build.rs b/vendor/memoffset-0.7.1/build.rs +deleted file mode 100644 +index 0604c19..0000000 +--- a/vendor/memoffset-0.7.1/build.rs ++++ /dev/null +@@ -1,22 +0,0 @@ +-extern crate autocfg; +- +-fn main() { +- let ac = autocfg::new(); +- +- // Check for a minimum version for a few features +- if ac.probe_rustc_version(1, 20) { +- println!("cargo:rustc-cfg=tuple_ty"); +- } +- if ac.probe_rustc_version(1, 31) { +- println!("cargo:rustc-cfg=allow_clippy"); +- } +- if ac.probe_rustc_version(1, 36) { +- println!("cargo:rustc-cfg=maybe_uninit"); +- } +- if ac.probe_rustc_version(1, 40) { +- println!("cargo:rustc-cfg=doctests"); +- } +- if ac.probe_rustc_version(1, 51) { +- println!("cargo:rustc-cfg=raw_ref_macros"); +- } +-} +diff --git a/vendor/memoffset-0.7.1/src/lib.rs b/vendor/memoffset-0.7.1/src/lib.rs +deleted file mode 100644 +index d80ff17..0000000 +--- a/vendor/memoffset-0.7.1/src/lib.rs ++++ /dev/null +@@ -1,92 +0,0 @@ +-// Copyright (c) 2017 Gilad Naaman +-// +-// Permission is hereby granted, free of charge, to any person obtaining a copy +-// of this software and associated documentation files (the "Software"), to deal +-// in the Software without restriction, including without limitation the rights +-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-// copies of the Software, and to permit persons to whom the Software is +-// furnished to do so, subject to the following conditions: +-// +-// The above copyright notice and this permission notice shall be included in all +-// copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-// SOFTWARE. +- +-//! A crate used for calculating offsets of struct members and their spans. +-//! +-//! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions. +-//! +-//! ## Examples +-//! ``` +-//! use memoffset::{offset_of, span_of}; +-//! +-//! #[repr(C, packed)] +-//! struct HelpMeIAmTrappedInAStructFactory { +-//! help_me_before_they_: [u8; 15], +-//! a: u32 +-//! } +-//! +-//! fn main() { +-//! assert_eq!(offset_of!(HelpMeIAmTrappedInAStructFactory, a), 15); +-//! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, a), 15..19); +-//! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, help_me_before_they_ .. a), 0..15); +-//! } +-//! ``` +-//! +-//! This functionality can be useful, for example, for checksum calculations: +-//! +-//! ```ignore +-//! #[repr(C, packed)] +-//! struct Message { +-//! header: MessageHeader, +-//! fragment_index: u32, +-//! fragment_count: u32, +-//! payload: [u8; 1024], +-//! checksum: u16 +-//! } +-//! +-//! let checksum_range = &raw[span_of!(Message, header..checksum)]; +-//! let checksum = crc16(checksum_range); +-//! ``` +- +-#![no_std] +-#![cfg_attr( +- feature = "unstable_const", +- feature(const_ptr_offset_from, const_refs_to_cell) +-)] +- +-#[macro_use] +-#[cfg(doctests)] +-#[cfg(doctest)] +-extern crate doc_comment; +-#[cfg(doctests)] +-#[cfg(doctest)] +-doctest!("../README.md"); +- +-/// Hidden module for things the macros need to access. +-#[doc(hidden)] +-pub mod __priv { +- #[doc(hidden)] +- pub use core::mem; +- #[doc(hidden)] +- pub use core::ptr; +- +- /// Use type inference to obtain the size of the pointee (without actually using the pointer). +- #[doc(hidden)] +- pub fn size_of_pointee(_ptr: *const T) -> usize { +- mem::size_of::() +- } +-} +- +-#[macro_use] +-mod raw_field; +-#[macro_use] +-mod offset_of; +-#[macro_use] +-mod span_of; +diff --git a/vendor/memoffset-0.7.1/src/offset_of.rs b/vendor/memoffset-0.7.1/src/offset_of.rs +deleted file mode 100644 +index d070181..0000000 +--- a/vendor/memoffset-0.7.1/src/offset_of.rs ++++ /dev/null +@@ -1,356 +0,0 @@ +-// Copyright (c) 2017 Gilad Naaman +-// +-// Permission is hereby granted, free of charge, to any person obtaining a copy +-// of this software and associated documentation files (the "Software"), to deal +-// in the Software without restriction, including without limitation the rights +-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-// copies of the Software, and to permit persons to whom the Software is +-// furnished to do so, subject to the following conditions: +-// +-// The above copyright notice and this permission notice shall be included in all +-// copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-// SOFTWARE. +- +-/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as +-/// much as is possible currently. +-#[cfg(maybe_uninit)] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__let_base_ptr { +- ($name:ident, $type:ty) => { +- // No UB here, and the pointer does not dangle, either. +- // But we have to make sure that `uninit` lives long enough, +- // so it has to be in the same scope as `$name`. That's why +- // `let_base_ptr` declares a variable (several, actually) +- // instead of returning one. +- let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit(); +- let $name: *const $type = uninit.as_ptr(); +- }; +-} +-#[cfg(not(maybe_uninit))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__let_base_ptr { +- ($name:ident, $type:ty) => { +- // No UB right here, but we will later dereference this pointer to +- // offset into a field, and that is UB because the pointer is dangling. +- let $name = $crate::__priv::mem::align_of::<$type>() as *const $type; +- }; +-} +- +-/// Macro to compute the distance between two pointers. +-#[cfg(feature = "unstable_const")] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset_offset_from_unsafe { +- ($field:expr, $base:expr) => {{ +- let field = $field; // evaluate $field outside the `unsafe` block +- let base = $base; // evaluate $base outside the `unsafe` block +- // Compute offset, with unstable `offset_from` for const-compatibility. +- // (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.) +- unsafe { (field as *const u8).offset_from(base as *const u8) as usize } +- }}; +-} +-#[cfg(not(feature = "unstable_const"))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset_offset_from_unsafe { +- ($field:expr, $base:expr) => { +- // Compute offset. +- ($field as usize) - ($base as usize) +- }; +-} +- +-/// Calculates the offset of the specified field from the start of the named struct. +-/// +-/// ## Examples +-/// ``` +-/// use memoffset::offset_of; +-/// +-/// #[repr(C, packed)] +-/// struct Foo { +-/// a: u32, +-/// b: u64, +-/// c: [u8; 5] +-/// } +-/// +-/// fn main() { +-/// assert_eq!(offset_of!(Foo, a), 0); +-/// assert_eq!(offset_of!(Foo, b), 4); +-/// } +-/// ``` +-/// +-/// ## Notes +-/// Rust's ABI is unstable, and [type layout can be changed with each +-/// compilation](https://doc.rust-lang.org/reference/type-layout.html). +-/// +-/// Using `offset_of!` with a `repr(Rust)` struct will return the correct offset of the +-/// specified `field` for a particular compilation, but the exact value may change +-/// based on the compiler version, concrete struct type, time of day, or rustc's mood. +-/// +-/// As a result, the value should not be retained and used between different compilations. +-#[macro_export(local_inner_macros)] +-macro_rules! offset_of { +- ($parent:path, $field:tt) => {{ +- // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). +- _memoffset__let_base_ptr!(base_ptr, $parent); +- // Get field pointer. +- let field_ptr = raw_field!(base_ptr, $parent, $field); +- // Compute offset. +- _memoffset_offset_from_unsafe!(field_ptr, base_ptr) +- }}; +-} +- +-/// Calculates the offset of the specified field from the start of the tuple. +-/// +-/// ## Examples +-/// ``` +-/// use memoffset::offset_of_tuple; +-/// +-/// fn main() { +-/// assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout"); +-/// } +-/// ``` +-#[cfg(tuple_ty)] +-#[macro_export(local_inner_macros)] +-macro_rules! offset_of_tuple { +- ($parent:ty, $field:tt) => {{ +- // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). +- _memoffset__let_base_ptr!(base_ptr, $parent); +- // Get field pointer. +- let field_ptr = raw_field_tuple!(base_ptr, $parent, $field); +- // Compute offset. +- _memoffset_offset_from_unsafe!(field_ptr, base_ptr) +- }}; +-} +- +-/// Calculates the offset of the specified union member from the start of the union. +-/// +-/// ## Examples +-/// ``` +-/// use memoffset::offset_of_union; +-/// +-/// #[repr(C, packed)] +-/// union Foo { +-/// foo32: i32, +-/// foo64: i64, +-/// } +-/// +-/// fn main() { +-/// assert!(offset_of_union!(Foo, foo64) == 0); +-/// } +-/// ``` +-/// +-/// ## Note +-/// Due to macro_rules limitations, this macro will accept structs with a single field as well as unions. +-/// This is not a stable guarantee, and future versions of this crate might fail +-/// on any use of this macro with a struct, without a semver bump. +-#[macro_export(local_inner_macros)] +-macro_rules! offset_of_union { +- ($parent:path, $field:tt) => {{ +- // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). +- _memoffset__let_base_ptr!(base_ptr, $parent); +- // Get field pointer. +- let field_ptr = raw_field_union!(base_ptr, $parent, $field); +- // Compute offset. +- _memoffset_offset_from_unsafe!(field_ptr, base_ptr) +- }}; +-} +- +-#[cfg(test)] +-mod tests { +- #[test] +- fn offset_simple() { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!(offset_of!(Foo, a), 0); +- assert_eq!(offset_of!(Foo, b), 4); +- assert_eq!(offset_of!(Foo, c), 8); +- } +- +- #[test] +- #[cfg_attr(miri, ignore)] // this creates unaligned references +- fn offset_simple_packed() { +- #[repr(C, packed)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!(offset_of!(Foo, a), 0); +- assert_eq!(offset_of!(Foo, b), 4); +- assert_eq!(offset_of!(Foo, c), 6); +- } +- +- #[test] +- fn tuple_struct() { +- #[repr(C)] +- struct Tup(i32, i32); +- +- assert_eq!(offset_of!(Tup, 0), 0); +- assert_eq!(offset_of!(Tup, 1), 4); +- } +- +- #[test] +- fn offset_union() { +- // Since we're specifying repr(C), all fields are supposed to be at offset 0 +- #[repr(C)] +- union Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!(offset_of_union!(Foo, a), 0); +- assert_eq!(offset_of_union!(Foo, b), 0); +- assert_eq!(offset_of_union!(Foo, c), 0); +- } +- +- #[test] +- fn path() { +- mod sub { +- #[repr(C)] +- pub struct Foo { +- pub x: u32, +- } +- } +- +- assert_eq!(offset_of!(sub::Foo, x), 0); +- } +- +- #[test] +- fn inside_generic_method() { +- struct Pair(T, U); +- +- fn foo(_: Pair) -> usize { +- offset_of!(Pair, 1) +- } +- +- assert_eq!(foo(Pair(0, 0)), 4); +- } +- +- #[cfg(tuple_ty)] +- #[test] +- fn test_tuple_offset() { +- let f = (0i32, 0.0f32, 0u8); +- let f_ptr = &f as *const _; +- let f1_ptr = &f.1 as *const _; +- +- assert_eq!( +- f1_ptr as usize - f_ptr as usize, +- offset_of_tuple!((i32, f32, u8), 1) +- ); +- } +- +- #[test] +- fn test_raw_field() { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- let f: Foo = Foo { +- a: 0, +- b: [0, 0], +- c: 0, +- }; +- let f_ptr = &f as *const _; +- assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize); +- assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize); +- assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize); +- } +- +- #[cfg(tuple_ty)] +- #[test] +- fn test_raw_field_tuple() { +- let t = (0u32, 0u8, false); +- let t_ptr = &t as *const _; +- let t_addr = t_ptr as usize; +- +- assert_eq!( +- &t.0 as *const _ as usize - t_addr, +- raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr +- ); +- assert_eq!( +- &t.1 as *const _ as usize - t_addr, +- raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr +- ); +- assert_eq!( +- &t.2 as *const _ as usize - t_addr, +- raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr +- ); +- } +- +- #[test] +- fn test_raw_field_union() { +- #[repr(C)] +- union Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- let f = Foo { a: 0 }; +- let f_ptr = &f as *const _; +- assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize); +- assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize); +- assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize); +- } +- +- #[cfg(feature = "unstable_const")] +- #[test] +- fn const_offset() { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!([0; offset_of!(Foo, b)].len(), 4); +- } +- +- #[cfg(feature = "unstable_const")] +- #[test] +- fn const_offset_interior_mutable() { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: core::cell::Cell, +- } +- +- assert_eq!([0; offset_of!(Foo, b)].len(), 4); +- } +- +- #[cfg(feature = "unstable_const")] +- #[test] +- fn const_fn_offset() { +- const fn test_fn() -> usize { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- offset_of!(Foo, b) +- } +- +- assert_eq!([0; test_fn()].len(), 4); +- } +-} +diff --git a/vendor/memoffset-0.7.1/src/raw_field.rs b/vendor/memoffset-0.7.1/src/raw_field.rs +deleted file mode 100644 +index e16df9f..0000000 +--- a/vendor/memoffset-0.7.1/src/raw_field.rs ++++ /dev/null +@@ -1,226 +0,0 @@ +-// Copyright (c) 2020 Gilad Naaman, Ralf Jung +-// +-// Permission is hereby granted, free of charge, to any person obtaining a copy +-// of this software and associated documentation files (the "Software"), to deal +-// in the Software without restriction, including without limitation the rights +-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-// copies of the Software, and to permit persons to whom the Software is +-// furnished to do so, subject to the following conditions: +-// +-// The above copyright notice and this permission notice shall be included in all +-// copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-// SOFTWARE. +- +-/// `addr_of!`, or just ref-then-cast when that is not available. +-#[cfg(raw_ref_macros)] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__addr_of { +- ($path:expr) => {{ +- $crate::__priv::ptr::addr_of!($path) +- }}; +-} +-#[cfg(not(raw_ref_macros))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__addr_of { +- ($path:expr) => {{ +- // This is UB because we create an intermediate reference to uninitialized memory. +- // Nothing we can do about that without `addr_of!` though. +- &$path as *const _ +- }}; +-} +- +-/// Deref-coercion protection macro. +-/// +-/// Prevents complilation if the specified field name is not a part of the +-/// struct definition. +-/// +-/// ```compile_fail +-/// use memoffset::_memoffset__field_check; +-/// +-/// struct Foo { +-/// foo: i32, +-/// } +-/// +-/// type BoxedFoo = Box; +-/// +-/// _memoffset__field_check!(BoxedFoo, foo); +-/// ``` +-#[cfg(allow_clippy)] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check { +- ($type:path, $field:tt) => { +- // Make sure the field actually exists. This line ensures that a +- // compile-time error is generated if $field is accessed through a +- // Deref impl. +- #[allow(clippy::unneeded_field_pattern)] +- let $type { $field: _, .. }; +- }; +-} +-#[cfg(not(allow_clippy))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check { +- ($type:path, $field:tt) => { +- // Make sure the field actually exists. This line ensures that a +- // compile-time error is generated if $field is accessed through a +- // Deref impl. +- let $type { $field: _, .. }; +- }; +-} +- +-/// Deref-coercion protection macro. +-/// +-/// Prevents complilation if the specified type is not a tuple. +-/// +-/// ```compile_fail +-/// use memoffset::_memoffset__field_check_tuple; +-/// +-/// _memoffset__field_check_tuple!(i32, 0); +-/// ``` +-#[cfg(allow_clippy)] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check_tuple { +- ($type:ty, $field:tt) => { +- // Make sure the type argument is a tuple +- #[allow(clippy::unneeded_wildcard_pattern)] +- let (_, ..): $type; +- }; +-} +-#[cfg(not(allow_clippy))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check_tuple { +- ($type:ty, $field:tt) => { +- // Make sure the type argument is a tuple +- let (_, ..): $type; +- }; +-} +- +-/// Deref-coercion protection macro for unions. +-/// Unfortunately accepts single-field structs as well, which is not ideal, +-/// but ultimately pretty harmless. +-/// +-/// ```compile_fail +-/// use memoffset::_memoffset__field_check_union; +-/// +-/// union Foo { +-/// variant_a: i32, +-/// } +-/// +-/// type BoxedFoo = Box; +-/// +-/// _memoffset__field_check_union!(BoxedFoo, variant_a); +-/// ``` +-#[cfg(allow_clippy)] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check_union { +- ($type:path, $field:tt) => { +- // Make sure the field actually exists. This line ensures that a +- // compile-time error is generated if $field is accessed through a +- // Deref impl. +- #[allow(clippy::unneeded_wildcard_pattern)] +- // rustc1.19 requires unsafe here for the pattern; not needed in newer versions +- #[allow(unused_unsafe)] +- unsafe { +- let $type { $field: _ }; +- } +- }; +-} +-#[cfg(not(allow_clippy))] +-#[macro_export] +-#[doc(hidden)] +-macro_rules! _memoffset__field_check_union { +- ($type:path, $field:tt) => { +- // Make sure the field actually exists. This line ensures that a +- // compile-time error is generated if $field is accessed through a +- // Deref impl. +- // rustc1.19 requires unsafe here for the pattern; not needed in newer versions +- #[allow(unused_unsafe)] +- unsafe { +- let $type { $field: _ }; +- } +- }; +-} +- +-/// Computes a const raw pointer to the given field of the given base pointer +-/// to the given parent type. +-/// +-/// The `base` pointer *must not* be dangling, but it *may* point to +-/// uninitialized memory. +-#[macro_export(local_inner_macros)] +-macro_rules! raw_field { +- ($base:expr, $parent:path, $field:tt) => {{ +- _memoffset__field_check!($parent, $field); +- let base = $base; // evaluate $base outside the `unsafe` block +- +- // Get the field address. +- // Crucially, we know that this will not trigger a deref coercion because +- // of the field check we did above. +- #[allow(unused_unsafe)] // for when the macro is used in an unsafe block +- unsafe { +- _memoffset__addr_of!((*(base as *const $parent)).$field) +- } +- }}; +-} +- +-/// Computes a const raw pointer to the given field of the given base pointer +-/// to the given parent tuple typle. +-/// +-/// The `base` pointer *must not* be dangling, but it *may* point to +-/// uninitialized memory. +-#[cfg(tuple_ty)] +-#[macro_export(local_inner_macros)] +-macro_rules! raw_field_tuple { +- ($base:expr, $parent:ty, $field:tt) => {{ +- _memoffset__field_check_tuple!($parent, $field); +- let base = $base; // evaluate $base outside the `unsafe` block +- +- // Get the field address. +- // Crucially, we know that this will not trigger a deref coercion because +- // of the field check we did above. +- #[allow(unused_unsafe)] // for when the macro is used in an unsafe block +- unsafe { +- _memoffset__addr_of!((*(base as *const $parent)).$field) +- } +- }}; +-} +- +-/// Computes a const raw pointer to the given field of the given base pointer +-/// to the given parent tuple typle. +-/// +-/// The `base` pointer *must not* be dangling, but it *may* point to +-/// uninitialized memory. +-/// +-/// ## Note +-/// This macro is the same as `raw_field`, except for a different Deref-coercion check that +-/// supports unions. +-/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. +-/// This is not a stable guarantee, and future versions of this crate might fail +-/// on any use of this macro with a struct, without a semver bump. +-#[macro_export(local_inner_macros)] +-macro_rules! raw_field_union { +- ($base:expr, $parent:path, $field:tt) => {{ +- _memoffset__field_check_union!($parent, $field); +- let base = $base; // evaluate $base outside the `unsafe` block +- +- // Get the field address. +- // Crucially, we know that this will not trigger a deref coercion because +- // of the field check we did above. +- #[allow(unused_unsafe)] // for when the macro is used in an unsafe block +- unsafe { +- _memoffset__addr_of!((*(base as *const $parent)).$field) +- } +- }}; +-} +diff --git a/vendor/memoffset-0.7.1/src/span_of.rs b/vendor/memoffset-0.7.1/src/span_of.rs +deleted file mode 100644 +index 89fccce..0000000 +--- a/vendor/memoffset-0.7.1/src/span_of.rs ++++ /dev/null +@@ -1,263 +0,0 @@ +-// Copyright (c) 2017 Gilad Naaman +-// +-// Permission is hereby granted, free of charge, to any person obtaining a copy +-// of this software and associated documentation files (the "Software"), to deal +-// in the Software without restriction, including without limitation the rights +-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-// copies of the Software, and to permit persons to whom the Software is +-// furnished to do so, subject to the following conditions: +-// +-// The above copyright notice and this permission notice shall be included in all +-// copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-// SOFTWARE. +- +-/// Reexport for `local_inner_macros`; see +-/// . +-#[doc(hidden)] +-#[macro_export] +-macro_rules! _memoffset__compile_error { +- ($($inner:tt)*) => { +- compile_error! { $($inner)* } +- } +-} +- +-/// Produces a range instance representing the sub-slice containing the specified member. +-/// +-/// This macro provides 2 forms of differing functionalities. +-/// +-/// The first form is identical to the appearance of the `offset_of!` macro. +-/// +-/// ```ignore +-/// span_of!(Struct, member) +-/// ``` +-/// +-/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another. +-/// The general pattern of this form is: +-/// +-/// ```ignore +-/// // Exclusive +-/// span_of!(Struct, member_a .. member_b) +-/// // Inclusive +-/// span_of!(Struct, member_a ..= member_b) +-/// +-/// // Open-ended ranges +-/// span_of!(Struct, .. end) +-/// span_of!(Struct, start ..) +-/// ``` +-/// +-/// ### Note +-/// This macro uses recursion in order to resolve the range expressions, so there is a limit to +-/// the complexity of the expression. +-/// In order to raise the limit, the compiler's recursion limit should be lifted. +-/// +-/// ### Safety +-/// The inter-field form mentioned above assumes that the first field is positioned before the +-/// second. +-/// This is only guarenteed for `repr(C)` structs. +-/// Usage with `repr(Rust)` structs may yield unexpected results, like downward-going ranges, +-/// spans that include unexpected fields, empty spans, or spans that include *unexpected* padding bytes. +-/// +-/// ## Examples +-/// ``` +-/// use memoffset::span_of; +-/// +-/// #[repr(C)] +-/// struct Florp { +-/// a: u32 +-/// } +-/// +-/// #[repr(C)] +-/// struct Blarg { +-/// x: [u32; 2], +-/// y: [u8; 56], +-/// z: Florp, +-/// egg: [[u8; 4]; 4] +-/// } +-/// +-/// fn main() { +-/// assert_eq!(0..84, span_of!(Blarg, ..)); +-/// assert_eq!(0..8, span_of!(Blarg, .. y)); +-/// assert_eq!(0..64, span_of!(Blarg, ..= y)); +-/// assert_eq!(0..8, span_of!(Blarg, x)); +-/// assert_eq!(8..84, span_of!(Blarg, y ..)); +-/// assert_eq!(0..8, span_of!(Blarg, x .. y)); +-/// assert_eq!(0..64, span_of!(Blarg, x ..= y)); +-/// } +-/// ``` +-#[macro_export(local_inner_macros)] +-macro_rules! span_of { +- (@helper $root:ident, [] ..=) => { +- _memoffset__compile_error!("Expected a range, found '..='") +- }; +- (@helper $root:ident, [] ..) => { +- _memoffset__compile_error!("Expected a range, found '..'") +- }; +- // No explicit begin for range. +- (@helper $root:ident, $parent:path, [] ..) => {{ +- ($root as usize, +- $root as usize + $crate::__priv::size_of_pointee($root)) +- }}; +- (@helper $root:ident, $parent:path, [] ..= $end:tt) => {{ +- let end = raw_field!($root, $parent, $end); +- ($root as usize, end as usize + $crate::__priv::size_of_pointee(end)) +- }}; +- (@helper $root:ident, $parent:path, [] .. $end:tt) => {{ +- ($root as usize, raw_field!($root, $parent, $end) as usize) +- }}; +- // Explicit begin and end for range. +- (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{ +- let begin = raw_field!($root, $parent, $begin); +- let end = raw_field!($root, $parent, $end); +- (begin as usize, end as usize + $crate::__priv::size_of_pointee(end)) +- }}; +- (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{ +- (raw_field!($root, $parent, $begin) as usize, +- raw_field!($root, $parent, $end) as usize) +- }}; +- // No explicit end for range. +- (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{ +- (raw_field!($root, $parent, $begin) as usize, +- $root as usize + $crate::__priv::size_of_pointee($root)) +- }}; +- (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{ +- _memoffset__compile_error!( +- "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?") +- }}; +- // Just one field. +- (@helper $root:ident, $parent:path, # $field:tt []) => {{ +- let field = raw_field!($root, $parent, $field); +- (field as usize, field as usize + $crate::__priv::size_of_pointee(field)) +- }}; +- // Parsing. +- (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{ +- span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*) +- }}; +- (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{ +- span_of!(@helper $root, $parent, #$tt [] $($rest)*) +- }}; +- +- // Entry point. +- ($sty:path, $($exp:tt)+) => ({ +- // Get a base pointer. +- _memoffset__let_base_ptr!(root, $sty); +- let base = root as usize; +- let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*); +- begin-base..end-base +- }); +-} +- +-#[cfg(test)] +-mod tests { +- use core::mem; +- +- #[test] +- fn span_simple() { +- #[repr(C)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!(span_of!(Foo, a), 0..4); +- assert_eq!(span_of!(Foo, b), 4..6); +- assert_eq!(span_of!(Foo, c), 8..8 + 8); +- } +- +- #[test] +- #[cfg_attr(miri, ignore)] // this creates unaligned references +- fn span_simple_packed() { +- #[repr(C, packed)] +- struct Foo { +- a: u32, +- b: [u8; 2], +- c: i64, +- } +- +- assert_eq!(span_of!(Foo, a), 0..4); +- assert_eq!(span_of!(Foo, b), 4..6); +- assert_eq!(span_of!(Foo, c), 6..6 + 8); +- } +- +- #[test] +- fn span_forms() { +- #[repr(C)] +- struct Florp { +- a: u32, +- } +- +- #[repr(C)] +- struct Blarg { +- x: u64, +- y: [u8; 56], +- z: Florp, +- egg: [[u8; 4]; 5], +- } +- +- // Love me some brute force +- assert_eq!(0..8, span_of!(Blarg, x)); +- assert_eq!(64..68, span_of!(Blarg, z)); +- assert_eq!(68..mem::size_of::(), span_of!(Blarg, egg)); +- +- assert_eq!(8..64, span_of!(Blarg, y..z)); +- assert_eq!(0..64, span_of!(Blarg, x..=y)); +- } +- +- #[test] +- fn ig_test() { +- #[repr(C)] +- struct Member { +- foo: u32, +- } +- +- #[repr(C)] +- struct Test { +- x: u64, +- y: [u8; 56], +- z: Member, +- egg: [[u8; 4]; 4], +- } +- +- assert_eq!(span_of!(Test, ..x), 0..0); +- assert_eq!(span_of!(Test, ..=x), 0..8); +- assert_eq!(span_of!(Test, ..y), 0..8); +- assert_eq!(span_of!(Test, ..=y), 0..64); +- assert_eq!(span_of!(Test, ..z), 0..64); +- assert_eq!(span_of!(Test, ..=z), 0..68); +- assert_eq!(span_of!(Test, ..egg), 0..68); +- assert_eq!(span_of!(Test, ..=egg), 0..84); +- assert_eq!(span_of!(Test, ..), 0..mem::size_of::()); +- assert_eq!( +- span_of!(Test, x..), +- offset_of!(Test, x)..mem::size_of::() +- ); +- assert_eq!( +- span_of!(Test, y..), +- offset_of!(Test, y)..mem::size_of::() +- ); +- +- assert_eq!( +- span_of!(Test, z..), +- offset_of!(Test, z)..mem::size_of::() +- ); +- assert_eq!( +- span_of!(Test, egg..), +- offset_of!(Test, egg)..mem::size_of::() +- ); +- assert_eq!( +- span_of!(Test, x..y), +- offset_of!(Test, x)..offset_of!(Test, y) +- ); +- assert_eq!( +- span_of!(Test, x..=y), +- offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>() +- ); +- } +-} +diff --git a/vfio/Cargo.toml b/vfio/Cargo.toml +index bede7fa..f5e0ecc 100644 +--- a/vfio/Cargo.toml ++++ b/vfio/Cargo.toml +@@ -10,7 +10,7 @@ description = "Virtual function I/O" + byteorder = "1.4.3" + thiserror = "1.0" + anyhow = "1.0" +-kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"] } ++kvm-bindings = { version = "0.10.0", features = [ "fam-wrappers" ] } + kvm-ioctls = "0.19.1" + libc = "0.2" + log = "0.4" +@@ -22,3 +22,4 @@ hypervisor = { path = "../hypervisor"} + machine_manager = { path = "../machine_manager" } + util = { path = "../util" } + devices = { path = "../devices" } ++clap = { version = "=4.1.4", default-features = false, features = ["std", "derive"] } +diff --git a/vfio/src/lib.rs b/vfio/src/lib.rs +index 49c77af..3d2705a 100644 +--- a/vfio/src/lib.rs ++++ b/vfio/src/lib.rs +@@ -22,15 +22,17 @@ pub use vfio_dev::{ + VFIO_GROUP_GET_DEVICE_FD, VFIO_GROUP_GET_STATUS, VFIO_GROUP_SET_CONTAINER, VFIO_IOMMU_MAP_DMA, + VFIO_IOMMU_UNMAP_DMA, VFIO_SET_IOMMU, + }; +-pub use vfio_pci::VfioPciDevice; ++pub use vfio_pci::{VfioConfig, VfioPciDevice}; + + use std::collections::HashMap; + use std::os::unix::io::RawFd; + use std::sync::{Arc, Mutex}; + ++use anyhow::Result; + use kvm_ioctls::DeviceFd; + use once_cell::sync::Lazy; + ++use devices::pci::register_pcidevops_type; + use vfio_dev::VfioGroup; + + pub static KVM_DEVICE_FD: Lazy>> = Lazy::new(|| Mutex::new(None)); +@@ -38,3 +40,7 @@ pub static CONTAINERS: Lazy>>>> = + Lazy::new(|| Mutex::new(HashMap::new())); + pub static GROUPS: Lazy>>> = + Lazy::new(|| Mutex::new(HashMap::new())); ++ ++pub fn vfio_register_pcidevops_type() -> Result<()> { ++ register_pcidevops_type::() ++} +diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs +index d354098..ebf028e 100644 +--- a/vfio/src/vfio_pci.rs ++++ b/vfio/src/vfio_pci.rs +@@ -17,6 +17,7 @@ use std::sync::{Arc, Mutex, Weak}; + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; ++use clap::{ArgAction, Parser}; + use log::error; + use vfio_bindings::bindings::vfio; + use vmm_sys_util::eventfd::EventFd; +@@ -43,12 +44,34 @@ use devices::pci::{ + pci_ext_cap_next, pci_ext_cap_ver, PciBus, PciDevBase, PciDevOps, + }; + use devices::{pci::MsiVector, Device, DeviceBase}; ++use machine_manager::config::{get_pci_df, parse_bool, valid_id}; ++use util::loop_context::create_new_eventfd; + use util::num_ops::ranges_overlap; + use util::unix::host_page_size; + + const PCI_NUM_BARS: u8 = 6; + const PCI_ROM_SLOT: u8 = 6; + ++#[derive(Parser, Default, Debug)] ++#[command(no_binary_name(true))] ++#[clap(group = clap::ArgGroup::new("path").args(&["host", "sysfsdev"]).multiple(false).required(true))] ++pub struct VfioConfig { ++ #[arg(long, value_parser = ["vfio-pci"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long, value_parser = valid_id)] ++ pub host: Option, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long)] ++ pub sysfsdev: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] ++ pub multifunction: Option, ++} ++ + struct MsixTable { + table_bar: u8, + table_offset: u64, +@@ -512,7 +535,7 @@ impl VfioPciDevice { + let mut locked_gsi_routes = cloned_gsi_routes.lock().unwrap(); + let gsi_route = locked_gsi_routes.get_mut(vector as usize).unwrap(); + if gsi_route.irq_fd.is_none() { +- let irq_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); ++ let irq_fd = create_new_eventfd().unwrap(); + gsi_route.irq_fd = Some(Arc::new(irq_fd)); + } + let irq_fd = gsi_route.irq_fd.clone(); +@@ -700,7 +723,7 @@ impl VfioPciDevice { + fn vfio_enable_msix(&mut self) -> Result<()> { + let mut gsi_routes = self.gsi_msi_routes.lock().unwrap(); + if gsi_routes.len() == 0 { +- let irq_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); ++ let irq_fd = create_new_eventfd().unwrap(); + let gsi_route = GsiMsiRoute { + irq_fd: Some(Arc::new(irq_fd)), + gsi: -1, +@@ -1009,3 +1032,38 @@ fn get_irq_rawfds(gsi_msi_routes: &[GsiMsiRoute], start: u32, count: u32) -> Vec + } + rawfds + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_vfio_config_cmdline_parser() { ++ // Test1: right. ++ let vfio_cmd1 = "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x5,multifunction=on"; ++ let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd1, true, false)); ++ assert!(result.is_ok()); ++ let vfio_config = result.unwrap(); ++ assert_eq!(vfio_config.host, Some("0000:1a:00.3".to_string())); ++ assert_eq!(vfio_config.id, "net"); ++ assert_eq!(vfio_config.bus, "pcie.0"); ++ assert_eq!(vfio_config.addr, (5, 0)); ++ assert_eq!(vfio_config.multifunction, Some(true)); ++ ++ // Test2: Missing bus/addr. ++ let vfio_cmd2 = "vfio-pci,host=0000:1a:00.3,id=net"; ++ let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd2, true, false)); ++ assert!(result.is_err()); ++ ++ // Test3: `host` conflicts with `sysfsdev`. ++ let vfio_cmd3 = "vfio-pci,host=0000:1a:00.3,sysfsdev=/sys/bus/pci/devices/0000:00:02.0,id=net,bus=pcie.0,addr=0x5"; ++ let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd3, true, false)); ++ assert!(result.is_err()); ++ ++ // Test4: Missing host/sysfsdev. ++ let vfio_cmd4 = "vfio-pci,id=net,bus=pcie.0,addr=0x1.0x2"; ++ let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd4, true, false)); ++ assert!(result.is_err()); ++ } ++} +diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs +index fd6347a..33f89d3 100644 +--- a/virtio/src/device/balloon.rs ++++ b/virtio/src/device/balloon.rs +@@ -612,11 +612,12 @@ impl BalloonIoHandler { + /// if `req_type` is `BALLOON_INFLATE_EVENT`, then inflate the balloon, otherwise, deflate the + /// balloon. + fn process_balloon_queue(&mut self, req_type: bool) -> Result<()> { ++ trace::trace_scope_start!(process_balloon_queue); + let queue = if req_type { + trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); + &self.inf_queue + } else { +- trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); ++ trace::virtio_receive_request("Balloon".to_string(), "to deflate".to_string()); + &self.def_queue + }; + let mut locked_queue = queue.lock().unwrap(); +@@ -648,6 +649,7 @@ impl BalloonIoHandler { + } + + fn reporting_evt_handler(&mut self) -> Result<()> { ++ trace::trace_scope_start!(reporting_evt_handler); + let queue = self + .report_queue + .as_ref() +@@ -682,6 +684,7 @@ impl BalloonIoHandler { + } + + fn auto_msg_evt_handler(&mut self) -> Result<()> { ++ trace::trace_scope_start!(auto_msg_evt_handler); + let queue = self + .msg_queue + .as_ref() +@@ -882,8 +885,10 @@ impl EventNotifierHelper for BalloonIoHandler { + } + + #[derive(Parser, Debug, Clone, Default)] +-#[command(name = "balloon")] ++#[command(no_binary_name(true))] + pub struct BalloonConfig { ++ #[arg(long)] ++ pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] +diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs +index a7719cf..9b14a88 100644 +--- a/virtio/src/device/block.rs ++++ b/virtio/src/device/block.rs +@@ -21,26 +21,30 @@ use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; ++use clap::Parser; + use log::{error, warn}; + use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; + + use crate::{ +- check_config_space_rw, gpa_hva_iovec_map, iov_discard_back, iov_discard_front, iov_to_buf, +- read_config_default, report_virtio_error, virtio_has_feature, Element, Queue, VirtioBase, +- VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_BLK_F_DISCARD, +- VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_SEG_MAX, +- VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, VIRTIO_BLK_S_OK, +- VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, VIRTIO_BLK_T_GET_ID, +- VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, ++ check_config_space_rw, gpa_hva_iovec_map_by_cache, iov_discard_back, iov_discard_front, ++ iov_to_buf_by_cache, read_config_default, report_virtio_error, virtio_has_feature, Element, ++ Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, ++ VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, ++ VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, ++ VIRTIO_BLK_S_OK, VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, ++ VIRTIO_BLK_T_GET_ID, VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, + VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, + VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, + }; +-use address_space::{AddressSpace, GuestAddress}; ++use address_space::{AddressSpace, GuestAddress, RegionCache}; + use block_backend::{ + create_block_backend, remove_block_backend, BlockDriverOps, BlockIoErrorCallback, + BlockProperty, BlockStatus, + }; +-use machine_manager::config::{BlkDevConfig, ConfigCheck, DriveFile, VmConfig}; ++use machine_manager::config::{ ++ get_pci_df, parse_bool, valid_block_device_virtqueue_size, valid_id, ConfigCheck, ConfigError, ++ DriveConfig, DriveFile, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE, ++}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; + use migration::{ + migration::Migratable, DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, +@@ -54,7 +58,8 @@ use util::aio::{ + use util::byte_code::ByteCode; + use util::leak_bucket::LeakBucket; + use util::loop_context::{ +- read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, ++ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, ++ NotifierOperation, + }; + use util::offset_of; + +@@ -76,6 +81,8 @@ const MAX_NUM_MERGE_BYTES: u64 = i32::MAX as u64; + const MAX_ITERATION_PROCESS_QUEUE: u16 = 10; + /// Max number sectors of per request. + const MAX_REQUEST_SECTORS: u32 = u32::MAX >> SECTOR_SHIFT; ++/// Max length of serial number. ++const MAX_SERIAL_NUM_LEN: usize = 20; + + type SenderConfig = ( + Option>>>, +@@ -86,6 +93,70 @@ type SenderConfig = ( + bool, + ); + ++fn valid_serial(s: &str) -> Result { ++ if s.len() > MAX_SERIAL_NUM_LEN { ++ return Err(anyhow!(ConfigError::StringLengthTooLong( ++ "device serial number".to_string(), ++ MAX_SERIAL_NUM_LEN, ++ ))); ++ } ++ Ok(s.to_string()) ++} ++ ++#[derive(Parser, Debug, Clone)] ++#[command(no_binary_name(true))] ++pub struct VirtioBlkDevConfig { ++ #[arg(long, value_parser = ["virtio-blk-pci", "virtio-blk-device"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, value_parser = parse_bool)] ++ pub multifunction: Option, ++ #[arg(long)] ++ pub drive: String, ++ #[arg(long)] ++ pub bootindex: Option, ++ #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u16).range(1..=MAX_VIRTIO_QUEUE as i64))] ++ pub num_queues: Option, ++ #[arg(long)] ++ pub iothread: Option, ++ #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] ++ pub queue_size: u16, ++ #[arg(long, value_parser = valid_serial)] ++ pub serial: Option, ++} ++ ++impl Default for VirtioBlkDevConfig { ++ fn default() -> Self { ++ Self { ++ classtype: "".to_string(), ++ id: "".to_string(), ++ bus: None, ++ addr: None, ++ multifunction: None, ++ drive: "".to_string(), ++ num_queues: Some(1), ++ bootindex: None, ++ iothread: None, ++ queue_size: DEFAULT_VIRTQUEUE_SIZE, ++ serial: None, ++ } ++ } ++} ++ ++impl ConfigCheck for VirtioBlkDevConfig { ++ fn check(&self) -> Result<()> { ++ if self.serial.is_some() { ++ valid_serial(&self.serial.clone().unwrap())?; ++ } ++ Ok(()) ++ } ++} ++ + fn get_serial_num_config(serial_num: &str) -> Vec { + let mut id_bytes = vec![0; VIRTIO_BLK_ID_BYTES as usize]; + let bytes_to_copy = cmp::min(serial_num.len(), VIRTIO_BLK_ID_BYTES as usize); +@@ -200,7 +271,12 @@ struct Request { + } + + impl Request { +- fn new(handler: &BlockIoHandler, elem: &mut Element, status: &mut u8) -> Result { ++ fn new( ++ handler: &BlockIoHandler, ++ cache: &Option, ++ elem: &mut Element, ++ status: &mut u8, ++ ) -> Result { + if elem.out_iovec.is_empty() || elem.in_iovec.is_empty() { + bail!( + "Missed header for block request: out {} in {} desc num {}", +@@ -211,8 +287,9 @@ impl Request { + } + + let mut out_header = RequestOutHeader::default(); +- iov_to_buf( ++ iov_to_buf_by_cache( + &handler.mem_space, ++ cache, + &elem.out_iovec, + out_header.as_mut_bytes(), + ) +@@ -268,7 +345,8 @@ impl Request { + } + .with_context(|| "Empty data for block request")?; + +- let (data_len, iovec) = gpa_hva_iovec_map(data_iovec, &handler.mem_space)?; ++ let (data_len, iovec) = ++ gpa_hva_iovec_map_by_cache(data_iovec, &handler.mem_space, cache)?; + request.data_len = data_len; + request.iovec = iovec; + } +@@ -581,7 +659,8 @@ impl BlockIoHandler { + + // Init and put valid request into request queue. + let mut status = VIRTIO_BLK_S_OK; +- let req = Request::new(self, &mut elem, &mut status)?; ++ let cache = queue.vring.get_cache(); ++ let req = Request::new(self, cache, &mut elem, &mut status)?; + if status != VIRTIO_BLK_S_OK { + let aiocompletecb = AioCompleteCb::new( + self.queue.clone(), +@@ -955,7 +1034,9 @@ pub struct Block { + /// Virtio device base property. + base: VirtioBase, + /// Configuration of the block device. +- blk_cfg: BlkDevConfig, ++ blk_cfg: VirtioBlkDevConfig, ++ /// Configuration of the block device's drive. ++ drive_cfg: DriveConfig, + /// Config space of the block device. + config_space: VirtioBlkConfig, + /// BLock backend opened by the block device. +@@ -978,14 +1059,16 @@ pub struct Block { + + impl Block { + pub fn new( +- blk_cfg: BlkDevConfig, ++ blk_cfg: VirtioBlkDevConfig, ++ drive_cfg: DriveConfig, + drive_files: Arc>>, + ) -> Block { +- let queue_num = blk_cfg.queues as usize; ++ let queue_num = blk_cfg.num_queues.unwrap_or(1) as usize; + let queue_size = blk_cfg.queue_size; + Self { + base: VirtioBase::new(VIRTIO_TYPE_BLOCK, queue_num, queue_size), + blk_cfg, ++ drive_cfg, + req_align: 1, + buf_align: 1, + drive_files, +@@ -999,11 +1082,11 @@ impl Block { + // seg_max = queue_size - 2: 32bits + self.config_space.seg_max = self.queue_size_max() as u32 - 2; + +- if self.blk_cfg.queues > 1 { +- self.config_space.num_queues = self.blk_cfg.queues; ++ if self.blk_cfg.num_queues.unwrap_or(1) > 1 { ++ self.config_space.num_queues = self.blk_cfg.num_queues.unwrap_or(1); + } + +- if self.blk_cfg.discard { ++ if self.drive_cfg.discard { + // Just support one segment per request. + self.config_space.max_discard_seg = 1; + // The default discard alignment is 1 sector. +@@ -1011,7 +1094,7 @@ impl Block { + self.config_space.max_discard_sectors = MAX_REQUEST_SECTORS; + } + +- if self.blk_cfg.write_zeroes != WriteZeroesState::Off { ++ if self.drive_cfg.write_zeroes != WriteZeroesState::Off { + // Just support one segment per request. + self.config_space.max_write_zeroes_seg = 1; + self.config_space.max_write_zeroes_sectors = MAX_REQUEST_SECTORS; +@@ -1058,35 +1141,36 @@ impl VirtioDevice for Block { + ); + } + +- if !self.blk_cfg.path_on_host.is_empty() { ++ if !self.drive_cfg.path_on_host.is_empty() { + let drive_files = self.drive_files.lock().unwrap(); +- let file = VmConfig::fetch_drive_file(&drive_files, &self.blk_cfg.path_on_host)?; +- let alignments = VmConfig::fetch_drive_align(&drive_files, &self.blk_cfg.path_on_host)?; ++ let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; ++ let alignments = ++ VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; + self.req_align = alignments.0; + self.buf_align = alignments.1; +- let drive_id = VmConfig::get_drive_id(&drive_files, &self.blk_cfg.path_on_host)?; ++ let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; + + let mut thread_pool = None; +- if self.blk_cfg.aio != AioEngine::Off { ++ if self.drive_cfg.aio != AioEngine::Off { + thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); + } + let aio = Aio::new( + Arc::new(BlockIoHandler::complete_func), +- self.blk_cfg.aio, ++ self.drive_cfg.aio, + thread_pool, + )?; + + let conf = BlockProperty { + id: drive_id, +- format: self.blk_cfg.format, ++ format: self.drive_cfg.format, + iothread: self.blk_cfg.iothread.clone(), +- direct: self.blk_cfg.direct, ++ direct: self.drive_cfg.direct, + req_align: self.req_align, + buf_align: self.buf_align, +- discard: self.blk_cfg.discard, +- write_zeroes: self.blk_cfg.write_zeroes, +- l2_cache_size: self.blk_cfg.l2_cache_size, +- refcount_cache_size: self.blk_cfg.refcount_cache_size, ++ discard: self.drive_cfg.discard, ++ write_zeroes: self.drive_cfg.write_zeroes, ++ l2_cache_size: self.drive_cfg.l2_cache_size, ++ refcount_cache_size: self.drive_cfg.refcount_cache_size, + }; + let backend = create_block_backend(file, aio, conf)?; + let disk_size = backend.lock().unwrap().disk_size()?; +@@ -1110,16 +1194,16 @@ impl VirtioDevice for Block { + | 1_u64 << VIRTIO_F_RING_EVENT_IDX + | 1_u64 << VIRTIO_BLK_F_FLUSH + | 1_u64 << VIRTIO_BLK_F_SEG_MAX; +- if self.blk_cfg.read_only { ++ if self.drive_cfg.readonly { + self.base.device_features |= 1_u64 << VIRTIO_BLK_F_RO; + }; +- if self.blk_cfg.queues > 1 { ++ if self.blk_cfg.num_queues.unwrap_or(1) > 1 { + self.base.device_features |= 1_u64 << VIRTIO_BLK_F_MQ; + } +- if self.blk_cfg.discard { ++ if self.drive_cfg.discard { + self.base.device_features |= 1_u64 << VIRTIO_BLK_F_DISCARD; + } +- if self.blk_cfg.write_zeroes != WriteZeroesState::Off { ++ if self.drive_cfg.write_zeroes != WriteZeroesState::Off { + self.base.device_features |= 1_u64 << VIRTIO_BLK_F_WRITE_ZEROES; + } + self.build_device_config_space(); +@@ -1130,7 +1214,7 @@ impl VirtioDevice for Block { + fn unrealize(&mut self) -> Result<()> { + MigrationManager::unregister_device_instance(BlockState::descriptor(), &self.blk_cfg.id); + let drive_files = self.drive_files.lock().unwrap(); +- let drive_id = VmConfig::get_drive_id(&drive_files, &self.blk_cfg.path_on_host)?; ++ let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; + remove_block_backend(&drive_id); + Ok(()) + } +@@ -1166,7 +1250,7 @@ impl VirtioDevice for Block { + continue; + } + let (sender, receiver) = channel(); +- let update_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); ++ let update_evt = Arc::new(create_new_eventfd()?); + let driver_features = self.base.driver_features; + let handler = BlockIoHandler { + queue: queue.clone(), +@@ -1176,20 +1260,20 @@ impl VirtioDevice for Block { + req_align: self.req_align, + buf_align: self.buf_align, + disk_sectors: self.disk_sectors, +- direct: self.blk_cfg.direct, +- serial_num: self.blk_cfg.serial_num.clone(), ++ direct: self.drive_cfg.direct, ++ serial_num: self.blk_cfg.serial.clone(), + driver_features, + receiver, + update_evt: update_evt.clone(), + device_broken: self.base.broken.clone(), + interrupt_cb: interrupt_cb.clone(), + iothread: self.blk_cfg.iothread.clone(), +- leak_bucket: match self.blk_cfg.iops { ++ leak_bucket: match self.drive_cfg.iops { + Some(iops) => Some(LeakBucket::new(iops)?), + None => None, + }, +- discard: self.blk_cfg.discard, +- write_zeroes: self.blk_cfg.write_zeroes, ++ discard: self.drive_cfg.discard, ++ write_zeroes: self.drive_cfg.write_zeroes, + }; + + let notifiers = EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(handler))); +@@ -1236,18 +1320,28 @@ impl VirtioDevice for Block { + Ok(()) + } + +- fn update_config(&mut self, dev_config: Option>) -> Result<()> { +- let is_plug = dev_config.is_some(); +- if let Some(conf) = dev_config { +- self.blk_cfg = conf ++ // configs[0]: DriveConfig. configs[1]: VirtioBlkDevConfig. ++ fn update_config(&mut self, configs: Vec>) -> Result<()> { ++ let mut is_plug = false; ++ if configs.len() == 2 { ++ self.drive_cfg = configs[0] ++ .as_any() ++ .downcast_ref::() ++ .unwrap() ++ .clone(); ++ self.blk_cfg = configs[1] + .as_any() +- .downcast_ref::() ++ .downcast_ref::() + .unwrap() + .clone(); + // microvm type block device don't support multiple queue. +- self.blk_cfg.queues = QUEUE_NUM_BLK as u16; +- } else { ++ self.blk_cfg.num_queues = Some(QUEUE_NUM_BLK as u16); ++ is_plug = true; ++ } else if configs.is_empty() { + self.blk_cfg = Default::default(); ++ self.drive_cfg = Default::default(); ++ } else { ++ bail!("Invalid update configs."); + } + + if !is_plug { +@@ -1296,8 +1390,8 @@ impl VirtioDevice for Block { + self.req_align, + self.buf_align, + self.disk_sectors, +- self.blk_cfg.serial_num.clone(), +- self.blk_cfg.direct, ++ self.blk_cfg.serial.clone(), ++ self.drive_cfg.direct, + )) + .with_context(|| VirtioError::ChannelSend("image fd".to_string()))?; + } +@@ -1354,7 +1448,9 @@ mod tests { + use super::*; + use crate::*; + use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; +- use machine_manager::config::{IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; ++ use machine_manager::config::{ ++ str_slip_to_clap, IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, ++ }; + + const QUEUE_NUM_BLK: usize = 1; + const CONFIG_SPACE_SIZE: usize = 60; +@@ -1390,11 +1486,36 @@ mod tests { + + fn init_default_block() -> Block { + Block::new( +- BlkDevConfig::default(), ++ VirtioBlkDevConfig::default(), ++ DriveConfig::default(), + Arc::new(Mutex::new(HashMap::new())), + ) + } + ++ #[test] ++ fn test_virtio_block_config_cmdline_parser() { ++ // Test1: Right. ++ let blk_cmd1 = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=4"; ++ let blk_config = ++ VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd1, true, false)).unwrap(); ++ assert_eq!(blk_config.id, "rootfs"); ++ assert_eq!(blk_config.bus.unwrap(), "pcie.0"); ++ assert_eq!(blk_config.addr.unwrap(), (1, 2)); ++ assert_eq!(blk_config.serial.unwrap(), "111111"); ++ assert_eq!(blk_config.num_queues.unwrap(), 4); ++ ++ // Test2: Default values. ++ assert_eq!(blk_config.queue_size, DEFAULT_VIRTQUEUE_SIZE); ++ ++ // Test3: Illegal values. ++ let blk_cmd3 = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=33"; ++ let result = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd3, true, false)); ++ assert!(result.is_err()); ++ let blk_cmd3 = "virtio-blk-pci,id=rootfs,drive=rootfs,serial=111111111111111111111111111111111111111111111111111111111111111111111"; ++ let result = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd3, true, false)); ++ assert!(result.is_err()); ++ } ++ + // Use different input parameters to verify block `new()` and `realize()` functionality. + #[test] + fn test_block_init() { +@@ -1410,16 +1531,16 @@ mod tests { + assert!(block.senders.is_empty()); + + // Realize block device: create TempFile as backing file. +- block.blk_cfg.read_only = true; +- block.blk_cfg.direct = false; ++ block.drive_cfg.readonly = true; ++ block.drive_cfg.direct = false; + let f = TempFile::new().unwrap(); +- block.blk_cfg.path_on_host = f.as_path().to_str().unwrap().to_string(); ++ block.drive_cfg.path_on_host = f.as_path().to_str().unwrap().to_string(); + VmConfig::add_drive_file( + &mut block.drive_files.lock().unwrap(), + "", +- &block.blk_cfg.path_on_host, +- block.blk_cfg.read_only, +- block.blk_cfg.direct, ++ &block.drive_cfg.path_on_host, ++ block.drive_cfg.readonly, ++ block.drive_cfg.direct, + ) + .unwrap(); + assert!(block.realize().is_ok()); +@@ -1541,25 +1662,26 @@ mod tests { + + // spawn io thread + let io_conf = IothreadConfig { ++ classtype: "iothread".to_string(), + id: thread_name.clone(), + }; + EventLoop::object_init(&Some(vec![io_conf])).unwrap(); + + let mut block = init_default_block(); + let file = TempFile::new().unwrap(); +- block.blk_cfg.path_on_host = file.as_path().to_str().unwrap().to_string(); +- block.blk_cfg.direct = false; ++ block.drive_cfg.path_on_host = file.as_path().to_str().unwrap().to_string(); ++ block.drive_cfg.direct = false; + + // config iothread and iops + block.blk_cfg.iothread = Some(thread_name); +- block.blk_cfg.iops = Some(100); ++ block.drive_cfg.iops = Some(100); + + VmConfig::add_drive_file( + &mut block.drive_files.lock().unwrap(), + "", +- &block.blk_cfg.path_on_host, +- block.blk_cfg.read_only, +- block.blk_cfg.direct, ++ &block.drive_cfg.path_on_host, ++ block.drive_cfg.readonly, ++ block.drive_cfg.direct, + ) + .unwrap(); + +diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs +index 97ca67c..2d138ed 100644 +--- a/virtio/src/device/gpu.rs ++++ b/virtio/src/device/gpu.rs +@@ -18,6 +18,7 @@ use std::sync::{Arc, Mutex, Weak}; + use std::{ptr, vec}; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::{ArgAction, Parser}; + use log::{error, info, warn}; + use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; + +@@ -36,7 +37,7 @@ use crate::{ + VIRTIO_GPU_RESP_OK_EDID, VIRTIO_GPU_RESP_OK_NODATA, VIRTIO_TYPE_GPU, + }; + use address_space::{AddressSpace, FileBackend, GuestAddress}; +-use machine_manager::config::{GpuDevConfig, DEFAULT_VIRTQUEUE_SIZE, VIRTIO_GPU_MAX_OUTPUTS}; ++use machine_manager::config::{get_pci_df, valid_id, DEFAULT_VIRTQUEUE_SIZE}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use migration_derive::ByteCode; + use ui::console::{ +@@ -72,6 +73,49 @@ const VIRTIO_GPU_RES_WIN_FRAMEBUF: u32 = 0x80000000; + const VIRTIO_GPU_RES_EFI_FRAMEBUF: u32 = 0x40000000; + const VIRTIO_GPU_RES_FRAMEBUF: u32 = VIRTIO_GPU_RES_WIN_FRAMEBUF | VIRTIO_GPU_RES_EFI_FRAMEBUF; + ++/// The maximum number of outputs. ++const VIRTIO_GPU_MAX_OUTPUTS: usize = 16; ++/// The default maximum memory 256M. ++const VIRTIO_GPU_DEFAULT_MAX_HOSTMEM: u64 = 0x10000000; ++ ++#[derive(Parser, Clone, Debug, Default)] ++#[command(no_binary_name(true))] ++pub struct GpuDevConfig { ++ #[arg(long, value_parser = ["virtio-gpu-pci"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ #[arg(long, alias = "max_outputs", default_value="1", value_parser = clap::value_parser!(u32).range(1..=VIRTIO_GPU_MAX_OUTPUTS as i64))] ++ pub max_outputs: u32, ++ #[arg(long, default_value="true", action = ArgAction::Append)] ++ pub edid: bool, ++ #[arg(long, default_value = "1024")] ++ pub xres: u32, ++ #[arg(long, default_value = "768")] ++ pub yres: u32, ++ // The default max_hostmem is 256M. ++ #[arg(long, alias = "max_hostmem", default_value="268435456", value_parser = clap::value_parser!(u64).range(1..))] ++ pub max_hostmem: u64, ++ #[arg(long, alias = "enable_bar0", default_value="false", action = ArgAction::Append)] ++ pub enable_bar0: bool, ++} ++ ++impl GpuDevConfig { ++ pub fn check(&self) { ++ if self.max_hostmem < VIRTIO_GPU_DEFAULT_MAX_HOSTMEM { ++ warn!( ++ "max_hostmem should >= {}, allocating less than it may cause \ ++ the GPU to fail to start or refresh.", ++ VIRTIO_GPU_DEFAULT_MAX_HOSTMEM ++ ); ++ } ++ } ++} ++ + #[derive(Debug)] + struct GpuResource { + resource_id: u32, +@@ -1182,6 +1226,12 @@ impl GpuIoHandler { + scanout.width = info_set_scanout.rect.width; + scanout.height = info_set_scanout.rect.height; + ++ if (self.driver_features & (1 << VIRTIO_GPU_F_EDID)) == 0 ++ && (info_set_scanout.resource_id & VIRTIO_GPU_RES_WIN_FRAMEBUF) != 0 ++ { ++ self.change_run_stage()?; ++ } ++ + self.response_nodata(VIRTIO_GPU_RESP_OK_NODATA, req) + } + +@@ -1843,3 +1893,50 @@ impl VirtioDevice for Gpu { + result + } + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_parse_virtio_gpu_pci_cmdline() { ++ // Test1: Right. ++ let gpu_cmd = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=5,edid=false,\ ++ xres=2048,yres=800,enable_bar0=true,max_hostmem=268435457"; ++ let gpu_cfg = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd, true, false)).unwrap(); ++ assert_eq!(gpu_cfg.id, "gpu_1"); ++ assert_eq!(gpu_cfg.bus, "pcie.0"); ++ assert_eq!(gpu_cfg.addr, (4, 0)); ++ assert_eq!(gpu_cfg.max_outputs, 5); ++ assert_eq!(gpu_cfg.xres, 2048); ++ assert_eq!(gpu_cfg.yres, 800); ++ assert_eq!(gpu_cfg.edid, false); ++ assert_eq!(gpu_cfg.max_hostmem, 268435457); ++ assert_eq!(gpu_cfg.enable_bar0, true); ++ ++ // Test2: Default. ++ let gpu_cmd2 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0"; ++ let gpu_cfg = ++ GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd2, true, false)).unwrap(); ++ assert_eq!(gpu_cfg.max_outputs, 1); ++ assert_eq!(gpu_cfg.xres, 1024); ++ assert_eq!(gpu_cfg.yres, 768); ++ assert_eq!(gpu_cfg.edid, true); ++ assert_eq!(gpu_cfg.max_hostmem, VIRTIO_GPU_DEFAULT_MAX_HOSTMEM); ++ assert_eq!(gpu_cfg.enable_bar0, false); ++ ++ // Test3/4: max_outputs is illegal. ++ let gpu_cmd3 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=17"; ++ let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd3, true, false)); ++ assert!(result.is_err()); ++ let gpu_cmd4 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=0"; ++ let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd4, true, false)); ++ assert!(result.is_err()); ++ ++ // Test5: max_hostmem is illegal. ++ let gpu_cmd5 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_hostmem=0"; ++ let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd5, true, false)); ++ assert!(result.is_err()); ++ } ++} +diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs +index 4e605fa..391a6cd 100644 +--- a/virtio/src/device/net.rs ++++ b/virtio/src/device/net.rs +@@ -46,7 +46,7 @@ use crate::{ + use address_space::{AddressSpace, RegionCache}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use machine_manager::{ +- config::{ConfigCheck, NetworkInterfaceConfig}, ++ config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}, + event_loop::EventLoop, + }; + use migration::{ +@@ -57,7 +57,8 @@ use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; + use util::loop_context::gen_delete_notifiers; + use util::loop_context::{ +- read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, ++ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, ++ NotifierOperation, + }; + use util::num_ops::str_to_num; + use util::tap::{ +@@ -672,30 +673,33 @@ impl EventNotifierHelper for NetCtrlHandler { + } + + struct TxVirtio { ++ tap_full: bool, + queue: Arc>, + queue_evt: Arc, + } + + impl TxVirtio { + fn new(queue: Arc>, queue_evt: Arc) -> Self { +- TxVirtio { queue, queue_evt } ++ TxVirtio { ++ tap_full: false, ++ queue, ++ queue_evt, ++ } + } + } + + struct RxVirtio { +- queue_full: bool, ++ queue_avail: bool, + queue: Arc>, + queue_evt: Arc, +- recv_evt: Arc, + } + + impl RxVirtio { +- fn new(queue: Arc>, queue_evt: Arc, recv_evt: Arc) -> Self { ++ fn new(queue: Arc>, queue_evt: Arc) -> Self { + RxVirtio { +- queue_full: false, ++ queue_avail: false, + queue, + queue_evt, +- recv_evt, + } + } + } +@@ -792,7 +796,11 @@ impl NetIoHandler { + .pop_avail(&self.mem_space, self.driver_features) + .with_context(|| "Failed to pop avail ring for net rx")?; + if elem.desc_num == 0 { +- self.rx.queue_full = true; ++ queue ++ .vring ++ .suppress_queue_notify(&self.mem_space, self.driver_features, false) ++ .with_context(|| "Failed to enable rx queue notify")?; ++ self.rx.queue_avail = false; + break; + } else if elem.in_iovec.is_empty() { + bail!("The length of in iovec is 0"); +@@ -863,9 +871,9 @@ impl NetIoHandler { + rx_packets += 1; + if rx_packets >= self.queue_size { + self.rx +- .recv_evt ++ .queue_evt + .write(1) +- .with_context(|| "Failed to trigger tap queue event".to_string())?; ++ .with_context(|| "Failed to trigger rx queue event".to_string())?; + break; + } + } +@@ -925,10 +933,12 @@ impl NetIoHandler { + }; + if tap_fd != -1 && self.send_packets(tap_fd, &iovecs) == -1 { + queue.vring.push_back(); +- self.tx.queue_evt.write(1).with_context(|| { +- "Failed to trigger tx queue event when writev blocked".to_string() +- })?; +- return Ok(()); ++ queue ++ .vring ++ .suppress_queue_notify(&self.mem_space, self.driver_features, true) ++ .with_context(|| "Failed to suppress tx queue notify")?; ++ self.tx.tap_full = true; ++ break; + } + + queue +@@ -959,6 +969,50 @@ impl NetIoHandler { + Ok(()) + } + ++ fn tap_fd_handler(net_io: &mut Self) -> Vec { ++ let mut notifiers = Vec::new(); ++ ++ if !net_io.is_listening && (net_io.rx.queue_avail || net_io.tx.tap_full) { ++ notifiers.push(EventNotifier::new( ++ NotifierOperation::Resume, ++ net_io.tap_fd, ++ None, ++ EventSet::empty(), ++ Vec::new(), ++ )); ++ net_io.is_listening = true; ++ } ++ ++ if !net_io.is_listening { ++ return notifiers; ++ } ++ ++ // NOTE: We want to poll for OUT event when the tap is full, and for IN event when the ++ // virtio queue is available. ++ let tap_events = match (net_io.rx.queue_avail, net_io.tx.tap_full) { ++ (true, true) => EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, ++ (false, true) => EventSet::OUT | EventSet::EDGE_TRIGGERED, ++ (true, false) => EventSet::IN | EventSet::EDGE_TRIGGERED, ++ (false, false) => EventSet::empty(), ++ }; ++ ++ let tap_operation = if tap_events.is_empty() { ++ net_io.is_listening = false; ++ NotifierOperation::Park ++ } else { ++ NotifierOperation::Modify ++ }; ++ ++ notifiers.push(EventNotifier::new( ++ tap_operation, ++ net_io.tap_fd, ++ None, ++ tap_events, ++ Vec::new(), ++ )); ++ notifiers ++ } ++ + fn update_evt_handler(net_io: &Arc>) -> Vec { + let mut locked_net_io = net_io.lock().unwrap(); + locked_net_io.tap = match locked_net_io.receiver.recv() { +@@ -977,7 +1031,6 @@ impl NetIoHandler { + let mut notifiers_fds = vec![ + locked_net_io.update_evt.as_raw_fd(), + locked_net_io.rx.queue_evt.as_raw_fd(), +- locked_net_io.rx.recv_evt.as_raw_fd(), + locked_net_io.tx.queue_evt.as_raw_fd(), + ]; + if old_tap_fd != -1 { +@@ -1055,30 +1108,40 @@ impl EventNotifierHelper for NetIoHandler { + return None; + } + +- if let Err(ref e) = locked_net_io.rx.recv_evt.write(1) { +- error!("Failed to trigger tap receive event, {:?}", e); ++ locked_net_io.rx.queue_avail = true; ++ let mut locked_queue = locked_net_io.rx.queue.lock().unwrap(); ++ ++ if let Err(ref err) = locked_queue.vring.suppress_queue_notify( ++ &locked_net_io.mem_space, ++ locked_net_io.driver_features, ++ true, ++ ) { ++ error!("Failed to suppress rx queue notify: {:?}", err); + report_virtio_error( + locked_net_io.interrupt_cb.clone(), + locked_net_io.driver_features, + &locked_net_io.device_broken, + ); ++ return None; ++ }; ++ ++ drop(locked_queue); ++ ++ if let Err(ref err) = locked_net_io.handle_rx() { ++ error!("Failed to handle receive queue event: {:?}", err); ++ report_virtio_error( ++ locked_net_io.interrupt_cb.clone(), ++ locked_net_io.driver_features, ++ &locked_net_io.device_broken, ++ ); ++ return None; + } + +- if let Some(tap) = locked_net_io.tap.as_ref() { +- if !locked_net_io.is_listening { +- let notifier = vec![EventNotifier::new( +- NotifierOperation::Resume, +- tap.as_raw_fd(), +- None, +- EventSet::IN | EventSet::EDGE_TRIGGERED, +- Vec::new(), +- )]; +- locked_net_io.is_listening = true; +- locked_net_io.rx.queue_full = false; +- return Some(notifier); +- } ++ if locked_net_io.tap.is_some() { ++ Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) ++ } else { ++ None + } +- None + }); + let rx_fd = locked_net_io.rx.queue_evt.as_raw_fd(); + notifiers.push(build_event_notifier( +@@ -1096,6 +1159,7 @@ impl EventNotifierHelper for NetIoHandler { + if locked_net_io.device_broken.load(Ordering::SeqCst) { + return None; + } ++ + if let Err(ref e) = locked_net_io.handle_tx() { + error!("Failed to handle tx(tx event) for net, {:?}", e); + report_virtio_error( +@@ -1104,7 +1168,12 @@ impl EventNotifierHelper for NetIoHandler { + &locked_net_io.device_broken, + ); + } +- None ++ ++ if locked_net_io.tap.is_some() { ++ Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) ++ } else { ++ None ++ } + }); + let tx_fd = locked_net_io.tx.queue_evt.as_raw_fd(); + notifiers.push(build_event_notifier( +@@ -1117,50 +1186,62 @@ impl EventNotifierHelper for NetIoHandler { + // Register event notifier for tap. + let cloned_net_io = net_io.clone(); + if let Some(tap) = locked_net_io.tap.as_ref() { +- let handler: Rc = Rc::new(move |_, _| { ++ let handler: Rc = Rc::new(move |events: EventSet, _| { + let mut locked_net_io = cloned_net_io.lock().unwrap(); + if locked_net_io.device_broken.load(Ordering::SeqCst) { + return None; + } + +- if let Err(ref e) = locked_net_io.handle_rx() { +- error!("Failed to handle rx(tap event), {:?}", e); +- report_virtio_error( +- locked_net_io.interrupt_cb.clone(), ++ if events.contains(EventSet::OUT) { ++ locked_net_io.tx.tap_full = false; ++ let mut locked_queue = locked_net_io.tx.queue.lock().unwrap(); ++ ++ if let Err(ref err) = locked_queue.vring.suppress_queue_notify( ++ &locked_net_io.mem_space, + locked_net_io.driver_features, +- &locked_net_io.device_broken, +- ); +- return None; ++ false, ++ ) { ++ error!("Failed to enable tx queue notify: {:?}", err); ++ report_virtio_error( ++ locked_net_io.interrupt_cb.clone(), ++ locked_net_io.driver_features, ++ &locked_net_io.device_broken, ++ ); ++ return None; ++ }; ++ ++ drop(locked_queue); ++ ++ if let Err(ref e) = locked_net_io.handle_tx() { ++ error!("Failed to handle tx(tx event) for net, {:?}", e); ++ report_virtio_error( ++ locked_net_io.interrupt_cb.clone(), ++ locked_net_io.driver_features, ++ &locked_net_io.device_broken, ++ ); ++ } + } + +- if let Some(tap) = locked_net_io.tap.as_ref() { +- if locked_net_io.rx.queue_full && locked_net_io.is_listening { +- let notifier = vec![EventNotifier::new( +- NotifierOperation::Park, +- tap.as_raw_fd(), +- None, +- EventSet::IN | EventSet::EDGE_TRIGGERED, +- Vec::new(), +- )]; +- locked_net_io.is_listening = false; +- return Some(notifier); ++ if events.contains(EventSet::IN) { ++ if let Err(ref err) = locked_net_io.handle_rx() { ++ error!("Failed to handle receive queue event: {:?}", err); ++ report_virtio_error( ++ locked_net_io.interrupt_cb.clone(), ++ locked_net_io.driver_features, ++ &locked_net_io.device_broken, ++ ); ++ return None; + } + } +- None ++ ++ Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) + }); + let tap_fd = tap.as_raw_fd(); + notifiers.push(build_event_notifier( + tap_fd, + Some(handler.clone()), + NotifierOperation::AddShared, +- EventSet::IN | EventSet::EDGE_TRIGGERED, +- )); +- let recv_evt_fd = locked_net_io.rx.recv_evt.as_raw_fd(); +- notifiers.push(build_event_notifier( +- recv_evt_fd, +- Some(handler), +- NotifierOperation::AddShared, +- EventSet::IN | EventSet::EDGE_TRIGGERED, ++ EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, + )); + } + +@@ -1190,6 +1271,8 @@ pub struct Net { + base: VirtioBase, + /// Configuration of the network device. + net_cfg: NetworkInterfaceConfig, ++ /// Configuration of the network device. ++ netdev_cfg: NetDevcfg, + /// Virtio net configurations. + config_space: Arc>, + /// Tap device opened. +@@ -1203,9 +1286,9 @@ pub struct Net { + } + + impl Net { +- pub fn new(net_cfg: NetworkInterfaceConfig) -> Self { ++ pub fn new(net_cfg: NetworkInterfaceConfig, netdev_cfg: NetDevcfg) -> Self { + let queue_num = if net_cfg.mq { +- (net_cfg.queues + 1) as usize ++ (netdev_cfg.queues + 1) as usize + } else { + QUEUE_NUM_NET + }; +@@ -1214,6 +1297,7 @@ impl Net { + Self { + base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), + net_cfg, ++ netdev_cfg, + ..Default::default() + } + } +@@ -1397,11 +1481,11 @@ impl VirtioDevice for Net { + ); + } + +- let queue_pairs = self.net_cfg.queues / 2; +- if !self.net_cfg.host_dev_name.is_empty() { +- self.taps = create_tap(None, Some(&self.net_cfg.host_dev_name), queue_pairs) ++ let queue_pairs = self.netdev_cfg.queues / 2; ++ if !self.netdev_cfg.ifname.is_empty() { ++ self.taps = create_tap(None, Some(&self.netdev_cfg.ifname), queue_pairs) + .with_context(|| "Failed to open tap with file path")?; +- } else if let Some(fds) = self.net_cfg.tap_fds.as_mut() { ++ } else if let Some(fds) = self.netdev_cfg.tap_fds.as_mut() { + let mut created_fds = 0; + if let Some(taps) = &self.taps { + for (index, tap) in taps.iter().enumerate() { +@@ -1444,7 +1528,7 @@ impl VirtioDevice for Net { + + let mut locked_config = self.config_space.lock().unwrap(); + +- let queue_pairs = self.net_cfg.queues / 2; ++ let queue_pairs = self.netdev_cfg.queues / 2; + if self.net_cfg.mq + && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) + .contains(&queue_pairs) +@@ -1561,10 +1645,9 @@ impl VirtioDevice for Net { + .with_context(|| "Failed to set tap offload")?; + } + +- let update_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); +- let recv_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); ++ let update_evt = Arc::new(create_new_eventfd()?); + let mut handler = NetIoHandler { +- rx: RxVirtio::new(rx_queue, rx_queue_evt, recv_evt), ++ rx: RxVirtio::new(rx_queue, rx_queue_evt), + tx: TxVirtio::new(tx_queue, tx_queue_evt), + tap: self.taps.as_ref().map(|t| t[index].clone()), + tap_fd: -1, +@@ -1596,9 +1679,15 @@ impl VirtioDevice for Net { + Ok(()) + } + +- fn update_config(&mut self, dev_config: Option>) -> Result<()> { +- if let Some(conf) = dev_config { +- self.net_cfg = conf ++ // configs[0]: NetDevcfg. configs[1]: NetworkInterfaceConfig. ++ fn update_config(&mut self, dev_config: Vec>) -> Result<()> { ++ if !dev_config.is_empty() { ++ self.netdev_cfg = dev_config[0] ++ .as_any() ++ .downcast_ref::() ++ .unwrap() ++ .clone(); ++ self.net_cfg = dev_config[1] + .as_any() + .downcast_ref::() + .unwrap() +@@ -1703,16 +1792,16 @@ mod tests { + #[test] + fn test_net_init() { + // test net new method +- let mut net = Net::new(NetworkInterfaceConfig::default()); ++ let mut net = Net::new(NetworkInterfaceConfig::default(), NetDevcfg::default()); + assert_eq!(net.base.device_features, 0); + assert_eq!(net.base.driver_features, 0); + + assert_eq!(net.taps.is_none(), true); + assert_eq!(net.senders.is_none(), true); + assert_eq!(net.net_cfg.mac.is_none(), true); +- assert_eq!(net.net_cfg.tap_fds.is_none(), true); +- assert_eq!(net.net_cfg.vhost_type.is_none(), true); +- assert_eq!(net.net_cfg.vhost_fds.is_none(), true); ++ assert_eq!(net.netdev_cfg.tap_fds.is_none(), true); ++ assert!(net.netdev_cfg.vhost_type().is_none()); ++ assert_eq!(net.netdev_cfg.vhost_fds.is_none(), true); + + // test net realize method + net.realize().unwrap(); +@@ -1864,7 +1953,7 @@ mod tests { + + #[test] + fn test_iothread() { +- let mut net = Net::new(NetworkInterfaceConfig::default()); ++ let mut net = Net::new(NetworkInterfaceConfig::default(), NetDevcfg::default()); + net.net_cfg.iothread = Some("iothread".to_string()); + if let Err(err) = net.realize() { + let err_msg = format!( +diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs +index c441052..9f1007e 100644 +--- a/virtio/src/device/rng.rs ++++ b/virtio/src/device/rng.rs +@@ -18,7 +18,8 @@ use std::path::Path; + use std::rc::Rc; + use std::sync::{Arc, Mutex}; + +-use anyhow::{bail, Context, Result}; ++use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use log::error; + use vmm_sys_util::epoll::EventSet; + use vmm_sys_util::eventfd::EventFd; +@@ -30,7 +31,7 @@ use crate::{ + }; + use address_space::AddressSpace; + use machine_manager::{ +- config::{RngConfig, DEFAULT_VIRTQUEUE_SIZE}, ++ config::{get_pci_df, valid_id, ConfigError, RngObjConfig, DEFAULT_VIRTQUEUE_SIZE}, + event_loop::EventLoop, + event_loop::{register_event_helper, unregister_event_helper}, + }; +@@ -46,6 +47,62 @@ use util::loop_context::{ + const QUEUE_NUM_RNG: usize = 1; + const RNG_SIZE_MAX: u32 = 1 << 20; + ++const MIN_BYTES_PER_SEC: u64 = 64; ++const MAX_BYTES_PER_SEC: u64 = 1_000_000_000; ++ ++/// Config structure for virtio-rng. ++#[derive(Parser, Debug, Clone, Default)] ++#[command(no_binary_name(true))] ++pub struct RngConfig { ++ #[arg(long, value_parser = ["virtio-rng-device", "virtio-rng-pci"])] ++ pub classtype: String, ++ #[arg(long, default_value = "", value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub rng: String, ++ #[arg(long, alias = "max-bytes")] ++ pub max_bytes: Option, ++ #[arg(long)] ++ pub period: Option, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long)] ++ pub multifunction: Option, ++} ++ ++impl RngConfig { ++ pub fn bytes_per_sec(&self) -> Result> { ++ if self.max_bytes.is_some() != self.period.is_some() { ++ bail!("\"max_bytes\" and \"period\" should be configured or not configured Simultaneously."); ++ } ++ ++ if let Some(max) = self.max_bytes { ++ let peri = self.period.unwrap(); ++ let mul = max ++ .checked_mul(1000) ++ .with_context(|| format!("Illegal max-bytes arguments: {:?}", max))?; ++ let bytes_per_sec = mul ++ .checked_div(peri) ++ .with_context(|| format!("Illegal period arguments: {:?}", peri))?; ++ ++ if !(MIN_BYTES_PER_SEC..=MAX_BYTES_PER_SEC).contains(&bytes_per_sec) { ++ return Err(anyhow!(ConfigError::IllegalValue( ++ "The bytes per second of rng device".to_string(), ++ MIN_BYTES_PER_SEC, ++ true, ++ MAX_BYTES_PER_SEC, ++ true, ++ ))); ++ } ++ ++ return Ok(Some(bytes_per_sec)); ++ } ++ Ok(None) ++ } ++} ++ + fn get_req_data_size(in_iov: &[ElemIovec]) -> Result { + let mut size = 0_u32; + for iov in in_iov { +@@ -216,34 +273,37 @@ pub struct RngState { + pub struct Rng { + /// Virtio device base property. + base: VirtioBase, +- /// Configuration of virtio rng device ++ /// Configuration of virtio rng device. + rng_cfg: RngConfig, ++ /// Configuration of rng-random. ++ rngobj_cfg: RngObjConfig, + /// The file descriptor of random number generator + random_file: Option, + } + + impl Rng { +- pub fn new(rng_cfg: RngConfig) -> Self { ++ pub fn new(rng_cfg: RngConfig, rngobj_cfg: RngObjConfig) -> Self { + Rng { + base: VirtioBase::new(VIRTIO_TYPE_RNG, QUEUE_NUM_RNG, DEFAULT_VIRTQUEUE_SIZE), + rng_cfg, ++ rngobj_cfg, + ..Default::default() + } + } + + fn check_random_file(&self) -> Result<()> { +- let path = Path::new(&self.rng_cfg.random_file); ++ let path = Path::new(&self.rngobj_cfg.filename); + if !path.exists() { + bail!( + "The path of random file {} is not existed", +- self.rng_cfg.random_file ++ self.rngobj_cfg.filename + ); + } + + if !path.metadata().unwrap().file_type().is_char_device() { + bail!( + "The type of random file {} is not a character special file", +- self.rng_cfg.random_file ++ self.rngobj_cfg.filename + ); + } + +@@ -263,7 +323,7 @@ impl VirtioDevice for Rng { + fn realize(&mut self) -> Result<()> { + self.check_random_file() + .with_context(|| "Failed to check random file")?; +- let file = File::open(&self.rng_cfg.random_file) ++ let file = File::open(&self.rngobj_cfg.filename) + .with_context(|| "Failed to open file of random number generator")?; + self.random_file = Some(file); + self.init_config_features()?; +@@ -308,7 +368,7 @@ impl VirtioDevice for Rng { + .unwrap() + .try_clone() + .with_context(|| "Failed to clone random file for virtio rng")?, +- leak_bucket: match self.rng_cfg.bytes_per_sec { ++ leak_bucket: match self.rng_cfg.bytes_per_sec()? { + Some(bps) => Some(LeakBucket::new(bps)?), + None => None, + }, +@@ -361,7 +421,7 @@ mod tests { + use super::*; + use crate::*; + use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; +- use machine_manager::config::{RngConfig, DEFAULT_VIRTQUEUE_SIZE}; ++ use machine_manager::config::{str_slip_to_clap, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; + + const VIRTQ_DESC_F_NEXT: u16 = 0x01; + const VIRTQ_DESC_F_WRITE: u16 = 0x02; +@@ -393,21 +453,60 @@ mod tests { + sys_space + } + ++ #[test] ++ fn test_rng_config_cmdline_parse() { ++ // Test1: Right rng-random. ++ let mut vm_config = VmConfig::default(); ++ assert!(vm_config ++ .add_object("rng-random,id=objrng0,filename=/path/to/random_file") ++ .is_ok()); ++ let rngobj_cfg = vm_config.object.rng_object.remove("objrng0").unwrap(); ++ assert_eq!(rngobj_cfg.filename, "/path/to/random_file"); ++ ++ // Test2: virtio-rng-device ++ let rng_cmd = "virtio-rng-device,rng=objrng0"; ++ let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); ++ assert_eq!(rng_config.bytes_per_sec().unwrap(), None); ++ assert_eq!(rng_config.multifunction, None); ++ ++ // Test3: virtio-rng-pci. ++ let rng_cmd = "virtio-rng-pci,bus=pcie.0,addr=0x1,rng=objrng0,max-bytes=1234,period=1000"; ++ let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); ++ assert_eq!(rng_config.bytes_per_sec().unwrap(), Some(1234)); ++ assert_eq!(rng_config.bus.unwrap(), "pcie.0"); ++ assert_eq!(rng_config.addr.unwrap(), (1, 0)); ++ ++ // Test4: Illegal max-bytes/period. ++ let rng_cmd = "virtio-rng-device,rng=objrng0,max-bytes=63,period=1000"; ++ let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); ++ assert!(rng_config.bytes_per_sec().is_err()); ++ ++ let rng_cmd = "virtio-rng-device,rng=objrng0,max-bytes=1000000001,period=1000"; ++ let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); ++ assert!(rng_config.bytes_per_sec().is_err()); ++ } ++ + #[test] + fn test_rng_init() { +- let file = TempFile::new().unwrap(); +- let random_file = file.as_path().to_str().unwrap().to_string(); ++ let rngobj_config = RngObjConfig { ++ classtype: "rng-random".to_string(), ++ id: "rng0".to_string(), ++ filename: "".to_string(), ++ }; + let rng_config = RngConfig { +- id: "".to_string(), +- random_file: random_file.clone(), +- bytes_per_sec: Some(64), ++ classtype: "virtio-rng-pci".to_string(), ++ rng: "rng0".to_string(), ++ max_bytes: Some(64), ++ period: Some(1000), ++ bus: Some("pcie.0".to_string()), ++ addr: Some((3, 0)), ++ ..Default::default() + }; +- let rng = Rng::new(rng_config); ++ let rng = Rng::new(rng_config, rngobj_config); + assert!(rng.random_file.is_none()); + assert_eq!(rng.base.driver_features, 0_u64); + assert_eq!(rng.base.device_features, 0_u64); +- assert_eq!(rng.rng_cfg.random_file, random_file); +- assert_eq!(rng.rng_cfg.bytes_per_sec, Some(64)); ++ assert_eq!(rng.rng_cfg.bytes_per_sec().unwrap().unwrap(), 64); + + assert_eq!(rng.queue_num(), QUEUE_NUM_RNG); + assert_eq!(rng.queue_size_max(), DEFAULT_VIRTQUEUE_SIZE); +@@ -416,18 +515,9 @@ mod tests { + + #[test] + fn test_rng_features() { +- let random_file = TempFile::new() +- .unwrap() +- .as_path() +- .to_str() +- .unwrap() +- .to_string(); +- let rng_config = RngConfig { +- id: "".to_string(), +- random_file, +- bytes_per_sec: Some(64), +- }; +- let mut rng = Rng::new(rng_config); ++ let rng_config = RngConfig::default(); ++ let rngobj_cfg = RngObjConfig::default(); ++ let mut rng = Rng::new(rng_config, rngobj_cfg); + + // If the device feature is 0, all driver features are not supported. + rng.base.device_features = 0; +diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs +index d3d6cf4..8f301df 100644 +--- a/virtio/src/device/scsi_cntlr.rs ++++ b/virtio/src/device/scsi_cntlr.rs +@@ -17,6 +17,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::{Arc, Mutex}; + + use anyhow::{bail, Context, Result}; ++use clap::Parser; + use log::{error, info, warn}; + use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; + +@@ -32,17 +33,23 @@ use devices::ScsiBus::{ + ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, + EMULATE_SCSI_OPS, SCSI_CMD_BUF_SIZE, SCSI_SENSE_INVALID_OPCODE, + }; +-use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; +-use machine_manager::{ +- config::{ScsiCntlrConfig, VIRTIO_SCSI_MAX_LUN, VIRTIO_SCSI_MAX_TARGET}, +- event_loop::EventLoop, ++use machine_manager::config::{ ++ get_pci_df, parse_bool, valid_block_device_virtqueue_size, valid_id, MAX_VIRTIO_QUEUE, + }; ++use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; + use util::aio::Iovec; + use util::byte_code::ByteCode; + use util::loop_context::{ + read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + }; + ++/// According to Virtio Spec. ++/// Max_channel should be 0. ++/// Max_target should be less than or equal to 255. ++const VIRTIO_SCSI_MAX_TARGET: u16 = 255; ++/// Max_lun should be less than or equal to 16383 (2^14 - 1). ++const VIRTIO_SCSI_MAX_LUN: u32 = 16383; ++ + /// Virtio Scsi Controller has 1 ctrl queue, 1 event queue and at least 1 cmd queue. + const SCSI_CTRL_QUEUE_NUM: usize = 1; + const SCSI_EVENT_QUEUE_NUM: usize = 1; +@@ -88,6 +95,27 @@ const VIRTIO_SCSI_S_BAD_TARGET: u8 = 3; + /// with a response equal to VIRTIO_SCSI_S_FAILURE. + const VIRTIO_SCSI_S_FAILURE: u8 = 9; + ++#[derive(Parser, Debug, Clone, Default)] ++#[command(no_binary_name(true))] ++pub struct ScsiCntlrConfig { ++ #[arg(long, value_parser = ["virtio-scsi-pci"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: String, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: (u8, u8), ++ #[arg(long, value_parser = parse_bool)] ++ pub multifunction: Option, ++ #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u32).range(1..=MAX_VIRTIO_QUEUE as i64))] ++ pub num_queues: Option, ++ #[arg(long)] ++ pub iothread: Option, ++ #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] ++ pub queue_size: u16, ++} ++ + #[repr(C, packed)] + #[derive(Copy, Clone, Debug, Default)] + struct VirtioScsiConfig { +@@ -121,7 +149,8 @@ pub struct ScsiCntlr { + impl ScsiCntlr { + pub fn new(config: ScsiCntlrConfig) -> ScsiCntlr { + // Note: config.queues <= MAX_VIRTIO_QUEUE(32). +- let queue_num = config.queues as usize + SCSI_CTRL_QUEUE_NUM + SCSI_EVENT_QUEUE_NUM; ++ let queue_num = ++ config.num_queues.unwrap() as usize + SCSI_CTRL_QUEUE_NUM + SCSI_EVENT_QUEUE_NUM; + let queue_size = config.queue_size; + + Self { +@@ -164,16 +193,15 @@ impl VirtioDevice for ScsiCntlr { + } + + fn init_config_features(&mut self) -> Result<()> { +- self.config_space.num_queues = self.config.queues; + self.config_space.max_sectors = 0xFFFF_u32; + // cmd_per_lun: maximum number of linked commands can be sent to one LUN. 32bit. + self.config_space.cmd_per_lun = 128; + // seg_max: queue size - 2, 32 bit. + self.config_space.seg_max = self.queue_size_max() as u32 - 2; + self.config_space.max_target = VIRTIO_SCSI_MAX_TARGET; +- self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN as u32; ++ self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN; + // num_queues: request queues number. +- self.config_space.num_queues = self.config.queues; ++ self.config_space.num_queues = self.config.num_queues.unwrap(); + + self.base.device_features |= (1_u64 << VIRTIO_F_VERSION_1) + | (1_u64 << VIRTIO_F_RING_EVENT_IDX) +@@ -965,3 +993,55 @@ pub fn scsi_cntlr_create_scsi_bus( + locked_scsi_cntlr.bus = Some(Arc::new(Mutex::new(bus))); + Ok(()) + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_scsi_cntlr_config_cmdline_parser() { ++ // Test1: Right. ++ let cmdline1 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3,multifunction=on,iothread=iothread1,num-queues=3,queue-size=128"; ++ let device_cfg = ++ ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline1, true, false)).unwrap(); ++ assert_eq!(device_cfg.id, "scsi0"); ++ assert_eq!(device_cfg.bus, "pcie.0"); ++ assert_eq!(device_cfg.addr, (3, 0)); ++ assert_eq!(device_cfg.multifunction, Some(true)); ++ assert_eq!(device_cfg.iothread.unwrap(), "iothread1"); ++ assert_eq!(device_cfg.num_queues.unwrap(), 3); ++ assert_eq!(device_cfg.queue_size, 128); ++ ++ // Test2: Default value. ++ let cmdline2 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1"; ++ let device_cfg = ++ ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline2, true, false)).unwrap(); ++ assert_eq!(device_cfg.addr, (3, 1)); ++ assert_eq!(device_cfg.multifunction, None); ++ assert_eq!(device_cfg.num_queues, None); ++ assert_eq!(device_cfg.queue_size, 256); ++ ++ // Test3: Illegal value. ++ let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,num-queues=33"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,queue-size=1025"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,queue-size=65"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); ++ assert!(result.is_err()); ++ ++ // Test4: Missing necessary parameters. ++ let cmdline4 = "virtio-scsi-pci,id=scsi0"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "virtio-scsi-pci,bus=pcie.0,addr=0x3.0x1"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ let cmdline4 = "virtio-scsi-pci,id=scsi0,addr=0x3.0x1"; ++ let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); ++ assert!(result.is_err()); ++ } ++} +diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs +index 7c6864f..102a3ed 100644 +--- a/virtio/src/device/serial.rs ++++ b/virtio/src/device/serial.rs +@@ -20,18 +20,19 @@ use std::{cmp, usize}; + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; + use log::{error, info, warn}; ++use machine_manager::config::ChardevConfig; + use vmm_sys_util::epoll::EventSet; + use vmm_sys_util::eventfd::EventFd; + + use crate::{ +- gpa_hva_iovec_map, iov_discard_front, iov_to_buf, read_config_default, report_virtio_error, +- Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, ++ gpa_hva_iovec_map, iov_to_buf, read_config_default, report_virtio_error, Element, Queue, ++ VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, + VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_F_SIZE, VIRTIO_F_VERSION_1, VIRTIO_TYPE_CONSOLE, + }; + use address_space::AddressSpace; + use chardev_backend::chardev::{Chardev, ChardevNotifyDevice, ChardevStatus, InputReceiver}; + use machine_manager::{ +- config::{ChardevType, VirtioSerialInfo, VirtioSerialPort, DEFAULT_VIRTQUEUE_SIZE}, ++ config::{ChardevType, VirtioSerialInfo, VirtioSerialPortCfg, DEFAULT_VIRTQUEUE_SIZE}, + event_loop::EventLoop, + event_loop::{register_event_helper, unregister_event_helper}, + }; +@@ -263,8 +264,8 @@ impl VirtioDevice for Serial { + 0 => 0, + 1 => continue, + _ => queue_id - 1, +- }; +- let port = find_port_by_nr(&self.ports, nr as u32); ++ } as u32; ++ let port = find_port_by_nr(&self.ports, nr); + let handler = SerialPortHandler { + input_queue: queues[queue_id * 2].clone(), + input_queue_evt: queue_evts[queue_id * 2].clone(), +@@ -275,6 +276,7 @@ impl VirtioDevice for Serial { + driver_features: self.base.driver_features, + device_broken: self.base.broken.clone(), + port: port.clone(), ++ nr, + }; + let handler_h = Arc::new(Mutex::new(handler)); + let notifiers = EventNotifierHelper::internal_notifiers(handler_h.clone()); +@@ -353,17 +355,21 @@ pub struct SerialPort { + } + + impl SerialPort { +- pub fn new(port_cfg: VirtioSerialPort) -> Self { ++ pub fn new(port_cfg: VirtioSerialPortCfg, chardev_cfg: ChardevConfig) -> Self { + // Console is default host connected. And pty chardev has opened by default in realize() + // function. +- let host_connected = port_cfg.is_console || port_cfg.chardev.backend == ChardevType::Pty; ++ let is_console = matches!(port_cfg.classtype.as_str(), "virtconsole"); ++ let mut host_connected = is_console; ++ if let ChardevType::Pty { .. } = chardev_cfg.classtype { ++ host_connected = true; ++ } + + SerialPort { + name: Some(port_cfg.id), + paused: false, +- chardev: Arc::new(Mutex::new(Chardev::new(port_cfg.chardev))), +- nr: port_cfg.nr, +- is_console: port_cfg.is_console, ++ chardev: Arc::new(Mutex::new(Chardev::new(chardev_cfg))), ++ nr: port_cfg.nr.unwrap(), ++ is_console, + guest_connected: false, + host_connected, + ctrl_handler: None, +@@ -412,6 +418,7 @@ struct SerialPortHandler { + /// Virtio serial device is broken or not. + device_broken: Arc, + port: Option>>, ++ nr: u32, + } + + /// Handler for queues which are used for control. +@@ -431,7 +438,7 @@ impl SerialPortHandler { + fn output_handle(&mut self) { + trace::virtio_receive_request("Serial".to_string(), "to IO".to_string()); + self.output_handle_internal().unwrap_or_else(|e| { +- error!("Port handle output error: {:?}", e); ++ error!("Port {} handle output error: {:?}", self.nr, e); + report_virtio_error( + self.interrupt_cb.clone(), + self.driver_features, +@@ -453,6 +460,14 @@ impl SerialPortHandler { + let mut queue_lock = self.output_queue.lock().unwrap(); + + loop { ++ if let Some(port) = self.port.as_ref() { ++ let locked_port = port.lock().unwrap(); ++ let locked_cdev = locked_port.chardev.lock().unwrap(); ++ if locked_cdev.outbuf_is_full() { ++ break; ++ } ++ } ++ + let elem = queue_lock + .vring + .pop_avail(&self.mem_space, self.driver_features)?; +@@ -462,23 +477,24 @@ impl SerialPortHandler { + + // Discard requests when there is no port using this queue. Popping elements without + // processing means discarding the request. +- if self.port.is_some() { +- let mut iovec = elem.out_iovec; +- let mut iovec_size = Element::iovec_size(&iovec); +- while iovec_size > 0 { +- let mut buffer = [0_u8; BUF_SIZE]; +- let size = iov_to_buf(&self.mem_space, &iovec, &mut buffer)? as u64; +- +- self.write_chardev_msg(&buffer, size as usize); +- +- iovec = iov_discard_front(&mut iovec, size) +- .unwrap_or_default() +- .to_vec(); +- // Safety: iovec follows the iov_discard_front operation and +- // iovec_size always equals Element::iovec_size(&iovec). +- iovec_size -= size; +- trace::virtio_serial_output_data(iovec_size, size); ++ if let Some(port) = self.port.as_ref() { ++ let iovec = elem.out_iovec; ++ let iovec_size = Element::iovec_size(&iovec); ++ let mut buf = vec![0u8; iovec_size as usize]; ++ let size = iov_to_buf(&self.mem_space, &iovec, &mut buf[..])? as u64; ++ ++ let locked_port = port.lock().unwrap(); ++ if locked_port.host_connected { ++ if let Err(e) = locked_port ++ .chardev ++ .lock() ++ .unwrap() ++ .fill_outbuf(buf, Some(self.output_queue_evt.clone())) ++ { ++ error!("Failed to append elem buffer to chardev with error {:?}", e); ++ } + } ++ trace::virtio_serial_output_data(iovec_size, size); + } + + queue_lock +@@ -509,30 +525,6 @@ impl SerialPortHandler { + Ok(()) + } + +- fn write_chardev_msg(&self, buffer: &[u8], write_len: usize) { +- let port_locked = self.port.as_ref().unwrap().lock().unwrap(); +- // Discard output buffer if this port's chardev is not connected. +- if !port_locked.host_connected { +- return; +- } +- +- if let Some(output) = &mut port_locked.chardev.lock().unwrap().output { +- let mut locked_output = output.lock().unwrap(); +- // To do: +- // If the buffer is not fully written to chardev, the incomplete part will be discarded. +- // This may occur when chardev is abnormal. Consider optimizing this logic in the +- // future. +- if let Err(e) = locked_output.write_all(&buffer[..write_len]) { +- error!("Failed to write msg to chardev: {:?}", e); +- } +- if let Err(e) = locked_output.flush() { +- error!("Failed to flush msg to chardev: {:?}", e); +- } +- } else { +- error!("Failed to get output fd"); +- }; +- } +- + fn get_input_avail_bytes(&mut self, max_size: usize) -> usize { + let port = self.port.as_ref(); + if port.is_none() || !port.unwrap().lock().unwrap().guest_connected { +@@ -552,7 +544,10 @@ impl SerialPortHandler { + { + Ok(n) => n, + Err(_) => { +- warn!("error occurred while getting available bytes of vring"); ++ warn!( ++ "error occurred while port {} getting available bytes of vring", ++ self.nr ++ ); + 0 + } + } +@@ -697,7 +692,7 @@ impl EventNotifierHelper for SerialPortHandler { + impl InputReceiver for SerialPortHandler { + fn receive(&mut self, buffer: &[u8]) { + self.input_handle_internal(buffer).unwrap_or_else(|e| { +- error!("Port handle input error: {:?}", e); ++ error!("Port {} handle input error: {:?}", self.nr, e); + report_virtio_error( + self.interrupt_cb.clone(), + self.driver_features, +@@ -1015,18 +1010,15 @@ impl ChardevNotifyDevice for SerialPort { + mod tests { + pub use super::*; + +- use machine_manager::config::PciBdf; +- + #[test] + fn test_set_driver_features() { + let mut serial = Serial::new(VirtioSerialInfo { ++ classtype: "virtio-serial-pci".to_string(), + id: "serial".to_string(), +- pci_bdf: Some(PciBdf { +- bus: "pcie.0".to_string(), +- addr: (0, 0), +- }), +- multifunction: false, ++ multifunction: Some(false), + max_ports: 31, ++ bus: Some("pcie.0".to_string()), ++ addr: Some((0, 0)), + }); + + // If the device feature is 0, all driver features are not supported. +@@ -1089,13 +1081,12 @@ mod tests { + fn test_read_config() { + let max_ports: u8 = 31; + let serial = Serial::new(VirtioSerialInfo { ++ classtype: "virtio-serial-pci".to_string(), + id: "serial".to_string(), +- pci_bdf: Some(PciBdf { +- bus: "pcie.0".to_string(), +- addr: (0, 0), +- }), +- multifunction: false, ++ multifunction: Some(false), + max_ports: max_ports as u32, ++ bus: Some("pcie.0".to_string()), ++ addr: Some((0, 0)), + }); + + // The offset of configuration that needs to be read exceeds the maximum. +diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs +index 9ef9dde..33edacf 100644 +--- a/virtio/src/lib.rs ++++ b/virtio/src/lib.rs +@@ -24,6 +24,7 @@ + //! + //! - `x86_64` + //! - `aarch64` ++//! - `riscv64` + + pub mod device; + pub mod error; +@@ -33,11 +34,11 @@ mod queue; + mod transport; + + pub use device::balloon::*; +-pub use device::block::{Block, BlockState, VirtioBlkConfig}; ++pub use device::block::{Block, BlockState, VirtioBlkConfig, VirtioBlkDevConfig}; + #[cfg(feature = "virtio_gpu")] + pub use device::gpu::*; + pub use device::net::*; +-pub use device::rng::{Rng, RngState}; ++pub use device::rng::{Rng, RngConfig, RngState}; + pub use device::scsi_cntlr as ScsiCntlr; + pub use device::serial::{find_port_by_nr, get_max_nr, Serial, SerialPort, VirtioSerialState}; + pub use error::VirtioError; +@@ -57,7 +58,9 @@ use anyhow::{anyhow, bail, Context, Result}; + use log::{error, warn}; + use vmm_sys_util::eventfd::EventFd; + +-use address_space::AddressSpace; ++use address_space::{AddressSpace, RegionCache}; ++use devices::pci::register_pcidevops_type; ++use devices::sysbus::register_sysbusdevops_type; + use machine_manager::config::ConfigCheck; + use migration_derive::ByteCode; + use util::aio::{mem_to_buf, Iovec}; +@@ -729,8 +732,9 @@ pub trait VirtioDevice: Send + AsAny { + /// + /// # Arguments + /// +- /// * `_file_path` - The related backend file path. +- fn update_config(&mut self, _dev_config: Option>) -> Result<()> { ++ /// * `_configs` - The related configs for device. ++ /// eg: DriveConfig and VirtioBlkDevConfig for virtio blk device. ++ fn update_config(&mut self, _configs: Vec>) -> Result<()> { + bail!("Unsupported to update configuration") + } + +@@ -789,12 +793,21 @@ pub fn report_virtio_error( + + /// Read iovec to buf and return the read number of bytes. + pub fn iov_to_buf(mem_space: &AddressSpace, iovec: &[ElemIovec], buf: &mut [u8]) -> Result { ++ iov_to_buf_by_cache(mem_space, &None, iovec, buf) ++} ++ ++pub fn iov_to_buf_by_cache( ++ mem_space: &AddressSpace, ++ cache: &Option, ++ iovec: &[ElemIovec], ++ buf: &mut [u8], ++) -> Result { + let mut start: usize = 0; + let mut end: usize = 0; + + for iov in iovec { + let mut addr_map = Vec::new(); +- mem_space.get_address_map(iov.addr, iov.len as u64, &mut addr_map)?; ++ mem_space.get_address_map(cache, iov.addr, iov.len as u64, &mut addr_map)?; + for addr in addr_map.into_iter() { + end = cmp::min(start + addr.iov_len as usize, buf.len()); + mem_to_buf(&mut buf[start..end], addr.iov_base)?; +@@ -838,14 +851,30 @@ pub fn iov_discard_back(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut [ + fn gpa_hva_iovec_map( + gpa_elemiovec: &[ElemIovec], + mem_space: &AddressSpace, ++) -> Result<(u64, Vec)> { ++ gpa_hva_iovec_map_by_cache(gpa_elemiovec, mem_space, &None) ++} ++ ++fn gpa_hva_iovec_map_by_cache( ++ gpa_elemiovec: &[ElemIovec], ++ mem_space: &AddressSpace, ++ cache: &Option, + ) -> Result<(u64, Vec)> { + let mut iov_size = 0; + let mut hva_iovec = Vec::with_capacity(gpa_elemiovec.len()); + + for elem in gpa_elemiovec.iter() { +- mem_space.get_address_map(elem.addr, elem.len as u64, &mut hva_iovec)?; ++ mem_space.get_address_map(cache, elem.addr, elem.len as u64, &mut hva_iovec)?; + iov_size += elem.len as u64; + } + + Ok((iov_size, hva_iovec)) + } ++ ++pub fn virtio_register_sysbusdevops_type() -> Result<()> { ++ register_sysbusdevops_type::() ++} ++ ++pub fn virtio_register_pcidevops_type() -> Result<()> { ++ register_pcidevops_type::() ++} +diff --git a/virtio/src/queue/mod.rs b/virtio/src/queue/mod.rs +index 7f581a0..1e612b2 100644 +--- a/virtio/src/queue/mod.rs ++++ b/virtio/src/queue/mod.rs +@@ -21,6 +21,7 @@ use vmm_sys_util::eventfd::EventFd; + + use address_space::{AddressSpace, GuestAddress, RegionCache}; + use machine_manager::config::DEFAULT_VIRTQUEUE_SIZE; ++use util::loop_context::create_new_eventfd; + + /// Split Virtqueue. + pub const QUEUE_TYPE_SPLIT_VRING: u16 = 1; +@@ -226,7 +227,7 @@ impl NotifyEventFds { + pub fn new(queue_num: usize) -> Self { + let mut events = Vec::new(); + for _i in 0..queue_num { +- events.push(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())); ++ events.push(Arc::new(create_new_eventfd().unwrap())); + } + + NotifyEventFds { events } +diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs +index 260c0de..77d0ca0 100644 +--- a/virtio/src/transport/virtio_mmio.rs ++++ b/virtio/src/transport/virtio_mmio.rs +@@ -15,7 +15,7 @@ use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; +-use log::{debug, error, warn}; ++use log::{debug, error, info, warn}; + use vmm_sys_util::eventfd::EventFd; + + use crate::error::VirtioError; +@@ -26,13 +26,14 @@ use crate::{ + QUEUE_TYPE_PACKED_VRING, VIRTIO_F_RING_PACKED, VIRTIO_MMIO_INT_CONFIG, VIRTIO_MMIO_INT_VRING, + }; + use address_space::{AddressRange, AddressSpace, GuestAddress, RegionIoEventFd}; +-use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; ++use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; + use devices::{Device, DeviceBase}; + #[cfg(target_arch = "x86_64")] + use machine_manager::config::{BootSource, Param}; + use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; + use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; ++use util::loop_context::create_new_eventfd; + + /// Registers of virtio-mmio device refer to Virtio Spec. + /// Magic value - Read Only. +@@ -105,7 +106,7 @@ impl HostNotifyInfo { + fn new(queue_num: usize) -> Self { + let mut events = Vec::new(); + for _i in 0..queue_num { +- events.push(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())); ++ events.push(Arc::new(create_new_eventfd().unwrap())); + } + + HostNotifyInfo { events } +@@ -134,14 +135,22 @@ pub struct VirtioMmioDevice { + } + + impl VirtioMmioDevice { +- pub fn new(mem_space: &Arc, device: Arc>) -> Self { ++ pub fn new( ++ mem_space: &Arc, ++ name: String, ++ device: Arc>, ++ ) -> Self { + let device_clone = device.clone(); + let queue_num = device_clone.lock().unwrap().queue_num(); + + VirtioMmioDevice { + base: SysBusDevBase { ++ base: DeviceBase { ++ id: name, ++ hotpluggable: false, ++ }, + dev_type: SysBusDevType::VirtioMmio, +- interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), ++ interrupt_evt: Some(Arc::new(create_new_eventfd().unwrap())), + ..Default::default() + }, + device, +@@ -161,7 +170,7 @@ impl VirtioMmioDevice { + if region_base >= sysbus.mmio_region.1 { + bail!("Mmio region space exhausted."); + } +- self.set_sys_resource(sysbus, region_base, region_size)?; ++ self.set_sys_resource(sysbus, region_base, region_size, "VirtioMmio")?; + self.assign_interrupt_cb(); + self.device + .lock() +@@ -170,7 +179,7 @@ impl VirtioMmioDevice { + .with_context(|| "Failed to realize virtio.")?; + + let dev = Arc::new(Mutex::new(self)); +- sysbus.attach_device(&dev, region_base, region_size, "VirtioMmio")?; ++ sysbus.attach_device(&dev)?; + + #[cfg(target_arch = "x86_64")] + bs.lock().unwrap().kernel_cmdline.push(Param { +@@ -188,7 +197,7 @@ impl VirtioMmioDevice { + /// Activate the virtio device, this function is called by vcpu thread when frontend + /// virtio driver is ready and write `DRIVER_OK` to backend. + fn activate(&mut self) -> Result<()> { +- trace::virtio_tpt_common("activate", &self.base.base.id); ++ info!("func: activate, id: {:?}", &self.base.base.id); + let mut locked_dev = self.device.lock().unwrap(); + let queue_num = locked_dev.queue_num(); + let queue_type = locked_dev.queue_type(); +@@ -409,10 +418,8 @@ impl SysBusDevOps for VirtioMmioDevice { + Ok(v) => v, + Err(ref e) => { + error!( +- "Failed to read mmio register {}, type: {}, {:?}", +- offset, +- self.device.lock().unwrap().device_type(), +- e, ++ "Failed to read mmio register {:#x}, device: {}, {:?}", ++ offset, self.base.base.id, e, + ); + return false; + } +@@ -427,9 +434,9 @@ impl SysBusDevOps for VirtioMmioDevice { + .read_config(offset - 0x100, data) + { + error!( +- "Failed to read virtio-dev config space {} type: {} {:?}", ++ "Failed to read virtio-dev config space {:#x} device: {}, {:?}", + offset - 0x100, +- self.device.lock().unwrap().device_type(), ++ self.base.base.id, + e, + ); + return false; +@@ -437,9 +444,8 @@ impl SysBusDevOps for VirtioMmioDevice { + } + _ => { + warn!( +- "Failed to read mmio register: overflows, offset is 0x{:x}, type: {}", +- offset, +- self.device.lock().unwrap().device_type(), ++ "Failed to read mmio register: overflows, offset is {:#x}, device: {}", ++ offset, self.base.base.id + ); + } + }; +@@ -454,10 +460,8 @@ impl SysBusDevOps for VirtioMmioDevice { + let value = LittleEndian::read_u32(data); + if let Err(ref e) = self.write_common_config(offset, value) { + error!( +- "Failed to write mmio register {}, type: {}, {:?}", +- offset, +- self.device.lock().unwrap().device_type(), +- e, ++ "Failed to write mmio register {:#x}, device: {}, {:?}", ++ offset, self.base.base.id, e, + ); + return false; + } +@@ -474,9 +478,8 @@ impl SysBusDevOps for VirtioMmioDevice { + drop(locked_dev); + if let Err(ref e) = self.activate() { + error!( +- "Failed to activate dev, type: {}, {:?}", +- self.device.lock().unwrap().device_type(), +- e, ++ "Failed to activate dev, device: {}, {:?}", ++ self.base.base.id, e, + ); + return false; + } +@@ -488,26 +491,25 @@ impl SysBusDevOps for VirtioMmioDevice { + if locked_device.check_device_status(CONFIG_STATUS_DRIVER, CONFIG_STATUS_FAILED) { + if let Err(ref e) = locked_device.write_config(offset - 0x100, data) { + error!( +- "Failed to write virtio-dev config space {}, type: {}, {:?}", ++ "Failed to write virtio-dev config space {:#x}, device: {}, {:?}", + offset - 0x100, +- locked_device.device_type(), ++ self.base.base.id, + e, + ); + return false; + } + } else { +- error!("Failed to write virtio-dev config space: driver is not ready 0x{:X}, type: {}", ++ error!("Failed to write virtio-dev config space: driver is not ready {:#x}, device: {}", + locked_device.device_status(), +- locked_device.device_type(), ++ self.base.base.id, + ); + return false; + } + } + _ => { + warn!( +- "Failed to write mmio register: overflows, offset is 0x{:x} type: {}", +- offset, +- self.device.lock().unwrap().device_type(), ++ "Failed to write mmio register: overflows, offset is {:#x} device: {}", ++ offset, self.base.base.id, + ); + return false; + } +@@ -528,10 +530,6 @@ impl SysBusDevOps for VirtioMmioDevice { + } + ret + } +- +- fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { +- Some(&mut self.base.res) +- } + } + + impl acpi::AmlBuilder for VirtioMmioDevice { +@@ -596,7 +594,7 @@ impl MigrationHook for VirtioMmioDevice { + } + + #[cfg(test)] +-mod tests { ++pub mod tests { + use super::*; + use crate::{ + check_config_space_rw, read_config_default, VirtioBase, QUEUE_TYPE_SPLIT_VRING, +@@ -604,7 +602,7 @@ mod tests { + }; + use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + +- fn address_space_init() -> Arc { ++ pub fn address_space_init() -> Arc { + let root = Region::init_container_region(1 << 36, "sysmem"); + let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); + let host_mmap = Arc::new( +@@ -699,12 +697,22 @@ mod tests { + } + } + +- #[test] +- fn test_virtio_mmio_device_new() { ++ fn virtio_mmio_test_init() -> (Arc>, VirtioMmioDevice) { + let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); ++ + let sys_space = address_space_init(); +- let virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let virtio_mmio_device = VirtioMmioDevice::new( ++ &sys_space, ++ "test_virtio_mmio_device".to_string(), ++ virtio_device.clone(), ++ ); ++ ++ (virtio_device, virtio_mmio_device) ++ } + ++ #[test] ++ fn test_virtio_mmio_device_new() { ++ let (virtio_device, virtio_mmio_device) = virtio_mmio_test_init(); + let locked_device = virtio_device.lock().unwrap(); + assert_eq!(locked_device.device_activated(), false); + assert_eq!( +@@ -721,9 +729,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_read_01() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // read the register of magic value +@@ -780,9 +786,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_read_02() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // read the register representing max size of the queue +@@ -872,9 +876,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_read_03() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // read the configuration atomic value +@@ -920,9 +922,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_write_01() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // write the selector for device features +@@ -1034,9 +1034,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_write_02() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // write the ready status of queue +@@ -1101,9 +1099,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_write_03() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + // write the low 32bit of queue's descriptor table address +@@ -1226,9 +1222,7 @@ mod tests { + + #[test] + fn test_virtio_mmio_device_write_04() { +- let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_space = address_space_init(); +- let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); ++ let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); + let addr = GuestAddress(0); + + virtio_mmio_device.assign_interrupt_cb(); +diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs +index aa27db4..111ae3d 100644 +--- a/virtio/src/transport/virtio_pci.rs ++++ b/virtio/src/transport/virtio_pci.rs +@@ -17,7 +17,7 @@ use std::sync::{Arc, Mutex, Weak}; + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; +-use log::{debug, error, warn}; ++use log::{debug, error, info, warn}; + use vmm_sys_util::eventfd::EventFd; + + #[cfg(feature = "virtio_gpu")] +@@ -316,6 +316,8 @@ pub struct VirtioPciDevice { + multi_func: bool, + /// If the device need to register irqfd. + need_irqfd: bool, ++ /// Device activation error ++ activate_err: bool, + } + + impl VirtioPciDevice { +@@ -326,6 +328,7 @@ impl VirtioPciDevice { + device: Arc>, + parent_bus: Weak>, + multi_func: bool, ++ need_irqfd: bool, + ) -> Self { + let queue_num = device.lock().unwrap().queue_num(); + VirtioPciDevice { +@@ -342,14 +345,11 @@ impl VirtioPciDevice { + notify_eventfds: Arc::new(NotifyEventFds::new(queue_num)), + interrupt_cb: None, + multi_func, +- need_irqfd: false, ++ need_irqfd, ++ activate_err: false, + } + } + +- pub fn enable_need_irqfd(&mut self) { +- self.need_irqfd = true; +- } +- + fn assign_interrupt_cb(&mut self) { + let locked_dev = self.device.lock().unwrap(); + let virtio_base = locked_dev.virtio_base(); +@@ -390,7 +390,9 @@ impl VirtioPciDevice { + + let mut locked_msix = cloned_msix.lock().unwrap(); + if locked_msix.enabled { +- locked_msix.notify(vector, dev_id.load(Ordering::Acquire)); ++ if vector != INVALID_VECTOR_NUM { ++ locked_msix.notify(vector, dev_id.load(Ordering::Acquire)); ++ } + } else { + cloned_intx.lock().unwrap().notify(1); + } +@@ -431,8 +433,8 @@ impl VirtioPciDevice { + Ok(write_start) + } + +- fn activate_device(&self) -> bool { +- trace::virtio_tpt_common("activate_device", &self.base.base.id); ++ fn activate_device(&mut self) -> bool { ++ info!("func: activate_device, id: {:?}", &self.base.base.id); + let mut locked_dev = self.device.lock().unwrap(); + if locked_dev.device_activated() { + return true; +@@ -457,7 +459,10 @@ impl VirtioPciDevice { + } + let queue = Queue::new(*q_config, queue_type).unwrap(); + if q_config.ready && !queue.is_valid(&self.sys_mem) { +- error!("Failed to activate device: Invalid queue"); ++ error!( ++ "Failed to activate device {}: Invalid queue", ++ self.base.base.id ++ ); + return false; + } + let arc_queue = Arc::new(Mutex::new(queue)); +@@ -479,12 +484,18 @@ impl VirtioPciDevice { + } + let call_evts = NotifyEventFds::new(queue_num); + if let Err(e) = locked_dev.set_guest_notifiers(&call_evts.events) { +- error!("Failed to set guest notifiers, error is {:?}", e); ++ error!( ++ "Failed to set guest notifiers, device {} error is {:?}", ++ self.base.base.id, e ++ ); + return false; + } + drop(locked_dev); + if !self.queues_register_irqfd(&call_evts.events) { +- error!("Failed to register queues irqfd."); ++ error!( ++ "Failed to register queues irqfd for device {}", ++ self.base.base.id ++ ); + return false; + } + locked_dev = self.device.lock().unwrap(); +@@ -496,40 +507,47 @@ impl VirtioPciDevice { + self.interrupt_cb.clone().unwrap(), + queue_evts, + ) { +- error!("Failed to activate device, error is {:?}", e); ++ // log only first activation error ++ if !self.activate_err { ++ self.activate_err = true; ++ error!( ++ "Failed to activate device {}, error is {:?}", ++ self.base.base.id, e ++ ); ++ } + return false; + } ++ self.activate_err = false; + + locked_dev.set_device_activated(true); + true + } + +- fn deactivate_device(&self) -> bool { +- trace::virtio_tpt_common("deactivate_device", &self.base.base.id); ++ fn deactivate_device(&self) { ++ info!("func: deactivate_device, id: {:?}", &self.base.base.id); + if self.need_irqfd && self.base.config.msix.is_some() { + let msix = self.base.config.msix.as_ref().unwrap(); + if msix.lock().unwrap().unregister_irqfd().is_err() { +- return false; ++ warn!("unregister_irqfd failed"); + } + } +- ++ // call deactivate unconditionally, since device can be ++ // in half initialized state + let mut locked_dev = self.device.lock().unwrap(); +- if locked_dev.device_activated() { +- if let Err(e) = locked_dev.deactivate() { +- error!("Failed to deactivate virtio device, error is {:?}", e); +- return false; +- } +- locked_dev.virtio_base_mut().reset(); ++ if let Err(e) = locked_dev.deactivate() { ++ error!( ++ "Failed to deactivate virtio device {}, error is {:?}", ++ self.base.base.id, e ++ ); + } ++ locked_dev.virtio_base_mut().reset(); + + if let Some(intx) = &self.base.config.intx { + intx.lock().unwrap().reset(); + } + if let Some(msix) = &self.base.config.msix { + msix.lock().unwrap().clear_pending_vectors(); +- } +- +- true ++ }; + } + + /// Read data from the common config of virtio device. +@@ -621,7 +639,7 @@ impl VirtioPciDevice { + } + COMMON_GF_REG => { + if locked_device.device_status() & CONFIG_STATUS_FEATURES_OK != 0 { +- error!("it's not allowed to set features after having been negoiated"); ++ error!("it's not allowed to set features after having been negoiated for device {}", self.base.base.id); + return Ok(()); + } + let gfeatures_sel = locked_device.gfeatures_sel(); +@@ -652,13 +670,16 @@ impl VirtioPciDevice { + let features = (locked_device.driver_features(1) as u64) << 32; + if !virtio_has_feature(features, VIRTIO_F_VERSION_1) { + error!( +- "Device is modern only, but the driver not support VIRTIO_F_VERSION_1" ++ "Device {} is modern only, but the driver not support VIRTIO_F_VERSION_1", self.base.base.id + ); + return Ok(()); + } + } + if value != 0 && (locked_device.device_status() & !value) != 0 { +- error!("Driver must not clear a device status bit"); ++ error!( ++ "Driver must not clear a device status bit, device {}", ++ self.base.base.id ++ ); + return Ok(()); + } + +@@ -688,7 +709,10 @@ impl VirtioPciDevice { + .map(|config| config.size = value as u16)?, + COMMON_Q_ENABLE_REG => { + if value != 1 { +- error!("Driver set illegal value for queue_enable {}", value); ++ error!( ++ "Driver set illegal value for queue_enable {}, device {}", ++ value, self.base.base.id ++ ); + return Err(anyhow!(PciError::QueueEnable(value))); + } + locked_device +@@ -924,7 +948,7 @@ impl VirtioPciDevice { + }; + if let Err(e) = result { + error!( +- "Failed to access virtio configuration through VirtioPciCfgAccessCap. {:?}", ++ "Failed to access virtio configuration through VirtioPciCfgAccessCap. device is {}, error is {:?}", self.base.base.id, + e + ); + } +@@ -940,7 +964,10 @@ impl VirtioPciDevice { + + fn queues_register_irqfd(&self, call_fds: &[Arc]) -> bool { + if self.base.config.msix.is_none() { +- error!("Failed to get msix in virtio pci device configure"); ++ error!( ++ "Failed to get msix in virtio pci device configure, device is {}", ++ self.base.base.id ++ ); + return false; + } + +@@ -997,6 +1024,7 @@ impl PciDevOps for VirtioPciDevice { + } + + fn realize(mut self) -> Result<()> { ++ info!("func: realize, id: {:?}", &self.base.base.id); + self.init_write_mask(false)?; + self.init_write_clear_mask(false)?; + +@@ -1164,7 +1192,7 @@ impl PciDevOps for VirtioPciDevice { + } + + fn unrealize(&mut self) -> Result<()> { +- trace::virtio_tpt_common("unrealize", &self.base.base.id); ++ info!("func: unrealize, id: {:?}", &self.base.base.id); + self.device + .lock() + .unwrap() +@@ -1191,8 +1219,8 @@ impl PciDevOps for VirtioPciDevice { + let end = offset + data_size; + if end > PCIE_CONFIG_SPACE_SIZE || data_size > REG_SIZE { + error!( +- "Failed to write pcie config space at offset 0x{:x} with data size {}", +- offset, data_size ++ "Failed to write pcie config space at offset {:#x} with data size {}, device is {}", ++ offset, data_size, self.base.base.id + ); + return; + } +@@ -1212,7 +1240,7 @@ impl PciDevOps for VirtioPciDevice { + } + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { +- trace::virtio_tpt_common("reset", &self.base.base.id); ++ info!("func: reset, id: {:?}", &self.base.base.id); + self.deactivate_device(); + self.device + .lock() +@@ -1333,10 +1361,16 @@ impl MigrationHook for VirtioPciDevice { + .unwrap() + .activate(self.sys_mem.clone(), cb, queue_evts) + { +- error!("Failed to resume device, error is {:?}", e); ++ error!( ++ "Failed to resume device {}, error is {:?}", ++ self.base.base.id, e ++ ); + } + } else { +- error!("Failed to resume device: No interrupt callback"); ++ error!( ++ "Failed to resume device {}: No interrupt callback", ++ self.base.base.id ++ ); + } + + Ok(()) +@@ -1351,8 +1385,9 @@ mod tests { + use vmm_sys_util::eventfd::EventFd; + + use super::*; ++ use crate::transport::virtio_mmio::tests::address_space_init; + use crate::VirtioBase; +- use address_space::{AddressSpace, GuestAddress, HostMemMapping}; ++ use address_space::{AddressSpace, GuestAddress}; + use devices::pci::{ + config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC}, + le_read_u16, +@@ -1434,30 +1469,40 @@ mod tests { + }; + } + +- #[test] +- fn test_common_config_dev_feature() { ++ fn virtio_pci_test_init( ++ multi_func: bool, ++ ) -> ( ++ Arc>, ++ Arc>, ++ VirtioPciDevice, ++ ) { + let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); ++ let sys_mem = address_space_init(); + let parent_bus = Arc::new(Mutex::new(PciBus::new( + String::from("test bus"), + #[cfg(target_arch = "x86_64")] + Region::init_container_region(1 << 16, "parent_bus"), + sys_mem.root().clone(), + ))); +- let mut virtio_pci = VirtioPciDevice::new( ++ let virtio_pci = VirtioPciDevice::new( + String::from("test device"), + 0, + sys_mem, + virtio_dev.clone(), + Arc::downgrade(&parent_bus), ++ multi_func, + false, + ); + ++ // Note: if parent_bus is used in the code execution during the testing process, a variable needs to ++ // be used to maintain the count and avoid rust from automatically releasing this `Arc`. ++ (virtio_dev, parent_bus, virtio_pci) ++ } ++ ++ #[test] ++ fn test_common_config_dev_feature() { ++ let (virtio_dev, _, mut virtio_pci) = virtio_pci_test_init(false); ++ + // Read virtio device features + virtio_dev.lock().unwrap().set_hfeatures_sel(0_u32); + com_cfg_read_test!(virtio_pci, COMMON_DF_REG, 0xFFFF_FFF0_u32); +@@ -1493,27 +1538,7 @@ mod tests { + + #[test] + fn test_common_config_queue() { +- let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 0, +- sys_mem, +- virtio_dev.clone(), +- Arc::downgrade(&parent_bus), +- false, +- ); ++ let (virtio_dev, _, virtio_pci) = virtio_pci_test_init(false); + + // Read Queue's Descriptor Table address + virtio_dev +@@ -1543,28 +1568,7 @@ mod tests { + + #[test] + fn test_common_config_queue_error() { +- let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let cloned_virtio_dev = virtio_dev.clone(); +- let mut virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 0, +- sys_mem, +- cloned_virtio_dev, +- Arc::downgrade(&parent_bus), +- false, +- ); ++ let (virtio_dev, _, mut virtio_pci) = virtio_pci_test_init(false); + + assert!(init_msix( + &mut virtio_pci.base, +@@ -1617,28 +1621,8 @@ mod tests { + + #[test] + fn test_virtio_pci_config_access() { +- let virtio_dev: Arc> = +- Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let mut virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 0, +- sys_mem, +- virtio_dev, +- Arc::downgrade(&parent_bus), +- false, +- ); ++ let (_, _parent_bus, mut virtio_pci) = virtio_pci_test_init(false); ++ + virtio_pci.init_write_mask(false).unwrap(); + virtio_pci.init_write_clear_mask(false).unwrap(); + +@@ -1657,67 +1641,14 @@ mod tests { + + #[test] + fn test_virtio_pci_realize() { +- let virtio_dev: Arc> = +- Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 0, +- sys_mem, +- virtio_dev, +- Arc::downgrade(&parent_bus), +- false, +- ); ++ let (_, _parent_bus, virtio_pci) = virtio_pci_test_init(false); + assert!(virtio_pci.realize().is_ok()); + } + + #[test] + fn test_device_activate() { +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let mem_size: u64 = 1024 * 1024; +- let host_mmap = Arc::new( +- HostMemMapping::new(GuestAddress(0), None, mem_size, None, false, false, false) +- .unwrap(), +- ); +- sys_mem +- .root() +- .add_subregion( +- Region::init_ram_region(host_mmap.clone(), "sysmem"), +- host_mmap.start_address().raw_value(), +- ) +- .unwrap(); ++ let (virtio_dev, _parent_bus, mut virtio_pci) = virtio_pci_test_init(false); + +- let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let mut virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 0, +- sys_mem, +- virtio_dev.clone(), +- Arc::downgrade(&parent_bus), +- false, +- ); + #[cfg(target_arch = "aarch64")] + virtio_pci.base.config.set_interrupt_pin(); + +@@ -1787,28 +1718,7 @@ mod tests { + + #[test] + fn test_multifunction() { +- let virtio_dev: Arc> = +- Arc::new(Mutex::new(VirtioDeviceTest::new())); +- let sys_mem = AddressSpace::new( +- Region::init_container_region(u64::max_value(), "sysmem"), +- "sysmem", +- None, +- ) +- .unwrap(); +- let parent_bus = Arc::new(Mutex::new(PciBus::new( +- String::from("test bus"), +- #[cfg(target_arch = "x86_64")] +- Region::init_container_region(1 << 16, "parent_bus"), +- sys_mem.root().clone(), +- ))); +- let mut virtio_pci = VirtioPciDevice::new( +- String::from("test device"), +- 24, +- sys_mem, +- virtio_dev, +- Arc::downgrade(&parent_bus), +- true, +- ); ++ let (_, _parent_bus, mut virtio_pci) = virtio_pci_test_init(true); + + assert!(init_multifunction( + virtio_pci.multi_func, +diff --git a/virtio/src/vhost/kernel/mod.rs b/virtio/src/vhost/kernel/mod.rs +index 02d55ca..2111e2b 100644 +--- a/virtio/src/vhost/kernel/mod.rs ++++ b/virtio/src/vhost/kernel/mod.rs +@@ -14,7 +14,7 @@ mod net; + mod vsock; + + pub use net::Net; +-pub use vsock::{Vsock, VsockState}; ++pub use vsock::{Vsock, VsockConfig, VsockState}; + + use std::fs::{File, OpenOptions}; + use std::os::unix::fs::OpenOptionsExt; +diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs +index 55a4972..89a2997 100644 +--- a/virtio/src/vhost/kernel/net.rs ++++ b/virtio/src/vhost/kernel/net.rs +@@ -31,10 +31,10 @@ use crate::{ + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MQ, VIRTIO_TYPE_NET, + }; + use address_space::AddressSpace; +-use machine_manager::config::NetworkInterfaceConfig; ++use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use util::byte_code::ByteCode; +-use util::loop_context::EventNotifierHelper; ++use util::loop_context::{create_new_eventfd, EventNotifierHelper}; + use util::tap::Tap; + + /// Number of virtqueues. +@@ -79,6 +79,8 @@ pub struct Net { + base: VirtioBase, + /// Configuration of the network device. + net_cfg: NetworkInterfaceConfig, ++ /// Configuration of the backend netdev. ++ netdev_cfg: NetDevcfg, + /// Virtio net configurations. + config_space: Arc>, + /// Tap device opened. +@@ -94,17 +96,22 @@ pub struct Net { + } + + impl Net { +- pub fn new(cfg: &NetworkInterfaceConfig, mem_space: &Arc) -> Self { +- let queue_num = if cfg.mq { +- (cfg.queues + 1) as usize ++ pub fn new( ++ net_cfg: &NetworkInterfaceConfig, ++ netdev_cfg: NetDevcfg, ++ mem_space: &Arc, ++ ) -> Self { ++ let queue_num = if net_cfg.mq { ++ (netdev_cfg.queues + 1) as usize + } else { + QUEUE_NUM_NET + }; +- let queue_size = cfg.queue_size; ++ let queue_size = net_cfg.queue_size; + + Net { + base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), +- net_cfg: cfg.clone(), ++ net_cfg: net_cfg.clone(), ++ netdev_cfg, + config_space: Default::default(), + taps: None, + backends: None, +@@ -125,10 +132,10 @@ impl VirtioDevice for Net { + } + + fn realize(&mut self) -> Result<()> { +- let queue_pairs = self.net_cfg.queues / 2; ++ let queue_pairs = self.netdev_cfg.queues / 2; + let mut backends = Vec::with_capacity(queue_pairs as usize); + for index in 0..queue_pairs { +- let fd = if let Some(fds) = self.net_cfg.vhost_fds.as_mut() { ++ let fd = if let Some(fds) = self.netdev_cfg.vhost_fds.as_mut() { + fds.get(index as usize).copied() + } else { + None +@@ -142,12 +149,12 @@ impl VirtioDevice for Net { + backends.push(backend); + } + +- let host_dev_name = match self.net_cfg.host_dev_name.as_str() { ++ let host_dev_name = match self.netdev_cfg.ifname.as_str() { + "" => None, +- _ => Some(self.net_cfg.host_dev_name.as_str()), ++ _ => Some(self.netdev_cfg.ifname.as_str()), + }; + +- self.taps = create_tap(self.net_cfg.tap_fds.as_ref(), host_dev_name, queue_pairs) ++ self.taps = create_tap(self.netdev_cfg.tap_fds.as_ref(), host_dev_name, queue_pairs) + .with_context(|| "Failed to create tap for vhost net")?; + self.backends = Some(backends); + +@@ -174,7 +181,7 @@ impl VirtioDevice for Net { + + let mut locked_config = self.config_space.lock().unwrap(); + +- let queue_pairs = self.net_cfg.queues / 2; ++ let queue_pairs = self.netdev_cfg.queues / 2; + if self.net_cfg.mq + && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) + .contains(&queue_pairs) +@@ -320,8 +327,7 @@ impl VirtioDevice for Net { + let event = if self.call_events.is_empty() { + let host_notify = VhostNotify { + notify_evt: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) +- .with_context(|| VirtioError::EventFdCreate)?, ++ create_new_eventfd().with_context(|| VirtioError::EventFdCreate)?, + ), + queue: queue_mutex.clone(), + }; +@@ -385,7 +391,7 @@ impl VirtioDevice for Net { + } + + fn reset(&mut self) -> Result<()> { +- let queue_pairs = self.net_cfg.queues / 2; ++ let queue_pairs = self.netdev_cfg.queues / 2; + for index in 0..queue_pairs as usize { + let backend = match &self.backends { + None => return Err(anyhow!("Failed to get backend for vhost net")), +@@ -441,46 +447,43 @@ mod tests { + + #[test] + fn test_vhost_net_realize() { +- let net1 = NetworkInterfaceConfig { +- id: "eth1".to_string(), +- host_dev_name: "tap1".to_string(), +- mac: Some("1F:2C:3E:4A:5B:6D".to_string()), +- vhost_type: Some("vhost-kernel".to_string()), ++ let netdev_cfg1 = NetDevcfg { ++ netdev_type: "tap".to_string(), ++ id: "net1".to_string(), + tap_fds: Some(vec![4]), ++ vhost_kernel: true, + vhost_fds: Some(vec![5]), +- iothread: None, ++ ifname: "tap1".to_string(), + queues: 2, ++ ..Default::default() ++ }; ++ let vhost_net_conf = NetworkInterfaceConfig { ++ id: "eth1".to_string(), ++ mac: Some("1F:2C:3E:4A:5B:6D".to_string()), ++ iothread: None, + mq: false, +- socket_path: None, + queue_size: DEFAULT_VIRTQUEUE_SIZE, ++ ..Default::default() + }; +- let conf = vec![net1]; +- let confs = Some(conf); +- let vhost_net_confs = confs.unwrap(); +- let vhost_net_conf = vhost_net_confs[0].clone(); + let vhost_net_space = vhost_address_space_init(); +- let mut vhost_net = Net::new(&vhost_net_conf, &vhost_net_space); ++ let mut vhost_net = Net::new(&vhost_net_conf, netdev_cfg1, &vhost_net_space); + // the tap_fd and vhost_fd attribute of vhost-net can't be assigned. +- assert_eq!(vhost_net.realize().is_ok(), false); ++ assert!(vhost_net.realize().is_err()); + +- let net1 = NetworkInterfaceConfig { +- id: "eth0".to_string(), +- host_dev_name: "".to_string(), +- mac: Some("1A:2B:3C:4D:5E:6F".to_string()), +- vhost_type: Some("vhost-kernel".to_string()), +- tap_fds: None, +- vhost_fds: None, +- iothread: None, ++ let netdev_cfg2 = NetDevcfg { ++ netdev_type: "tap".to_string(), ++ id: "net2".to_string(), ++ vhost_kernel: true, + queues: 2, +- mq: false, +- socket_path: None, ++ ..Default::default() ++ }; ++ let net_cfg2 = NetworkInterfaceConfig { ++ id: "eth2".to_string(), ++ mac: Some("1A:2B:3C:4D:5E:6F".to_string()), + queue_size: DEFAULT_VIRTQUEUE_SIZE, ++ ..Default::default() + }; +- let conf = vec![net1]; +- let confs = Some(conf); +- let vhost_net_confs = confs.unwrap(); +- let vhost_net_conf = vhost_net_confs[0].clone(); +- let mut vhost_net = Net::new(&vhost_net_conf, &vhost_net_space); ++ let mut vhost_net = Net::new(&net_cfg2, netdev_cfg2, &vhost_net_space); + + // if fail to open vhost-net device, no need to continue. + if let Err(_e) = File::open("/dev/vhost-net") { +diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs +index 8d782c6..ade3ec2 100644 +--- a/virtio/src/vhost/kernel/vsock.rs ++++ b/virtio/src/vhost/kernel/vsock.rs +@@ -16,6 +16,7 @@ use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, bail, Context, Result}; + use byteorder::{ByteOrder, LittleEndian}; ++use clap::{ArgAction, Parser}; + use vmm_sys_util::eventfd::EventFd; + use vmm_sys_util::ioctl::ioctl_with_ref; + +@@ -26,12 +27,12 @@ use crate::{ + VirtioInterruptType, VIRTIO_F_ACCESS_PLATFORM, VIRTIO_TYPE_VSOCK, + }; + use address_space::AddressSpace; +-use machine_manager::config::{VsockConfig, DEFAULT_VIRTQUEUE_SIZE}; ++use machine_manager::config::{get_pci_df, parse_bool, valid_id, DEFAULT_VIRTQUEUE_SIZE}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; + use migration_derive::{ByteCode, Desc}; + use util::byte_code::ByteCode; +-use util::loop_context::EventNotifierHelper; ++use util::loop_context::{create_new_eventfd, EventNotifierHelper}; + + /// Number of virtqueues. + const QUEUE_NUM_VSOCK: usize = 3; +@@ -40,6 +41,29 @@ const VHOST_PATH: &str = "/dev/vhost-vsock"; + /// Event transport reset + const VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: u32 = 0; + ++const MAX_GUEST_CID: u64 = 4_294_967_295; ++const MIN_GUEST_CID: u64 = 3; ++ ++/// Config structure for virtio-vsock. ++#[derive(Parser, Debug, Clone, Default)] ++#[command(no_binary_name(true))] ++pub struct VsockConfig { ++ #[arg(long, value_parser = ["vhost-vsock-pci", "vhost-vsock-device"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] ++ pub multifunction: Option, ++ #[arg(long, alias = "guest-cid", value_parser = clap::value_parser!(u64).range(MIN_GUEST_CID..=MAX_GUEST_CID))] ++ pub guest_cid: u64, ++ #[arg(long, alias = "vhostfd")] ++ pub vhost_fd: Option, ++} ++ + trait VhostVsockBackend { + /// Each guest should have an unique CID which is used to route data to the guest. + fn set_guest_cid(&self, cid: u64) -> Result<()>; +@@ -287,8 +311,7 @@ impl VirtioDevice for Vsock { + let event = if self.call_events.is_empty() { + let host_notify = VhostNotify { + notify_evt: Arc::new( +- EventFd::new(libc::EFD_NONBLOCK) +- .with_context(|| VirtioError::EventFdCreate)?, ++ create_new_eventfd().with_context(|| VirtioError::EventFdCreate)?, + ), + queue: queue_mutex.clone(), + }; +@@ -390,9 +413,9 @@ impl MigrationHook for Vsock { + + #[cfg(test)] + mod tests { +- pub use super::super::*; +- pub use super::*; +- pub use address_space::*; ++ use super::*; ++ use address_space::*; ++ use machine_manager::config::str_slip_to_clap; + + fn vsock_address_space_init() -> Arc { + let root = Region::init_container_region(u64::max_value(), "sysmem"); +@@ -405,12 +428,30 @@ mod tests { + id: "test_vsock_1".to_string(), + guest_cid: 3, + vhost_fd: None, ++ ..Default::default() + }; + let sys_mem = vsock_address_space_init(); + let vsock = Vsock::new(&vsock_conf, &sys_mem); + vsock + } + ++ #[test] ++ fn test_vsock_config_cmdline_parser() { ++ let vsock_cmd = "vhost-vsock-device,id=test_vsock,guest-cid=3"; ++ let vsock_config = ++ VsockConfig::try_parse_from(str_slip_to_clap(vsock_cmd, true, false)).unwrap(); ++ assert_eq!(vsock_config.id, "test_vsock"); ++ assert_eq!(vsock_config.guest_cid, 3); ++ assert_eq!(vsock_config.vhost_fd, None); ++ ++ let vsock_cmd = "vhost-vsock-device,id=test_vsock,guest-cid=3,vhostfd=4"; ++ let vsock_config = ++ VsockConfig::try_parse_from(str_slip_to_clap(vsock_cmd, true, false)).unwrap(); ++ assert_eq!(vsock_config.id, "test_vsock"); ++ assert_eq!(vsock_config.guest_cid, 3); ++ assert_eq!(vsock_config.vhost_fd, Some(4)); ++ } ++ + #[test] + fn test_vsock_init() { + // test vsock new method +diff --git a/virtio/src/vhost/user/block.rs b/virtio/src/vhost/user/block.rs +index 1fe8ac8..8c55cac 100644 +--- a/virtio/src/vhost/user/block.rs ++++ b/virtio/src/vhost/user/block.rs +@@ -13,6 +13,7 @@ + use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use vmm_sys_util::eventfd::EventFd; + + use super::client::VhostUserClient; +@@ -30,14 +31,41 @@ use crate::{ + VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, + }; + use address_space::AddressSpace; +-use machine_manager::{config::BlkDevConfig, event_loop::unregister_event_helper}; ++use machine_manager::config::{ ++ get_chardev_socket_path, get_pci_df, valid_block_device_virtqueue_size, valid_id, ++ ChardevConfig, MAX_VIRTIO_QUEUE, ++}; ++use machine_manager::event_loop::unregister_event_helper; + use util::byte_code::ByteCode; + ++#[derive(Parser, Debug, Clone, Default)] ++#[command(no_binary_name(true))] ++pub struct VhostUserBlkDevConfig { ++ #[arg(long, value_parser = ["vhost-user-blk-device", "vhost-user-blk-pci"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u16).range(1..=MAX_VIRTIO_QUEUE as i64))] ++ pub num_queues: Option, ++ #[arg(long)] ++ pub chardev: String, ++ #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] ++ pub queue_size: u16, ++ #[arg(long)] ++ pub bootindex: Option, ++} ++ + pub struct Block { + /// Virtio device base property. + base: VirtioBase, + /// Configuration of the block device. +- blk_cfg: BlkDevConfig, ++ blk_cfg: VhostUserBlkDevConfig, ++ /// Configuration of the vhost user blk's socket chardev. ++ chardev_cfg: ChardevConfig, + /// Config space of the block device. + config_space: VirtioBlkConfig, + /// System address space. +@@ -51,13 +79,18 @@ pub struct Block { + } + + impl Block { +- pub fn new(cfg: &BlkDevConfig, mem_space: &Arc) -> Self { +- let queue_num = cfg.queues as usize; ++ pub fn new( ++ cfg: &VhostUserBlkDevConfig, ++ chardev_cfg: ChardevConfig, ++ mem_space: &Arc, ++ ) -> Self { ++ let queue_num = cfg.num_queues.unwrap_or(1) as usize; + let queue_size = cfg.queue_size; + + Block { + base: VirtioBase::new(VIRTIO_TYPE_BLOCK, queue_num, queue_size), + blk_cfg: cfg.clone(), ++ chardev_cfg, + config_space: Default::default(), + mem_space: mem_space.clone(), + client: None, +@@ -68,12 +101,7 @@ impl Block { + + /// Connect with spdk and register update event. + fn init_client(&mut self) -> Result<()> { +- let socket_path = self +- .blk_cfg +- .socket_path +- .as_ref() +- .map(|path| path.to_string()) +- .with_context(|| "vhost-user: socket path is not found")?; ++ let socket_path = get_chardev_socket_path(self.chardev_cfg.clone())?; + let client = VhostUserClient::new( + &self.mem_space, + &socket_path, +@@ -146,10 +174,10 @@ impl VirtioDevice for Block { + ); + } + +- if self.blk_cfg.queues > 1 { +- self.config_space.num_queues = self.blk_cfg.queues; ++ if self.blk_cfg.num_queues.unwrap_or(1) > 1 { ++ self.config_space.num_queues = self.blk_cfg.num_queues.unwrap_or(1); + } +- } else if self.blk_cfg.queues > 1 { ++ } else if self.blk_cfg.num_queues.unwrap_or(1) > 1 { + bail!( + "spdk doesn't support multi queue, spdk protocol features: {:#b}", + protocol_features +@@ -169,7 +197,7 @@ impl VirtioDevice for Block { + | 1_u64 << VIRTIO_BLK_F_WRITE_ZEROES + | 1_u64 << VIRTIO_BLK_F_SEG_MAX + | 1_u64 << VIRTIO_BLK_F_RO; +- if self.blk_cfg.queues > 1 { ++ if self.blk_cfg.num_queues.unwrap_or(1) > 1 { + self.base.device_features |= 1_u64 << VIRTIO_BLK_F_MQ; + } + self.base.device_features &= features; +@@ -217,13 +245,7 @@ impl VirtioDevice for Block { + + if !self.enable_irqfd { + let queue_num = self.base.queues.len(); +- listen_guest_notifier( +- &mut self.base, +- &mut client, +- self.blk_cfg.iothread.as_ref(), +- queue_num, +- interrupt_cb, +- )?; ++ listen_guest_notifier(&mut self.base, &mut client, None, queue_num, interrupt_cb)?; + } + + client.activate_vhost_user()?; +@@ -232,18 +254,10 @@ impl VirtioDevice for Block { + } + + fn deactivate(&mut self) -> Result<()> { +- self.client +- .as_ref() +- .with_context(|| "Failed to get client when deactivating device")? +- .lock() +- .unwrap() +- .reset_vhost_user()?; +- if !self.base.deactivate_evts.is_empty() { +- unregister_event_helper( +- self.blk_cfg.iothread.as_ref(), +- &mut self.base.deactivate_evts, +- )?; ++ if let Some(client) = &self.client { ++ client.lock().unwrap().reset_vhost_user(false); + } ++ unregister_event_helper(None, &mut self.base.deactivate_evts)?; + Ok(()) + } + +diff --git a/virtio/src/vhost/user/client.rs b/virtio/src/vhost/user/client.rs +index 0bab675..b32bf72 100644 +--- a/virtio/src/vhost/user/client.rs ++++ b/virtio/src/vhost/user/client.rs +@@ -142,9 +142,9 @@ fn vhost_user_reconnect(client: &Arc>) { + } + + if let Err(e) = locked_client.activate_vhost_user() { +- error!("Failed to reactivate vhost-user net, {:?}", e); ++ error!("Failed to reactivate vhost-user {}, {:?}", dev_type, e); + } else { +- info!("Reconnecting vhost-user net succeed."); ++ info!("Reconnecting vhost-user {} succeed.", dev_type); + } + } + +@@ -612,7 +612,7 @@ impl VhostUserClient { + Ok(()) + } + +- pub fn reset_vhost_user(&mut self) -> Result<()> { ++ fn reset_queues(&mut self) -> Result<()> { + for (queue_index, queue_mutex) in self.queues.iter().enumerate() { + if !queue_mutex.lock().unwrap().vring.is_enabled() { + continue; +@@ -622,12 +622,25 @@ impl VhostUserClient { + self.get_vring_base(queue_index) + .with_context(|| format!("Failed to get vring base, index: {}", queue_index))?; + } ++ Ok(()) ++ } ++ ++ pub fn reset_vhost_user(&mut self, reset_owner: bool) { ++ let dev_type = self.backend_type.to_string(); ++ if reset_owner { ++ if let Err(e) = self.reset_owner() { ++ warn!("Failed to reset owner for vhost-user {}: {:?}", dev_type, e); ++ } ++ } else if let Err(e) = self.reset_queues() { ++ warn!( ++ "Failed to reset queues for vhost-user {}: {:?}", ++ dev_type, e ++ ); ++ } + + self.queue_evts.clear(); + self.call_events.clear(); + self.queues.clear(); +- +- Ok(()) + } + + pub fn add_event(client: &Arc>) -> Result<()> { +@@ -1055,7 +1068,16 @@ impl VhostOps for VhostUserClient { + } + + fn reset_owner(&self) -> Result<()> { +- bail!("Does not support for resetting owner") ++ trace::vhost_reset_owner(); ++ let hdr = VhostUserMsgHdr::new(VhostUserMsgReq::ResetOwner as u32, 0, 0); ++ let body_opt: Option<&u32> = None; ++ let payload_opt: Option<&[u8]> = None; ++ let client = self.client.lock().unwrap(); ++ client ++ .sock ++ .send_msg(Some(&hdr), body_opt, payload_opt, &[]) ++ .with_context(|| "Failed to send msg for reset_owner")?; ++ Ok(()) + } + + fn get_vring_base(&self, queue_idx: usize) -> Result { +diff --git a/virtio/src/vhost/user/fs.rs b/virtio/src/vhost/user/fs.rs +index 3f60f68..75c3698 100644 +--- a/virtio/src/vhost/user/fs.rs ++++ b/virtio/src/vhost/user/fs.rs +@@ -19,7 +19,8 @@ const VIRTIO_FS_QUEUE_SIZE: u16 = 128; + + use std::sync::{Arc, Mutex}; + +-use anyhow::{anyhow, Context, Result}; ++use anyhow::{anyhow, bail, Context, Result}; ++use clap::Parser; + use vmm_sys_util::eventfd::EventFd; + + use super::super::super::{VirtioDevice, VIRTIO_TYPE_FS}; +@@ -27,10 +28,45 @@ use super::super::VhostOps; + use super::{listen_guest_notifier, VhostBackendType, VhostUserClient}; + use crate::{read_config_default, VirtioBase, VirtioInterrupt}; + use address_space::AddressSpace; +-use machine_manager::config::{FsConfig, MAX_TAG_LENGTH}; ++use machine_manager::config::{ ++ get_pci_df, parse_bool, valid_id, ChardevConfig, ConfigError, SocketType, ++}; + use machine_manager::event_loop::unregister_event_helper; + use util::byte_code::ByteCode; + ++const MAX_TAG_LENGTH: usize = 36; ++ ++/// Config struct for `fs`. ++/// Contains fs device's attr. ++#[derive(Parser, Debug, Clone)] ++#[command(no_binary_name(true))] ++pub struct FsConfig { ++ #[arg(long, value_parser = ["vhost-user-fs-pci", "vhost-user-fs-device"])] ++ pub classtype: String, ++ #[arg(long, value_parser = valid_id)] ++ pub id: String, ++ #[arg(long)] ++ pub chardev: String, ++ #[arg(long, value_parser = valid_tag)] ++ pub tag: String, ++ #[arg(long)] ++ pub bus: Option, ++ #[arg(long, value_parser = get_pci_df)] ++ pub addr: Option<(u8, u8)>, ++ #[arg(long, value_parser = parse_bool)] ++ pub multifunction: Option, ++} ++ ++fn valid_tag(tag: &str) -> Result { ++ if tag.len() >= MAX_TAG_LENGTH { ++ return Err(anyhow!(ConfigError::StringLengthTooLong( ++ "fs device tag".to_string(), ++ MAX_TAG_LENGTH - 1, ++ ))); ++ } ++ Ok(tag.to_string()) ++} ++ + #[derive(Copy, Clone)] + #[repr(C, packed)] + struct VirtioFsConfig { +@@ -52,6 +88,7 @@ impl ByteCode for VirtioFsConfig {} + pub struct Fs { + base: VirtioBase, + fs_cfg: FsConfig, ++ chardev_cfg: ChardevConfig, + config_space: VirtioFsConfig, + client: Option>>, + mem_space: Arc, +@@ -64,14 +101,16 @@ impl Fs { + /// # Arguments + /// + /// `fs_cfg` - The config of this Fs device. ++ /// `chardev_cfg` - The config of this Fs device's chardev. + /// `mem_space` - The address space of this Fs device. +- pub fn new(fs_cfg: FsConfig, mem_space: Arc) -> Self { ++ pub fn new(fs_cfg: FsConfig, chardev_cfg: ChardevConfig, mem_space: Arc) -> Self { + let queue_num = VIRIOT_FS_HIGH_PRIO_QUEUE_NUM + VIRTIO_FS_REQ_QUEUES_NUM; + let queue_size = VIRTIO_FS_QUEUE_SIZE; + + Fs { + base: VirtioBase::new(VIRTIO_TYPE_FS, queue_num, queue_size), + fs_cfg, ++ chardev_cfg, + config_space: VirtioFsConfig::default(), + client: None, + mem_space, +@@ -91,9 +130,15 @@ impl VirtioDevice for Fs { + + fn realize(&mut self) -> Result<()> { + let queues_num = VIRIOT_FS_HIGH_PRIO_QUEUE_NUM + VIRTIO_FS_REQ_QUEUES_NUM; ++ ++ let socket_path = match self.chardev_cfg.classtype.socket_type()? { ++ SocketType::Unix { path } => path, ++ _ => bail!("Vhost-user-fs Chardev backend should be unix-socket type."), ++ }; ++ + let client = VhostUserClient::new( + &self.mem_space, +- &self.fs_cfg.sock, ++ &socket_path, + queues_num as u64, + VhostBackendType::TypeFs, + ) +@@ -167,6 +212,9 @@ impl VirtioDevice for Fs { + } + + fn deactivate(&mut self) -> Result<()> { ++ if let Some(client) = &self.client { ++ client.lock().unwrap().reset_vhost_user(true); ++ } + unregister_event_helper(None, &mut self.base.deactivate_evts)?; + Ok(()) + } +@@ -191,3 +239,24 @@ impl VirtioDevice for Fs { + self.realize() + } + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use machine_manager::config::str_slip_to_clap; ++ ++ #[test] ++ fn test_vhostuserfs_cmdline_parser() { ++ // Test1: Right. ++ let fs_cmd = "vhost-user-fs-device,id=fs0,chardev=chardev0,tag=tag0"; ++ let fs_config = FsConfig::try_parse_from(str_slip_to_clap(fs_cmd, true, false)).unwrap(); ++ assert_eq!(fs_config.id, "fs0"); ++ assert_eq!(fs_config.chardev, "chardev0"); ++ assert_eq!(fs_config.tag, "tag0"); ++ ++ // Test2: Illegal value. ++ let fs_cmd = "vhost-user-fs-device,id=fs0,chardev=chardev0,tag=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; ++ let result = FsConfig::try_parse_from(str_slip_to_clap(fs_cmd, true, false)); ++ assert!(result.is_err()); ++ } ++} +diff --git a/virtio/src/vhost/user/mod.rs b/virtio/src/vhost/user/mod.rs +index 2f0dc96..8a6e8d4 100644 +--- a/virtio/src/vhost/user/mod.rs ++++ b/virtio/src/vhost/user/mod.rs +@@ -18,7 +18,7 @@ mod message; + mod net; + mod sock; + +-pub use self::block::Block; ++pub use self::block::{Block, VhostUserBlkDevConfig}; + pub use self::client::*; + pub use self::fs::*; + pub use self::message::*; +diff --git a/virtio/src/vhost/user/net.rs b/virtio/src/vhost/user/net.rs +index e7f0964..4dc7634 100644 +--- a/virtio/src/vhost/user/net.rs ++++ b/virtio/src/vhost/user/net.rs +@@ -28,7 +28,7 @@ use crate::{ + VIRTIO_NET_F_MRG_RXBUF, VIRTIO_TYPE_NET, + }; + use address_space::AddressSpace; +-use machine_manager::config::NetworkInterfaceConfig; ++use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; + use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; + use util::byte_code::ByteCode; + use util::loop_context::EventNotifierHelper; +@@ -42,6 +42,10 @@ pub struct Net { + base: VirtioBase, + /// Configuration of the vhost user network device. + net_cfg: NetworkInterfaceConfig, ++ /// Configuration of the backend netdev. ++ netdev_cfg: NetDevcfg, ++ /// path of the socket chardev. ++ sock_path: String, + /// Virtio net configurations. + config_space: Arc>, + /// System address space. +@@ -53,18 +57,25 @@ pub struct Net { + } + + impl Net { +- pub fn new(cfg: &NetworkInterfaceConfig, mem_space: &Arc) -> Self { +- let queue_num = if cfg.mq { ++ pub fn new( ++ net_cfg: &NetworkInterfaceConfig, ++ netdev_cfg: NetDevcfg, ++ sock_path: String, ++ mem_space: &Arc, ++ ) -> Self { ++ let queue_num = if net_cfg.mq { + // If support multi-queue, it should add 1 control queue. +- (cfg.queues + 1) as usize ++ (netdev_cfg.queues + 1) as usize + } else { + QUEUE_NUM_NET + }; +- let queue_size = cfg.queue_size; ++ let queue_size = net_cfg.queue_size; + + Net { + base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), +- net_cfg: cfg.clone(), ++ net_cfg: net_cfg.clone(), ++ netdev_cfg, ++ sock_path, + config_space: Default::default(), + mem_space: mem_space.clone(), + client: None, +@@ -115,14 +126,9 @@ impl VirtioDevice for Net { + } + + fn realize(&mut self) -> Result<()> { +- let socket_path = self +- .net_cfg +- .socket_path +- .as_ref() +- .with_context(|| "vhost-user: socket path is not found")?; + let client = VhostUserClient::new( + &self.mem_space, +- socket_path, ++ &self.sock_path, + self.queue_num() as u64, + VhostBackendType::TypeNet, + ) +@@ -158,7 +164,7 @@ impl VirtioDevice for Net { + + let mut locked_config = self.config_space.lock().unwrap(); + +- let queue_pairs = self.net_cfg.queues / 2; ++ let queue_pairs = self.netdev_cfg.queues / 2; + if self.net_cfg.mq + && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) + .contains(&queue_pairs) +-- +2.43.0 + diff --git a/0007-vfio-pci-fix-a-deadlock-problem.patch b/0007-vfio-pci-fix-a-deadlock-problem.patch new file mode 100644 index 0000000000000000000000000000000000000000..89d9e2fdf8875acec01d68bdf058bcd9eb80e899 --- /dev/null +++ b/0007-vfio-pci-fix-a-deadlock-problem.patch @@ -0,0 +1,37 @@ +From a399e1bf2e06b7268090c7f0b818689dcc42d794 Mon Sep 17 00:00:00 2001 +From: sujerry1991 +Date: Wed, 21 May 2025 15:33:51 +0800 +Subject: [PATCH] vfio-pci: fix a deadlock problem + +Fix c491725bbd "InterruptManager: Introduce the Interrupt Manager in Machine". + +Signed-off-by: Yan Wang +--- + vfio/src/vfio_pci.rs | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs +index d354098..87bb78f 100644 +--- a/vfio/src/vfio_pci.rs ++++ b/vfio/src/vfio_pci.rs +@@ -487,7 +487,6 @@ impl VfioPciDevice { + let parent_bus = self.base.parent_bus.clone(); + let dev_id = self.dev_id.clone(); + let devfn = self.base.devfn; +- let cloned_msix = msix.clone(); + let write = move |data: &[u8], _: GuestAddress, offset: u64| -> bool { + let mut locked_msix = msix.lock().unwrap(); + locked_msix.table[offset as usize..(offset as usize + data.len())] +@@ -516,8 +515,7 @@ impl VfioPciDevice { + gsi_route.irq_fd = Some(Arc::new(irq_fd)); + } + let irq_fd = gsi_route.irq_fd.clone(); +- let msi_irq_manager = &cloned_msix.lock().unwrap().msi_irq_manager; +- let irq_manager = msi_irq_manager.as_ref().unwrap(); ++ let irq_manager = &locked_msix.msi_irq_manager.as_ref().unwrap(); + if gsi_route.gsi == -1 { + gsi_route.gsi = match irq_manager.allocate_irq(msix_vector) { + Ok(g) => g as i32, +-- +2.33.0 + diff --git a/0008-QMP-bugfix-the-error-in-the-return-result-of-query_c.patch b/0008-QMP-bugfix-the-error-in-the-return-result-of-query_c.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b4dc2bf61ee55923fa7333ae9e981339b0904b7 --- /dev/null +++ b/0008-QMP-bugfix-the-error-in-the-return-result-of-query_c.patch @@ -0,0 +1,171 @@ +From 1cd0eea327faf629b7eef5433be6c42c83a32e09 Mon Sep 17 00:00:00 2001 +From: Mingwang Li +Date: Thu, 22 May 2025 11:02:00 +0800 +Subject: [PATCH 1/2] QMP: bugfix the error in the return result of + query_commands + +There is no need to use conditional judgment for enumeration variable aliases; +otherwise, the names of each variable in the enumeration will be wrongly obtained. + +Signed-off-by: Mingwang Li +Signed-off-by: Kunkun Jiang +--- + machine_manager/src/qmp/qmp_schema.rs | 128 +++++++++++++------------- + 1 file changed, 64 insertions(+), 64 deletions(-) + +diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs +index 4281624..4f05689 100644 +--- a/machine_manager/src/qmp/qmp_schema.rs ++++ b/machine_manager/src/qmp/qmp_schema.rs +@@ -54,7 +54,7 @@ impl QmpErrorClass { + } + + macro_rules! define_qmp_command_enum { +- ($($command:ident($name:expr, $args_type:ty, $need_strum:ident $(, $serde_default:ident)?)),*) => { ++ ($($command:ident($name:expr, $args_type:ty $(, $serde_default:ident)?)),*) => { + /// A enum to store all command struct + #[derive(Debug, Clone, Serialize, Deserialize, EnumIter, EnumVariantNames, EnumString)] + #[serde(tag = "execute")] +@@ -62,7 +62,7 @@ macro_rules! define_qmp_command_enum { + pub enum QmpCommand { + $( + #[serde(rename = $name)] +- #[cfg_attr($need_strum, strum(serialize = $name))] ++ #[strum(serialize = $name)] + $command { + $(#[serde($serde_default)])? + arguments: $args_type, +@@ -76,68 +76,68 @@ macro_rules! define_qmp_command_enum { + + // QMP command enum definition example: command("name", arguments, ..) + define_qmp_command_enum!( +- qmp_capabilities("qmp_capabilities", qmp_capabilities, FALSE, default), +- quit("quit", quit, FALSE, default), +- stop("stop", stop, FALSE, default), +- cont("cont", cont, FALSE, default), +- system_powerdown("system_powerdown", system_powerdown, FALSE, default), +- system_reset("system_reset", system_reset, FALSE, default), +- device_add("device_add", Box, FALSE), +- device_del("device_del", device_del, FALSE), +- chardev_add("chardev-add", chardev_add, FALSE), +- chardev_remove("chardev-remove", chardev_remove, FALSE), +- netdev_add("netdev_add", Box, FALSE), +- netdev_del("netdev_del", netdev_del, FALSE), +- cameradev_add("cameradev_add", cameradev_add, FALSE), +- cameradev_del("cameradev_del", cameradev_del, FALSE), +- query_hotpluggable_cpus("query-hotpluggable-cpus", query_hotpluggable_cpus, TRUE, default), +- query_cpus("query-cpus", query_cpus, TRUE, default), +- query_status("query-status", query_status, FALSE, default), +- getfd("getfd", getfd, FALSE), +- blockdev_add("blockdev-add", Box, FALSE), +- blockdev_del("blockdev-del", blockdev_del, FALSE), +- balloon("balloon", balloon, FALSE, default), +- query_mem("query-mem", query_mem, FALSE, default), +- query_mem_gpa("query-mem-gpa", query_mem_gpa, FALSE, default), +- query_balloon("query-balloon", query_balloon, FALSE, default), +- query_vnc("query-vnc", query_vnc, TRUE, default), +- query_display_image("query-display-image", query_display_image, FALSE, default), +- switch_audio_record("switch-audio-record", switch_audio_record, FALSE), +- migrate("migrate", migrate, FALSE), +- query_migrate("query-migrate", query_migrate, FALSE, default), +- cancel_migrate("migrate_cancel", cancel_migrate, FALSE, default), +- query_version("query-version", query_version, FALSE, default), +- query_commands("query-commands", query_commands, FALSE, default), +- query_target("query-target", query_target, FALSE, default), +- query_kvm("query-kvm", query_kvm, FALSE, default), +- query_machines("query-machines", query_machines, FALSE, default), +- query_events("query-events", query_events, TRUE, default), +- list_type("qom-list-types", list_type, FALSE, default), +- device_list_properties("device-list-properties", device_list_properties, FALSE, default), +- block_commit("block-commit", block_commit, TRUE, default), +- query_tpm_models("query-tpm-models", query_tpm_models, FALSE, default), +- query_tpm_types("query-tpm-types", query_tpm_types, FALSE, default), +- query_command_line_options("query-command-line-options", query_command_line_options, FALSE, default), +- query_migrate_capabilities("query-migrate-capabilities", query_migrate_capabilities, FALSE, default), +- query_qmp_schema("query-qmp-schema", query_qmp_schema, FALSE, default), +- query_sev_capabilities("query-sev-capabilities", query_sev_capabilities, FALSE, default), +- query_chardev("query-chardev", query_chardev, TRUE, default), +- qom_list("qom-list", qom_list, TRUE, default), +- qom_get("qom-get", qom_get, TRUE, default), +- query_block("query-block", query_block, TRUE, default), +- query_named_block_nodes("query-named-block-nodes", query_named_block_nodes, TRUE, default), +- query_blockstats("query-blockstats", query_blockstats, TRUE, default), +- query_block_jobs("query-block-jobs", query_block_jobs, TRUE, default), +- query_gic_capabilities("query-gic-capabilities", query_gic_capabilities, TRUE, default), +- query_iothreads("query-iothreads", query_iothreads, TRUE, default), +- update_region("update_region", update_region, TRUE, default), +- input_event("input_event", input_event, FALSE, default), +- human_monitor_command("human-monitor-command", human_monitor_command, FALSE), +- blockdev_snapshot_internal_sync("blockdev-snapshot-internal-sync", blockdev_snapshot_internal, FALSE), +- blockdev_snapshot_delete_internal_sync("blockdev-snapshot-delete-internal-sync", blockdev_snapshot_internal, FALSE), +- query_vcpu_reg("query-vcpu-reg", query_vcpu_reg, FALSE), +- trace_get_state("trace-get-state", trace_get_state, FALSE), +- trace_set_state("trace-set-state", trace_set_state, FALSE) ++ qmp_capabilities("qmp_capabilities", qmp_capabilities, default), ++ quit("quit", quit, default), ++ stop("stop", stop, default), ++ cont("cont", cont, default), ++ system_powerdown("system_powerdown", system_powerdown, default), ++ system_reset("system_reset", system_reset, default), ++ device_add("device_add", Box), ++ device_del("device_del", device_del), ++ chardev_add("chardev-add", chardev_add), ++ chardev_remove("chardev-remove", chardev_remove), ++ netdev_add("netdev_add", Box), ++ netdev_del("netdev_del", netdev_del), ++ cameradev_add("cameradev_add", cameradev_add), ++ cameradev_del("cameradev_del", cameradev_del), ++ query_hotpluggable_cpus("query-hotpluggable-cpus", query_hotpluggable_cpus, default), ++ query_cpus("query-cpus", query_cpus, default), ++ query_status("query-status", query_status, default), ++ getfd("getfd", getfd), ++ blockdev_add("blockdev-add", Box), ++ blockdev_del("blockdev-del", blockdev_del), ++ balloon("balloon", balloon, default), ++ query_mem("query-mem", query_mem, default), ++ query_mem_gpa("query-mem-gpa", query_mem_gpa, default), ++ query_balloon("query-balloon", query_balloon, default), ++ query_vnc("query-vnc", query_vnc, default), ++ query_display_image("query-display-image", query_display_image, default), ++ switch_audio_record("switch-audio-record", switch_audio_record), ++ migrate("migrate", migrate), ++ query_migrate("query-migrate", query_migrate, default), ++ cancel_migrate("migrate_cancel", cancel_migrate, default), ++ query_version("query-version", query_version, default), ++ query_commands("query-commands", query_commands, default), ++ query_target("query-target", query_target, default), ++ query_kvm("query-kvm", query_kvm, default), ++ query_machines("query-machines", query_machines, default), ++ query_events("query-events", query_events, default), ++ list_type("qom-list-types", list_type, default), ++ device_list_properties("device-list-properties", device_list_properties, default), ++ block_commit("block-commit", block_commit, default), ++ query_tpm_models("query-tpm-models", query_tpm_models, default), ++ query_tpm_types("query-tpm-types", query_tpm_types, default), ++ query_command_line_options("query-command-line-options", query_command_line_options, default), ++ query_migrate_capabilities("query-migrate-capabilities", query_migrate_capabilities, default), ++ query_qmp_schema("query-qmp-schema", query_qmp_schema, default), ++ query_sev_capabilities("query-sev-capabilities", query_sev_capabilities, default), ++ query_chardev("query-chardev", query_chardev, default), ++ qom_list("qom-list", qom_list, default), ++ qom_get("qom-get", qom_get, default), ++ query_block("query-block", query_block, default), ++ query_named_block_nodes("query-named-block-nodes", query_named_block_nodes, default), ++ query_blockstats("query-blockstats", query_blockstats, default), ++ query_block_jobs("query-block-jobs", query_block_jobs, default), ++ query_gic_capabilities("query-gic-capabilities", query_gic_capabilities, default), ++ query_iothreads("query-iothreads", query_iothreads, default), ++ update_region("update_region", update_region, default), ++ input_event("input_event", input_event, default), ++ human_monitor_command("human-monitor-command", human_monitor_command), ++ blockdev_snapshot_internal_sync("blockdev-snapshot-internal-sync", blockdev_snapshot_internal), ++ blockdev_snapshot_delete_internal_sync("blockdev-snapshot-delete-internal-sync", blockdev_snapshot_internal), ++ query_vcpu_reg("query-vcpu-reg", query_vcpu_reg), ++ trace_get_state("trace-get-state", trace_get_state), ++ trace_set_state("trace-set-state", trace_set_state) + ); + + /// Command trait for Deserialize and find back Response. +-- +2.43.0 + diff --git a/0009-QMP-add-query-cpus-fast.patch b/0009-QMP-add-query-cpus-fast.patch new file mode 100644 index 0000000000000000000000000000000000000000..3be4cc0442adb8599642aa5d55822f16966447be --- /dev/null +++ b/0009-QMP-add-query-cpus-fast.patch @@ -0,0 +1,231 @@ +From 121df9ccb7a5dffa26ec4fc8412799a385abf05d Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Thu, 22 May 2025 12:30:04 +0800 +Subject: [PATCH 2/2] QMP: add query-cpus-fast + +This commit introduces a replacement for query-cpus called +query-cpus-fast. query-cpus has been discarded in libvirt. + +Signed-off-by: Kunkun Jiang +--- + machine/src/micro_common/mod.rs | 27 +++++++++ + machine/src/standard_common/mod.rs | 27 +++++++++ + machine_manager/src/machine.rs | 2 + + machine_manager/src/qmp/qmp_schema.rs | 85 +++++++++++++++++++++++++++ + machine_manager/src/qmp/qmp_socket.rs | 1 + + 5 files changed, 142 insertions(+) + +diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs +index b97f046..8b40b16 100644 +--- a/machine/src/micro_common/mod.rs ++++ b/machine/src/micro_common/mod.rs +@@ -577,6 +577,33 @@ impl DeviceInterface for LightMachine { + Response::create_response(cpu_vec.into(), None) + } + ++ fn query_cpus_fast(&self) -> Response { ++ let mut cpu_vec: Vec = Vec::new(); ++ let cpu_topo = self.get_cpu_topo(); ++ let cpus = self.get_cpus(); ++ for cpu_index in 0..cpu_topo.max_cpus { ++ if cpu_topo.get_mask(cpu_index as usize) == 1 { ++ let thread_id = cpus[cpu_index as usize].tid(); ++ let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index as usize); ++ #[cfg(target_arch = "x86_64")] ++ let target = String::from("x86_64"); ++ #[cfg(target_arch = "aarch64")] ++ let target = String::from("aarch64"); ++ let cpu_info = qmp_schema::CpuInfoFast { ++ qom_path: String::from("/machine/unattached/device[") ++ + &cpu_index.to_string() ++ + "]", ++ props: Some(cpu_instance), ++ cpu_index: cpu_index as isize, ++ thread_id: thread_id as isize, ++ target: target, ++ }; ++ cpu_vec.push(serde_json::to_value(cpu_info).unwrap()); ++ } ++ } ++ Response::create_response(cpu_vec.into(), None) ++ } ++ + fn query_hotpluggable_cpus(&self) -> Response { + let mut hotplug_vec: Vec = Vec::new(); + #[cfg(target_arch = "x86_64")] +diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs +index 1ab0be0..fc10707 100644 +--- a/machine/src/standard_common/mod.rs ++++ b/machine/src/standard_common/mod.rs +@@ -1008,6 +1008,33 @@ impl DeviceInterface for StdMachine { + Response::create_response(cpu_vec.into(), None) + } + ++ fn query_cpus_fast(&self) -> Response { ++ let mut cpu_vec: Vec = Vec::new(); ++ let cpu_topo = self.get_cpu_topo(); ++ let cpus = self.get_cpus(); ++ for cpu_index in 0..cpu_topo.max_cpus { ++ if cpu_topo.get_mask(cpu_index as usize) == 1 { ++ let thread_id = cpus[cpu_index as usize].tid(); ++ let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index as usize); ++ #[cfg(target_arch = "x86_64")] ++ let target = String::from("x86_64"); ++ #[cfg(target_arch = "aarch64")] ++ let target = String::from("aarch64"); ++ let cpu_info = qmp_schema::CpuInfoFast { ++ qom_path: String::from("/machine/unattached/device[") ++ + &cpu_index.to_string() ++ + "]", ++ props: Some(cpu_instance), ++ cpu_index: cpu_index as isize, ++ thread_id: thread_id as isize, ++ target: target, ++ }; ++ cpu_vec.push(serde_json::to_value(cpu_info).unwrap()); ++ } ++ } ++ Response::create_response(cpu_vec.into(), None) ++ } ++ + fn query_hotpluggable_cpus(&self) -> Response { + Response::create_empty_response() + } +diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs +index f0f00aa..4d36e80 100644 +--- a/machine_manager/src/machine.rs ++++ b/machine_manager/src/machine.rs +@@ -155,6 +155,8 @@ pub trait DeviceInterface { + /// Query each cpu's the topology info. + fn query_cpus(&self) -> Response; + ++ fn query_cpus_fast(&self) -> Response; ++ + /// Query each `hotpluggable_cpus`'s topology info and hotplug message. + fn query_hotpluggable_cpus(&self) -> Response; + +diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs +index 4f05689..110e1f9 100644 +--- a/machine_manager/src/qmp/qmp_schema.rs ++++ b/machine_manager/src/qmp/qmp_schema.rs +@@ -92,6 +92,7 @@ define_qmp_command_enum!( + cameradev_del("cameradev_del", cameradev_del), + query_hotpluggable_cpus("query-hotpluggable-cpus", query_hotpluggable_cpus, default), + query_cpus("query-cpus", query_cpus, default), ++ query_cpus_fast("query-cpus-fast", query_cpus_fast, default), + query_status("query-status", query_status, default), + getfd("getfd", getfd), + blockdev_add("blockdev-add", Box), +@@ -851,6 +852,63 @@ pub struct CpuInfoX86 {} + #[derive(Default, Debug, Clone, Serialize, Deserialize)] + pub struct CpuInfoArm {} + ++/// @query-cpus-fast: ++/// ++/// Returns information about all virtual CPUs. ++/// ++/// Returns: list of @CpuInfoFast ++/// ++/// Since: 2.12 ++/// ++/// Example: ++/// ++/// -> { "execute": "query-cpus-fast" } ++/// <- { "return": [ ++/// { ++/// "thread-id": 25627, ++/// "props": { ++/// "core-id": 0, ++/// "thread-id": 0, ++/// "socket-id": 0 ++/// }, ++/// "qom-path": "/machine/unattached/device[0]", ++/// "target":"x86_64", ++/// "cpu-index": 0 ++/// }, ++/// { ++/// "thread-id": 25628, ++/// "props": { ++/// "core-id": 0, ++/// "thread-id": 0, ++/// "socket-id": 1 ++/// }, ++/// "qom-path": "/machine/unattached/device[2]", ++/// "target":"x86_64", ++/// "cpu-index": 1 ++/// } ++/// ] ++/// } ++/// ++/// ``` ++#[derive(Default, Debug, Clone, Serialize, Deserialize)] ++#[serde(deny_unknown_fields)] ++pub struct query_cpus_fast {} ++generate_command_impl!(query_cpus_fast, Vec); ++ ++#[derive(Debug, Clone, Serialize, Deserialize)] ++pub struct CpuInfoFast { ++ #[serde(rename = "qom_path")] ++ pub qom_path: String, ++ #[serde(rename = "props", default, skip_serializing_if = "Option::is_none")] ++ pub props: Option, ++ #[serde(rename = "cpu-index")] ++ pub cpu_index: isize, ++ #[serde(rename = "thread-id")] ++ pub thread_id: isize, ++ #[serde(rename = "target")] ++ pub target: String, ++} ++ + /// query-status + /// + /// Query the run status of all VCPUs. +@@ -2170,6 +2228,33 @@ mod tests { + let ret_msg = r#"invalid type: string "isdf", expected struct query_cpus"#; + assert!(err_msg == ret_msg); + ++ // qmp: query-cpus-fast. ++ let json_msg = r#" ++ { ++ "execute": "query-cpus-fast" ++ } ++ "#; ++ let err_msg = match serde_json::from_str::(json_msg) { ++ Ok(_) => "ok".to_string(), ++ Err(e) => e.to_string(), ++ }; ++ let ret_msg = r#"ok"#; ++ assert!(err_msg == ret_msg); ++ ++ // unexpected arguments for query-cpus-fast. ++ let json_msg = r#" ++ { ++ "execute": "query-cpus-fast" , ++ "arguments": "isdf" ++ } ++ "#; ++ let err_msg = match serde_json::from_str::(json_msg) { ++ Ok(_) => "ok".to_string(), ++ Err(e) => e.to_string(), ++ }; ++ let ret_msg = r#"invalid type: string "isdf", expected struct query_cpus_fast"#; ++ assert!(err_msg == ret_msg); ++ + // qmp: query-ststus. + let json_msg = r#" + { +diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs +index 35ad238..3ae155c 100644 +--- a/machine_manager/src/qmp/qmp_socket.rs ++++ b/machine_manager/src/qmp/qmp_socket.rs +@@ -460,6 +460,7 @@ fn qmp_command_exec( + (query_migrate, query_migrate), + (cancel_migrate, cancel_migrate), + (query_cpus, query_cpus), ++ (query_cpus_fast, query_cpus_fast), + (query_balloon, query_balloon), + (query_mem, query_mem), + (query_vnc, query_vnc), +-- +2.43.0 + diff --git a/0010-add-support-to-interconnecting-with-libvirt.patch b/0010-add-support-to-interconnecting-with-libvirt.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3217ba9f453a9abf7ca255bdfa970e21d2f9a71 --- /dev/null +++ b/0010-add-support-to-interconnecting-with-libvirt.patch @@ -0,0 +1,233 @@ +From 763110fef62e39eb2f2a3db75f7583f799e4ad9c Mon Sep 17 00:00:00 2001 +From: Ming Yang +Date: Fri, 23 May 2025 11:47:40 +0800 +Subject: [PATCH] add support to interconnecting with libvirt + +--- + machine_manager/src/cmdline.rs | 19 ++++++++-------- + machine_manager/src/config/chardev.rs | 20 +++++++++++----- + machine_manager/src/config/machine_config.rs | 2 +- + machine_manager/src/machine.rs | 19 +++++++++++++++- + machine_manager/src/qmp/qmp_schema.rs | 24 ++++++++++++++++++++ + machine_manager/src/qmp/qmp_socket.rs | 1 + + 6 files changed, 68 insertions(+), 17 deletions(-) + +diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs +index 5b0d275..d440cbc 100644 +--- a/machine_manager/src/cmdline.rs ++++ b/machine_manager/src/cmdline.rs +@@ -183,8 +183,8 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { + Arg::with_name("qmp") + .long("qmp") + .value_name("") +- .help("\n\t\tset unix socket path: unix:,server,nowait; \ +- \n\t\tset tcp socket path: tcp:ip:port,server,nowait") ++ .help("\n\t\tset unix socket path: unix:,server,nowait/wait=off; \ ++ \n\t\tset tcp socket path: tcp:ip:port,server,nowait/wait=off") + .takes_value(true) + ) + .arg( +@@ -222,8 +222,8 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { + .help("\n\t\tadd standard i/o device: -chardev stdio,id=; \ + \n\t\tadd pseudo-terminal: -chardev pty,id=; \ + \n\t\tadd file: -chardev file,id=,path=; \ +- \n\t\tadd unix-socket: -chardev socket,id=,path=[,server][,nowait]; \ +- \n\t\tadd tcp-socket: -chardev socket,id=,port=[,host=host][,server][,nowait];") ++ \n\t\tadd unix-socket: -chardev socket,id=,path=[,server][,nowait/wait=off]; \ ++ \n\t\tadd tcp-socket: -chardev socket,id=,port=[,host=host][,server][,nowait/wait=off];") + .takes_values(true), + ) + .arg( +@@ -266,8 +266,8 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { + \n\t\tuse standard i/o device: -serial stdio; \ + \n\t\tuse pseudo-terminal: -serial pty; \ + \n\t\tuse file: -serial file,path=; \ +- \n\t\tuse unix-socket: -serial socket,path=[,server][,nowait]; \ +- \n\t\tuse tcp-socket: -serial socket,port=[,host=][,server][,nowait]; \ ++ \n\t\tuse unix-socket: -serial socket,path=[,server][,nowait/wait=off]; \ ++ \n\t\tuse tcp-socket: -serial socket,port=[,host=][,server][,nowait/wait=off]; \ + ") + .takes_value(true), + ) +@@ -615,7 +615,7 @@ pub fn check_api_channel( + let mut sock_paths = Vec::new(); + if let Some(qmp_config) = args.value_of("qmp") { + let mut cmd_parser = CmdParser::new("qmp"); +- cmd_parser.push("").push("server").push("nowait"); ++ cmd_parser.push("").push("server").push("nowait").push("wait"); + + cmd_parser.parse(&qmp_config)?; + if let Some(uri) = cmd_parser.get_value::("")? { +@@ -628,8 +628,9 @@ pub fn check_api_channel( + if cmd_parser.get_value::("server")?.is_none() { + bail!("Argument \'server\' is needed for qmp"); + } +- if cmd_parser.get_value::("nowait")?.is_none() { +- bail!("Argument \'nowait\' is needed for qmp"); ++ if cmd_parser.get_value::("nowait")?.is_none() && cmd_parser ++ .get_value::("wait")?.is_none() { ++ bail!("Argument \'nowait\' or \'wait=off\'is needed for qmp"); + } + } + if let Some(mon_config) = args.value_of("mon") { +diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs +index 943de72..7fa040c 100644 +--- a/machine_manager/src/config/chardev.rs ++++ b/machine_manager/src/config/chardev.rs +@@ -171,10 +171,7 @@ fn parse_file_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result Result { + let mut server_enabled = false; + let server = cmd_parser.get_value::("server")?; +- if let Some(server) = server { +- if server.ne("") { +- bail!("No parameter needed for server"); +- } ++ if let Some(_server) = server { + server_enabled = true; + } + +@@ -187,9 +184,20 @@ fn parse_socket_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result("wait")?; ++ if let Some(wait) = wait { ++ if wait.eq("off") { ++ nowait_enabled = true; ++ } else if wait.eq("on") { ++ nowait_enabled = false; ++ } else { ++ bail!("Unsupported parameters for wait"); ++ } ++ } ++ + let path = cmd_parser.get_value::("path")?; + if let Some(path) = path { +- let supported_fields = ["", "id", "path", "server", "nowait"]; ++ let supported_fields = ["", "id", "path", "server", "nowait", "wait"]; + check_chardev_fields("unix-socket", &cmd_parser, &supported_fields)?; + + let default_value = path.clone(); +@@ -232,7 +240,7 @@ fn parse_socket_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result Result { + let mut cmd_parser = CmdParser::new("chardev"); +- for field in ["", "id", "path", "host", "port", "server", "nowait"] { ++ for field in ["", "id", "path", "host", "port", "server", "nowait", "wait"] { + cmd_parser.push(field); + } + +diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs +index c1a6fb7..c83e12e 100644 +--- a/machine_manager/src/config/machine_config.rs ++++ b/machine_manager/src/config/machine_config.rs +@@ -474,7 +474,7 @@ impl VmConfig { + + fn get_mem_zone_size(&self, cmd_parser: &CmdParser) -> Result { + if let Some(mem) = cmd_parser.get_value::("size")? { +- let size = memory_unit_conversion(&mem, M)?; ++ let size = memory_unit_conversion(&mem, 1)?; + Ok(size) + } else { + Err(anyhow!(ConfigError::FieldIsMissing( +diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs +index 4d36e80..92df5e2 100644 +--- a/machine_manager/src/machine.rs ++++ b/machine_manager/src/machine.rs +@@ -342,6 +342,7 @@ pub trait DeviceInterface { + ("usb-kbd", "usb-hid"), + ("usb-storage", "usb-storage-dev"), + ("virtio-gpu-pci", "virtio-gpu"), ++ ("pl011", "sys-bus-device"), + ]; + + for list in list_types { +@@ -351,6 +352,11 @@ pub trait DeviceInterface { + Response::create_response(serde_json::to_value(&vec_types).unwrap(), None) + } + ++ fn qom_list_properties(&self, _typename: String) -> Response { ++ let types = Vec::::new(); ++ Response::create_response(serde_json::to_value(types).unwrap(), None) ++ } ++ + fn device_list_properties(&self, typename: String) -> Response { + let mut vec_props = Vec::::new(); + let prop = DeviceProps { +@@ -411,7 +417,18 @@ pub trait DeviceInterface { + } + + fn query_qmp_schema(&self) -> Response { +- Response::create_empty_response() ++ let mut vec_types = Vec::new(); ++ let list_types: Vec<(&str, &str)> = vec![ ++ ("name", "query-status"), ++ ("ret-type", "1"), ++ ("meta-type", "command"), ++ ("arg-type", "0"), ++ ]; ++ for list in list_types { ++ let re = TypeLists::new(String::from(list.0), String::from(list.1)); ++ vec_types.push(re); ++ } ++ Response::create_response(serde_json::to_value(&vec_types).unwrap(), None) + } + + fn query_sev_capabilities(&self) -> Response { +diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs +index 72314e8..8c38864 100644 +--- a/machine_manager/src/qmp/qmp_schema.rs ++++ b/machine_manager/src/qmp/qmp_schema.rs +@@ -114,6 +114,7 @@ define_qmp_command_enum!( + query_machines("query-machines", query_machines, default), + query_events("query-events", query_events, default), + list_type("qom-list-types", list_type, default), ++ qom_list_properties("qom-list-properties", qom_list_properties, default), + device_list_properties("device-list-properties", device_list_properties, default), + block_commit("block-commit", block_commit, default), + query_tpm_models("query-tpm-models", query_tpm_models, default), +@@ -1366,6 +1367,29 @@ impl TypeLists { + } + } + ++/// qom-list-properties ++/// ++/// List properties associated with a qom. ++/// ++/// # Examples ++/// ++/// ```text ++/// -> { "execute": "qom-list-properties", "arguments": { "typename": "memory-backend-file" } } ++/// <- { "return": [] } ++/// ``` ++#[derive(Default, Debug, Clone, Serialize, Deserialize)] ++pub struct qom_list_properties { ++ pub typename: String, ++} ++generate_command_impl!(qom_list_properties, Vec); ++ ++#[derive(Default, Debug, Clone, Serialize, Deserialize)] ++pub struct QomListProps { ++ pub name: String, ++ #[serde(rename = "typename")] ++ pub prop_type: String, ++} ++ + /// device-list-properties + /// + /// List properties associated with a device. +diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs +index 3ae155c..2372c96 100644 +--- a/machine_manager/src/qmp/qmp_socket.rs ++++ b/machine_manager/src/qmp/qmp_socket.rs +@@ -468,6 +468,7 @@ fn qmp_command_exec( + (list_type, list_type), + (query_hotpluggable_cpus, query_hotpluggable_cpus); + (input_event, input_event, key, value), ++ (qom_list_properties, qom_list_properties, typename), + (device_list_properties, device_list_properties, typename), + (device_del, device_del, id), + (switch_audio_record, switch_audio_record, authorized), +-- +2.43.0 + diff --git a/0011-virtio-net-do-not-delete-fd-which-has-not-been-added.patch b/0011-virtio-net-do-not-delete-fd-which-has-not-been-added.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9572124ff8bd78dfda3cd680904f6ccbb8e94ac --- /dev/null +++ b/0011-virtio-net-do-not-delete-fd-which-has-not-been-added.patch @@ -0,0 +1,18 @@ +diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs +index 4e605fa..84e5ce6 100644 +--- a/virtio/src/device/net.rs ++++ b/virtio/src/device/net.rs +@@ -977,11 +977,11 @@ impl NetIoHandler { + let mut notifiers_fds = vec![ + locked_net_io.update_evt.as_raw_fd(), + locked_net_io.rx.queue_evt.as_raw_fd(), +- locked_net_io.rx.recv_evt.as_raw_fd(), + locked_net_io.tx.queue_evt.as_raw_fd(), + ]; + if old_tap_fd != -1 { + notifiers_fds.push(old_tap_fd); ++ notifiers_fds.push(locked_net_io.rx.recv_evt.as_raw_fd()); + } + let mut notifiers = gen_delete_notifiers(¬ifiers_fds); + drop(locked_net_io); + diff --git a/stratovirt.spec b/stratovirt.spec index 15931e0692f54b3db894f245529478daed4b042e..e3eb1b1def35e9d115f55b7326ed86761168d081 100644 --- a/stratovirt.spec +++ b/stratovirt.spec @@ -6,15 +6,28 @@ Name: stratovirt Version: 2.4.0 -Release: 2 +Release: 10 Summary: StratoVirt is an opensource VMM(Virtual Machine Manager) which aims to perform next generation virtualization. License: MulanPSL-2.0 URL: https://gitee.com/openeuler/stratovirt Source0: https://gitee.com/openeuler/stratovirt/releases/download/v%{version}/%{name}-%{version}.tar.gz +Patch001:0001-Micro-fix-the-ioctl-allow-for-aarch64.patch +Patch002:0002-snapshot-bugfix-VM-run-failed-from-memory-snapshot.patch +Patch003:0003-hypervisor-kvm-Fix-setting-core-reg-error-when-resto.patch +Patch004:0004-micro_comman-syscall-Update-ioctl-allow-list.patch -ExclusiveArch: x86_64 aarch64 +%ifarch riscv64 +Patch005:0005-update-Rust-VMM-dependencies-and-re-vendor.patch +Patch006:0006-introduce-riscv64-architecture-support.patch +%endif + +Patch007:0007-vfio-pci-fix-a-deadlock-problem.patch +Patch008:0008-QMP-bugfix-the-error-in-the-return-result-of-query_c.patch +Patch009:0009-QMP-add-query-cpus-fast.patch +Patch010:0010-add-support-to-interconnecting-with-libvirt.patch +Patch011:0011-virtio-net-do-not-delete-fd-which-has-not-been-added.patch Requires: pixman Requires: pixman-devel @@ -52,6 +65,9 @@ BuildRequires: rust-packaging %define rust_gnu_target aarch64-unknown-linux-gnu %define rust_musl_target aarch64-unknown-linux-musl %endif +%ifarch riscv64 +%define rust_gnu_target riscv64gc-unknown-linux-gnu +%endif %define _cargo /usr/bin/env CARGO_HOME=.cargo RUSTC_BOOTSTRAP=1 /usr/bin/cargo @@ -63,7 +79,9 @@ Summary: %{summary} %files -n stratovirt %defattr(-,root,root,-) %{_bindir}/stratovirt +%ifnarch riscv64 %{_libdir}/stratovirt/static/stratovirt +%endif %prep %autosetup -p1 @@ -86,23 +104,59 @@ sed -i '$adebug = true' ./.cargo/config sed -i 's/rustflags = \[/&"-Clink-arg=-lgcc", /' ./.cargo/config %endif +%ifnarch riscv64 %{_cargo} build --release -Z avoid-dev-deps --target=%{rust_musl_target} --features "boot_time pvpanic demo_device vnc vnc_auth ramfb virtio_gpu trace_to_logger trace_to_ftrace trace_to_hitrace" sed -i 's/rustflags = \[/&"-Clink-arg=-lpixman-1", /' ./.cargo/config %{_cargo} build --release -Z avoid-dev-deps --target=%{rust_gnu_target} --features "boot_time pvpanic demo_device vnc vnc_auth ramfb virtio_gpu trace_to_logger trace_to_ftrace trace_to_hitrace" +%endif + +%ifarch riscv64 +%{_cargo} build --release -Z avoid-dev-deps --target=%{rust_gnu_target} +%endif %check +%ifnarch riscv64 RUST_BACKTRACE=1 cargo test --workspace --exclude mod_test -- --nocapture --test-threads=1 +%endif %install rm -rf %{buildroot} install -d %{buildroot}%{_bindir} install -D -m555 ./target/%{rust_gnu_target}/release/stratovirt %{buildroot}%{_bindir} +%ifnarch riscv64 install -d %{buildroot}%{_libdir}/stratovirt/static install -D -m555 ./target/%{rust_musl_target}/release/stratovirt %{buildroot}%{_libdir}/stratovirt/static +%endif %changelog +* Thu Jun 19 2025 Yan Wang 2.4.0-10 +- Do not delete fd which has not been added + +* Fri May 23 2025 Ming Yang 2.4.0-9 +- add support to interconnect with libvirt + +* Thu May 22 2025 jiangkunkun 2.4.0-8 +- bugfix the error in the return result of query_commands +- add QMP query-cpus-fast + +* Wed May 21 2025 shenyage 2.4.0-7 +- vfio-pci: fix a deadlock problem + +* Fri Dec 20 2024 heruoqing 2.4.0-6 +- Introduce riscv64 architecture support + +* Tue Dec 17 2024 frankyj915 - 2.4.0-5 +- Fix setting core reg error when restoring VM. +- Update ioctl allow list. + +* Wed Dec 11 2024 Mingwang Li - 2.4.0-4 +- bugfix VM run failed from memory snapshot + +* Thu Nov 21 2024 jinyihua - 2.4.0-3 +- Micro fix the ioctl allow for aarch64 + * Tue Jul 30 2024 xufei - 2.4.0-2 - set debug is true for build debug package - add rust to BuildRequires