Skip to content
Closed
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
119 changes: 107 additions & 12 deletions dstack-mr/src/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,68 @@ use anyhow::{bail, Context, Result};
use log::debug;
use scale::Decode;

use crate::Machine;
use crate::{Machine, SmbiosConfig};

const LDR_LENGTH: usize = 4096;
const FIXED_STRING_LEN: usize = 56;

fn acpi_tables_tool(version: (u32, u32, u32)) -> (&'static str, &'static str) {
if version < (9, 0, 0) {
(
"/usr/local/bin/dstack-acpi-tables-8.2.2",
"/usr/local/share/qemu-8.2.2",
)
} else {
(
"/usr/local/bin/dstack-acpi-tables-9.2.1",
"/usr/local/share/qemu-9.2.1",
)
}
}

#[derive(Debug, Clone)]
pub struct Tables {
pub tables: Vec<u8>,
pub rsdp: Vec<u8>,
pub loader: Vec<u8>,
}

fn cfg_if(ty: &mut Vec<String>, name: &str, v: &Option<String>) {
if let Some(v) = v {
ty.push(format!("{name}={v}"));
}
}

fn append_smbios(cmd: &mut std::process::Command, smbios: &SmbiosConfig) {
let mut types: [Vec<String>; 4] = Default::default();
cfg_if(&mut types[0], "vendor", &smbios.bios_vendor);
cfg_if(&mut types[0], "version", &smbios.bios_version);
cfg_if(&mut types[0], "date", &smbios.bios_date);
cfg_if(&mut types[0], "release", &smbios.bios_release);
cfg_if(&mut types[1], "manufacturer", &smbios.sys_vendor);
cfg_if(&mut types[1], "product", &smbios.product_name);
cfg_if(&mut types[1], "version", &smbios.product_version);
cfg_if(&mut types[1], "serial", &smbios.product_serial);
cfg_if(&mut types[1], "uuid", &smbios.product_uuid);
cfg_if(&mut types[1], "family", &smbios.product_family);
cfg_if(&mut types[1], "sku", &smbios.product_sku);
cfg_if(&mut types[2], "manufacturer", &smbios.board_vendor);
cfg_if(&mut types[2], "product", &smbios.board_name);
cfg_if(&mut types[2], "version", &smbios.board_version);
cfg_if(&mut types[2], "serial", &smbios.board_serial);
cfg_if(&mut types[2], "asset", &smbios.board_asset_tag);
cfg_if(&mut types[3], "manufacturer", &smbios.chassis_vendor);
cfg_if(&mut types[3], "version", &smbios.chassis_version);
cfg_if(&mut types[3], "serial", &smbios.chassis_serial);
cfg_if(&mut types[3], "asset", &smbios.chassis_asset_tag);

for (i, t) in types.iter().enumerate() {
if !t.is_empty() {
cmd.arg("-smbios").arg(format!("type={i},{}", t.join(",")));
}
}
}

