x86_64: fill cache info in cpuid, stop spoofing CPU vendor id

The fix passes through cache-related CPU entries 2, 4, 0x80000005
and 0x80000006 similar to how QEMU does it.

Note passing this cpuid info itself is not sufficient unless
CPU vendor is something Linux kernel recognizes. Therefore, I am
removing cute spoofing of the vendor id, allowing host value to
pass through.

I believe it is generally a bad idea to spoof vendor id as lots of
kernel and user space code gets confused and may take unoptimized paths.
The corollary is that removing the spoofing may have unintended
consequences correctness- and performance-wise. I would appreciate
recommendation on additional testing.

BUG=chromium:859678
TEST=lscpu in Guest, 'cargo test'

Change-Id: I6963b00d9eecf49fb4578bcc75ad744c3099f045
Reviewed-on: https://chromium-review.googlesource.com/1125529
Commit-Ready: Slava Malyugin <slavamn@chromium.org>
Tested-by: Slava Malyugin <slavamn@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Slava Malyugin 2018-07-03 21:01:03 -07:00 committed by chrome-bot
parent ef7352f208
commit ac5a8dbe50
5 changed files with 62 additions and 16 deletions

1
Cargo.lock generated
View file

@ -376,6 +376,7 @@ version = "0.1.0"
dependencies = [
"arch 0.1.0",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"data_model 0.1.0",
"devices 0.1.0",
"kernel_cmdline 0.1.0",

View file

@ -2,6 +2,7 @@
name = "x86_64"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
build = "build.rs"
[dependencies]
arch = { path = "../arch" }
@ -15,3 +16,7 @@ kernel_cmdline = { path = "../kernel_cmdline" }
kernel_loader = { path = "../kernel_loader" }
libc = "*"
byteorder = "*"
[build-dependencies]
cc = "=1.0.15"

11
x86_64/build.rs Normal file
View file

@ -0,0 +1,11 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
extern crate cc;
fn main() {
cc::Build::new()
.file("host_cpuid.c")
.compile("host_cpuid");
}

11
x86_64/host_cpuid.c Normal file
View file

@ -0,0 +1,11 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
void host_cpuid(uint32_t func, uint32_t func2, uint32_t *pEax,
uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx) {
asm volatile("cpuid" : "=a"(*pEax), "=b"(*pEbx), "=c"(*pEcx), "=d"(*pEdx) :
"0"(func), "2"(func2) : "cc");
}

View file

@ -9,13 +9,6 @@ use std::error::{self, Error as CpuidError};
use kvm;
use sys_util;
// Query the CPU vendor. ebx/ecx/edx pack an ASCII string into these 3 regs
// in little endian format. We set to "crosvmBestVM".
// https://en.wikipedia.org/wiki/CPUID#EAX=0:_Get_vendor_ID_(including_EAX=1:_Get_CPUID)
const VENDOR_EBX_VAL: u32 = 0x736f7263; // sorc
const VENDOR_ECX_VAL: u32 = 0x4d567473; // MVts
const VENDOR_EDX_VAL: u32 = 0x65426d76; // eBmv
#[derive(Debug, PartialEq)]
pub enum Error {
GetSupportedCpusFailed(sys_util::Error),
@ -40,6 +33,19 @@ impl Display for Error {
}
}
// This function is implemented in C because stable rustc does not
// support inline assembly.
extern "C" {
fn host_cpuid(func: u32,
func2: u32,
rEax: *mut u32,
rEbx: *mut u32,
rEcx: *mut u32,
rEdx: *mut u32)
-> ();
}
// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
@ -54,12 +60,6 @@ fn filter_cpuid(cpu_id: u64, cpu_count: u64, kvm_cpuid: &mut kvm::CpuId) -> Resu
for entry in entries.iter_mut() {
match entry.function {
0 => {
// Vendor name.
entry.ebx = VENDOR_EBX_VAL;
entry.ecx = VENDOR_ECX_VAL;
entry.edx = VENDOR_EDX_VAL;
}
1 => {
// X86 hypervisor feature
if entry.index == 0 {
@ -72,6 +72,27 @@ fn filter_cpuid(cpu_id: u64, cpu_count: u64, kvm_cpuid: &mut kvm::CpuId) -> Resu
entry.edx |= 1 << EDX_HTT_SHIFT;
}
}
2 | 0x80000005 | 0x80000006 => {
unsafe {
host_cpuid(entry.function,
0,
&mut entry.eax as *mut u32,
&mut entry.ebx as *mut u32,
&mut entry.ecx as *mut u32,
&mut entry.edx as *mut u32);
}
}
4 => {
unsafe {
host_cpuid(entry.function,
entry.index,
&mut entry.eax as *mut u32,
&mut entry.ebx as *mut u32,
&mut entry.ecx as *mut u32,
&mut entry.edx as *mut u32);
}
entry.eax &= !0xFC000000;
}
6 => {
// Clear X86 EPB feature. No frequency selection in the hypervisor.
entry.ecx &= !(1 << ECX_EPB_SHIFT);
@ -121,9 +142,6 @@ mod tests {
{
let entries = cpuid.mut_entries_slice();
assert_eq!(entries[0].function, 0);
assert_eq!(entries[0].ebx, VENDOR_EBX_VAL);
assert_eq!(entries[0].ecx, VENDOR_ECX_VAL);
assert_eq!(entries[0].edx, VENDOR_EDX_VAL);
assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
assert_eq!(EBX_CLFLUSH_CACHELINE,