vmm:AArch64: load standalone firmware

A new firmware item has been added into payload config, we need
extend ability to load standalone firmware on AArch64.
"load_kernel" method will be the entry of image loading work including
kernel and firmware.

This change is back compatible. So, we can either load firmware through
"-kernel" like before or "-firmware".

Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
This commit is contained in:
Jianyong Wu
2022-08-29 10:12:18 +08:00
committed by Rob Bradford
parent 2054c8699a
commit 9b1452f258
+52 -25
View File
@@ -301,7 +301,6 @@ pub enum Error {
#[error("Error joining kernel loading thread")] #[error("Error joining kernel loading thread")]
KernelLoadThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>), KernelLoadThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
#[cfg(target_arch = "x86_64")]
#[error("Payload configuration is not bootable")] #[error("Payload configuration is not bootable")]
InvalidPayload, InvalidPayload,
@@ -458,7 +457,7 @@ pub fn physical_bits(max_phys_bits: u8) -> u8 {
} }
pub struct Vm { pub struct Vm {
#[cfg(any(target_arch = "aarch64", feature = "tdx"))] #[cfg(feature = "tdx")]
kernel: Option<File>, kernel: Option<File>,
initramfs: Option<File>, initramfs: Option<File>,
threads: Vec<thread::JoinHandle<()>>, threads: Vec<thread::JoinHandle<()>>,
@@ -587,7 +586,7 @@ impl Vm {
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0; let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
#[cfg(any(target_arch = "aarch64", feature = "tdx"))] #[cfg(feature = "tdx")]
let kernel = config let kernel = config
.lock() .lock()
.unwrap() .unwrap()
@@ -609,7 +608,7 @@ impl Vm {
.map_err(Error::InitramfsFile)?; .map_err(Error::InitramfsFile)?;
Ok(Vm { Ok(Vm {
#[cfg(any(target_arch = "aarch64", feature = "tdx"))] #[cfg(feature = "tdx")]
kernel, kernel,
initramfs, initramfs,
device_manager, device_manager,
@@ -965,24 +964,42 @@ impl Vm {
fn load_kernel(&mut self) -> Result<EntryPoint> { fn load_kernel(&mut self) -> Result<EntryPoint> {
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory(); let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
let mem = guest_memory.memory(); let mem = guest_memory.memory();
let mut kernel = self.kernel.as_ref().unwrap(); let payload = self
let entry_addr = match linux_loader::loader::pe::PE::load( .config
mem.deref(), .lock()
Some(arch::layout::KERNEL_START), .unwrap()
&mut kernel, .payload
None, .as_ref()
) { .unwrap()
Ok(entry_addr) => entry_addr.kernel_load, .clone();
// Try to load the binary as kernel PE file at first. let entry_addr = match (payload.firmware, payload.kernel) {
// If failed, retry to load it as UEFI binary. (None, Some(kernel)) => {
// As the UEFI binary is formatless, it must be the last option to try. let mut kernel = File::open(kernel).map_err(Error::KernelFile)?;
Err(linux_loader::loader::Error::Pe(InvalidImageMagicNumber)) => { match linux_loader::loader::pe::PE::load(
self.load_firmware(kernel)?; mem.deref(),
Some(arch::layout::KERNEL_START),
&mut kernel,
None,
) {
Ok(entry_addr) => entry_addr.kernel_load,
// Try to load the binary as kernel PE file at first.
// If failed, retry to load it as UEFI binary.
// As the UEFI binary is formatless, it must be the last option to try.
Err(linux_loader::loader::Error::Pe(InvalidImageMagicNumber)) => {
self.load_firmware(&kernel)?;
arch::layout::UEFI_START
}
Err(e) => {
return Err(Error::KernelLoad(e));
}
}
}
(Some(firmware), None) => {
let firmware = File::open(firmware).map_err(Error::FirmwareFile)?;
self.load_firmware(&firmware)?;
arch::layout::UEFI_START arch::layout::UEFI_START
} }
Err(e) => { _ => return Err(Error::InvalidPayload),
return Err(Error::KernelLoad(e));
}
}; };
Ok(EntryPoint { Ok(EntryPoint {
@@ -2121,11 +2138,21 @@ impl Vm {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn entry_point(&mut self) -> Result<Option<EntryPoint>> { fn entry_point(&mut self) -> Result<Option<EntryPoint>> {
Ok(if self.kernel.as_ref().is_some() { let payload = self
Some(self.load_kernel()?) .config
} else { .lock()
None .unwrap()
}) .payload
.as_ref()
.unwrap()
.clone();
Ok(
if payload.kernel.as_ref().is_some() || payload.firmware.as_ref().is_some() {
Some(self.load_kernel()?)
} else {
None
},
)
} }
pub fn boot(&mut self) -> Result<()> { pub fn boot(&mut self) -> Result<()> {