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
340 changes: 14 additions & 326 deletions alioth/src/board/board.rs

Large diffs are not rendered by default.

34 changes: 3 additions & 31 deletions alioth/src/board/board_aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
// limitations under the License.

use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;

use crate::arch::layout::{
Expand All @@ -24,10 +23,10 @@ use crate::arch::layout::{
RAM_32_SIZE, RAM_32_START,
};
use crate::arch::reg::MpidrEl1;
use crate::board::{Board, BoardConfig, CpuTopology, PCIE_MMIO_64_SIZE, Result, VcpuGuard};
use crate::board::{Board, BoardConfig, CpuTopology, PCIE_MMIO_64_SIZE, Result};
use crate::firmware::dt::{DeviceTree, Node, PropVal};
use crate::hv::{GicV2, GicV2m, GicV3, Hypervisor, Its, Vcpu, Vm};
use crate::loader::{Executable, InitState, Payload};
use crate::hv::{GicV2, GicV2m, GicV3, Hypervisor, Its, Vm};
use crate::loader::{Executable, InitState};
use crate::mem::{MemRegion, MemRegionType};

enum Gic<V>
Expand Down Expand Up @@ -108,29 +107,6 @@ where
encode_mpidr(&self.config.cpu.topology, index).0
}

pub fn setup_firmware(&self, _: &Path, _: &Payload, _: &V::Vcpu) -> Result<InitState> {
unimplemented!()
}

pub fn init_ap(&self, _id: u16, _vcpu: &mut V::Vcpu, _vcpus: &VcpuGuard) -> Result<()> {
Ok(())
}

pub fn init_boot_vcpu(&self, vcpu: &mut V::Vcpu, init_state: &InitState) -> Result<()> {
vcpu.set_regs(&init_state.regs)?;
vcpu.set_sregs(&init_state.sregs)?;
Ok(())
}

pub fn init_vcpu(&self, index: u16, vcpu: &mut V::Vcpu) -> Result<()> {
self.reset_vcpu(index, vcpu)
}

pub fn reset_vcpu(&self, index: u16, vcpu: &mut V::Vcpu) -> Result<()> {
vcpu.reset(index == 0)?;
Ok(())
}

pub fn create_ram(&self) -> Result<()> {
let mem_size = self.config.mem.size;
let memory = &self.memory;
Expand Down Expand Up @@ -158,10 +134,6 @@ where
Ok(())
}

pub fn coco_finalize(&self, _id: u16, _vcpus: &VcpuGuard) -> Result<()> {
Ok(())
}

pub fn arch_init(&self) -> Result<()> {
match &self.arch.gic {
Gic::V2(v2) => v2.init(),
Expand Down
105 changes: 7 additions & 98 deletions alioth/src/board/board_x86_64/board_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ mod tdx;
use std::arch::x86_64::{__cpuid, CpuidResult};
use std::collections::HashMap;
use std::mem::{offset_of, size_of, size_of_val};
use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, AtomicU64};

Expand All @@ -31,8 +30,7 @@ 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, RAM_32_SIZE,
};
use crate::arch::msr::{MiscEnable, Msr};
use crate::board::{Board, BoardConfig, CpuTopology, PCIE_MMIO_64_SIZE, Result, VcpuGuard, error};
use crate::board::{Board, BoardConfig, CpuTopology, PCIE_MMIO_64_SIZE, Result, error};
use crate::device::ioapic::IoApic;
use crate::firmware::acpi::bindings::{
AcpiTableFadt, AcpiTableHeader, AcpiTableRsdp, AcpiTableXsdt3,
Expand All @@ -41,19 +39,18 @@ use crate::firmware::acpi::reg::{AcpiPmTimer, FadtReset, FadtSleepControl};
use crate::firmware::acpi::{
AcpiTable, create_fadt, create_madt, create_mcfg, create_rsdp, create_xsdt,
};
use crate::hv::{Coco, Hypervisor, Vcpu, Vm};
use crate::loader::{Executable, InitState, Payload, firmware};
use crate::mem::mapped::ArcMemPages;
use crate::hv::{Coco, Hypervisor, Vm};
use crate::loader::{Executable, InitState, Payload};
use crate::mem::{MemRange, MemRegion, MemRegionEntry, MemRegionType};
use crate::utils::wrapping_sum;

pub struct ArchBoard<V>
where
V: Vm,
{
cpuids: HashMap<CpuidIn, CpuidResult>,
sev_ap_eip: AtomicU32,
tdx_hob: AtomicU64,
pub(crate) cpuids: HashMap<CpuidIn, CpuidResult>,
pub(crate) sev_ap_eip: AtomicU32,
pub(crate) tdx_hob: AtomicU64,
pub(crate) io_apic: Arc<IoApic<V::MsiSender>>,
}

Expand Down Expand Up @@ -176,7 +173,7 @@ where
encode_x2apic_id(&self.config.cpu.topology, index) as u64
}

