From b79c31e61314baa77185e84c37c0b96a9b891191 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Thu, 11 Jan 2024 23:54:44 -0800 Subject: [PATCH] multiple corrections to page table setup and fix vcpu structs --- xencall/src/domctl.rs | 30 +++++++++++++--- xencall/src/sys.rs | 15 ++++++-- xenclient/src/boot.rs | 79 ++++++++++++++++++++++++++++++++++++------- xenclient/src/mem.rs | 3 +- xenclient/src/x86.rs | 2 +- 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/xencall/src/domctl.rs b/xencall/src/domctl.rs index 09c5871..53816a6 100644 --- a/xencall/src/domctl.rs +++ b/xencall/src/domctl.rs @@ -1,9 +1,9 @@ use crate::sys::{ - ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext, GetDomainInfo, - HypercallInit, MaxMem, MaxVcpus, VcpuGuestContext, VcpuGuestContextAny, HYPERVISOR_DOMCTL, - XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN, XEN_DOMCTL_GETDOMAININFO, + AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext, + GetDomainInfo, HypercallInit, MaxMem, MaxVcpus, VcpuGuestContext, VcpuGuestContextAny, + HYPERVISOR_DOMCTL, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN, XEN_DOMCTL_GETDOMAININFO, XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM, - XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_SETVCPUCONTEXT, + XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_SETVCPUCONTEXT, XEN_DOMCTL_SET_ADDRESS_SIZE, }; use crate::{XenCall, XenCallError}; use log::trace; @@ -117,6 +117,26 @@ impl DomainControl<'_> { Ok(()) } + pub fn set_address_size(&self, domid: u32, size: u32) -> Result<(), XenCallError> { + trace!( + "domctl fd={} set_address_size domid={} size={}", + self.call.handle.as_raw_fd(), + domid, + size, + ); + let mut domctl = DomCtl { + cmd: XEN_DOMCTL_SET_ADDRESS_SIZE, + interface_version: XEN_DOMCTL_INTERFACE_VERSION, + domid, + value: DomCtlValue { + address_size: AddressSize { size }, + }, + }; + self.call + .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?; + Ok(()) + } + pub fn set_vcpu_context( &self, domid: u32, @@ -152,7 +172,7 @@ impl DomainControl<'_> { pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> { trace!( - "domctl fd={} hypercall_init domid={} max_vcpus={}", + "domctl fd={} hypercall_init domid={} gmfn={}", self.call.handle.as_raw_fd(), domid, gmfn diff --git a/xencall/src/sys.rs b/xencall/src/sys.rs index e45ed7f..2fd1b77 100644 --- a/xencall/src/sys.rs +++ b/xencall/src/sys.rs @@ -207,6 +207,12 @@ pub struct DomCtlVcpuContext { pub ctx: u64, } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct AddressSize { + pub size: u32, +} + #[repr(C)] #[derive(Copy, Clone)] pub union DomCtlValue { @@ -215,8 +221,9 @@ pub union DomCtlValue { pub max_mem: MaxMem, pub max_cpus: MaxVcpus, pub hypercall_init: HypercallInit, - pub pad: [u8; 128], pub vcpu_context: DomCtlVcpuContext, + pub address_size: AddressSize, + pub pad: [u8; 128], } #[repr(C)] @@ -400,7 +407,7 @@ pub struct TrapInfo { #[derive(Copy, Clone, Debug)] pub struct VcpuGuestContext { pub fpu_ctx: VcpuGuestContextFpuCtx, - pub flags: c_ulong, + pub flags: u64, pub user_regs: CpuUserRegs, pub trap_ctx: [TrapInfo; 256], pub ldt_base: u64, @@ -411,6 +418,8 @@ pub struct VcpuGuestContext { pub kernel_sp: u64, pub ctrlreg: [u64; 8], pub debugreg: [u64; 8], + pub event_callback_eip: u64, + pub failsafe_callback_eip: u64, pub syscall_callback_eip: u64, pub vm_assist: u64, pub fs_base: u64, @@ -433,6 +442,8 @@ impl Default for VcpuGuestContext { kernel_sp: 0, ctrlreg: [0; 8], debugreg: [0; 8], + event_callback_eip: 0, + failsafe_callback_eip: 0, syscall_callback_eip: 0, vm_assist: 0, fs_base: 0, diff --git a/xenclient/src/boot.rs b/xenclient/src/boot.rs index 2aed541..45b38d3 100644 --- a/xenclient/src/boot.rs +++ b/xenclient/src/boot.rs @@ -95,6 +95,8 @@ impl BootSetup<'_> { } fn initialize_memory(&mut self, memkb: u64) -> Result<(), XenClientError> { + self.domctl.set_address_size(self.domid, 64)?; + let mem_mb: u64 = memkb / 1024; let page_count: u64 = mem_mb << (20 - XEN_PAGE_SHIFT); let mut vmemranges: Vec = Vec::new(); @@ -224,8 +226,11 @@ impl BootSetup<'_> { let start_info_segment = self.alloc_page()?; let xenstore_segment = self.alloc_page()?; let console_segment = self.alloc_page()?; - let boot_stack_segment = self.alloc_page()?; let (page_table_segment, page_table) = self.alloc_page_tables(&image_info)?; + let boot_stack_segment = self.alloc_page()?; + if self.virt_pgtab_end > 0 { + self.alloc_padding_pages(self.virt_pgtab_end)?; + } Ok(BootState { kernel_segment, start_info_segment, @@ -264,7 +269,7 @@ impl BootSetup<'_> { vcpu.kernel_ss = vcpu.user_regs.ss as u64; vcpu.kernel_sp = vcpu.user_regs.rsp; let _vcpu = vcpu; - self.domctl.set_vcpu_context(self.domid, 0, None)?; + self.domctl.set_vcpu_context(self.domid, 0, Some(&vcpu))?; Ok(()) } @@ -296,7 +301,11 @@ impl BootSetup<'_> { let p_e = (min(to, lvl.to) - from) >> (X86_PAGE_SHIFT + lvl_idx as u64 * X86_PGTABLE_LEVEL_SHIFT); let mut pfn = (max(from, lvl.from) - from) - >> ((X86_PAGE_SHIFT + lvl_idx as u64 * X86_PGTABLE_LEVEL_SHIFT) + lvl.pfn); + .checked_shr( + ((X86_PAGE_SHIFT + lvl_idx as u64 * X86_PGTABLE_LEVEL_SHIFT) + lvl.pfn) + as u32, + ) + .unwrap_or(0u64); for p in p_s..p_e + 1 { unsafe { @@ -343,7 +352,10 @@ impl BootSetup<'_> { image_loader: &dyn BootImageLoader, image_info: &BootImageInfo, ) -> Result { - let kernel_segment = self.alloc_segment(image_info.virt_kend - image_info.virt_kstart)?; + let kernel_segment = self.alloc_segment( + image_info.virt_kstart, + image_info.virt_kend - image_info.virt_kstart, + )?; let kernel_segment_ptr = kernel_segment.addr as *mut u8; debug!( "BootSetup initialize kernel_segment ptr={:#x}", @@ -440,7 +452,7 @@ impl BootSetup<'_> { let mut try_virt_end: u64; loop { - try_virt_end = (self.virt_alloc_end + pages * X86_PAGE_SIZE) | (1 << 22); + try_virt_end = (self.virt_alloc_end + pages * X86_PAGE_SIZE) | ((1 << 22) - 1); self.count_page_tables(&mut table, image_info.virt_base, try_virt_end, 0)?; pages = table.mappings[0].area.pgtables as u64 + extra_pages; if self.virt_alloc_end + pages * X86_PAGE_SIZE <= try_virt_end + 1 { @@ -454,7 +466,7 @@ impl BootSetup<'_> { map.area.pfn = 0; table.mappings_count += 1; self.virt_pgtab_end = try_virt_end + 1; - segment = self.alloc_segment(map.area.pgtables as u64 * X86_PAGE_SIZE)?; + segment = self.alloc_segment(0, map.area.pgtables as u64 * X86_PAGE_SIZE)?; } debug!( "BootSetup alloc_page_tables table={:?} segment={:?}", @@ -463,10 +475,15 @@ impl BootSetup<'_> { Ok((segment, table)) } - fn alloc_segment(&mut self, size: u64) -> Result { + fn alloc_segment(&mut self, start: u64, size: u64) -> Result { + if start > 0 { + self.alloc_padding_pages(start)?; + } + + let start = self.virt_alloc_end; let page_size = 1u64 << XEN_PAGE_SHIFT; let pages = (size + page_size - 1) / page_size; - let start = self.virt_alloc_end; + let mut segment = DomainSegment { vstart: start, _vend: 0, @@ -475,20 +492,58 @@ impl BootSetup<'_> { size, _pages: pages, }; + + self.chk_alloc_pages(pages)?; + let ptr = self.phys.pfn_to_ptr(segment.pfn, pages)?; segment.addr = ptr; unsafe { memset(ptr as *mut c_void, 0, (pages * page_size) as usize); } - self.virt_alloc_end += pages * page_size; segment._vend = self.virt_alloc_end; - self.pfn_alloc_end += 1; - debug!("BootSetup alloc_segment size={} ptr={:#x}", size, ptr); + debug!( + "BootSetup alloc_segment start={:#x} size={} ptr={:#x}", + start, size, ptr + ); Ok(segment) } fn alloc_page(&mut self) -> Result { let page_size = 1u64 << XEN_PAGE_SHIFT; - self.alloc_segment(page_size) + self.alloc_segment(0, page_size) + } + + fn alloc_padding_pages(&mut self, boundary: u64) -> Result<(), XenClientError> { + if (boundary & (X86_PAGE_SIZE - 1)) != 0 { + return Err(XenClientError::new( + format!("segment boundary isn't page aligned: {:#x}", boundary).as_str(), + )); + } + + if boundary < self.virt_alloc_end { + return Err(XenClientError::new("segment boundary too low")); + } + let pages = (boundary - self.virt_alloc_end) / X86_PAGE_SIZE; + self.chk_alloc_pages(pages)?; + Ok(()) + } + + fn chk_alloc_pages(&mut self, pages: u64) -> Result<(), XenClientError> { + if pages > self.total_pages + || self.pfn_alloc_end > self.total_pages + || pages > self.total_pages - self.pfn_alloc_end + { + return Err(XenClientError::new( + format!( + "segment too large: pages={} total_pages={} pfn_alloc_end={}", + pages, self.total_pages, self.pfn_alloc_end + ) + .as_str(), + )); + } + + self.pfn_alloc_end += pages; + self.virt_alloc_end += pages * X86_PAGE_SIZE; + Ok(()) } } diff --git a/xenclient/src/mem.rs b/xenclient/src/mem.rs index 635aa0c..5a528c3 100644 --- a/xenclient/src/mem.rs +++ b/xenclient/src/mem.rs @@ -1,6 +1,7 @@ use crate::sys::XEN_PAGE_SHIFT; use crate::XenClientError; +use crate::x86::X86_PAGE_SHIFT; use xencall::sys::MmapEntry; use xencall::XenCall; @@ -59,7 +60,7 @@ impl PhysicalPages<'_> { } } - return Ok(page.ptr + ((pfn - page.pfn) << XEN_PAGE_SHIFT)); + return Ok(page.ptr + ((pfn - page.pfn) << X86_PAGE_SHIFT)); } if count == 0 { diff --git a/xenclient/src/x86.rs b/xenclient/src/x86.rs index ba51644..6268ba5 100644 --- a/xenclient/src/x86.rs +++ b/xenclient/src/x86.rs @@ -3,7 +3,7 @@ use libc::c_char; 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; +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;