mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
cleanup elf loader and more work towards boot support
This commit is contained in:
parent
5ff0ea8a1b
commit
d46d0cf0c3
@ -5,7 +5,7 @@ use xencall::{XenCall, XenCallError};
|
||||
fn main() -> Result<(), XenCallError> {
|
||||
let call = XenCall::open()?;
|
||||
let domctl: DomainControl = DomainControl::new(&call);
|
||||
let info = domctl.create_domain(CreateDomain::default())?;
|
||||
println!("created domain {}", info.domid);
|
||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||
println!("created domain {}", domid);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::sys::{
|
||||
ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, GetDomainInfo, MaxMem, MaxVcpus,
|
||||
HYPERVISOR_DOMCTL, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_GETDOMAININFO,
|
||||
XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM, XEN_DOMCTL_MAX_VCPUS,
|
||||
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,
|
||||
};
|
||||
use crate::{XenCall, XenCallError};
|
||||
use std::ffi::c_ulong;
|
||||
@ -11,10 +12,6 @@ pub struct DomainControl<'a> {
|
||||
call: &'a XenCall,
|
||||
}
|
||||
|
||||
pub struct CreatedDomain {
|
||||
pub domid: u32,
|
||||
}
|
||||
|
||||
impl DomainControl<'_> {
|
||||
pub fn new(call: &XenCall) -> DomainControl {
|
||||
DomainControl { call }
|
||||
@ -55,10 +52,7 @@ impl DomainControl<'_> {
|
||||
Ok(unsafe { domctl.value.get_domain_info })
|
||||
}
|
||||
|
||||
pub fn create_domain(
|
||||
&self,
|
||||
create_domain: CreateDomain,
|
||||
) -> Result<CreatedDomain, XenCallError> {
|
||||
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> {
|
||||
let domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_CREATEDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
@ -67,9 +61,7 @@ impl DomainControl<'_> {
|
||||
};
|
||||
self.call
|
||||
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?;
|
||||
Ok(CreatedDomain {
|
||||
domid: domctl.domid,
|
||||
})
|
||||
Ok(domctl.domid)
|
||||
}
|
||||
|
||||
pub fn set_max_mem(&mut self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
|
||||
@ -99,4 +91,30 @@ impl DomainControl<'_> {
|
||||
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
|
||||
let domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_HYPERCALL_INIT,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
hypercall_init: HypercallInit { gmfn },
|
||||
},
|
||||
};
|
||||
self.call
|
||||
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> {
|
||||
let domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_DESTROYDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue { pad: [0; 128] },
|
||||
};
|
||||
self.call
|
||||
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +195,8 @@ pub union DomCtlValue {
|
||||
pub get_domain_info: GetDomainInfo,
|
||||
pub max_mem: MaxMem,
|
||||
pub max_cpus: MaxVcpus,
|
||||
pub hypercall_init: HypercallInit,
|
||||
pub pad: [u8; 128],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -277,6 +279,12 @@ pub struct MaxVcpus {
|
||||
pub max_vcpus: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct HypercallInit {
|
||||
pub gmfn: u64,
|
||||
}
|
||||
|
||||
pub const XEN_DOMCTL_INTERFACE_VERSION: u32 = 0x00000015;
|
||||
pub const SECINITSID_DOMU: u32 = 13;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::alloc::Layout;
|
||||
use std::{env, process};
|
||||
use xencall::domctl::DomainControl;
|
||||
use xencall::sys::CreateDomain;
|
||||
use xencall::XenCall;
|
||||
@ -7,12 +8,27 @@ use xenclient::elfloader::ElfImageLoader;
|
||||
use xenclient::XenClientError;
|
||||
|
||||
fn main() -> Result<(), XenClientError> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
println!("usage: boot <kernel-image>");
|
||||
process::exit(1);
|
||||
}
|
||||
let kernel_image_path = args.get(1).expect("argument not specified");
|
||||
let call = XenCall::open()?;
|
||||
let domctl = DomainControl::new(&call);
|
||||
let _domain = domctl.create_domain(CreateDomain::default())?;
|
||||
let boot = ElfImageLoader::load_file_kernel("/boot/vmlinuz-6.1.0-17-amd64")?;
|
||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||
let domain = domctl.get_domain_info(domid)?;
|
||||
println!("domain created: {:?}", domain);
|
||||
let boot = ElfImageLoader::load_file_kernel(kernel_image_path.as_str())?;
|
||||
let ptr = unsafe { std::alloc::alloc(Layout::from_size_align(128 * 1024 * 1024, 16).unwrap()) };
|
||||
let info = boot.load(ptr)?;
|
||||
println!("{:?}", info);
|
||||
println!("loaded kernel image into memory: {:?}", info);
|
||||
// The address calculations don't make sense here and I am certain something
|
||||
// is wrong up the stack.
|
||||
// if info.virt_hypercall != XEN_UNSET_ADDR {
|
||||
// domctl.hypercall_init(domid, info.virt_hypercall)?;
|
||||
// }
|
||||
domctl.destroy_domain(domid)?;
|
||||
println!("domain destroyed: {}", domid);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4,10 +4,13 @@ pub trait BootImageLoader {
|
||||
fn load(&self, dst: *mut u8) -> Result<BootImageInfo, XenClientError>;
|
||||
}
|
||||
|
||||
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BootImageInfo {
|
||||
pub virt_kstart: u64,
|
||||
pub virt_kend: u64,
|
||||
pub virt_hypercall: u64,
|
||||
pub entry: u64,
|
||||
pub hv_start_low: u64,
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::boot::{BootImageInfo, BootImageLoader};
|
||||
use crate::sys::{XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HV_START_LOW, XEN_ELFNOTE_VIRT_BASE};
|
||||
use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR};
|
||||
use crate::sys::{
|
||||
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HV_START_LOW, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_VIRT_BASE,
|
||||
};
|
||||
use crate::XenClientError;
|
||||
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
|
||||
use elf::endian::AnyEndian;
|
||||
@ -22,17 +24,43 @@ pub struct ElfImageLoader {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
fn xen_note_value_u64(endian: AnyEndian, notes: &HashMap<u64, Vec<u8>>, key: u64) -> Option<u64> {
|
||||
let value = notes.get(&key);
|
||||
value?;
|
||||
let value = value.unwrap();
|
||||
let bytes: Option<[u8; size_of::<u64>()]> = value.clone().try_into().ok();
|
||||
bytes?;
|
||||
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u64::from_le_bytes(bytes.unwrap()),
|
||||
AnyEndian::Big => u64::from_be_bytes(bytes.unwrap()),
|
||||
})
|
||||
fn xen_note_value_as_u64(
|
||||
endian: AnyEndian,
|
||||
notes: &HashMap<u64, Vec<u8>>,
|
||||
key: u64,
|
||||
) -> Option<u64> {
|
||||
let value = notes.get(&key)?;
|
||||
match value.len() {
|
||||
1 => {
|
||||
let bytes: Option<[u8; size_of::<u8>()]> = value.clone().try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u8::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u8::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
2 => {
|
||||
let bytes: Option<[u8; size_of::<u16>()]> = value.clone().try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u16::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u16::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
4 => {
|
||||
let bytes: Option<[u8; size_of::<u32>()]> = value.clone().try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u32::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u32::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
8 => {
|
||||
let bytes: Option<[u8; size_of::<u64>()]> = value.clone().try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u64::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u64::from_be_bytes(bytes?),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl ElfImageLoader {
|
||||
@ -100,11 +128,8 @@ impl ElfImageLoader {
|
||||
}
|
||||
|
||||
for start in find_iter(file.as_slice(), &[0xfd, 0x37, 0x7a, 0x58]) {
|
||||
match ElfImageLoader::load_xz(&file[start..]) {
|
||||
Ok(elf) => return Ok(elf),
|
||||
Err(error) => {
|
||||
println!("{}", error);
|
||||
}
|
||||
if let Ok(elf) = ElfImageLoader::load_xz(&file[start..]) {
|
||||
return Ok(elf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,16 +180,23 @@ impl BootImageLoader for ElfImageLoader {
|
||||
));
|
||||
}
|
||||
|
||||
let virt_base = xen_note_value_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_VIRT_BASE)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find virt_base note in kernel.",
|
||||
))?;
|
||||
let entry = xen_note_value_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_ENTRY)
|
||||
let virt_base =
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_VIRT_BASE).ok_or(
|
||||
XenClientError::new("Unable to find virt_base note in kernel."),
|
||||
)?;
|
||||
let entry = xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_ENTRY)
|
||||
.ok_or(XenClientError::new("Unable to find entry note in kernel."))?;
|
||||
let hv_start_low =
|
||||
xen_note_value_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_HV_START_LOW).ok_or(
|
||||
XenClientError::new("Unable to find hv_start_low note in kernel."),
|
||||
)?;
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_HV_START_LOW)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find hv_start_low note in kernel.",
|
||||
))?;
|
||||
|
||||
let hypercall_page =
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_HYPERCALL_PAGE)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find hypercall_page note in kernel.",
|
||||
))?;
|
||||
|
||||
let mut start: u64 = u64::MAX;
|
||||
let mut end: u64 = 0;
|
||||
@ -200,15 +232,19 @@ impl BootImageLoader for ElfImageLoader {
|
||||
std::ptr::write_bytes((dest + filesz) as *mut u8, 0, (memsz - filesz) as usize);
|
||||
}
|
||||
}
|
||||
|
||||
let virt_base = if virt_base == u64::MAX { 0 } else { virt_base };
|
||||
|
||||
let virt_kstart = start + virt_base;
|
||||
let virt_kend = end + virt_base;
|
||||
let virt_base = if virt_base == XEN_UNSET_ADDR {
|
||||
0
|
||||
} else {
|
||||
virt_base
|
||||
};
|
||||
let virt_kstart = start.wrapping_add(virt_base);
|
||||
let virt_kend = end.wrapping_add(virt_base);
|
||||
let virt_hypercall = hypercall_page.wrapping_add(virt_base);
|
||||
|
||||
Ok(BootImageInfo {
|
||||
virt_kstart,
|
||||
virt_kend,
|
||||
virt_hypercall,
|
||||
entry,
|
||||
hv_start_low,
|
||||
})
|
||||
|
@ -76,8 +76,8 @@ impl XenClient {
|
||||
|
||||
pub fn create(&mut self, config: DomainConfig) -> Result<(), XenClientError> {
|
||||
let domctl = DomainControl::new(&self.call);
|
||||
let created = domctl.create_domain(CreateDomain::default())?;
|
||||
let domain = self.store.get_domain_path(created.domid)?;
|
||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||
let domain = self.store.get_domain_path(domid)?;
|
||||
let vm = self.store.read_string(format!("{}/vm", domain).as_str())?;
|
||||
|
||||
let mut tx = self.store.transaction()?;
|
||||
@ -88,7 +88,7 @@ impl XenClient {
|
||||
}
|
||||
|
||||
let domid_path = format!("{}/domid", domain);
|
||||
tx.write(domid_path.as_str(), created.domid.to_string().into_bytes())?;
|
||||
tx.write(domid_path.as_str(), domid.to_string().into_bytes())?;
|
||||
|
||||
for (key, value) in config.clone_domain_entries() {
|
||||
let path = format!("{}/{}", vm, key);
|
||||
|
Loading…
Reference in New Issue
Block a user