Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tool: add cargo xflowey custom-vmfirmwareigvm-dll #291

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
101 changes: 101 additions & 0 deletions flowey/flowey_hvlite/src/pipelines/custom_vmfirmwareigvm_dll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! See [`CustomVmfirmwareigvmDllCli`]

use crate::pipelines_shared::cfg_common_params::CommonArchCli;
use anyhow::Context;
use flowey::node::prelude::ReadVar;
use flowey::pipeline::prelude::*;
use std::path::PathBuf;

/// Encapsulate an existing pre-built IGVM file into *unsigned*
/// `vmfirmwareigvm.dll` resource DLL.
///
/// Unlike `build-igvm`, this tool will NOT build OpenHCL from scratch. This
/// tool streamlines the process of building the in-tree `vmfirmwareigvm_dll`
/// crate (which requires setting various env vars, installing certain
/// dependencies, etc...).
///
/// NOTE: This tool is primarily intended for use by Microsoft employees, as
/// open-source deployments of OpenHCL typically load the IGVM file directly
/// (rather than being encapsulated in a resource-DLL).
#[derive(clap::Args)]
pub struct CustomVmfirmwareigvmDllCli {
/// Path to IGVM payload to encapsulate in the vmfirmwareigvm resource DLL.
pub igvm_payload: PathBuf,

/// Architecture the DLL should be built for.
///
/// Defaults to the current host architecture.
#[clap(long)]
pub arch: Option<CommonArchCli>,
}

impl IntoPipeline for CustomVmfirmwareigvmDllCli {
fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> {
if !matches!(backend_hint, PipelineBackendHint::Local) {
anyhow::bail!("build-igvm is for local use only")
}

// DEVNOTE: it would be nice to figure out what sort of magic is
// required for the WSL2 case to work. The tricky part is dealing with
// the underlying invocations to `rc.exe` via WSL2.
daprilik marked this conversation as resolved.
Show resolved Hide resolved
if !matches!(FlowPlatform::host(backend_hint), FlowPlatform::Windows) {
anyhow::bail!("custom-vmfirmwareigvm-dll only runs on Windows (WSL2 is NOT supported)")
}

let CustomVmfirmwareigvmDllCli { arch, igvm_payload } = self;

let arch = match arch {
Some(arch) => arch,
None => FlowArch::host(backend_hint).try_into()?,
};
let igvm_payload = std::path::absolute(igvm_payload)
.context("could not make path to igvm payload absolute")?;

let openvmm_repo = flowey_lib_common::git_checkout::RepoSource::ExistingClone(
ReadVar::from_static(crate::repo_root()),
);

let mut pipeline = Pipeline::new();

let (pub_out_dir, _) = pipeline.new_artifact("custom-vmfirmwareigvm-dll");

pipeline
.new_job(
FlowPlatform::host(backend_hint),
FlowArch::host(backend_hint),
"custom-vmfirmwareigvm-dll",
)
.dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request {})
.dep_on(
|_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params {
hvlite_repo_source: openvmm_repo,
},
)
.dep_on(|_| flowey_lib_hvlite::_jobs::cfg_common::Params {
local_only: Some(flowey_lib_hvlite::_jobs::cfg_common::LocalOnlyParams {
interactive: true,
auto_install: false,
force_nuget_mono: false, // no oss nuget packages
external_nuget_auth: false,
ignore_rust_version: true,
}),
verbose: ReadVar::from_static(false),
locked: false,
deny_warnings: false,
})
.dep_on(
|ctx| flowey_lib_hvlite::_jobs::local_custom_vmfirmwareigvm_dll::Params {
arch: arch.into(),
igvm_payload,
artifact_dir: ctx.publish_artifact(pub_out_dir),
done: ctx.new_done_handle(),
},
)
.finish();

Ok(pipeline)
}
}
3 changes: 3 additions & 0 deletions flowey/flowey_hvlite/src/pipelines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use restore_packages::RestorePackagesCli;

pub mod build_igvm;
pub mod checkin_gates;
pub mod custom_vmfirmwareigvm_dll;
pub mod restore_packages;

#[derive(clap::Subcommand)]
Expand All @@ -19,6 +20,7 @@ pub enum OpenvmmPipelines {
},

BuildIgvm(build_igvm::BuildIgvmCli),
CustomVmfirmwareigvmDll(custom_vmfirmwareigvm_dll::CustomVmfirmwareigvmDllCli),

/// Flowey pipelines primarily designed to run in CI.
#[clap(subcommand)]
Expand Down Expand Up @@ -54,6 +56,7 @@ impl IntoPipeline for OpenvmmPipelines {
}

OpenvmmPipelines::BuildIgvm(cmd) => cmd.into_pipeline(pipeline_hint),
OpenvmmPipelines::CustomVmfirmwareigvmDll(cmd) => cmd.into_pipeline(pipeline_hint),

