mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
hvm nonredist
This commit is contained in:
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -320,6 +320,26 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "c2rust-bitfields"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b43c3f07ab0ef604fa6f595aa46ec2f8a22172c975e186f6f5bf9829a3b72c41"
|
||||
dependencies = [
|
||||
"c2rust-bitfields-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "c2rust-bitfields-derive"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3cbc102e2597c9744c8bd8c15915d554300601c91a079430d309816b0912545"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
@ -1606,6 +1626,7 @@ name = "krata-xenclient"
|
||||
version = "0.0.10"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"c2rust-bitfields",
|
||||
"elf",
|
||||
"env_logger",
|
||||
"flate2",
|
||||
|
@ -227,7 +227,7 @@ impl GuestLauncher {
|
||||
kernel: request.kernel,
|
||||
initrd: request.initrd,
|
||||
cmdline,
|
||||
use_console_backend: Some("krata-console".to_string()),
|
||||
swap_console_backend: Some("krata-console".to_string()),
|
||||
disks,
|
||||
channels: vec![DomainChannel {
|
||||
typ: "krata-channel".to_string(),
|
||||
|
@ -3,7 +3,7 @@ pub mod sys;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::sys::{
|
||||
AddressSize, AssignDevice, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
||||
AddToPhysmap, AddressSize, AssignDevice, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
||||
EvtChnAllocUnbound, GetDomainInfo, GetPageFrameInfo3, HvmContext, HvmParam, Hypercall,
|
||||
HypercallInit, IoMemPermission, IoPortPermission, IrqPermission, MaxMem, MaxVcpus, MemoryMap,
|
||||
MemoryReservation, MmapBatch, MmapResource, MmuExtOp, MultiCallEntry, PagingMempool,
|
||||
@ -15,7 +15,8 @@ use crate::sys::{
|
||||
XEN_DOMCTL_IOMEM_PERMISSION, XEN_DOMCTL_IOPORT_PERMISSION, XEN_DOMCTL_IRQ_PERMISSION,
|
||||
XEN_DOMCTL_MAX_MEM, XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETHVMCONTEXT,
|
||||
XEN_DOMCTL_SETVCPUCONTEXT, XEN_DOMCTL_SET_ADDRESS_SIZE, XEN_DOMCTL_SET_PAGING_MEMPOOL_SIZE,
|
||||
XEN_DOMCTL_UNPAUSEDOMAIN, XEN_MEM_CLAIM_PAGES, XEN_MEM_MEMORY_MAP, XEN_MEM_POPULATE_PHYSMAP,
|
||||
XEN_DOMCTL_UNPAUSEDOMAIN, XEN_MEM_ADD_TO_PHYSMAP, XEN_MEM_CLAIM_PAGES, XEN_MEM_MEMORY_MAP,
|
||||
XEN_MEM_POPULATE_PHYSMAP,
|
||||
};
|
||||
use libc::{c_int, mmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
|
||||
use log::trace;
|
||||
@ -653,6 +654,31 @@ impl XenCall {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add_to_physmap(&self, domid: u32, space: u32, idx: u64, pfn: u64) -> Result<()> {
|
||||
trace!(
|
||||
"memory fd={} add_to_physmap domid={} space={} idx={} pfn={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
space,
|
||||
idx,
|
||||
pfn,
|
||||
);
|
||||
let mut add = AddToPhysmap {
|
||||
domid: domid as u16,
|
||||
size: 0,
|
||||
space,
|
||||
idx,
|
||||
gpfn: pfn,
|
||||
};
|
||||
self.hypercall2(
|
||||
HYPERVISOR_MEMORY_OP,
|
||||
XEN_MEM_ADD_TO_PHYSMAP as c_ulong,
|
||||
addr_of_mut!(add) as c_ulong,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn mmuext(&self, domid: u32, cmd: c_uint, arg1: u64, arg2: u64) -> Result<()> {
|
||||
let mut ops = MmuExtOp { cmd, arg1, arg2 };
|
||||
|
||||
|
@ -401,6 +401,16 @@ pub struct MemoryReservation {
|
||||
pub domid: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AddToPhysmap {
|
||||
pub domid: u16,
|
||||
pub size: u16,
|
||||
pub space: u32,
|
||||
pub idx: u64,
|
||||
pub gpfn: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MultiCallEntry {
|
||||
@ -413,6 +423,7 @@ pub const XEN_MEM_POPULATE_PHYSMAP: u32 = 6;
|
||||
pub const XEN_MEM_MEMORY_MAP: u32 = 10;
|
||||
pub const XEN_MEM_SET_MEMORY_MAP: u32 = 13;
|
||||
pub const XEN_MEM_CLAIM_PAGES: u32 = 24;
|
||||
pub const XEN_MEM_ADD_TO_PHYSMAP: u32 = 7;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -10,6 +10,7 @@ resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
c2rust-bitfields = "0.18.0"
|
||||
elf = { workspace = true }
|
||||
flate2 = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
|
@ -20,11 +20,11 @@ async fn main() -> Result<()> {
|
||||
backend_domid: 0,
|
||||
name: "xenclient-test".to_string(),
|
||||
max_vcpus: 1,
|
||||
mem_mb: 512,
|
||||
mem_mb: 300,
|
||||
kernel: fs::read(&kernel_image_path).await?,
|
||||
initrd: fs::read(&initrd_path).await?,
|
||||
cmdline: "debug elevator=noop".to_string(),
|
||||
use_console_backend: None,
|
||||
cmdline: "debug elevator=noop earlyprintk=xen".to_string(),
|
||||
swap_console_backend: None,
|
||||
disks: vec![],
|
||||
channels: vec![],
|
||||
vifs: vec![],
|
||||
|
@ -37,12 +37,14 @@ pub struct BootDomain {
|
||||
pub virt_pgtab_end: u64,
|
||||
pub total_pages: u64,
|
||||
pub target_pages: u64,
|
||||
pub max_vcpus: u32,
|
||||
pub image_info: BootImageInfo,
|
||||
pub phys: PhysicalPages,
|
||||
pub store_evtchn: u32,
|
||||
pub store_mfn: u64,
|
||||
pub initrd_segment: DomainSegment,
|
||||
pub consoles: Vec<(u32, u64)>,
|
||||
pub cmdline: String,
|
||||
}
|
||||
|
||||
impl BootDomain {
|
||||
@ -157,9 +159,15 @@ impl<I: BootImageLoader, P: BootSetupPlatform> BootSetup<I, P> {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize(&mut self, initrd: &[u8], mem_mb: u64) -> Result<BootDomain> {
|
||||
pub async fn initialize(
|
||||
&mut self,
|
||||
initrd: &[u8],
|
||||
mem_mb: u64,
|
||||
max_vcpus: u32,
|
||||
cmdline: &str,
|
||||
) -> Result<BootDomain> {
|
||||
let total_pages = mem_mb << (20 - self.platform.page_shift());
|
||||
let image_info = self.image_loader.parse().await?;
|
||||
let image_info = self.image_loader.parse(true).await?;
|
||||
let mut domain = BootDomain {
|
||||
domid: self.domid,
|
||||
call: self.call.clone(),
|
||||
@ -171,10 +179,12 @@ impl<I: BootImageLoader, P: BootSetupPlatform> BootSetup<I, P> {
|
||||
page_size: self.platform.page_size(),
|
||||
image_info,
|
||||
consoles: Vec::new(),
|
||||
max_vcpus,
|
||||
phys: PhysicalPages::new(self.call.clone(), self.domid, self.platform.page_shift()),
|
||||
initrd_segment: DomainSegment::default(),
|
||||
store_evtchn: 0,
|
||||
store_mfn: 0,
|
||||
cmdline: cmdline.to_string(),
|
||||
};
|
||||
|
||||
self.platform.initialize_early(&mut domain).await?;
|
||||
@ -294,7 +304,7 @@ pub trait BootSetupPlatform: Clone {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait BootImageLoader {
|
||||
async fn parse(&self) -> Result<BootImageInfo>;
|
||||
async fn parse(&self, hvm: bool) -> Result<BootImageInfo>;
|
||||
async fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()>;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use crate::boot::{BootImageInfo, BootImageLoader};
|
||||
use crate::error::Result;
|
||||
use crate::sys::{
|
||||
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_INIT_P2M, XEN_ELFNOTE_MOD_START_PFN,
|
||||
XEN_ELFNOTE_PADDR_OFFSET, XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE,
|
||||
XEN_ELFNOTE_PADDR_OFFSET, XEN_ELFNOTE_PHYS32_ENTRY, XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE,
|
||||
};
|
||||
use crate::Error;
|
||||
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
|
||||
@ -130,7 +130,7 @@ struct ElfNoteValue {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BootImageLoader for ElfImageLoader {
|
||||
async fn parse(&self) -> Result<BootImageInfo> {
|
||||
async fn parse(&self, hvm: bool) -> Result<BootImageInfo> {
|
||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
||||
let headers = elf.section_headers().ok_or(Error::ElfInvalidImage)?;
|
||||
let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
|
||||
@ -201,6 +201,8 @@ impl BootImageLoader for ElfImageLoader {
|
||||
.ok_or(Error::ElfInvalidImage)?
|
||||
.value;
|
||||
|
||||
let phys32_entry = xen_notes.get(&XEN_ELFNOTE_PHYS32_ENTRY).map(|x| x.value);
|
||||
|
||||
let mut start: u64 = u64::MAX;
|
||||
let mut end: u64 = 0;
|
||||
|
||||
@ -228,8 +230,14 @@ impl BootImageLoader for ElfImageLoader {
|
||||
let virt_offset = virt_base - paddr_offset;
|
||||
let virt_kstart = start + virt_offset;
|
||||
let virt_kend = end + virt_offset;
|
||||
let virt_entry = entry;
|
||||
|
||||
let mut virt_entry = entry;
|
||||
if hvm {
|
||||
if let Some(entry) = phys32_entry {
|
||||
virt_entry = entry;
|
||||
} else {
|
||||
virt_entry = elf.ehdr.e_entry;
|
||||
}
|
||||
}
|
||||
let image_info = BootImageInfo {
|
||||
start,
|
||||
virt_base,
|
||||
|
@ -27,6 +27,7 @@ use xenstore::{
|
||||
};
|
||||
|
||||
pub mod pci;
|
||||
mod x86acpi;
|
||||
pub mod x86pv;
|
||||
pub mod x86pvh;
|
||||
|
||||
@ -113,7 +114,7 @@ pub struct DomainConfig {
|
||||
pub initrd: Vec<u8>,
|
||||
pub cmdline: String,
|
||||
pub disks: Vec<DomainDisk>,
|
||||
pub use_console_backend: Option<String>,
|
||||
pub swap_console_backend: Option<String>,
|
||||
pub channels: Vec<DomainChannel>,
|
||||
pub vifs: Vec<DomainNetworkInterface>,
|
||||
pub filesystems: Vec<DomainFilesystem>,
|
||||
@ -280,14 +281,21 @@ impl XenClient {
|
||||
|
||||
self.call.set_max_vcpus(domid, config.max_vcpus).await?;
|
||||
self.call
|
||||
.set_max_mem(domid, (config.mem_mb * 1024) + 1024)
|
||||
.set_max_mem(domid, (config.mem_mb * 1024) + 2048)
|
||||
.await?;
|
||||
let mut domain: BootDomain;
|
||||
{
|
||||
let loader = ElfImageLoader::load_file_kernel(&config.kernel)?;
|
||||
let platform = (*self.platform).clone();
|
||||
let mut boot = BootSetup::new(self.call.clone(), domid, platform, loader, None);
|
||||
domain = boot.initialize(&config.initrd, config.mem_mb).await?;
|
||||
domain = boot
|
||||
.initialize(
|
||||
&config.initrd,
|
||||
config.mem_mb,
|
||||
config.max_vcpus,
|
||||
&config.cmdline,
|
||||
)
|
||||
.await?;
|
||||
boot.boot(&mut domain, &config.cmdline).await?;
|
||||
}
|
||||
|
||||
@ -350,11 +358,11 @@ impl XenClient {
|
||||
&tx,
|
||||
&DomainChannel {
|
||||
typ: config
|
||||
.use_console_backend
|
||||
.swap_console_backend
|
||||
.clone()
|
||||
.unwrap_or("xenconsoled".to_string())
|
||||
.to_string(),
|
||||
initialized: true,
|
||||
initialized: false,
|
||||
},
|
||||
&dom_path,
|
||||
&backend_dom_path,
|
||||
@ -490,7 +498,7 @@ impl XenClient {
|
||||
("virtual-device", id.to_string()),
|
||||
("device-type", "disk".to_string()),
|
||||
("trusted", "1".to_string()),
|
||||
("protocol", "x86_64-abi".to_string()),
|
||||
("protocol", "x86_32-abi".to_string()),
|
||||
];
|
||||
|
||||
self.device_add(
|
||||
|
@ -131,7 +131,7 @@ pub struct GrantEntry {
|
||||
pub frame: u32,
|
||||
}
|
||||
|
||||
pub const XEN_HVM_START_MAGIC_VALUE: u64 = 0x336ec578;
|
||||
pub const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
||||
|
||||
pub const HVM_PARAM_STORE_PFN: u32 = 1;
|
||||
pub const HVM_PARAM_STORE_EVTCHN: u32 = 2;
|
||||
@ -144,3 +144,4 @@ pub const HVM_PARAM_MONITOR_RING_PFN: u32 = 28;
|
||||
pub const HVM_PARAM_SHARING_RING_PFN: u32 = 29;
|
||||
pub const HVM_PARAM_TIMER_MODE: u32 = 10;
|
||||
pub const HVM_PARAM_ALTP2M: u32 = 35;
|
||||
pub const HVM_PARAM_IDENT_PT: u32 = 12;
|
||||
|
29727
crates/xen/xenclient/src/x86acpi.rs
Normal file
29727
crates/xen/xenclient/src/x86acpi.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,13 @@
|
||||
use std::{
|
||||
mem::{size_of, MaybeUninit},
|
||||
os::raw::{c_char, c_void},
|
||||
ptr::addr_of_mut,
|
||||
ptr::{addr_of, addr_of_mut},
|
||||
slice,
|
||||
};
|
||||
|
||||
use libc::munmap;
|
||||
use libc::{c_void, malloc, munmap};
|
||||
use nix::errno::Errno;
|
||||
use xencall::sys::{
|
||||
ArchDomainConfig, CreateDomain, E820Entry, E820_RAM, E820_RESERVED,
|
||||
ArchDomainConfig, CreateDomain, E820Entry, E820_ACPI, E820_RAM, E820_RESERVED,
|
||||
MEMFLAGS_POPULATE_ON_DEMAND, XEN_DOMCTL_CDF_HAP, XEN_DOMCTL_CDF_HVM_GUEST,
|
||||
XEN_DOMCTL_CDF_IOMMU, XEN_X86_EMU_LAPIC,
|
||||
};
|
||||
@ -17,74 +16,16 @@ use crate::{
|
||||
boot::{BootDomain, BootSetupPlatform, DomainSegment},
|
||||
error::{Error, Result},
|
||||
sys::{
|
||||
GrantEntry, HVM_PARAM_ALTP2M, HVM_PARAM_BUFIOREQ_PFN, HVM_PARAM_CONSOLE_PFN,
|
||||
HVM_PARAM_IOREQ_PFN, HVM_PARAM_MONITOR_RING_PFN, HVM_PARAM_PAGING_RING_PFN,
|
||||
HVM_PARAM_SHARING_RING_PFN, HVM_PARAM_STORE_PFN, HVM_PARAM_TIMER_MODE, XEN_PAGE_SHIFT,
|
||||
GrantEntry, HVM_PARAM_ALTP2M, HVM_PARAM_BUFIOREQ_PFN, HVM_PARAM_CONSOLE_EVTCHN,
|
||||
HVM_PARAM_CONSOLE_PFN, HVM_PARAM_IDENT_PT, HVM_PARAM_IOREQ_PFN, HVM_PARAM_MONITOR_RING_PFN,
|
||||
HVM_PARAM_PAGING_RING_PFN, HVM_PARAM_SHARING_RING_PFN, HVM_PARAM_STORE_EVTCHN,
|
||||
HVM_PARAM_STORE_PFN, HVM_PARAM_TIMER_MODE, XEN_HVM_START_MAGIC_VALUE, XEN_PAGE_SHIFT,
|
||||
},
|
||||
x86acpi::{acpi_build_tables, acpi_config, acpi_ctxt, acpi_mem_ops, dsdt_pvh, hvm_info_table},
|
||||
};
|
||||
|
||||
pub const X86_PAGE_SHIFT: u64 = 12;
|
||||
pub const X86_PAGE_SIZE: u64 = 1 << X86_PAGE_SHIFT;
|
||||
pub const X86_VIRT_BITS: u64 = 48;
|
||||
pub const X86_VIRT_MASK: u64 = (1 << X86_VIRT_BITS) - 1;
|
||||
pub const X86_PGTABLE_LEVELS: u64 = 4;
|
||||
pub const X86_PGTABLE_LEVEL_SHIFT: u64 = 9;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PageTableMappingLevel {
|
||||
pub from: u64,
|
||||
pub to: u64,
|
||||
pub pfn: u64,
|
||||
pub pgtables: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PageTableMapping {
|
||||
pub area: PageTableMappingLevel,
|
||||
pub levels: [PageTableMappingLevel; X86_PGTABLE_LEVELS as usize],
|
||||
}
|
||||
|
||||
pub const X86_PAGE_TABLE_MAX_MAPPINGS: usize = 2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PageTable {
|
||||
pub mappings_count: usize,
|
||||
pub mappings: [PageTableMapping; X86_PAGE_TABLE_MAX_MAPPINGS],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct StartInfoConsole {
|
||||
pub mfn: u64,
|
||||
pub evtchn: u32,
|
||||
}
|
||||
|
||||
pub const MAX_GUEST_CMDLINE: usize = 1024;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct StartInfo {
|
||||
pub magic: [c_char; 32],
|
||||
pub nr_pages: u64,
|
||||
pub shared_info: u64,
|
||||
pub flags: u32,
|
||||
pub store_mfn: u64,
|
||||
pub store_evtchn: u32,
|
||||
pub console: StartInfoConsole,
|
||||
pub pt_base: u64,
|
||||
pub nr_pt_frames: u64,
|
||||
pub mfn_list: u64,
|
||||
pub mod_start: u64,
|
||||
pub mod_len: u64,
|
||||
pub cmdline: [c_char; MAX_GUEST_CMDLINE],
|
||||
pub first_p2m_pfn: u64,
|
||||
pub nr_p2m_frames: u64,
|
||||
}
|
||||
|
||||
pub const X86_GUEST_MAGIC: &str = "xen-3.0-x86_64";
|
||||
const X86_PAGE_SHIFT: u64 = 12;
|
||||
const X86_PAGE_SIZE: u64 = 1 << X86_PAGE_SHIFT;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Copy, Clone, Debug)]
|
||||
@ -238,6 +179,27 @@ struct BspCtx {
|
||||
end: HvmEnd,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct HvmMtrr {
|
||||
msr_pat_cr: u64,
|
||||
msr_mtrr_var: [u64; 16],
|
||||
msr_mtrr_fixed: [u64; 11],
|
||||
msr_mtrr_cap: u64,
|
||||
msr_mtrr_def_type: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct MtrrCtx {
|
||||
header_d: HvmSaveDescriptor,
|
||||
header: HvmSaveHeader,
|
||||
mtrr_d: HvmSaveDescriptor,
|
||||
mtrr: HvmMtrr,
|
||||
end_d: HvmSaveDescriptor,
|
||||
end: HvmEnd,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VmemRange {
|
||||
start: u64,
|
||||
@ -246,12 +208,20 @@ struct VmemRange {
|
||||
_nid: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct AcpiModule {
|
||||
data: u64,
|
||||
length: u32,
|
||||
guest_addr: u64,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct X86PvhPlatform {
|
||||
start_info_segment: Option<DomainSegment>,
|
||||
lowmem_end: u64,
|
||||
highmem_end: u64,
|
||||
mmio_start: u64,
|
||||
acpi_modules: Vec<AcpiModule>,
|
||||
}
|
||||
|
||||
const X86_CR0_PE: u64 = 0x01;
|
||||
@ -285,6 +255,14 @@ impl X86PvhPlatform {
|
||||
typ: E820_RESERVED,
|
||||
});
|
||||
|
||||
for module in &self.acpi_modules {
|
||||
entries.push(E820Entry {
|
||||
addr: module.guest_addr & !(self.page_size() - 1),
|
||||
size: module.length as u64 + (module.guest_addr & (self.page_size() - 1)),
|
||||
typ: E820_ACPI,
|
||||
});
|
||||
}
|
||||
|
||||
if highmem_size > 0 {
|
||||
entries.push(E820Entry {
|
||||
addr: 1u64 << 32,
|
||||
@ -296,11 +274,31 @@ impl X86PvhPlatform {
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
const _PAGE_PRESENT: u64 = 0x001;
|
||||
const _PAGE_RW: u64 = 0x002;
|
||||
const _PAGE_USER: u64 = 0x004;
|
||||
const _PAGE_ACCESSED: u64 = 0x020;
|
||||
const _PAGE_DIRTY: u64 = 0x040;
|
||||
unsafe fn get_save_record<T: Sized>(ctx: &mut [u8], typ: u16, instance: u16) -> *mut T {
|
||||
let mut ptr = ctx.as_mut_ptr();
|
||||
loop {
|
||||
let sd = ptr as *mut HvmSaveDescriptor;
|
||||
|
||||
if (*sd).typecode == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*sd).typecode == typ && (*sd).instance == instance {
|
||||
return ptr.add(size_of::<HvmSaveDescriptor>()) as *mut T;
|
||||
}
|
||||
ptr = ptr
|
||||
.add(size_of::<HvmSaveDescriptor>())
|
||||
.add((*sd).length as usize) as *mut u8;
|
||||
}
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
|
||||
const PAGE_PRESENT: u32 = 0x001;
|
||||
const PAGE_RW: u32 = 0x002;
|
||||
const PAGE_USER: u32 = 0x004;
|
||||
const PAGE_ACCESSED: u32 = 0x020;
|
||||
const PAGE_DIRTY: u32 = 0x040;
|
||||
const PAGE_PSE: u32 = 0x080;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@ -329,6 +327,111 @@ impl BootSetupPlatform for X86PvhPlatform {
|
||||
}
|
||||
|
||||
async fn initialize_early(&mut self, domain: &mut BootDomain) -> Result<()> {
|
||||
{
|
||||
let mut config: acpi_config = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
let mut hvminfo: Vec<hvm_info_table> =
|
||||
vec![unsafe { MaybeUninit::zeroed().assume_init() }; 1];
|
||||
config.hvminfo = hvminfo.as_ptr();
|
||||
let h = hvminfo.get_mut(0).unwrap();
|
||||
h.nr_vcpus = domain.max_vcpus;
|
||||
for i in 0..domain.max_vcpus {
|
||||
h.vcpu_online[(i / 8) as usize] |= 1 << (i & 7);
|
||||
}
|
||||
config.lapic_base_address = LAPIC_BASE_ADDRESS as u32;
|
||||
config.lapic_id = Some(acpi_lapic_id);
|
||||
config.acpi_revision = 5;
|
||||
unsafe {
|
||||
config.dsdt_15cpu = addr_of!(dsdt_pvh) as *mut u8;
|
||||
config.dsdt_15cpu_len = dsdt_pvh.len() as u32;
|
||||
config.dsdt_anycpu = addr_of!(dsdt_pvh) as *mut u8;
|
||||
config.dsdt_anycpu_len = dsdt_pvh.len() as u32;
|
||||
};
|
||||
unsafe {
|
||||
config.rsdp = malloc(self.page_size() as usize) as u64;
|
||||
config.infop = malloc(self.page_size() as usize) as u64;
|
||||
let buf = malloc((8 * self.page_size()) as usize);
|
||||
let mut ctx = AcpiBuildContext {
|
||||
page_size: self.page_size(),
|
||||
page_shift: self.page_shift(),
|
||||
buf: buf as *mut u8,
|
||||
guest_start: ACPI_INFO_PHYSICAL_ADDRESS + self.page_size(),
|
||||
guest_curr: ACPI_INFO_PHYSICAL_ADDRESS + self.page_size(),
|
||||
guest_end: ACPI_INFO_PHYSICAL_ADDRESS
|
||||
+ self.page_size()
|
||||
+ (8 * self.page_size()),
|
||||
};
|
||||
let mut ctxt = acpi_ctxt {
|
||||
ptr: addr_of_mut!(ctx) as *mut c_void,
|
||||
mem_ops: acpi_mem_ops {
|
||||
alloc: Some(acpi_mem_alloc),
|
||||
free: Some(acpi_mem_free),
|
||||
v2p: Some(acpi_v2p),
|
||||
},
|
||||
};
|
||||
if acpi_build_tables(addr_of_mut!(ctxt), addr_of_mut!(config)) > 0 {
|
||||
return Err(Error::GenericError("acpi_build_tables failed".to_string()));
|
||||
}
|
||||
|
||||
let acpi_pages_num = (align_it(ctx.guest_curr, self.page_size()) - ctx.guest_start)
|
||||
>> self.page_shift();
|
||||
self.acpi_modules.push(AcpiModule {
|
||||
data: config.rsdp,
|
||||
length: 64,
|
||||
guest_addr: ACPI_INFO_PHYSICAL_ADDRESS
|
||||
+ (1 + acpi_pages_num) * self.page_size(),
|
||||
});
|
||||
|
||||
self.acpi_modules.push(AcpiModule {
|
||||
data: config.infop,
|
||||
length: 4096,
|
||||
guest_addr: ACPI_INFO_PHYSICAL_ADDRESS,
|
||||
});
|
||||
|
||||
self.acpi_modules.push(AcpiModule {
|
||||
data: ctx.buf as u64,
|
||||
length: (acpi_pages_num << self.page_shift()) as u32,
|
||||
guest_addr: ACPI_INFO_PHYSICAL_ADDRESS + self.page_size(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for module in &self.acpi_modules {
|
||||
let num_pages = ((module.length as u64
|
||||
+ (module.guest_addr & !(!(self.page_size() - 1))))
|
||||
+ (self.page_size() - 1))
|
||||
>> self.page_shift();
|
||||
let base = module.guest_addr >> self.page_shift();
|
||||
for i in 0..num_pages {
|
||||
let e = base + i;
|
||||
if domain
|
||||
.call
|
||||
.populate_physmap(domain.domid, 1, 0, 0, &[e])
|
||||
.await
|
||||
.unwrap_or(Vec::new())
|
||||
.len()
|
||||
== 1
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let idx = self.lowmem_end;
|
||||
self.lowmem_end -= 1;
|
||||
domain.call.add_to_physmap(domain.domid, 2, idx, e).await?;
|
||||
}
|
||||
|
||||
let ptr = domain
|
||||
.phys
|
||||
.map_foreign_pages(base, num_pages << self.page_shift())
|
||||
.await? as *mut u8;
|
||||
let dst = unsafe { std::slice::from_raw_parts_mut(ptr, module.length as usize) };
|
||||
let src = unsafe {
|
||||
std::slice::from_raw_parts(module.data as *mut u8, module.length as usize)
|
||||
};
|
||||
slice_copy::copy(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
let mut memory_start =
|
||||
(X86_HVM_END_SPECIAL_REGION - X86_HVM_NR_SPECIAL_PAGES) << self.page_shift();
|
||||
memory_start = memory_start.min(LAPIC_BASE_ADDRESS);
|
||||
@ -526,11 +629,34 @@ impl BootSetupPlatform for X86PvhPlatform {
|
||||
.await?;
|
||||
|
||||
let mut start_info_size = size_of::<HvmStartInfo>();
|
||||
|
||||
start_info_size += BootDomain::round_up("".len() as u64 + 3, 3) as usize;
|
||||
start_info_size += domain.cmdline.len() + 1;
|
||||
start_info_size += size_of::<E820Entry>() * memmap.len();
|
||||
|
||||
self.start_info_segment = Some(domain.alloc_segment(0, start_info_size as u64).await?);
|
||||
|
||||
let pt = domain
|
||||
.phys
|
||||
.map_foreign_pages(special_pfn(SPECIALPAGE_IDENT_PT), self.page_size())
|
||||
.await? as *mut u32;
|
||||
for i in 0..(self.page_size() / size_of::<u32>() as u64) {
|
||||
unsafe {
|
||||
*(pt.offset(i as isize)) = ((i as u32) << 22)
|
||||
| X86PvhPlatform::PAGE_PRESENT
|
||||
| X86PvhPlatform::PAGE_RW
|
||||
| X86PvhPlatform::PAGE_USER
|
||||
| X86PvhPlatform::PAGE_ACCESSED
|
||||
| X86PvhPlatform::PAGE_DIRTY
|
||||
| X86PvhPlatform::PAGE_PSE;
|
||||
}
|
||||
}
|
||||
domain
|
||||
.call
|
||||
.set_hvm_param(
|
||||
domain.domid,
|
||||
HVM_PARAM_IDENT_PT,
|
||||
special_pfn(SPECIALPAGE_IDENT_PT),
|
||||
)
|
||||
.await?;
|
||||
|
||||
domain.consoles.push((0, special_pfn(SPECIALPAGE_CONSOLE)));
|
||||
domain.store_mfn = special_pfn(SPECIALPAGE_XENSTORE);
|
||||
|
||||
@ -541,11 +667,63 @@ impl BootSetupPlatform for X86PvhPlatform {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn setup_start_info(&mut self, _: &mut BootDomain, _: &str, _: u64) -> Result<()> {
|
||||
async fn setup_start_info(&mut self, domain: &mut BootDomain, _: &str, _: u64) -> Result<()> {
|
||||
let memmap = self.construct_memmap()?;
|
||||
let start_info_segment = self
|
||||
.start_info_segment
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::GenericError("start_info_segment missing".to_string()))?;
|
||||
let ptr = domain.phys.pfn_to_ptr(start_info_segment.pfn, 1).await?;
|
||||
let byte_slice =
|
||||
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) };
|
||||
byte_slice.fill(0);
|
||||
let info = ptr as *mut HvmStartInfo;
|
||||
unsafe {
|
||||
(*info).magic = XEN_HVM_START_MAGIC_VALUE;
|
||||
(*info).version = 1;
|
||||
(*info).cmdline_paddr =
|
||||
(start_info_segment.pfn << self.page_shift()) + size_of::<HvmStartInfo>() as u64;
|
||||
(*info).memmap_paddr = (start_info_segment.pfn << self.page_shift())
|
||||
+ size_of::<HvmStartInfo>() as u64
|
||||
+ domain.cmdline.len() as u64
|
||||
+ 1;
|
||||
(*info).memmap_entries = memmap.len() as u32;
|
||||
(*info).rsdp_paddr = self.acpi_modules[0].guest_addr;
|
||||
};
|
||||
let cmdline_ptr = (ptr + size_of::<HvmStartInfo>() as u64) as *mut u8;
|
||||
for (i, c) in domain.cmdline.chars().enumerate() {
|
||||
unsafe { *cmdline_ptr.add(i) = c as u8 };
|
||||
}
|
||||
let entries = (ptr + size_of::<HvmStartInfo>() as u64 + domain.cmdline.len() as u64 + 1)
|
||||
as *mut HvmMemmapTableEntry;
|
||||
let entries = unsafe { std::slice::from_raw_parts_mut(entries, memmap.len()) };
|
||||
for (i, e820) in memmap.iter().enumerate() {
|
||||
let entry = &mut entries[i];
|
||||
entry.addr = e820.addr;
|
||||
entry.size = e820.size;
|
||||
entry.typ = e820.typ;
|
||||
entry.reserved = 0;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn bootlate(&mut self, _: &mut BootDomain) -> Result<()> {
|
||||
async fn bootlate(&mut self, domain: &mut BootDomain) -> Result<()> {
|
||||
domain
|
||||
.call
|
||||
.set_hvm_param(
|
||||
domain.domid,
|
||||
HVM_PARAM_STORE_EVTCHN,
|
||||
domain.store_evtchn as u64,
|
||||
)
|
||||
.await?;
|
||||
domain
|
||||
.call
|
||||
.set_hvm_param(
|
||||
domain.domid,
|
||||
HVM_PARAM_CONSOLE_EVTCHN,
|
||||
domain.consoles[0].0 as u64,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -564,7 +742,13 @@ impl BootSetupPlatform for X86PvhPlatform {
|
||||
size_of::<HvmSaveDescriptor>() + size_of::<HvmSaveHeader>(),
|
||||
)
|
||||
};
|
||||
let start_info_segment = self
|
||||
.start_info_segment
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::GenericError("start_info_segment missing".to_string()))?;
|
||||
ctx.cpu_d.typecode = 2;
|
||||
ctx.cpu_d.instance = 0;
|
||||
ctx.cpu_d.length = size_of::<HvmCpu>() as u32;
|
||||
ctx.cpu.cs_base = 0;
|
||||
ctx.cpu.ds_base = 0;
|
||||
ctx.cpu.es_base = 0;
|
||||
@ -582,8 +766,43 @@ impl BootSetupPlatform for X86PvhPlatform {
|
||||
ctx.cpu.tr_arbytes = 0x8b;
|
||||
ctx.cpu.cr0 = X86_CR0_PE | X86_CR0_ET;
|
||||
ctx.cpu.rip = domain.image_info.virt_entry;
|
||||
ctx.cpu.rbx = start_info_segment.pfn << self.page_shift();
|
||||
ctx.cpu.dr6 = 0xffff0ff0;
|
||||
ctx.cpu.dr7 = 0x00000400;
|
||||
ctx.end_d.typecode = 0;
|
||||
ctx.end_d.instance = 0;
|
||||
ctx.end_d.length = 0;
|
||||
unsafe {
|
||||
let existing = X86PvhPlatform::get_save_record::<HvmMtrr>(&mut full_context, 14, 0);
|
||||
if existing.is_null() {
|
||||
return Err(Error::GenericError("mtrr record not found".to_string()));
|
||||
}
|
||||
let mut mtrr: MtrrCtx = MaybeUninit::zeroed().assume_init();
|
||||
mtrr.header_d = ctx.header_d;
|
||||
mtrr.header = ctx.header;
|
||||
mtrr.mtrr_d.typecode = 14;
|
||||
mtrr.mtrr_d.instance = 0;
|
||||
mtrr.mtrr_d.length = size_of::<HvmMtrr>() as u32;
|
||||
mtrr.mtrr = *existing;
|
||||
mtrr.mtrr.msr_mtrr_def_type = 6u64 | (1u64 << 11);
|
||||
mtrr.end_d.typecode = 0;
|
||||
mtrr.end_d.instance = 0;
|
||||
mtrr.end_d.length = 0;
|
||||
for i in 0..domain.max_vcpus {
|
||||
mtrr.mtrr_d.instance = i as u16;
|
||||
domain
|
||||
.call
|
||||
.set_hvm_context(
|
||||
domain.domid,
|
||||
std::slice::from_raw_parts_mut(
|
||||
addr_of_mut!(mtrr) as *mut u8,
|
||||
size_of::<MtrrCtx>(),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
};
|
||||
|
||||
let addr = addr_of_mut!(ctx) as *mut u8;
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut(addr, size_of::<BspCtx>()) };
|
||||
domain.call.set_hvm_context(domain.domid, slice).await?;
|
||||
@ -631,7 +850,51 @@ const SPECIALPAGE_SHARING: u32 = 2;
|
||||
const SPECIALPAGE_BUFIOREQ: u32 = 3;
|
||||
const SPECIALPAGE_XENSTORE: u32 = 4;
|
||||
const SPECIALPAGE_IOREQ: u32 = 5;
|
||||
const _SPECIALPAGE_IDENT_PT: u32 = 6;
|
||||
const SPECIALPAGE_IDENT_PT: u32 = 6;
|
||||
const SPECIALPAGE_CONSOLE: u32 = 7;
|
||||
const LAPIC_BASE_ADDRESS: u64 = 0xfee00000;
|
||||
const ACPI_INFO_PHYSICAL_ADDRESS: u64 = 0xFC000000;
|
||||
|
||||
unsafe extern "C" fn acpi_lapic_id(cpu: libc::c_uint) -> u32 {
|
||||
cpu * 2
|
||||
}
|
||||
|
||||
fn align_it(p: u64, a: u64) -> u64 {
|
||||
((p) + ((a) - 1)) & !((a) - 1)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn acpi_mem_alloc(
|
||||
ctxt: *mut acpi_ctxt,
|
||||
size: u32,
|
||||
mut align: u32,
|
||||
) -> *mut c_void {
|
||||
let ctx = (*ctxt).ptr as *mut AcpiBuildContext;
|
||||
if align < 16 {
|
||||
align = 16;
|
||||
}
|
||||
|
||||
let s = align_it((*ctx).guest_curr, align as u64);
|
||||
let e = s + size as u64 - 1;
|
||||
if (e < s) || (e >= (*ctx).guest_end) {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
(*ctx).guest_curr = e;
|
||||
(*ctx).buf.add((s - (*ctx).guest_start) as usize) as *mut c_void
|
||||
}
|
||||
|
||||
unsafe extern "C" fn acpi_mem_free(_: *mut acpi_ctxt, _: *mut libc::c_void, _: u32) {}
|
||||
|
||||
unsafe extern "C" fn acpi_v2p(ctxt: *mut acpi_ctxt, v: *mut c_void) -> libc::c_ulong {
|
||||
let ctx = (*ctxt).ptr as *mut AcpiBuildContext;
|
||||
(*ctx).guest_start + (v.sub((*ctx).buf as usize) as u64)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct AcpiBuildContext {
|
||||
page_size: u64,
|
||||
page_shift: u64,
|
||||
buf: *mut u8,
|
||||
guest_curr: u64,
|
||||
guest_start: u64,
|
||||
guest_end: u64,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86_64 6.8.9 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Debian 13.2.0-23) 13.2.0"
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Debian 13.2.0-24) 13.2.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=130200
|
||||
CONFIG_CLANG_VERSION=0
|
||||
@ -672,8 +672,35 @@ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
|
||||
# end of Binary Emulations
|
||||
|
||||
CONFIG_HAVE_KVM=y
|
||||
CONFIG_HAVE_KVM_PFNCACHE=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_HAVE_KVM_IRQFD=y
|
||||
CONFIG_HAVE_KVM_IRQ_ROUTING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING_TSO=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
|
||||
CONFIG_HAVE_KVM_EVENTFD=y
|
||||
CONFIG_KVM_MMIO=y
|
||||
CONFIG_KVM_ASYNC_PF=y
|
||||
CONFIG_HAVE_KVM_MSI=y
|
||||
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
|
||||
CONFIG_KVM_VFIO=y
|
||||
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
||||
CONFIG_KVM_COMPAT=y
|
||||
CONFIG_HAVE_KVM_IRQ_BYPASS=y
|
||||
CONFIG_HAVE_KVM_NO_POLL=y
|
||||
CONFIG_KVM_XFER_TO_GUEST_WORK=y
|
||||
CONFIG_HAVE_KVM_PM_NOTIFIER=y
|
||||
CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
# CONFIG_KVM is not set
|
||||
CONFIG_KVM=m
|
||||
CONFIG_KVM_WERROR=y
|
||||
# CONFIG_KVM_INTEL is not set
|
||||
# CONFIG_KVM_AMD is not set
|
||||
CONFIG_KVM_SMM=y
|
||||
# CONFIG_KVM_XEN is not set
|
||||
# CONFIG_KVM_PROVE_MMU is not set
|
||||
CONFIG_KVM_MAX_NR_VCPUS=1024
|
||||
CONFIG_AS_AVX512=y
|
||||
CONFIG_AS_SHA1_NI=y
|
||||
CONFIG_AS_SHA256_NI=y
|
||||
@ -702,6 +729,7 @@ CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
||||
CONFIG_KRETPROBES=y
|
||||
CONFIG_KRETPROBE_ON_RETHOOK=y
|
||||
CONFIG_USER_RETURN_NOTIFIER=y
|
||||
CONFIG_HAVE_IOREMAP_PROT=y
|
||||
CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
@ -928,6 +956,7 @@ CONFIG_BFQ_GROUP_IOSCHED=y
|
||||
# CONFIG_BFQ_CGROUP_DEBUG is not set
|
||||
# end of IO Schedulers
|
||||
|
||||
CONFIG_PREEMPT_NOTIFIERS=y
|
||||
CONFIG_ASN1=y
|
||||
CONFIG_UNINLINE_SPIN_UNLOCK=y
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
@ -1494,11 +1523,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
|
||||
#
|
||||
# Firmware loader
|
||||
#
|
||||
CONFIG_FW_LOADER=m
|
||||
CONFIG_FW_LOADER=y
|
||||
CONFIG_FW_LOADER_DEBUG=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_FW_LOADER_SYSFS=y
|
||||
CONFIG_EXTRA_FIRMWARE=""
|
||||
# CONFIG_FW_LOADER_USER_HELPER is not set
|
||||
# CONFIG_FW_LOADER_COMPRESS is not set
|
||||
CONFIG_FW_LOADER_USER_HELPER=y
|
||||
# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
|
||||
CONFIG_FW_LOADER_COMPRESS=y
|
||||
CONFIG_FW_LOADER_COMPRESS_XZ=y
|
||||
CONFIG_FW_LOADER_COMPRESS_ZSTD=y
|
||||
CONFIG_FW_CACHE=y
|
||||
# CONFIG_FW_UPLOAD is not set
|
||||
# end of Firmware loader
|
||||
@ -3029,6 +3063,7 @@ CONFIG_SYNC_FILE=y
|
||||
|
||||
# CONFIG_UIO is not set
|
||||
# CONFIG_VFIO is not set
|
||||
CONFIG_IRQ_BYPASS_MANAGER=m
|
||||
CONFIG_VIRT_DRIVERS=y
|
||||
CONFIG_VMGENID=y
|
||||
# CONFIG_VBOXGUEST is not set
|
||||
|
Reference in New Issue
Block a user