fn setup_fw_cfg(&self, payload: &Payload) -> Result<()> {
pub(crate) fn setup_fw_cfg(&self, payload: &Payload) -> Result<()> {
let Some(dev) = &*self.fw_cfg.lock() else {
return Ok(());
};
Expand All @@ -193,79 +190,6 @@ where
Ok(())
}

fn setup_coco(&self, fw: &mut ArcMemPages, vcpu: &V::Vcpu) -> Result<()> {
let Some(coco) = &self.config.coco else {
return Ok(());
};
match coco {
Coco::AmdSev { policy } => self.setup_sev(fw, *policy),
Coco::AmdSnp { .. } => self.setup_snp(fw),
Coco::IntelTdx { .. } => self.setup_tdx(fw, vcpu),
}
}

pub fn setup_firmware(
&self,
fw: &Path,
payload: &Payload,
vcpu: &V::Vcpu,
) -> Result<InitState> {
let (init_state, mut rom) = firmware::load(&self.memory, fw)?;
self.setup_coco(&mut rom, vcpu)?;
self.setup_fw_cfg(payload)?;
Ok(init_state)
}

pub fn init_ap(&self, index: u16, vcpu: &mut V::Vcpu, vcpus: &VcpuGuard) -> Result<()> {
let Some(coco) = &self.config.coco else {
return Ok(());
};
self.sync_vcpus(vcpus)?;
if index == 0 {
return Ok(());
}
match coco {
Coco::AmdSev { policy } => {
if policy.es() {
self.sev_init_ap(vcpu)?;
}
}
Coco::AmdSnp { .. } => self.sev_init_ap(vcpu)?,
Coco::IntelTdx { .. } => self.tdx_init_ap(vcpu)?,
}
Ok(())
}

pub fn init_boot_vcpu(&self, vcpu: &mut V::Vcpu, init_state: &InitState) -> Result<()> {
if matches!(self.config.coco, Some(Coco::IntelTdx { .. })) {
return Ok(());
}
vcpu.set_sregs(&init_state.sregs, &init_state.seg_regs, &init_state.dt_regs)?;
vcpu.set_msrs(&init_state.msrs)?;
vcpu.set_regs(&init_state.regs)?;
Ok(())
}

pub fn init_vcpu(&self, index: u16, vcpu: &mut V::Vcpu) -> Result<()> {
let mut cpuids = self.arch.cpuids.clone();
let apic_id = self.encode_cpu_identity(index) as u32;
for (in_, out) in &mut cpuids {
if in_.func == 0x1 {
out.ebx &= 0x00ff_ffff;
out.ebx |= apic_id << 24;
} else if in_.func == 0xb || in_.func == 0x1f || in_.func == 0x80000026 {
out.edx = apic_id;
}
}
vcpu.set_cpuids(cpuids)?;
vcpu.set_msrs(&[(Msr::MISC_ENABLE, MiscEnable::FAST_STRINGS.bits())])?;
Ok(())
}

pub fn reset_vcpu(&self, _index: u16, _vcpu: &mut V::Vcpu) -> Result<()> {
Ok(())
}

pub fn create_ram(&self) -> Result<()> {
let config = &self.config;
let memory = &self.memory;
Expand Down Expand Up @@ -324,21 +248,6 @@ where
Ok(())
}

pub fn coco_finalize(&self, index: u16, vcpus: &VcpuGuard) -> Result<()> {
let Some(coco) = &self.config.coco else {
return Ok(());
};
self.sync_vcpus(vcpus)?;
if index != 0 {
return Ok(());
};
match coco {
Coco::AmdSev { policy } => self.sev_finalize(*policy),
Coco::AmdSnp { .. } => self.snp_finalize(),
Coco::IntelTdx { .. } => self.tdx_finalize(),
}
}

fn patch_dsdt(&self, data: &mut [u8; 352]) {
let pcie_mmio_64_start = self.config.pcie_mmio_64_start();
let pcei_mmio_64_max = pcie_mmio_64_start - 1 + PCIE_MMIO_64_SIZE;
Expand Down
130 changes: 2 additions & 128 deletions alioth/src/board/board_x86_64/sev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,15 @@

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::arch::sev::{SevPolicy, SnpPolicy};
use crate::board::{Board, Result, error};
use crate::firmware::ovmf::sev::{
SevDescType, SevMetadataDesc, SnpCpuidFunc, SnpCpuidInfo, parse_desc, parse_sev_ap_eip,
};
use crate::hv::{Coco, Vcpu, Vm, VmMemory};
use crate::hv::{Coco, Vm, VmMemory};
use crate::mem::mapped::ArcMemPages;
use crate::mem::{self, LayoutChanged, MarkPrivateMemory};

Expand Down Expand Up @@ -117,123 +108,6 @@ impl<V> Board<V>
where
V: Vm,
{
fn fill_snp_cpuid(&self, entries: &mut [SnpCpuidFunc]) {
for ((in_, out), dst) in zip(self.arch.cpuids.iter(), entries.iter_mut()) {
dst.eax_in = in_.func;
dst.ecx_in = in_.index.unwrap_or(0);
dst.eax = out.eax;
dst.ebx = out.ebx;
dst.ecx = out.ecx;
dst.edx = out.edx;
if dst.eax_in == 0xd && (dst.ecx_in == 0x0 || dst.ecx_in == 0x1) {
dst.ebx = 0x240;
dst.xcr0_in = 1;
dst.xss_in = 0;
}
}
}

fn parse_sev_api_eip(&self, data: &[u8]) -> Result<()> {
let ap_eip = parse_sev_ap_eip(data)?;
self.arch.sev_ap_eip.store(ap_eip, Ordering::Release);
Ok(())
}

fn update_snp_desc(&self, desc: &SevMetadataDesc) -> Result<()> {
let mut cpuid_table = SnpCpuidInfo::new_zeroed();
let ram_bus = self.memory.ram_bus();
let ram = ram_bus.lock_layout();
let page_type = match desc.type_ {
SevDescType::SNP_DESC_MEM => SnpPageType::UNMEASURED,
SevDescType::SNP_SECRETS => SnpPageType::SECRETS,
SevDescType::CPUID => {
assert!(desc.len as usize >= size_of::<SnpCpuidInfo>());
assert!(cpuid_table.entries.len() >= self.arch.cpuids.len());
cpuid_table.count = self.arch.cpuids.len() as u32;
self.fill_snp_cpuid(&mut cpuid_table.entries);
ram.write_t(desc.base as _, &cpuid_table)?;
SnpPageType::CPUID
}
_ => SnpPageType::ZERO,
};
let range_ref = ram.get_slice::<u8>(desc.base as u64, desc.len as u64)?;
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 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, &updated_cpuid.entries) {
if set != got {
log::error!("set {set:#x?}, but firmware expects {got:#x?}");
}
}
}
ret?;
Ok(())
}

pub(crate) fn setup_sev(&self, fw: &mut ArcMemPages, policy: SevPolicy) -> Result<()> {
self.memory.register_encrypted_pages(fw)?;

let data = fw.as_slice_mut();
if policy.es() {
self.parse_sev_api_eip(data)?;
}
self.vm.sev_launch_update_data(data)?;
Ok(())
}

pub(crate) fn setup_snp(&self, fw: &mut ArcMemPages) -> Result<()> {
self.memory.register_encrypted_pages(fw)?;

let data = fw.as_slice_mut();
self.parse_sev_api_eip(data)?;
for desc in parse_desc(data)? {
self.update_snp_desc(desc)?;
}
let fw_gpa = MEM_64_START - data.len() as u64;
self.memory
.mark_private_memory(fw_gpa, data.len() as _, true)?;
self.vm
.snp_launch_update(data, fw_gpa, SnpPageType::NORMAL)?;
Ok(())
}

pub(crate) fn sev_finalize(&self, policy: SevPolicy) -> Result<()> {
if policy.es() {
self.vm.sev_launch_update_vmsa()?;
}
self.vm.sev_launch_measure()?;
self.vm.sev_launch_finish()?;
Ok(())
}

pub(crate) fn snp_finalize(&self) -> Result<()> {
self.vm.snp_launch_finish()?;
Ok(())
}

pub(crate) fn sev_init_ap(&self, vcpu: &mut V::Vcpu) -> Result<()> {
let eip = self.arch.sev_ap_eip.load(Ordering::Acquire);
vcpu.set_regs(&[(Reg::Rip, eip as u64 & 0xffff)])?;
vcpu.set_sregs(
&[],
&[(
SegReg::Cs,
SegRegVal {
selector: 0xf000,
base: eip as u64 & 0xffff_0000,
limit: 0xffff,
access: SegAccess(0x9b),
},
)],
&[],
)?;
Ok(())
}

pub(crate) fn sev_init(&self, policy: SevPolicy, memory: Arc<V::Memory>) -> Result<()> {
self.vm.sev_launch_start(policy)?;
let encrypt_pages = Box::new(EncryptPages { memory });
Expand Down
Loading