vmm: Set the APIC ID in the extended topology

KVM exposes CPUID 0BH when host supports that, but the APIC ID that KVM
provides is the host APIC ID so we need replace that with ours.

Without this Linux guest reports something like:
[Firmware Bug]: CPU1: APIC id mismatch. Firmware: 1 APIC: 21

Fixes #42

Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
This commit is contained in:
Chao Peng 2019-06-11 13:53:38 +00:00 committed by Samuel Ortiz
parent 0d0d19e223
commit a0f4376eb0
2 changed files with 49 additions and 1 deletions

View File

@ -202,6 +202,13 @@ mod tests {
.unwrap()
}
fn get_initial_apicid() -> u32 {
ssh_command("grep \"initial apicid\" /proc/cpuinfo | grep -o \"[0-9]*\"")
.trim()
.parse()
.unwrap()
}
fn get_total_memory() -> u32 {
ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")
.trim()
@ -232,6 +239,7 @@ mod tests {
thread::sleep(std::time::Duration::new(10, 0));
aver_eq!(tb, get_cpu_count(), 1);
aver_eq!(tb, get_initial_apicid(), 0);
aver!(tb, get_total_memory() > 496_000);
aver!(tb, get_entropy() >= 1000);

View File

@ -193,6 +193,15 @@ pub enum DeviceManagerError {
}
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
#[allow(dead_code)]
#[derive(Copy, Clone)]
enum CpuidReg {
EAX,
EBX,
ECX,
EDX,
}
/// A wrapper around creating and using a kvm-based VCPU.
pub struct Vcpu {
fd: VcpuFd,
@ -227,8 +236,10 @@ impl Vcpu {
/// * `kernel_start_addr` - Offset from `guest_mem` at which the kernel starts.
/// * `vm` - The virtual machine this vcpu will get attached to.
pub fn configure(&mut self, kernel_start_addr: GuestAddress, vm: &Vm) -> Result<()> {
let mut cpuid = vm.cpuid.clone();
Vcpu::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(self.id));
self.fd
.set_cpuid2(&vm.cpuid)
.set_cpuid2(&cpuid)
.map_err(Error::SetSupportedCpusFailed)?;
arch::x86_64::regs::setup_msrs(&self.fd).map_err(Error::MSRSConfiguration)?;
@ -285,6 +296,35 @@ impl Vcpu {
},
}
}
fn set_cpuid_reg(
cpuid: &mut CpuId,
function: u32,
index: Option<u32>,
reg: CpuidReg,
value: u32,
) {
let entries = cpuid.mut_entries_slice();
for entry in entries.iter_mut() {
if entry.function == function && (index == None || index.unwrap() == entry.index) {
match reg {
CpuidReg::EAX => {
entry.eax = value;
}
CpuidReg::EBX => {
entry.ebx = value;
}
CpuidReg::ECX => {
entry.ecx = value;
}
CpuidReg::EDX => {
entry.edx = value;
}
}
}
}
}
}
struct DeviceManager {