use std::fs::OpenOptions;
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
use base::MemoryMappingBuilder;
use hypervisor::MemCacheType;
use hypervisor::Vm;
use resources::AddressRange;
use vm_memory::GuestAddress;
use crate::Pstore;
mod sys;
pub struct RamoopsRegion {
    pub address: u64,
    pub size: u32,
}
pub fn create_memory_region(
    vm: &mut impl Vm,
    region: AddressRange,
    pstore: &Pstore,
) -> Result<RamoopsRegion> {
    let region_size = region.len().context("failed to get region len")?;
    if region_size < pstore.size.into() {
        bail!("insufficient space for pstore {} {}", region, pstore.size);
    }
    let mut open_opts = OpenOptions::new();
    open_opts.read(true).write(true).create(true);
    sys::set_extra_open_opts(&mut open_opts);
    let file = open_opts
        .open(&pstore.path)
        .context("failed to open pstore")?;
    file.set_len(pstore.size as u64)
        .context("failed to set pstore length")?;
    let memory_mapping = MemoryMappingBuilder::new(pstore.size as usize)
        .from_file(&file)
        .build()
        .context("failed to mmap pstore")?;
    vm.add_memory_region(
        GuestAddress(region.start),
        Box::new(memory_mapping),
        false,
        false,
        MemCacheType::CacheCoherent,
    )
    .context("failed to add pstore region")?;
    Ok(RamoopsRegion {
        address: region.start,
        size: pstore.size,
    })
}
pub fn add_ramoops_kernel_cmdline(
    cmdline: &mut kernel_cmdline::Cmdline,
    ramoops_region: &RamoopsRegion,
) -> std::result::Result<(), kernel_cmdline::Error> {
    let ramoops_opts = [
        ("mem_address", ramoops_region.address),
        ("mem_size", ramoops_region.size as u64),
    ];
    for (name, val) in &ramoops_opts {
        cmdline.insert_str(format!("ramoops.{}={:#x}", name, val))?;
    }
    Ok(())
}