mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
implement setvcpucontext, it's not working properly yet
This commit is contained in:
parent
492a836213
commit
4b4f22ffcd
@ -1,8 +1,9 @@
|
||||
use crate::sys::{
|
||||
ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, GetDomainInfo, HypercallInit, MaxMem,
|
||||
MaxVcpus, 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,
|
||||
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,
|
||||
};
|
||||
use crate::{XenCall, XenCallError};
|
||||
use log::trace;
|
||||
@ -116,6 +117,39 @@ impl DomainControl<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_vcpu_context(
|
||||
&self,
|
||||
domid: u32,
|
||||
vcpu: u32,
|
||||
context: Option<&VcpuGuestContext>,
|
||||
) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} set_vcpu_context domid={} context={:?}",
|
||||
self.call.handle.as_raw_fd(),
|
||||
domid,
|
||||
context,
|
||||
);
|
||||
let mut wrapper = context.map(|ctx| VcpuGuestContextAny { value: *ctx });
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_SETVCPUCONTEXT,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
vcpu_context: DomCtlVcpuContext {
|
||||
vcpu,
|
||||
ctx: if wrapper.is_some() {
|
||||
addr_of_mut!(wrapper) as c_ulong
|
||||
} else {
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
self.call
|
||||
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} hypercall_init domid={} max_vcpus={}",
|
||||
|
@ -200,6 +200,13 @@ pub struct DomCtl {
|
||||
pub value: DomCtlValue,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DomCtlVcpuContext {
|
||||
pub vcpu: u32,
|
||||
pub ctx: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union DomCtlValue {
|
||||
@ -209,6 +216,7 @@ pub union DomCtlValue {
|
||||
pub max_cpus: MaxVcpus,
|
||||
pub hypercall_init: HypercallInit,
|
||||
pub pad: [u8; 128],
|
||||
pub vcpu_context: DomCtlVcpuContext,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -327,3 +335,113 @@ pub struct MultiCallEntry {
|
||||
}
|
||||
|
||||
pub const XEN_MEM_POPULATE_PHYSMAP: u32 = 6;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VcpuGuestContextFpuCtx {
|
||||
pub x: [c_char; 512],
|
||||
}
|
||||
|
||||
impl Default for VcpuGuestContextFpuCtx {
|
||||
fn default() -> Self {
|
||||
VcpuGuestContextFpuCtx { x: [0; 512] }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct CpuUserRegs {
|
||||
pub r15: u64,
|
||||
pub r14: u64,
|
||||
pub r13: u64,
|
||||
pub r12: u64,
|
||||
pub rbp: u64,
|
||||
pub rbx: u64,
|
||||
pub r11: u64,
|
||||
pub r10: u64,
|
||||
pub r9: u64,
|
||||
pub r8: u64,
|
||||
pub rax: u64,
|
||||
pub rcx: u64,
|
||||
pub rdx: u64,
|
||||
pub rsi: u64,
|
||||
pub rdi: u64,
|
||||
pub error_code: u32,
|
||||
pub entry_vector: u32,
|
||||
pub rip: u64,
|
||||
pub cs: u16,
|
||||
_pad0: [u16; 1],
|
||||
pub saved_upcall_mask: u8,
|
||||
_pad1: [u8; 3],
|
||||
pub rflags: u64,
|
||||
pub rsp: u64,
|
||||
pub ss: u16,
|
||||
_pad2: [u16; 3],
|
||||
pub es: u16,
|
||||
_pad3: [u16; 3],
|
||||
pub ds: u16,
|
||||
_pad4: [u16; 3],
|
||||
pub fs: u16,
|
||||
_pad5: [u16; 3],
|
||||
pub gs: u16,
|
||||
_pad6: [u16; 3],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct TrapInfo {
|
||||
pub vector: u8,
|
||||
pub flags: u8,
|
||||
pub cs: u16,
|
||||
pub address: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VcpuGuestContext {
|
||||
pub fpu_ctx: VcpuGuestContextFpuCtx,
|
||||
pub flags: c_ulong,
|
||||
pub user_regs: CpuUserRegs,
|
||||
pub trap_ctx: [TrapInfo; 256],
|
||||
pub ldt_base: u64,
|
||||
pub ldt_ents: u64,
|
||||
pub gdt_frames: [u64; 16],
|
||||
pub gdt_ents: u64,
|
||||
pub kernel_ss: u64,
|
||||
pub kernel_sp: u64,
|
||||
pub ctrlreg: [u64; 8],
|
||||
pub debugreg: [u64; 8],
|
||||
pub syscall_callback_eip: u64,
|
||||
pub vm_assist: u64,
|
||||
pub fs_base: u64,
|
||||
pub gs_base_kernel: u64,
|
||||
pub gs_base_user: u64,
|
||||
}
|
||||
|
||||
impl Default for VcpuGuestContext {
|
||||
fn default() -> Self {
|
||||
VcpuGuestContext {
|
||||
fpu_ctx: Default::default(),
|
||||
flags: 0,
|
||||
user_regs: Default::default(),
|
||||
trap_ctx: [TrapInfo::default(); 256],
|
||||
ldt_base: 0,
|
||||
ldt_ents: 0,
|
||||
gdt_frames: [0; 16],
|
||||
gdt_ents: 0,
|
||||
kernel_ss: 0,
|
||||
kernel_sp: 0,
|
||||
ctrlreg: [0; 8],
|
||||
debugreg: [0; 8],
|
||||
syscall_callback_eip: 0,
|
||||
vm_assist: 0,
|
||||
fs_base: 0,
|
||||
gs_base_kernel: 0,
|
||||
gs_base_user: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub union VcpuGuestContextAny {
|
||||
pub value: VcpuGuestContext,
|
||||
}
|
||||
|
@ -19,13 +19,24 @@ fn main() -> Result<(), XenClientError> {
|
||||
let call = XenCall::open()?;
|
||||
let domctl = DomainControl::new(&call);
|
||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||
println!("domain created: {:?}", domid);
|
||||
let image_loader = ElfImageLoader::load_file_kernel(kernel_image_path.as_str())?;
|
||||
let memctl = MemoryControl::new(&call);
|
||||
let mut boot = BootSetup::new(&call, &domctl, &memctl, domid);
|
||||
let mut state = boot.initialize(&image_loader, 512 * 1024)?;
|
||||
boot.boot(&mut state, "debug")?;
|
||||
let result = boot(domid, kernel_image_path.as_str(), &call, &domctl);
|
||||
domctl.destroy_domain(domid)?;
|
||||
result?;
|
||||
println!("domain destroyed: {}", domid);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn boot(
|
||||
domid: u32,
|
||||
kernel_image_path: &str,
|
||||
call: &XenCall,
|
||||
domctl: &DomainControl,
|
||||
) -> Result<(), XenClientError> {
|
||||
println!("domain created: {:?}", domid);
|
||||
let image_loader = ElfImageLoader::load_file_kernel(kernel_image_path)?;
|
||||
let memctl = MemoryControl::new(call);
|
||||
let mut boot = BootSetup::new(call, domctl, &memctl, domid);
|
||||
let mut state = boot.initialize(&image_loader, 512 * 1024)?;
|
||||
boot.boot(&mut state, "debug")?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use std::ffi::c_void;
|
||||
use std::slice;
|
||||
use xencall::domctl::DomainControl;
|
||||
use xencall::memory::MemoryControl;
|
||||
use xencall::sys::VcpuGuestContext;
|
||||
use xencall::XenCall;
|
||||
|
||||
pub trait BootImageLoader {
|
||||
@ -26,6 +27,7 @@ pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BootImageInfo {
|
||||
pub start: u64,
|
||||
pub virt_base: u64,
|
||||
pub virt_kstart: u64,
|
||||
pub virt_kend: u64,
|
||||
@ -70,6 +72,7 @@ pub struct BootState {
|
||||
pub boot_stack_segment: DomainSegment,
|
||||
pub page_table_segment: DomainSegment,
|
||||
pub page_table: PageTable,
|
||||
pub image_info: BootImageInfo,
|
||||
}
|
||||
|
||||
impl BootSetup<'_> {
|
||||
@ -195,11 +198,14 @@ impl BootSetup<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _initialize_hypercall(&mut self, image_info: BootImageInfo) -> Result<(), XenClientError> {
|
||||
if image_info.virt_hypercall != XEN_UNSET_ADDR {
|
||||
self.domctl
|
||||
.hypercall_init(self.domid, image_info.virt_hypercall)?;
|
||||
fn setup_hypercall_page(&mut self, image_info: &BootImageInfo) -> Result<(), XenClientError> {
|
||||
if image_info.virt_hypercall == XEN_UNSET_ADDR {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let pfn = (image_info.virt_hypercall - image_info.virt_base) >> X86_PAGE_SHIFT;
|
||||
let mfn = self.phys.p2m[pfn as usize];
|
||||
self.domctl.hypercall_init(self.domid, mfn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -213,6 +219,7 @@ impl BootSetup<'_> {
|
||||
self.initialize_memory(memkb)?;
|
||||
|
||||
let image_info = image_loader.parse()?;
|
||||
self.virt_alloc_end = image_info.virt_base;
|
||||
let kernel_segment = self.load_kernel_segment(image_loader, &image_info)?;
|
||||
let start_info_segment = self.alloc_page()?;
|
||||
let xenstore_segment = self.alloc_page()?;
|
||||
@ -227,12 +234,37 @@ impl BootSetup<'_> {
|
||||
boot_stack_segment,
|
||||
page_table_segment,
|
||||
page_table,
|
||||
image_info,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
|
||||
self.setup_page_tables(state)?;
|
||||
self.setup_start_info(state, cmdline);
|
||||
self.setup_hypercall_page(&state.image_info)?;
|
||||
|
||||
let mut vcpu = VcpuGuestContext::default();
|
||||
vcpu.user_regs.rip = state.image_info.virt_entry;
|
||||
vcpu.user_regs.rsp =
|
||||
state.image_info.virt_base + (state.boot_stack_segment.pfn + 1) * X86_PAGE_SIZE;
|
||||
vcpu.user_regs.rsi =
|
||||
state.image_info.virt_base + (state.start_info_segment.pfn) * X86_PAGE_SIZE;
|
||||
vcpu.user_regs.rflags = 1 << 9;
|
||||
vcpu.debugreg[6] = 0xffff0ff0;
|
||||
vcpu.debugreg[7] = 0x00000400;
|
||||
vcpu.flags = (1 << 2) | (1 << 5);
|
||||
let cr3_pfn = self.phys.p2m[state.page_table_segment.pfn as usize];
|
||||
vcpu.ctrlreg[3] = cr3_pfn << 12;
|
||||
vcpu.user_regs.ds = 0xe021;
|
||||
vcpu.user_regs.es = 0xe021;
|
||||
vcpu.user_regs.fs = 0xe021;
|
||||
vcpu.user_regs.gs = 0xe021;
|
||||
vcpu.user_regs.ss = 0xe02b;
|
||||
vcpu.user_regs.cs = 0xe019;
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -263,7 +295,8 @@ impl BootSetup<'_> {
|
||||
>> (X86_PAGE_SHIFT + lvl_idx as u64 * X86_PGTABLE_LEVEL_SHIFT);
|
||||
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);
|
||||
let mut pfn = (max(from, lvl.from) - from)
|
||||
>> ((X86_PAGE_SHIFT + lvl_idx as u64 * X86_PGTABLE_LEVEL_SHIFT) + lvl.pfn);
|
||||
|
||||
for p in p_s..p_e + 1 {
|
||||
unsafe {
|
||||
|
@ -265,24 +265,13 @@ impl BootImageLoader for ElfImageLoader {
|
||||
));
|
||||
}
|
||||
|
||||
let virt_base = 0;
|
||||
|
||||
let _paddr_offset = if paddr_offset == XEN_UNSET_ADDR {
|
||||
0
|
||||
} else {
|
||||
paddr_offset
|
||||
};
|
||||
|
||||
let virt_offset = 0;
|
||||
let virt_offset = virt_base - paddr_offset;
|
||||
let virt_kstart = start + virt_offset;
|
||||
let virt_kend = end + virt_offset;
|
||||
let virt_entry = if entry == XEN_UNSET_ADDR {
|
||||
elf.ehdr.e_entry
|
||||
} else {
|
||||
entry
|
||||
};
|
||||
let virt_entry = entry;
|
||||
|
||||
Ok(BootImageInfo {
|
||||
start,
|
||||
virt_base,
|
||||
virt_kstart,
|
||||
virt_kend,
|
||||
@ -307,7 +296,7 @@ impl BootImageLoader for ElfImageLoader {
|
||||
let paddr = header.p_paddr;
|
||||
let filesz = header.p_filesz;
|
||||
let memsz = header.p_memsz;
|
||||
let base_offset = paddr - image_info.virt_kstart;
|
||||
let base_offset = paddr - image_info.start;
|
||||
let data = elf.segment_data(&header)?;
|
||||
let segment_dst = &mut dst[base_offset as usize..];
|
||||
let copy_slice = &data[0..filesz as usize];
|
||||
|
@ -8,8 +8,7 @@ pub const X86_PGTABLE_LEVELS: u64 = 4;
|
||||
pub const X86_PGTABLE_LEVEL_SHIFT: u64 = 9;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PageTableMappingLevel {
|
||||
pub from: u64,
|
||||
pub to: u64,
|
||||
@ -18,8 +17,7 @@ pub struct PageTableMappingLevel {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PageTableMapping {
|
||||
pub area: PageTableMappingLevel,
|
||||
pub levels: [PageTableMappingLevel; X86_PGTABLE_LEVELS as usize],
|
||||
@ -28,19 +26,12 @@ pub struct PageTableMapping {
|
||||
pub const X86_PAGE_TABLE_MAX_MAPPINGS: usize = 2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Default)]
|
||||
#[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 {
|
||||
|
Loading…
Reference in New Issue
Block a user