Merge with upstream 2022-06-30 2/2

8dd4be42 audio_streams: Add StreamSourceGenerator trait
b9ddd723 virtio-vhost: Enable handler to be built and tested on Windows
e5c6e657 devices: pit: remove clock_gettime() usage
aeea40d6 crosvm: Fix android and gfxstream build errors
e30f4fda x86_64: move Fpu initialization to vcpu_init
1b7d5b8f arch: provide one vcpu_init per vcpu
20085de6 hypervisor: fix capability confusion for TSC leaves.
d8842cf3 virtio: vhost: user: handler: make sys module follow style guidelines
04230748 fs: Fix compiler warnings for feature chromeos

517bfb7acf..8dd4be42e9

BUG=b:237095693
BUG=chromium:908689
BUG=b:236873276
BUG=b:220649000
BUG=b:237011316
BUG=b:213152505
BUG=b:213149155

Change-Id: I35b495fa053c98abe6204830e2ac1f994ab5a086
This commit is contained in:
crosvm-luci-ci-builder 2022-06-30 07:01:27 -07:00
commit 3895458e50
24 changed files with 161 additions and 102 deletions

View file

@ -525,11 +525,13 @@ impl arch::LinuxArch for AArch64 {
)
.map_err(Error::CreateFdt)?;
let vcpu_init = vec![VcpuInitAArch64::default(); vcpu_count];
Ok(RunnableLinuxVm {
vm,
vcpu_count,
vcpus: Some(vcpus),
vcpu_init: VcpuInitAArch64 {},
vcpu_init,
vcpu_affinity: components.vcpu_affinity,
no_smt: components.no_smt,
irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?,
@ -553,7 +555,7 @@ impl arch::LinuxArch for AArch64 {
_hypervisor: &dyn Hypervisor,
_irq_chip: &mut dyn IrqChipAArch64,
_vcpu: &mut dyn VcpuAArch64,
_vcpu_init: &VcpuInitAArch64,
_vcpu_init: VcpuInitAArch64,
_vcpu_id: usize,
_num_cpus: usize,
_has_bios: bool,

View file

@ -148,7 +148,8 @@ pub struct RunnableLinuxVm<V: VmArch, Vcpu: VcpuArch> {
pub suspend_evt: Event,
pub vcpu_affinity: Option<VcpuAffinity>,
pub vcpu_count: usize,
pub vcpu_init: VcpuInitArch,
/// Per-VCPU initialization data, indexed by vcpu_id.
pub vcpu_init: Vec<VcpuInitArch>,
/// If vcpus is None, then it's the responsibility of the vcpu thread to create vcpus.
/// If it's Some, then `build_vm` already created the vcpus.
pub vcpus: Option<Vec<Vcpu>>,
@ -244,7 +245,7 @@ pub trait LinuxArch {
hypervisor: &dyn HypervisorArch,
irq_chip: &mut dyn IrqChipArch,
vcpu: &mut dyn VcpuArch,
vcpu_init: &VcpuInitArch,
vcpu_init: VcpuInitArch,
vcpu_id: usize,
num_cpus: usize,
has_bios: bool,

View file

@ -24,10 +24,22 @@ impl Clock {
self.0.duration_since(earlier.0)
}
pub fn checked_duration_since(&self, earlier: &Self) -> Option<Duration> {
self.0.checked_duration_since(earlier.0)
}
pub fn saturating_duration_since(&self, earlier: &Self) -> Duration {
self.0.saturating_duration_since(earlier.0)
}
pub fn elapsed(&self) -> Duration {
self.0.elapsed()
}
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
Some(Clock(self.0.checked_add(duration)?))
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
Some(Clock(self.0.checked_sub(duration)?))
}
@ -71,8 +83,22 @@ impl FakeClock {
/// Get the duration since |earlier|, assuming that earlier < self.
pub fn duration_since(&self, earlier: &Self) -> Duration {
let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch;
Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32)
self.checked_duration_since(earlier).unwrap()
}
/// Get the duration since |earlier|
pub fn checked_duration_since(&self, earlier: &Self) -> Option<Duration> {
let ns_diff = self.ns_since_epoch.checked_sub(earlier.ns_since_epoch)?;
Some(Duration::new(
ns_diff / NS_PER_SEC,
(ns_diff % NS_PER_SEC) as u32,
))
}
/// Get the duration since |earlier|, or 0 if earlier < self.
pub fn saturating_duration_since(&self, earlier: &Self) -> Duration {
self.checked_duration_since(earlier)
.unwrap_or(Duration::ZERO)
}
/// Get the time that has elapsed since this clock was made. Always returns 0 on a FakeClock.
@ -80,6 +106,15 @@ impl FakeClock {
self.now().duration_since(self)
}
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
Some(FakeClock {
ns_since_epoch: self
.ns_since_epoch
.checked_add(duration.as_nanos() as u64)?,
deadlines: Vec::new(),
})
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
Some(FakeClock {
ns_since_epoch: self

View file

@ -139,6 +139,12 @@ pub enum Error {
Unimplemented,
}
/// `StreamSourceGenerator` is a trait used to abstract types that create [`StreamSource`].
/// It can be used when multiple types of `StreamSource` are needed.
pub trait StreamSourceGenerator: Sync + Send {
fn generate(&self) -> Result<Box<dyn StreamSource>, BoxError>;
}
/// `StreamSource` creates streams for playback or capture of audio.
pub trait StreamSource: Send {
/// Returns a stream control and buffer generator object. These are separate as the buffer
@ -684,6 +690,22 @@ impl StreamSource for NoopStreamSource {
}
}
/// `NoopStreamSourceGenerator` is a struct that implements [`StreamSourceGenerator`]
/// to generate [`NoopStreamSource`].
pub struct NoopStreamSourceGenerator;
impl NoopStreamSourceGenerator {
pub fn new() -> Self {
NoopStreamSourceGenerator {}
}
}
impl StreamSourceGenerator for NoopStreamSourceGenerator {
fn generate(&self) -> Result<Box<dyn StreamSource>, BoxError> {
Ok(Box::new(NoopStreamSource))
}
}
#[cfg(test)]
mod tests {
use super::async_api::test::TestExecutor;
@ -916,4 +938,12 @@ mod tests {
let ex = TestExecutor {};
this_test(&ex).now_or_never();
}
#[test]
fn generate_noop_stream_source() {
let generator: Box<dyn StreamSourceGenerator> = Box::new(NoopStreamSourceGenerator::new());
generator
.generate()
.expect("failed to generate stream source");
}
}

View file

@ -78,6 +78,9 @@ power_monitor = { path = "../power_monitor" }
usb_util = { path = "../usb_util" }
vfio_sys = { path = "../vfio_sys" }
[target.'cfg(windows)'.dependencies]
tube_transporter = { path = "../tube_transporter" }
[dependencies.futures]
version = "*"
features = ["async-await", "std"]

View file

@ -10,6 +10,8 @@ mod bus;
mod irq_event;
pub mod irqchip;
mod pci;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod pit;
pub mod serial_device;
mod sys;
pub mod virtio;
@ -28,6 +30,8 @@ pub use self::pci::{
PciDeviceError, PciInterruptPin, PciRoot, PciVirtualConfigMmio, StubPciDevice,
StubPciParameters,
};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::pit::{Pit, PitError};
#[cfg(all(feature = "tpm", feature = "chromeos", target_arch = "x86_64"))]
pub use self::vtpm_proxy::VtpmProxy;
@ -41,8 +45,6 @@ cfg_if::cfg_if! {
#[cfg(feature = "direct")]
pub mod direct_irq;
mod i8042;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod pit;
pub mod pl030;
mod platform;
mod proxy;
@ -80,8 +82,6 @@ cfg_if::cfg_if! {
PvPanicCode, PcieRootPort, PcieHostPort,
PvPanicPciDevice, VfioPciDevice, PciBridge,
};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::pit::{Pit, PitError};
pub use self::pl030::Pl030;
pub use self::platform::VfioPlatformDevice;
pub use self::proxy::Error as ProxyError;

View file

@ -435,21 +435,6 @@ fn adjust_count(count: u32) -> u32 {
}
}
/// Get the current monotonic time of host in nanoseconds
fn get_monotonic_time() -> u64 {
let mut time = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
// Safe because time struct is local to this function and we check the returncode
let ret = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut time) };
if ret != 0 {
0
} else {
time.tv_sec as u64 * 1_000_000_000u64 + time.tv_nsec as u64
}
}
impl PitCounter {
fn new(
counter_id: usize,
@ -485,11 +470,8 @@ impl PitCounter {
}
fn get_channel_state(&self) -> PitChannelState {
// Crosvm Pit stores start as an Instant. We do our best to convert to the host's
// monotonic clock by taking the current monotonic time and subtracting the elapsed
// time since self.start.
let load_time = match &self.start {
Some(t) => get_monotonic_time() - t.elapsed().as_nanos() as u64,
Some(t) => t.saturating_duration_since(&self.creation_time).as_nanos() as u64,
None => 0,
};
@ -566,16 +548,9 @@ impl PitCounter {
self.read_low_byte = state.read_state == PitRWState::Word1;
self.wrote_low_byte = state.write_state == PitRWState::Word1;
// To convert the count_load_time to an instant we have to convert it to a
// duration by comparing it to get_monotonic_time. Then subtract that duration from
// a "now" instant.
self.start = self
.clock
.lock()
.now()
.checked_sub(std::time::Duration::from_nanos(
get_monotonic_time() - state.count_load_time,
));
.creation_time
.checked_add(Duration::from_nanos(state.count_load_time));
}
fn get_access_mode(&self) -> Option<CommandAccess> {

View file

@ -1045,7 +1045,7 @@ impl PassthroughFs {
let fd = unsafe { dbus::arg::OwnedFd::new(base::clone_descriptor(&*data)?) };
match proxy.set_media_rwdata_file_project_id(fd, proto.write_to_bytes().unwrap()) {
Ok(r) => {
let r = protobuf::parse_from_bytes::<SetMediaRWDataFileProjectIdReply>(&r)
let r = SetMediaRWDataFileProjectIdReply::parse_from_bytes(&r)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
if !r.success {
return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
@ -1140,10 +1140,8 @@ impl PassthroughFs {
proto.write_to_bytes().unwrap(),
) {
Ok(r) => {
let r = protobuf::parse_from_bytes::<
SetMediaRWDataFileProjectInheritanceFlagReply,
>(&r)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let r = SetMediaRWDataFileProjectInheritanceFlagReply::parse_from_bytes(&r)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
if !r.success {
return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
r.error,

View file

@ -127,7 +127,13 @@ pub fn create_guest_memory(
region.memory_size,
GuestAddress(region.guest_phys_addr),
region.mmap_offset,
Arc::new(SharedMemory::from_safe_descriptor(SafeDescriptor::from(file), None).unwrap()),
Arc::new(
SharedMemory::from_safe_descriptor(
SafeDescriptor::from(file),
Some(region.memory_size),
)
.unwrap(),
),
)
.map_err(|e| {
error!("failed to create a memory region: {}", e);
@ -753,10 +759,12 @@ mod tests {
fn stop_queue(&mut self, _idx: usize) {}
}
#[cfg(unix)]
fn temp_dir() -> TempDir {
Builder::new().prefix("/tmp/vhost_test").tempdir().unwrap()
}
#[cfg(unix)]
#[test]
fn test_vhost_user_activate() {
use vmm_vhost::{

View file

@ -4,10 +4,12 @@
cfg_if::cfg_if! {
if #[cfg(unix)] {
mod unix;
pub(crate) use self::unix::*;
pub mod unix;
use unix as platform;
} else if #[cfg(windows)] {
mod windows;
pub(crate) use self::windows::*;
pub mod windows;
use windows as platform;
}
}
pub(crate) use platform::*;

View file

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
pub(crate) use base::SharedMemoryWindows as SharedMemorySys;
use std::fs::File;
use std::mem::ManuallyDrop;
use std::sync::Arc;

View file

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
mod handler;
cfg_if::cfg_if! {
if #[cfg(unix)] {
mod block;
@ -11,7 +13,6 @@ cfg_if::cfg_if! {
#[cfg(feature = "audio_cras")]
mod cras_snd;
mod fs;
mod handler;
mod net;
mod vsock;
mod vvu;

View file

@ -122,7 +122,7 @@ pub trait VcpuAArch64: Vcpu {
impl_downcast!(VcpuAArch64);
/// Initial state for AArch64 VCPUs.
#[derive(Copy, Clone)]
#[derive(Clone, Default)]
pub struct VcpuInitAArch64 {}
// Convenience constructors for IrqRoutes

View file

@ -66,6 +66,9 @@ impl Hypervisor for Haxm {
fn check_capability(&self, cap: HypervisorCap) -> bool {
match cap {
HypervisorCap::UserMemory => true,
// under haxm, guests rely on this leaf to calibrate their
// clocksource.
HypervisorCap::CalibratedTscLeafRequired => true,
_ => false,
}
}

View file

@ -182,13 +182,8 @@ impl Vm for HaxmVm {
})
}
fn check_capability(&self, c: VmCap) -> bool {
match c {
// under haxm, guests rely on this leaf to calibrate their
// clocksource.
VmCap::CalibratedTscLeafRequired => true,
_ => false,
}
fn check_capability(&self, _c: VmCap) -> bool {
false
}
fn get_memory(&self) -> &GuestMemory {

View file

@ -176,6 +176,8 @@ impl Hypervisor for Whpx {
false
})
}
// under whpx, guests rely on this leaf to calibrate their clocksource.
HypervisorCap::CalibratedTscLeafRequired => true,
_ => false,
}
}

View file

@ -375,8 +375,6 @@ impl Vm for WhpxVm {
VmCap::Protected => false,
// whpx initializes cpuid early during VM creation.
VmCap::EarlyInitCpuid => true,
// under whpx, guests rely on this leaf to calibrate their clocksource.
VmCap::CalibratedTscLeafRequired => true,
}
}

View file

@ -172,10 +172,13 @@ pub(crate) fn host_phys_addr_bits() -> u8 {
}
/// Initial state for x86_64 VCPUs.
#[derive(Copy, Clone, Default)]
#[derive(Clone, Default)]
pub struct VcpuInitX86_64 {
/// General-purpose registers.
pub regs: Regs,
/// Floating-point registers.
pub fpu: Fpu,
}
/// A CpuId Entry contains supported feature information for the given processor.
@ -651,7 +654,7 @@ pub struct Sregs {
/// State of a VCPU's floating point unit.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub struct Fpu {
pub fpr: [[u8; 16usize]; 8usize],
pub fcw: u16,
@ -664,6 +667,22 @@ pub struct Fpu {
pub mxcsr: u32,
}
impl Default for Fpu {
fn default() -> Self {
Fpu {
fpr: Default::default(),
fcw: 0x37f, // Intel SDM Vol. 1, 13.6
fsw: 0,
ftwx: 0,
last_opcode: 0,
last_ip: 0,
last_dp: 0,
xmm: Default::default(),
mxcsr: 0x1f80, // Intel SDM Vol. 1, 11.6.4
}
}
}
/// State of a VCPU's debug registers.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]

View file

@ -1952,7 +1952,11 @@ fn run_control<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
let guest_suspended_cvar = Arc::new((Mutex::new(false), Condvar::new()));
for (cpu_id, vcpu) in vcpus.into_iter().enumerate() {
// Architecture-specific code must supply a vcpu_init element for each VCPU.
assert_eq!(vcpus.len(), linux.vcpu_init.len());
for ((cpu_id, vcpu), vcpu_init) in vcpus.into_iter().enumerate().zip(linux.vcpu_init.drain(..))
{
let (to_vcpu_channel, from_main_channel) = mpsc::channel();
let vcpu_affinity = match linux.vcpu_affinity.clone() {
Some(VcpuAffinity::Global(v)) => v,
@ -1963,7 +1967,7 @@ fn run_control<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
cpu_id,
vcpu_ids[cpu_id],
vcpu,
linux.vcpu_init,
vcpu_init,
linux.vm.try_clone().context("failed to clone vm")?,
linux
.irq_chip

View file

@ -133,7 +133,7 @@ pub fn runnable_vcpu<V>(
cpu_id: usize,
vcpu_id: usize,
vcpu: Option<V>,
vcpu_init: &VcpuInitArch,
vcpu_init: VcpuInitArch,
vm: impl VmArch,
irq_chip: &mut dyn IrqChipArch,
vcpu_count: usize,
@ -609,7 +609,7 @@ where
cpu_id,
vcpu_id,
vcpu,
&vcpu_init,
vcpu_init,
vm,
irq_chip.as_mut(),
vcpu_count,

View file

@ -98,7 +98,7 @@ pub fn check_ac97_backend(
// server is required for and exclusive to vios backend
#[cfg(target_os = "android")]
match ac97_params.backend {
Ac97Backend::VIOS => {
devices::Ac97Backend::VIOS => {
if ac97_params.vios_server_path.is_none() {
return Err(String::from("server argument is required for VIOS backend"));
}
@ -390,10 +390,10 @@ pub fn parse_gpu_options(s: &str) -> Result<GpuParameters, String> {
gpu_params.gfxstream_use_syncfd = false;
}
_ => {
return Err(argument::Error::InvalidValue {
value: v.to_string(),
expected: String::from("gpu parameter 'syncfd' should be a boolean"),
});
return Err(invalid_value_err(
v,
"gpu parameter 'syncfd' should be a boolean",
));
}
}
}
@ -495,7 +495,7 @@ pub fn parse_gpu_options(s: &str) -> Result<GpuParameters, String> {
#[cfg(feature = "gfxstream")]
{
if !vulkan_specified && gpu_params.mode == GpuMode::ModeGfxstream {
gpu_params.use_vulkan = sys::use_vulkan();
gpu_params.use_vulkan = use_vulkan();
}
if syncfd_specified || angle_specified {

View file

@ -184,7 +184,7 @@ pub enum Error {
#[error("failed to set up cpuid: {0}")]
SetupCpuid(cpuid::Error),
#[error("failed to set up FPU: {0}")]
SetupFpu(regs::Error),
SetupFpu(base::Error),
#[error("failed to set up guest memory: {0}")]
SetupGuestMemory(GuestMemoryError),
#[error("failed to set up mptable: {0}")]
@ -698,7 +698,7 @@ impl arch::LinuxArch for X8664arch {
.map_err(Error::Cmdline)?;
}
let mut vcpu_init = VcpuInitX86_64::default();
let mut vcpu_init = vec![VcpuInitX86_64::default(); vcpu_count];
match components.vm_image {
VmImage::Bios(ref mut bios) => {
@ -724,11 +724,11 @@ impl arch::LinuxArch for X8664arch {
params,
)?;
// Configure the VCPU for the Linux/x86 64-bit boot protocol.
// Configure the bootstrap VCPU for the Linux/x86 64-bit boot protocol.
// <https://www.kernel.org/doc/html/latest/x86/boot.html>
vcpu_init.regs.rip = kernel_entry.offset();
vcpu_init.regs.rsp = BOOT_STACK_POINTER;
vcpu_init.regs.rsi = ZERO_PAGE_OFFSET;
vcpu_init[0].regs.rip = kernel_entry.offset();
vcpu_init[0].regs.rsp = BOOT_STACK_POINTER;
vcpu_init[0].regs.rsi = ZERO_PAGE_OFFSET;
}
}
@ -762,7 +762,7 @@ impl arch::LinuxArch for X8664arch {
hypervisor: &dyn HypervisorX86_64,
irq_chip: &mut dyn IrqChipX86_64,
vcpu: &mut dyn VcpuX86_64,
vcpu_init: &VcpuInitX86_64,
vcpu_init: VcpuInitX86_64,
vcpu_id: usize,
num_cpus: usize,
has_bios: bool,
@ -788,6 +788,8 @@ impl arch::LinuxArch for X8664arch {
.map_err(Error::SetupCpuid)?;
}
vcpu.set_fpu(&vcpu_init.fpu).map_err(Error::SetupFpu)?;
if has_bios {
regs::set_reset_vector(vcpu).map_err(Error::SetupRegs)?;
regs::reset_msrs(vcpu).map_err(Error::SetupMsrs)?;
@ -797,7 +799,6 @@ impl arch::LinuxArch for X8664arch {
let guest_mem = vm.get_memory();
regs::setup_msrs(vm, vcpu, read_pci_mmio_before_32bit().start).map_err(Error::SetupMsrs)?;
vcpu.set_regs(&vcpu_init.regs).map_err(Error::WriteRegs)?;
regs::setup_fpu(vcpu).map_err(Error::SetupFpu)?;
regs::setup_sregs(guest_mem, vcpu).map_err(Error::SetupSregs)?;
interrupts::set_lint(vcpu_id, irq_chip).map_err(Error::SetLint)?;

View file

@ -5,7 +5,7 @@
use std::{mem, result};
use base::{self, warn};
use hypervisor::{Fpu, Register, Sregs, VcpuX86_64, Vm};
use hypervisor::{Register, Sregs, VcpuX86_64, Vm};
use remain::sorted;
use thiserror::Error;
use vm_memory::{GuestAddress, GuestMemory};
@ -15,9 +15,6 @@ use crate::gdt;
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
/// Failed to configure the FPU.
#[error("failed to configure the FPU: {0}")]
FpuIoctlFailed(base::Error),
/// Failed to get sregs for this cpu.
#[error("failed to get sregs for this cpu: {0}")]
GetSRegsIoctlFailed(base::Error),
@ -204,21 +201,6 @@ pub fn setup_msrs(vm: &dyn Vm, vcpu: &dyn VcpuX86_64, pci_start: u64) -> Result<
vcpu.set_msrs(&msrs).map_err(Error::MsrIoctlFailed)
}
/// Configure FPU registers for x86
///
/// # Arguments
///
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
pub fn setup_fpu(vcpu: &dyn VcpuX86_64) -> Result<()> {
let fpu = Fpu {
fcw: 0x37f,
mxcsr: 0x1f80,
..Default::default()
};
vcpu.set_fpu(&fpu).map_err(Error::FpuIoctlFailed)
}
const X86_CR0_PE: u64 = 0x1;
const X86_CR0_PG: u64 = 0x80000000;
const X86_CR4_PAE: u64 = 0x20;

View file

@ -21,7 +21,7 @@ use vm_memory::{GuestAddress, GuestMemory};
use super::cpuid::setup_cpuid;
use super::interrupts::set_lint;
use super::regs::{setup_fpu, setup_msrs, setup_sregs};
use super::regs::{setup_msrs, setup_sregs};
use super::X8664arch;
use super::{
acpi, arch_memory_regions, bootparam, init_low_memory_layout, mptable,
@ -265,7 +265,9 @@ where
vcpu_regs.rcx = 0x0;
vcpu.set_regs(&vcpu_regs).expect("set regs failed");
setup_fpu(&vcpu).unwrap();
let vcpu_fpu_regs = Default::default();
vcpu.set_fpu(&vcpu_fpu_regs).expect("set fpu regs failed");
setup_sregs(&guest_mem, &vcpu).unwrap();
set_lint(0, &mut irq_chip).unwrap();