x86_64: move Fpu initialization to vcpu_init

Implement Default for Fpu to initialize the floating point registers to
their officially documented reset values, and use the default Fpu values
to initialize all VCPU floating point state.

These are the same values as used in the previous setup_fpu() function,
so there is no change in behavior. (We now set the FPU state for both
BIOS and non-BIOS, but since the FPU values should match the ones used
at CPU reset, it should not cause any actual behavior change.)

BUG=b:237095693
TEST=boot x86-64 Linux kernel

Change-Id: I4eb656822d8fa4730203970aee178043c19af9ff
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3723799
Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Daniel Verkamp 2022-06-23 18:48:11 -07:00 committed by Chromeos LUCI
parent 1b7d5b8fba
commit e30f4fda83
4 changed files with 28 additions and 24 deletions

View file

@ -176,6 +176,9 @@ pub(crate) fn host_phys_addr_bits() -> u8 {
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

@ -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}")]
@ -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();