multiple corrections to page table setup and fix vcpu structs

This commit is contained in:
Alex Zenla 2024-01-11 23:54:44 -08:00
parent 4b4f22ffcd
commit b79c31e613
No known key found for this signature in database
GPG Key ID: 067B238899B51269
5 changed files with 108 additions and 21 deletions

View File

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

View File

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

View File

@ -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<VmemRange> = 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<DomainSegment, XenClientError> {
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<DomainSegment, XenClientError> {
fn alloc_segment(&mut self, start: u64, size: u64) -> Result<DomainSegment, XenClientError> {
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<DomainSegment, XenClientError> {
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(())
}
}

View File

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

View File

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