mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 04:09:48 +00:00
kernel_loader: move load_cmdline() to x86_64
This is only used by the x86_64 arch code, and it isn't really related to kernel loading. Moving it to x86_64 will also allow x86-specific changes in upcoming CLs. No functional change intended. BUG=b:362168475 Change-Id: I4d01ba81d4f14fe73b38d62981a2c5a651b1bf03 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5842390 Reviewed-by: Junichi Uekawa <uekawa@chromium.org> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
d7b16c03b6
commit
ad41ae89ec
2 changed files with 79 additions and 85 deletions
|
@ -4,7 +4,6 @@
|
|||
|
||||
//! Linux kernel ELF file loader.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
use base::FileReadWriteAtVolatile;
|
||||
|
@ -38,10 +37,6 @@ pub use multiboot::multiboot_header_from_file;
|
|||
pub enum Error {
|
||||
#[error("trying to load big-endian binary on little-endian machine")]
|
||||
BigEndianOnLittle,
|
||||
#[error("failed writing command line to guest memory")]
|
||||
CommandLineCopy,
|
||||
#[error("command line overflowed guest memory")]
|
||||
CommandLineOverflow,
|
||||
#[error("invalid elf class")]
|
||||
InvalidElfClass,
|
||||
#[error("invalid elf version")]
|
||||
|
@ -255,37 +250,6 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Writes the command line string to the given memory slice.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
|
||||
/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
|
||||
/// * `cmdline` - The kernel command line.
|
||||
pub fn load_cmdline(
|
||||
guest_mem: &GuestMemory,
|
||||
guest_addr: GuestAddress,
|
||||
cmdline: &CStr,
|
||||
) -> Result<()> {
|
||||
let len = cmdline.to_bytes().len();
|
||||
if len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let end = guest_addr
|
||||
.checked_add(len as u64 + 1)
|
||||
.ok_or(Error::CommandLineOverflow)?; // Extra for null termination.
|
||||
if end > guest_mem.end_addr() {
|
||||
return Err(Error::CommandLineOverflow);
|
||||
}
|
||||
|
||||
guest_mem
|
||||
.write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
|
||||
.map_err(|_| Error::CommandLineCopy)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Elf64 {
|
||||
file_header: elf::Elf64_Ehdr,
|
||||
program_headers: Vec<elf::Elf64_Phdr>,
|
||||
|
@ -420,48 +384,6 @@ mod test {
|
|||
GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmdline_overflow() {
|
||||
let gm = create_guest_mem();
|
||||
let cmdline_address = GuestAddress(MEM_SIZE - 5);
|
||||
assert_eq!(
|
||||
Err(Error::CommandLineOverflow),
|
||||
load_cmdline(
|
||||
&gm,
|
||||
cmdline_address,
|
||||
CStr::from_bytes_with_nul(b"12345\0").unwrap()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmdline_write_end() {
|
||||
let gm = create_guest_mem();
|
||||
let mut cmdline_address = GuestAddress(45);
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
load_cmdline(
|
||||
&gm,
|
||||
cmdline_address,
|
||||
CStr::from_bytes_with_nul(b"1234\0").unwrap()
|
||||
)
|
||||
);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'1');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'2');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'3');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'4');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'\0');
|
||||
}
|
||||
|
||||
// Elf32 image that prints hello world on x86.
|
||||
fn make_elf32_bin() -> File {
|
||||
// test_elf32.bin built on Linux with gcc -m32 -static-pie
|
||||
|
|
|
@ -165,6 +165,10 @@ pub enum Error {
|
|||
CloneTube(TubeError),
|
||||
#[error("the given kernel command line was invalid: {0}")]
|
||||
Cmdline(kernel_cmdline::Error),
|
||||
#[error("failed writing command line to guest memory")]
|
||||
CommandLineCopy,
|
||||
#[error("command line overflowed guest memory")]
|
||||
CommandLineOverflow,
|
||||
#[error("failed to configure hotplugged pci device: {0}")]
|
||||
ConfigurePciDevice(arch::DeviceRegistrationError),
|
||||
#[error("failed to configure segment registers: {0}")]
|
||||
|
@ -222,8 +226,6 @@ pub enum Error {
|
|||
LoadBios(io::Error),
|
||||
#[error("error loading kernel bzImage: {0}")]
|
||||
LoadBzImage(bzimage::Error),
|
||||
#[error("error loading command line: {0}")]
|
||||
LoadCmdline(kernel_loader::Error),
|
||||
#[error("error loading initrd: {0}")]
|
||||
LoadInitrd(arch::LoadImageError),
|
||||
#[error("error loading Kernel: {0}")]
|
||||
|
@ -1004,12 +1006,11 @@ impl arch::LinuxArch for X8664arch {
|
|||
match components.vm_image {
|
||||
VmImage::Bios(ref mut bios) => {
|
||||
// Allow a bios to hardcode CMDLINE_OFFSET and read the kernel command line from it.
|
||||
kernel_loader::load_cmdline(
|
||||
Self::load_cmdline(
|
||||
&mem,
|
||||
GuestAddress(CMDLINE_OFFSET),
|
||||
&CString::new(cmdline).unwrap(),
|
||||
)
|
||||
.map_err(Error::LoadCmdline)?;
|
||||
)?;
|
||||
Self::load_bios(&mem, bios)?;
|
||||
regs::set_default_msrs(&mut msrs);
|
||||
// The default values for `Regs` and `Sregs` already set up the reset vector.
|
||||
|
@ -1344,6 +1345,37 @@ impl X8664arch {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes the command line string to the given memory slice.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
|
||||
/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
|
||||
/// * `cmdline` - The kernel command line.
|
||||
fn load_cmdline(
|
||||
guest_mem: &GuestMemory,
|
||||
guest_addr: GuestAddress,
|
||||
cmdline: &CStr,
|
||||
) -> Result<()> {
|
||||
let len = cmdline.to_bytes().len();
|
||||
if len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let end = guest_addr
|
||||
.checked_add(len as u64 + 1)
|
||||
.ok_or(Error::CommandLineOverflow)?; // Extra for null termination.
|
||||
if end > guest_mem.end_addr() {
|
||||
return Err(Error::CommandLineOverflow);
|
||||
}
|
||||
|
||||
guest_mem
|
||||
.write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
|
||||
.map_err(|_| Error::CommandLineCopy)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads the kernel from an open file.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -1400,8 +1432,7 @@ impl X8664arch {
|
|||
dump_device_tree_blob: Option<PathBuf>,
|
||||
device_tree_overlays: Vec<DtbOverlay>,
|
||||
) -> Result<()> {
|
||||
kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)
|
||||
.map_err(Error::LoadCmdline)?;
|
||||
Self::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)?;
|
||||
|
||||
let mut setup_data = Vec::<SetupData>::new();
|
||||
if let Some(android_fstab) = android_fstab {
|
||||
|
@ -2267,4 +2298,45 @@ mod tests {
|
|||
entry2_data
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmdline_overflow() {
|
||||
const MEM_SIZE: u64 = 0x1000;
|
||||
let gm = GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap();
|
||||
let cmdline_address = GuestAddress(MEM_SIZE - 5);
|
||||
let err = X8664arch::load_cmdline(
|
||||
&gm,
|
||||
cmdline_address,
|
||||
CStr::from_bytes_with_nul(b"12345\0").unwrap(),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, Error::CommandLineOverflow));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmdline_write_end() {
|
||||
const MEM_SIZE: u64 = 0x1000;
|
||||
let gm = GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap();
|
||||
let mut cmdline_address = GuestAddress(45);
|
||||
X8664arch::load_cmdline(
|
||||
&gm,
|
||||
cmdline_address,
|
||||
CStr::from_bytes_with_nul(b"1234\0").unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'1');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'2');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'3');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'4');
|
||||
cmdline_address = cmdline_address.unchecked_add(1);
|
||||
let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
|
||||
assert_eq!(val, b'\0');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue