diff --git a/arch/Cargo.toml b/arch/Cargo.toml index 1e62413ab..e973cc07b 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -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" diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 6e9eb4a94..85f041ce3 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -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; diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 65223de62..220a00211 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -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, ) -> 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)?; diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index ad513671e..084891d0b 100755 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -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" diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index d14b8dbed..e5a6c00e9 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -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 = result::Result; @@ -797,13 +803,24 @@ impl<'a> Vm<'a> { pub fn load_kernel(&mut self) -> Result { 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<()> {