impl Machine<'_> {
fn create_tables(&self) -> Result<Vec<u8>> {
if self.cpu_count == 0 {
Expand All @@ -32,9 +82,30 @@ impl Machine<'_> {
let dummy_disk = "/bin/sh";
let shared_dir = "/bin";

let vopt = self
.versioned_options()
.context("Failed to get versioned options")?;
let (acpi_tables_bin, qemu_data_dir) = acpi_tables_tool(vopt.version);

let tdx_object_arg = match self.qgs_port {
Some(port) => serde_json::json!({
"qom-type": "tdx-guest",
"id": "tdx",
"quote-generation-socket": {
"type": "vsock",
"cid": "2",
"port": port.to_string(),
},
})
.to_string(),
None => "tdx-guest,id=tdx".to_string(),
};

// Prepare the command arguments
let mut cmd = std::process::Command::new("dstack-acpi-tables");
let mut cmd = std::process::Command::new(acpi_tables_bin);
cmd.args([
"-L",
qemu_data_dir,
"-cpu",
"qemu64",
"-smp",
Expand All @@ -59,20 +130,25 @@ impl Machine<'_> {
"user,id=net0",
"-device",
"virtio-net-pci,netdev=net0",
"-object",
"tdx-guest,id=tdx",
"-device",
"vhost-vsock-pci,guest-cid=3",
]);
cmd.args(["-object", &tdx_object_arg]);
append_smbios(&mut cmd, &self.smbios);
cmd.args(["-device", "vhost-vsock-pci,guest-cid=3"]);

// Configure shared files delivery: either via disk or 9p
match self.host_share_mode.as_str() {
"" | "9p" => {
// Use 9p virtfs (default)
let security_model = self.virtfs_security_model.as_str();
let security_model = if security_model.is_empty() {
"none"
} else {
security_model
};
cmd.args([
"-virtfs",
&format!(
"local,path={shared_dir},mount_tag=host-shared,readonly=on,security_model=none,id=virtfs0",
"local,path={shared_dir},mount_tag=host-shared,readonly=on,security_model={security_model},id=virtfs0",
),
]);
}
Expand Down Expand Up @@ -109,10 +185,6 @@ impl Machine<'_> {
machine.push_str(",smm=off");
}

let vopt = self
.versioned_options()
.context("Failed to get versioned options")?;

if vopt.pic {
machine.push_str(",pic=on");
} else {
Expand Down Expand Up @@ -184,7 +256,7 @@ impl Machine<'_> {
format!("{}.{}.{}", ver.0, ver.1, ver.2),
)
.output()
.context("failed to execute dstack-acpi-tables")?;
.with_context(|| format!("failed to execute {acpi_tables_bin}"))?;

// Check if the command was successful
if !output.status.success() {
Expand Down Expand Up @@ -327,6 +399,29 @@ impl Machine<'_> {
}
}

#[cfg(test)]
mod tests {
use super::acpi_tables_tool;

#[test]
fn selects_acpi_tables_tool_by_qemu_major_version() {
assert_eq!(
acpi_tables_tool((8, 2, 2)),
(
"/usr/local/bin/dstack-acpi-tables-8.2.2",
"/usr/local/share/qemu-8.2.2"
)
);
assert_eq!(
acpi_tables_tool((9, 2, 1)),
(
"/usr/local/bin/dstack-acpi-tables-9.2.1",
"/usr/local/share/qemu-9.2.1"
)
);
}
}

/// An enum to represent the different QEMU loader commands in a type-safe way.
#[derive(Debug)]
enum LoaderCmd<'a> {
Expand Down
2 changes: 1 addition & 1 deletion dstack-mr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use serde::{Deserialize, Serialize};
use serde_human_bytes as hex_bytes;

pub use machine::{Machine, TdxMeasurementDetails};
pub use machine::{Machine, SmbiosConfig, TdxMeasurementDetails};

use util::{measure_log, measure_sha384, utf16_encode};

Expand Down
29 changes: 29 additions & 0 deletions dstack-mr/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ use anyhow::{bail, Context, Result};
use fs_err as fs;
use log::debug;

#[derive(Debug, Clone, Default)]
pub struct SmbiosConfig {
pub bios_vendor: Option<String>,
pub bios_version: Option<String>,
pub bios_date: Option<String>,
pub bios_release: Option<String>,
pub sys_vendor: Option<String>,
pub product_name: Option<String>,
pub product_version: Option<String>,
pub product_serial: Option<String>,
pub product_uuid: Option<String>,
pub product_family: Option<String>,
pub product_sku: Option<String>,
pub board_vendor: Option<String>,
pub board_name: Option<String>,
pub board_version: Option<String>,
pub board_serial: Option<String>,
pub board_asset_tag: Option<String>,
pub chassis_vendor: Option<String>,
pub chassis_version: Option<String>,
pub chassis_serial: Option<String>,
pub chassis_asset_tag: Option<String>,
}

#[derive(Debug, bon::Builder)]
pub struct Machine<'a> {
pub cpu_count: u32,
Expand All @@ -32,6 +56,11 @@ pub struct Machine<'a> {
pub root_verity: bool,
#[builder(default)]
pub host_share_mode: String,
#[builder(default)]
pub smbios: SmbiosConfig,
#[builder(default)]
pub virtfs_security_model: String,
pub qgs_port: Option<u32>,
}

