mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-27 10:36:40 +00:00
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:
parent
ef7352f208
commit
ac5a8dbe50
5 changed files with 62 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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
11
x86_64/build.rs
Normal 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
11
x86_64/host_cpuid.c
Normal 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");
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue