Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions alioth/src/arch/x86_64/cpuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,64 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use bitfield::bitfield;

use crate::bitflags;

#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)]
pub struct CpuidIn {
pub func: u32,
pub index: Option<u32>,
}

bitflags! {
pub struct Cpuid1Ecx(u32) {
TSC_DEADLINE = 1 << 24;
HYPERVISOR = 1 << 31;
}
}

bitflags! {
pub struct Cpuid7Index0Ebx(u32) {
TSC_ADJUST = 1 << 1;
}
}

bitflags! {
pub struct Cpuid7Index0Edx(u32) {
IBRS_IBPB = 1 << 26;
SPEC_CTRL_ST_PREDICTORS = 1 << 27;
L1D_FLUSH_INTERFACE = 1 << 28;
ARCH_CAPABILITIES = 1 << 29;
CORE_CAPABILITIES = 1 << 30;
SPEC_CTRL_SSBD = 1 << 31;
}
}

bitflags! {
pub struct CpuidExt8Ebx(u32) {
SSBD_VIRT_SPEC_CTRL = 1 << 25;
}
}

bitflags! {
pub struct CpuidExt1fEAx(u32) {
SEV = 1 << 1;
SEV_ES = 1 << 3;
SEV_SNP = 1 << 4;
}
}

bitfield! {
pub struct CpuidExt1fEbx(u32);
impl new;
pub u8, cbit_pos, set_cbit_pos : 5, 0;
pub u8, phys_addr_reduction, set_phys_addr_reduction : 11, 6;
pub u8, num_vmpl, set_num_vmpl : 15, 12;
}

bitflags! {
pub struct CpuidExt21EAx(u32) {
NO_SMM_CTL_MSR = 1 << 9;
}
}
30 changes: 6 additions & 24 deletions alioth/src/board/board_x86_64/board_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use parking_lot::Mutex;
use snafu::ResultExt;
use zerocopy::{FromZeros, IntoBytes};

use crate::arch::cpuid::CpuidIn;
use crate::arch::cpuid::{Cpuid1Ecx, CpuidIn};
use crate::arch::layout::{
BIOS_DATA_END, EBDA_END, EBDA_START, IOAPIC_START, MEM_64_START, PORT_ACPI_RESET,
PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_TIMER, PORT_CMOS_REG, RAM_32_SIZE,
Expand Down Expand Up @@ -125,7 +125,7 @@ impl<V: Vm> ArchBoard<V> {
let Some(out) = cpuids.get_mut(&leaf1) else {
return error::MissingCpuid { leaf: leaf1 }.fail();
};
out.ecx |= (1 << 24) | (1 << 31);
out.ecx |= (Cpuid1Ecx::TSC_DEADLINE | Cpuid1Ecx::HYPERVISOR).bits();

let leaf_8000_0000 = __cpuid(0x8000_0000);
cpuids.insert(
Expand All @@ -143,28 +143,10 @@ impl<V: Vm> ArchBoard<V> {
cpuids.insert(CpuidIn { func, index: None }, host_cpuid);
}

if matches!(
&config.coco,
Some(Coco::AmdSev { .. } | Coco::AmdSnp { .. })
) {
// AMD Volume 3, section E.4.17.
let leaf = CpuidIn {
func: 0x8000_001f,
index: None,
};
let Some(out) = cpuids.get_mut(&leaf) else {
return error::MissingCpuid { leaf }.fail();
};
let host_ebx = __cpuid(leaf.func).ebx;
// set PhysAddrReduction to 1
out.ebx = (1 << 6) | (host_ebx & 0x3f);
out.ecx = 0;
out.edx = 0;
if let Some(Coco::AmdSev { policy }) = &config.coco {
out.eax = if policy.es() { 0x2 | 0x8 } else { 0x2 };
} else if let Some(Coco::AmdSnp { .. }) = &config.coco {
out.eax = 0x2 | 0x8 | 0x10;
}
if let Some(coco) = &config.coco
&& matches!(coco, Coco::AmdSev { .. } | Coco::AmdSnp { .. })
{
sev::adjust_cpuid(coco, &mut cpuids)?;
}

Ok(Self {
Expand Down
102 changes: 90 additions & 12 deletions alioth/src/board/board_x86_64/sev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,107 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::arch::x86_64::{__cpuid, CpuidResult};
use std::collections::HashMap;
use std::iter::zip;
use std::sync::Arc;
use std::sync::atomic::Ordering;

use zerocopy::FromZeros;

use crate::arch::cpuid::{
Cpuid1Ecx, Cpuid7Index0Ebx, Cpuid7Index0Edx, CpuidExt1fEAx, CpuidExt1fEbx, CpuidExt8Ebx,
CpuidExt21EAx, CpuidIn,
};
use crate::arch::layout::MEM_64_START;
use crate::arch::reg::{Reg, SegAccess, SegReg, SegRegVal};
use crate::arch::sev::{SevPolicy, SnpPageType, SnpPolicy};
use crate::board::{Board, Result};
use crate::board::{Board, Result, error};
use crate::firmware::ovmf::sev::{
SevDescType, SevMetadataDesc, SnpCpuidFunc, SnpCpuidInfo, parse_desc, parse_sev_ap_eip,
};
use crate::hv::{Vcpu, Vm, VmMemory};
use crate::hv::{Coco, Vcpu, Vm, VmMemory};
use crate::mem::mapped::ArcMemPages;
use crate::mem::{self, LayoutChanged, MarkPrivateMemory};

pub fn adjust_cpuid(coco: &Coco, cpuids: &mut HashMap<CpuidIn, CpuidResult>) -> Result<()> {
// AMD Volume 3, section E.4.17.
let in_ = CpuidIn {
func: 0x8000_001f,
index: None,
};
let Some(out) = cpuids.get_mut(&in_) else {
return error::MissingCpuid { leaf: in_ }.fail();
};
let host_ebx = CpuidExt1fEbx(__cpuid(in_.func).ebx);
out.ebx = CpuidExt1fEbx::new(host_ebx.cbit_pos(), 1, 0).0;
out.ecx = 0;
out.edx = 0;
if let Coco::AmdSev { policy } = coco {
out.eax = if policy.es() {
(CpuidExt1fEAx::SEV | CpuidExt1fEAx::SEV_ES).bits()
} else {
CpuidExt1fEAx::SEV.bits()
};
} else if let Coco::AmdSnp { .. } = coco {
out.eax = (CpuidExt1fEAx::SEV | CpuidExt1fEAx::SEV_ES | CpuidExt1fEAx::SEV_SNP).bits()
}

if let Coco::AmdSnp { .. } = coco {
snp_adjust_cpuids(cpuids);
}

Ok(())
}

fn snp_adjust_cpuids(cpuids: &mut HashMap<CpuidIn, CpuidResult>) {
let in_ = CpuidIn {
func: 0x1,
index: None,
};
if let Some(out) = cpuids.get_mut(&in_) {
out.ecx &= !Cpuid1Ecx::TSC_DEADLINE.bits()
};

let in_ = CpuidIn {
func: 0x7,
index: Some(0),
};
if let Some(out) = cpuids.get_mut(&in_) {
out.ebx &= !Cpuid7Index0Ebx::TSC_ADJUST.bits();
out.edx &= !(Cpuid7Index0Edx::IBRS_IBPB
| Cpuid7Index0Edx::SPEC_CTRL_ST_PREDICTORS
| Cpuid7Index0Edx::L1D_FLUSH_INTERFACE
| Cpuid7Index0Edx::ARCH_CAPABILITIES
| Cpuid7Index0Edx::CORE_CAPABILITIES
| Cpuid7Index0Edx::SPEC_CTRL_SSBD)
.bits()
}

let in_ = CpuidIn {
func: 0x8000_0008,
index: None,
};
if let Some(out) = cpuids.get_mut(&in_) {
out.ebx &= !CpuidExt8Ebx::SSBD_VIRT_SPEC_CTRL.bits();
}

let in_ = CpuidIn {
func: 0x8000_0021,
index: None,
};
if let Some(out) = cpuids.get_mut(&in_) {
out.eax &= !CpuidExt21EAx::NO_SMM_CTL_MSR.bits();
}

for index in 0..=4 {
cpuids.remove(&CpuidIn {
func: 0x8000_0026,
index: Some(index),
});
}
}

impl<V> Board<V>
where
V: Vm,
Expand Down Expand Up @@ -59,7 +143,7 @@ where
let mut cpuid_table = SnpCpuidInfo::new_zeroed();
let ram_bus = self.memory.ram_bus();
let ram = ram_bus.lock_layout();
let snp_page_type = match desc.type_ {
let page_type = match desc.type_ {
SevDescType::SNP_DESC_MEM => SnpPageType::UNMEASURED,
SevDescType::SNP_SECRETS => SnpPageType::SECRETS,
SevDescType::CPUID => {
Expand All @@ -73,24 +157,18 @@ where
_ => unimplemented!(),
};
let range_ref = ram.get_slice::<u8>(desc.base as u64, desc.len as u64)?;
let range_bytes =
let bytes =
unsafe { std::slice::from_raw_parts_mut(range_ref.as_ptr() as _, range_ref.len()) };
self.memory
.mark_private_memory(desc.base as _, desc.len as _, true)?;
let mut ret = self
.vm
.snp_launch_update(range_bytes, desc.base as _, snp_page_type);
let ret = self.vm.snp_launch_update(bytes, desc.base as _, page_type);
if ret.is_err() && desc.type_ == SevDescType::CPUID {
let updated_cpuid: SnpCpuidInfo = ram.read_t(desc.base as _)?;
for (set, got) in zip(cpuid_table.entries.iter(), updated_cpuid.entries.iter()) {
for (set, got) in zip(&cpuid_table.entries, &updated_cpuid.entries) {
if set != got {
log::error!("set {set:#x?}, but firmware expects {got:#x?}");
}
}
ram.write_t(desc.base as _, &updated_cpuid)?;
ret = self
.vm
.snp_launch_update(range_bytes, desc.base as _, snp_page_type);
}
ret?;
Ok(())
Expand Down