hvm nonredist

This commit is contained in:
Alex Zenla
2024-05-06 02:07:26 -07:00
parent e60fb29f52
commit 7dfd38fca9
13 changed files with 30216 additions and 105 deletions

21
Cargo.lock generated
View File

@ -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",

View File

@ -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(),

View File

@ -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 };

View File

@ -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)]

View File

@ -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 }

View File

@ -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![],

View File

@ -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<()>;
}

View File

@ -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,

View File

@ -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(

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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,
}

View File

@ -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