fn parse_version_tuple(v: &str) -> Result<(u32, u32, u32)> {
Expand Down
36 changes: 36 additions & 0 deletions dstack-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,42 @@ pub struct VmConfig {
/// If false (default), shared files are provided via 9p virtfs
#[serde(default)]
pub host_share_mode: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub qgs_port: Option<u32>,
#[serde(default, skip_serializing_if = "SmbiosConfig::is_empty")]
pub product: SmbiosConfig,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub virtfs_security_model: Option<String>,
}

#[derive(Deserialize, Serialize, Debug, Clone, Default, PartialEq, Eq)]
pub struct SmbiosConfig {
pub bios_vendor: Option<String>,
pub bios_version: Option<String>,
pub bios_date: Option<String>,
pub bios_release: Option<String>,
pub sys_vendor: Option<String>,
pub product_name: Option<String>,
pub product_version: Option<String>,
pub product_serial: Option<String>,
pub product_uuid: Option<String>,
pub product_family: Option<String>,
pub product_sku: Option<String>,
pub board_vendor: Option<String>,
pub board_name: Option<String>,
pub board_version: Option<String>,
pub board_serial: Option<String>,
pub board_asset_tag: Option<String>,
pub chassis_vendor: Option<String>,
pub chassis_version: Option<String>,
pub chassis_serial: Option<String>,
pub chassis_asset_tag: Option<String>,
}

impl SmbiosConfig {
pub fn is_empty(&self) -> bool {
self == &Self::default()
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down
50 changes: 39 additions & 11 deletions kms/dstack-app/builder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ RUN rustup target add x86_64-unknown-linux-musl
RUN cd dstack && cargo build --release -p dstack-kms --target x86_64-unknown-linux-musl
RUN echo "${DSTACK_REV}" > /build/.GIT_REV

FROM debian:bookworm@sha256:0d8498a0e9e6a60011df39aab78534cfe940785e7c59d19dfae1eb53ea59babe
FROM debian:bookworm@sha256:0d8498a0e9e6a60011df39aab78534cfe940785e7c59d19dfae1eb53ea59babe AS acpi-builder-base
COPY --from=build-shared /pin-packages.sh /config-qemu.sh /build/
COPY ./shared/qemu-pinned-packages.txt /build/
WORKDIR /build
ARG QEMU_REV=dbcec07c0854bf873d346a09e87e4c993ccf2633
RUN ./pin-packages.sh ./qemu-pinned-packages.txt && \
apt-get update && \
apt-get install -y --no-install-recommends \
Expand All @@ -46,20 +45,49 @@ RUN ./pin-packages.sh ./qemu-pinned-packages.txt && \
flex \
bison && \
rm -rf /var/lib/apt/lists/* /var/log/* /var/cache/ldconfig/aux-cache
RUN git clone https://github.com/kvinwang/qemu-tdx.git --depth 1 --branch dstack-qemu-9.2.1 --single-branch && \
cd qemu-tdx && git fetch --depth 1 origin ${QEMU_REV} && \
git checkout ${QEMU_REV} && \

FROM acpi-builder-base AS acpi-builder-8
ARG QEMU_8_REV=8a609a153956e35d756269b742e5299dcb7788be
RUN git clone https://github.com/Leechael/qemu-tdx.git --depth 1 --branch dstack-qemu-8.2.2-qgs --single-branch qemu-tdx-8 && \
cd qemu-tdx-8 && git fetch --depth 1 origin ${QEMU_8_REV} && \
git checkout ${QEMU_8_REV} && \
../config-qemu.sh ./build /usr/local && \
cd build && \
ninja && \
strip qemu-system-x86_64 && \
install -m 755 qemu-system-x86_64 /usr/local/bin/dstack-acpi-tables-8.2.2 && \
cd ../ && \
install -d /usr/local/share/qemu-8.2.2 && \
install -m 644 pc-bios/efi-virtio.rom /usr/local/share/qemu-8.2.2/ && \
install -m 644 pc-bios/kvmvapic.bin /usr/local/share/qemu-8.2.2/ && \
install -m 644 pc-bios/linuxboot_dma.bin /usr/local/share/qemu-8.2.2/ && \
cd .. && rm -rf qemu-tdx-8

FROM acpi-builder-base AS acpi-builder-9
ARG QEMU_9_REV=dbcec07c0854bf873d346a09e87e4c993ccf2633
RUN git clone https://github.com/kvinwang/qemu-tdx.git --depth 1 --branch dstack-qemu-9.2.1 --single-branch qemu-tdx-9 && \
cd qemu-tdx-9 && git fetch --depth 1 origin ${QEMU_9_REV} && \
git checkout ${QEMU_9_REV} && \
../config-qemu.sh ./build /usr/local && \
cd build && \
ninja && \
strip qemu-system-x86_64 && \
install -m 755 qemu-system-x86_64 /usr/local/bin/dstack-acpi-tables && \
install -m 755 qemu-system-x86_64 /usr/local/bin/dstack-acpi-tables-9.2.1 && \
ln -sf dstack-acpi-tables-9.2.1 /usr/local/bin/dstack-acpi-tables && \
cd ../ && \
install -d /usr/local/share/qemu && \
install -m 644 pc-bios/efi-virtio.rom /usr/local/share/qemu/ && \
install -m 644 pc-bios/kvmvapic.bin /usr/local/share/qemu/ && \
install -m 644 pc-bios/linuxboot_dma.bin /usr/local/share/qemu/ && \
cd .. && rm -rf qemu-tdx
install -d /usr/local/share/qemu-9.2.1 && \
install -m 644 pc-bios/efi-virtio.rom /usr/local/share/qemu-9.2.1/ && \
install -m 644 pc-bios/kvmvapic.bin /usr/local/share/qemu-9.2.1/ && \
install -m 644 pc-bios/linuxboot_dma.bin /usr/local/share/qemu-9.2.1/ && \
ln -sfn qemu-9.2.1 /usr/local/share/qemu && \
cd .. && rm -rf qemu-tdx-9

FROM acpi-builder-9 AS acpi-builder
COPY --from=acpi-builder-8 /usr/local/bin/dstack-acpi-tables-8.2.2 /usr/local/bin/dstack-acpi-tables-8.2.2
COPY --from=acpi-builder-8 /usr/local/share/qemu-8.2.2 /usr/local/share/qemu-8.2.2
RUN test -x /usr/local/bin/dstack-acpi-tables-8.2.2 && \
test -x /usr/local/bin/dstack-acpi-tables-9.2.1 && \
test -x /usr/local/bin/dstack-acpi-tables
COPY --from=kms-builder /build/dstack/target/x86_64-unknown-linux-musl/release/dstack-kms /usr/local/bin/dstack-kms
COPY --from=kms-builder /build/.GIT_REV /etc/
CMD ["dstack-kms"]
Loading
Loading