// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
// Copyright © 2023, Microsoft Corporation
//
/*
 *  The IGVM(Independent Guest Virtual Machine) file format
 *  is designed to encapsulate all information required to
 *  launch a virtual machine on any given virtualization stack,
 *  with support for different isolation technologies such as
 *  AMD SEV-SNP and Intel TDX.
 *  At a conceptual level, this file format is a set of commands created
 *  by the tool that generated the file, used by the loader to construct
 *  the initial guest state. The file format also contains measurement
 *  information that the underlying platform will use to confirm that
 *  the file was loaded correctly and signed by the appropriate authorities.
 *
 *  The IGVM file is generated by the tool:
 *  https://github.com/microsoft/igvm-tooling
 *
 *  The IGVM file is parsed by the following crates:
 *  https://github.com/microsoft/igvm
 *
 *  This module takes the IGVM file, parses it, and loads it to the
 *  guest memory. Currently igvm only supported on Microsoft Hypervisor, as
 *  booting a legacy VM, as well as SNP based isolated VM.
 */

pub mod igvm_loader;
mod loader;
use std::path::Path;

use igvm::snp_defs::SevVmsa;
use igvm::{IgvmFile, IsolationType};
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
use zerocopy::FromZeros;

pub fn parse_igvm(igvm_path: &Path) -> Result<IgvmFile, igvm_loader::Error> {
    let file_contents = std::fs::read(igvm_path).map_err(igvm_loader::Error::Igvm)?;
    IgvmFile::new_from_binary(&file_contents, Some(IsolationType::Snp))
        .map_err(igvm_loader::Error::InvalidIgvmFile)
}

#[derive(Debug, Clone)]
pub struct IgvmLoadedInfo {
    pub gpas: Vec<u64>,
    pub vmsa_gpa: u64,
    pub snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
    pub has_snp_id_block: bool,
    pub vmsa: SevVmsa,
}

impl Default for IgvmLoadedInfo {
    fn default() -> Self {
        IgvmLoadedInfo {
            gpas: Vec::new(),
            vmsa_gpa: 0,
            snp_id_block: IGVM_VHS_SNP_ID_BLOCK::new_zeroed(),
            has_snp_id_block: false,
            vmsa: SevVmsa::new_zeroed(),
        }
    }
}

pub const HV_PAGE_SIZE: u64 = 4096;

/// The page acceptance used for importing pages into the initial launch context of the guest.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BootPageAcceptance {
    /// The page is accepted exclusive (no host visibility) and the page data is measured.
    Exclusive,
    /// The page is accepted exclusive (no host visibility) and the page data is unmeasured.
    ExclusiveUnmeasured,
    /// The page contains hardware-specific VP context information.
    VpContext,
    /// This page communicates error information to the host.
    ErrorPage,
    /// This page communicates hardware-specific secret information and the page data is unmeasured.
    SecretsPage,
    /// This page includes guest-specified CPUID information.
    CpuidPage,
    /// This page should include the enumeration of extended state CPUID leaves.
    CpuidExtendedStatePage,
}

/// The startup memory type used to notify a well behaved host that memory should be present before attempting to
/// start the guest.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum StartupMemoryType {
    /// The range is normal memory.
    Ram,
}