OpenvmmPipelines::Ci(cmd) => match cmd {
OpenvmmPipelinesCi::CheckinGates(cmd) => cmd.into_pipeline(pipeline_hint),
Expand Down
28 changes: 6 additions & 22 deletions flowey/flowey_hvlite/src/pipelines/restore_packages.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::pipelines_shared::cfg_common_params::CommonArchCli;
use flowey::node::prelude::ReadVar;
use flowey::pipeline::prelude::*;
use flowey_lib_hvlite::run_cargo_build::common::CommonArch;

#[derive(clap::ValueEnum, Clone, Copy)]
pub enum CommonArchCli {
X86_64,
Aarch64,
}

impl From<CommonArchCli> for CommonArch {
fn from(value: CommonArchCli) -> Self {
match value {
CommonArchCli::X86_64 => CommonArch::X86_64,
CommonArchCli::Aarch64 => CommonArch::Aarch64,
}
}
}

#[derive(clap::Args)]
/// Download and restore packages needed for building the specified architectures.
#[derive(clap::Args)]
pub struct RestorePackagesCli {
/// Specify what architectures to restore packages for.
///
/// If none are specified, defaults to just the current host architecture.
arch: Vec<CommonArchCli>,
}

Expand Down Expand Up @@ -60,11 +48,7 @@ impl IntoPipeline for RestorePackagesCli {

let arches = {
if self.arch.is_empty() {
vec![match FlowArch::host(backend_hint) {
FlowArch::X86_64 => CommonArchCli::X86_64,
FlowArch::Aarch64 => CommonArchCli::Aarch64,
arch => anyhow::bail!("unsupported arch {arch}"),
}]
vec![FlowArch::host(backend_hint).try_into()?]
} else {
self.arch
}
Expand Down
28 changes: 28 additions & 0 deletions flowey/flowey_hvlite/src/pipelines_shared/cfg_common_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use flowey::node::prelude::*;
use flowey::pipeline::prelude::*;
use flowey_lib_hvlite::run_cargo_build::common::CommonArch;

#[derive(Clone, Default, clap::Args)]
#[clap(next_help_heading = "Local Only")]
Expand Down Expand Up @@ -98,3 +99,30 @@ pub fn get_cfg_common_params(
}
}
}

#[derive(clap::ValueEnum, Clone, Copy)]
pub enum CommonArchCli {
X86_64,
Aarch64,
}

impl From<CommonArchCli> for CommonArch {
fn from(value: CommonArchCli) -> Self {
match value {
CommonArchCli::X86_64 => CommonArch::X86_64,
CommonArchCli::Aarch64 => CommonArch::Aarch64,
}
}
}

impl TryFrom<FlowArch> for CommonArchCli {
type Error = anyhow::Error;

fn try_from(arch: FlowArch) -> anyhow::Result<Self> {
Ok(match arch {
FlowArch::X86_64 => CommonArchCli::X86_64,
FlowArch::Aarch64 => CommonArchCli::Aarch64,
arch => anyhow::bail!("unsupported arch {arch}"),
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::run_cargo_build::common::CommonArch;
use flowey::node::prelude::*;

flowey_request! {
pub struct Params {
pub igvm_payload: PathBuf,
pub arch: CommonArch,

pub artifact_dir: ReadVar<PathBuf>,
pub done: WriteVar<SideEffect>,
}
}

new_simple_flow_node!(struct Node);

impl SimpleFlowNode for Node {
type Request = Params;

fn imports(ctx: &mut ImportCtx<'_>) {
ctx.import::<crate::build_vmfirmwareigvm_dll::Node>();
}

fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
let Params {
arch,
igvm_payload,

artifact_dir,
done,
} = request;

let built_dll = ctx.reqv(|v| crate::build_vmfirmwareigvm_dll::Request {
arch,
igvm: ReadVar::from_static(crate::run_igvmfilegen::IgvmOutput {
igvm_bin: igvm_payload,
igvm_map: None,
igvm_tdx_json: None,
igvm_snp_json: None,
igvm_vbs_json: None,
}),
// fixed version to signal that this is a custom dll
dll_version: ReadVar::from_static((1, 0, 1337, 0)),
internal_dll_name: "vmfirmwareigvm.dll".into(),
vmfirmwareigvm_dll: v,
});

ctx.emit_rust_step("copy resulting vmfirmwareigvm.dll", |ctx| {
done.claim(ctx);
let artifact_dir = artifact_dir.claim(ctx);
let built_dll = built_dll.claim(ctx);
|rt| {
let artifact_dir = rt.read(artifact_dir);
let built_dll = rt.read(built_dll);

fs_err::copy(built_dll.dll, artifact_dir.join("vmfirmwareigvm.dll"))?;

for e in fs_err::read_dir(artifact_dir)? {
let e = e?;
log::info!("{}", e.path().display());
}
Ok(())
}
});

Ok(())
}
}
Loading