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