vmm: Add bzimage loader support

VMM may load different format kernel image to start guest, we currently
only have elf loader support, so add bzimage loader support in case
that VMM would like to load bzimage.

Signed-off-by: Cathy Zhang <cathy.zhang@intel.com>
This commit is contained in:
Cathy Zhang 2019-06-10 17:14:02 +08:00 committed by Rob Bradford
parent 0f54429848
commit 429b53a672
5 changed files with 71 additions and 19 deletions

View File

@ -15,5 +15,9 @@ arch_gen = { path = "../arch_gen" }
git = "https://github.com/rust-vmm/vm-memory"
features = ["backend-mmap"]
[dependencies.linux-loader]
git = "https://github.com/bjzhjing/linux-loader"
features = ["elf", "bzimage"]
[dev-dependencies]
rand = ">=0.5.5"

View File

@ -15,6 +15,7 @@ extern crate libc;
extern crate arch_gen;
extern crate kvm_ioctls;
extern crate linux_loader;
extern crate vm_memory;
use std::result;

View File

@ -13,7 +13,7 @@ pub mod regs;
use std::mem;
use arch_gen::x86::bootparam::{boot_params, E820_RAM};
use linux_loader::loader::bootparam::{boot_params, setup_header, E820_RAM};
use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestUsize,
};
@ -95,6 +95,7 @@ pub fn configure_system(
cmdline_addr: GuestAddress,
cmdline_size: usize,
num_cpus: u8,
setup_hdr: Option<setup_header>,
) -> super::Result<()> {
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
@ -110,12 +111,18 @@ pub fn configure_system(
let mut params: BootParamsWrapper = BootParamsWrapper(boot_params::default());
params.0.hdr.type_of_loader = KERNEL_LOADER_OTHER;
params.0.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
params.0.hdr.header = KERNEL_HDR_MAGIC;
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
params.0.hdr.cmdline_size = cmdline_size as u32;
params.0.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
if setup_hdr.is_some() {
params.0.hdr = setup_hdr.unwrap();
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
params.0.hdr.cmdline_size = cmdline_size as u32;
} else {
params.0.hdr.type_of_loader = KERNEL_LOADER_OTHER;
params.0.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
params.0.hdr.header = KERNEL_HDR_MAGIC;
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
params.0.hdr.cmdline_size = cmdline_size as u32;
params.0.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
};
add_e820_entry(&mut params.0, 0, EBDA_START.raw_value(), E820_RAM)?;

View File

@ -21,7 +21,7 @@ vmm-sys-util = { git = "https://github.com/rust-vmm/vmm-sys-util" }
[dependencies.linux-loader]
git = "https://github.com/bjzhjing/linux-loader"
features = ["elf"]
features = ["elf", "bzimage"]
[dependencies.vm-memory]
git = "https://github.com/rust-vmm/vm-memory"

View File

@ -55,6 +55,9 @@ const DEFAULT_MSIX_VEC_NUM: u16 = 2;
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
// 64 bit direct boot entry offset for bzImage
const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200;
/// Errors associated with VM management
#[derive(Debug)]
pub enum Error {
@ -143,6 +146,9 @@ pub enum Error {
/// Unexpected KVM_RUN exit reason
VcpuUnhandledKvmExit,
/// Memory is overflow
MemOverflow,
}
pub type Result<T> = result::Result<T, Error>;
@ -797,13 +803,24 @@ impl<'a> Vm<'a> {
pub fn load_kernel(&mut self) -> Result<GuestAddress> {
let cmdline_cstring =
CString::new(self.config.cmdline.args.clone()).map_err(|_| Error::CmdLine)?;
let entry_addr = linux_loader::loader::Elf::load(
let entry_addr = match linux_loader::loader::Elf::load(
&self.memory,
None,
&mut self.kernel,
Some(arch::HIMEM_START),
)
.map_err(Error::KernelLoad)?;
) {
Ok(entry_addr) => entry_addr,
Err(linux_loader::loader::Error::InvalidElfMagicNumber) => {
linux_loader::loader::BzImage::load(
&self.memory,
None,
&mut self.kernel,
Some(arch::HIMEM_START),
)
.map_err(Error::KernelLoad)?
}
_ => panic!("Invalid elf file"),
};
linux_loader::loader::load_cmdline(
&self.memory,
@ -814,15 +831,38 @@ impl<'a> Vm<'a> {
let vcpu_count = u8::from(&self.config.cpus);
arch::configure_system(
&self.memory,
self.config.cmdline.offset,
cmdline_cstring.to_bytes().len() + 1,
vcpu_count,
)
.map_err(|_| Error::CmdLine)?;
match entry_addr.setup_header {
Some(hdr) => {
arch::configure_system(
&self.memory,
self.config.cmdline.offset,
cmdline_cstring.to_bytes().len() + 1,
vcpu_count,
Some(hdr),
)
.map_err(|_| Error::CmdLine)?;
Ok(entry_addr.kernel_load)
let load_addr = entry_addr
.kernel_load
.raw_value()
.checked_add(KERNEL_64BIT_ENTRY_OFFSET)
.ok_or(Error::MemOverflow)?;
Ok(GuestAddress(load_addr))
}
None => {
arch::configure_system(
&self.memory,
self.config.cmdline.offset,
cmdline_cstring.to_bytes().len() + 1,
vcpu_count,
None,
)
.map_err(|_| Error::CmdLine)?;
Ok(entry_addr.kernel_load)
}
}
}
pub fn control_loop(&mut self) -> Result<()> {