cleanup elf loader and more work towards boot support

This commit is contained in:
Alex Zenla
2024-01-10 10:08:39 -08:00
parent 5ff0ea8a1b
commit d46d0cf0c3
7 changed files with 134 additions and 53 deletions

View File

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

View File

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

View File

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