use alloc::format;
use uefi::boot::{allocate_pool, MemoryType};
use uefi::runtime::{set_variable, VariableAttributes, VariableVendor};
use uefi::{CString16, Guid};
use vck_common::handover::payload::{
encode_locator, encode_payload, HandoverLocator, HandoverPayload,
};
use vck_common::{VckError, VckResult};
pub fn install_handover<P: HandoverPayload>(payload: &P) -> VckResult<()> {
let data = encode_payload(payload)?;
let len = data.len();
let buf = allocate_pool(MemoryType::RUNTIME_SERVICES_DATA, len).map_err(|e| {
VckError::Io(format!(
"allocate_pool(RUNTIME_SERVICES_DATA, {len}) failed: {e:?}"
))
})?;
unsafe {
core::ptr::copy_nonoverlapping(data.as_ptr(), buf.as_ptr(), len);
}
let address = buf.as_ptr() as u64;
let locator = HandoverLocator::new(address, len as u64);
let loc_bytes = encode_locator(&locator)?;
let name = CString16::try_from(P::VAR_NAME)
.map_err(|_| VckError::InvalidData("handover variable name not valid UCS-2"))?;
let vendor = VariableVendor(Guid::from_bytes(P::VAR_GUID));
let attrs = VariableAttributes::BOOTSERVICE_ACCESS | VariableAttributes::RUNTIME_ACCESS;
set_variable(&name, &vendor, attrs, &loc_bytes)
.map_err(|e| VckError::Io(format!("SetVariable(handover locator) failed: {e:?}")))
}