(
vcpu: &dyn hypervisor::Vcpu,
id: u32,
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
cpuid: Vec<CpuIdEntry>,
kvm_hyperv: bool,
cpu_vendor: CpuVendor,
| 811 | |
| 812 | #[allow(clippy::too_many_arguments)] |
| 813 | pub fn configure_vcpu( |
| 814 | vcpu: &dyn hypervisor::Vcpu, |
| 815 | id: u32, |
| 816 | boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>, |
| 817 | cpuid: Vec<CpuIdEntry>, |
| 818 | kvm_hyperv: bool, |
| 819 | cpu_vendor: CpuVendor, |
| 820 | topology: (u16, u16, u16, u16), |
| 821 | nested: bool, |
| 822 | setup_registers: bool, |
| 823 | ) -> super::Result<()> { |
| 824 | let x2apic_id = get_x2apic_id(id, Some(topology)); |
| 825 | |
| 826 | // Per vCPU CPUID changes; common are handled via generate_common_cpuid() |
| 827 | let mut cpuid = cpuid; |
| 828 | CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, x2apic_id); |
| 829 | CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, x2apic_id); |
| 830 | if matches!(cpu_vendor, CpuVendor::AMD) { |
| 831 | CpuidPatch::set_cpuid_reg(&mut cpuid, 0x8000_001e, Some(0), CpuidReg::EAX, x2apic_id); |
| 832 | } |
| 833 | |
| 834 | // Set ApicId in cpuid for each vcpu - found in cpuid ebx when eax = 1 |
| 835 | let mut apic_id_patched = false; |
| 836 | for entry in &mut cpuid { |
| 837 | if entry.function == 1 { |
| 838 | entry.ebx &= 0xffffff; |
| 839 | entry.ebx |= x2apic_id << 24; |
| 840 | apic_id_patched = true; |
| 841 | if matches!(cpu_vendor, CpuVendor::Intel) { |
| 842 | if !nested { |
| 843 | // Disable nested virtualization for Intel |
| 844 | entry.ecx &= !(1 << VMX_ECX_BIT); |
| 845 | } |
| 846 | break; |
| 847 | } |
| 848 | } |
| 849 | if entry.function == 0x8000_0001 { |
| 850 | if !nested { |
| 851 | // Disable the nested virtualization for AMD |
| 852 | entry.ecx &= !(1 << SVM_ECX_BIT); |
| 853 | } |
| 854 | break; |
| 855 | } |
| 856 | } |
| 857 | assert!(apic_id_patched); |
| 858 | |
| 859 | update_cpuid_topology( |
| 860 | &mut cpuid, topology.0, topology.1, topology.2, topology.3, cpu_vendor, id, |
| 861 | ); |
| 862 | |
| 863 | // The TSC frequency CPUID leaf should not be included when running with HyperV emulation |
| 864 | if !kvm_hyperv && let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? { |
| 865 | // Need to check that the TSC doesn't vary with dynamic frequency |
| 866 | #[allow(unused_unsafe)] |
| 867 | // SAFETY: cpuid called with valid leaves |
| 868 | if unsafe { std::arch::x86_64::__cpuid(0x8000_0007) }.edx & (1u32 << INVARIANT_TSC_EDX_BIT) |
| 869 | > 0 |
| 870 | { |
no test coverage detected