Skip to content

Commit

Permalink
Support external initramfs and custom cmdline
Browse files Browse the repository at this point in the history
Complement the external kernel support added in the previous commits
with support for external initramfs and a custom kernel command line.

We don't have an immediate use case for this, as loading an external
initramfs may imply losing control of what's happening in the
guest, but it's a low-hanging fruit and may be useful for debugging or
a future use case.

Signed-off-by: Sergio Lopez <[email protected]>
  • Loading branch information
slp committed Feb 18, 2025
1 parent 0e60cff commit beb5379
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 104 deletions.
4 changes: 3 additions & 1 deletion include/libkrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,9 @@ int32_t krun_set_exec(uint32_t ctx_id,
/* Supported disk image formats */
int32_t krun_set_kernel(uint32_t ctx_id,
const char *kernel_path,
uint32_t kernel_format);
uint32_t kernel_format,
const char *initramfs,
const char *cmdline);

/**
* Sets environment variables to be configured in the context of the executable.
Expand Down
6 changes: 5 additions & 1 deletion src/arch/src/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ use crate::DeviceType;

/// Returns a Vec of the valid memory addresses for aarch64.
/// See [`layout`](layout) module for a drawing of the specific memory model for this platform.
pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
pub fn arch_memory_regions(
size: usize,
initrd_size: u64,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
let dram_size = round_up(size, page_size);
let ram_last_addr = layout::DRAM_MEM_START + (dram_size as u64);
Expand All @@ -57,6 +60,7 @@ pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, u
ram_last_addr,
shm_start_addr,
page_size,
initrd_addr: ram_last_addr - layout::FDT_MAX_SIZE as u64 - initrd_size,
};
let regions = if cfg!(feature = "efi") {
vec![
Expand Down
1 change: 1 addition & 0 deletions src/arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub struct ArchMemoryInfo {
pub ram_last_addr: u64,
pub shm_start_addr: u64,
pub page_size: usize,
pub initrd_addr: u64,
}

/// Module for aarch64 related functionality.
Expand Down
19 changes: 13 additions & 6 deletions src/arch/src/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub fn arch_memory_regions(
size: usize,
kernel_load_addr: Option<u64>,
kernel_size: usize,
initrd_size: u64,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };

Expand Down Expand Up @@ -136,6 +137,7 @@ pub fn arch_memory_regions(
ram_last_addr,
shm_start_addr,
page_size,
initrd_addr: ram_last_addr - initrd_size,
};
(info, regions)
}
Expand Down Expand Up @@ -340,7 +342,8 @@ mod tests {

#[test]
fn regions_lt_4gb() {
let (_info, regions) = arch_memory_regions(1usize << 29, KERNEL_LOAD_ADDR, KERNEL_SIZE);
let (_info, regions) =
arch_memory_regions(1usize << 29, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
assert_eq!(2, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
Expand All @@ -353,8 +356,12 @@ mod tests {

#[test]
fn regions_gt_4gb() {
let (_info, regions) =
arch_memory_regions((1usize << 32) + 0x8000, KERNEL_LOAD_ADDR, KERNEL_SIZE);
let (_info, regions) = arch_memory_regions(
(1usize << 32) + 0x8000,
Some(KERNEL_LOAD_ADDR),
KERNEL_SIZE,
0,
);
assert_eq!(3, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
Expand All @@ -381,21 +388,21 @@ mod tests {
// Now assigning some memory that falls before the 32bit memory hole.
let mem_size = 128 << 20;
let (arch_mem_info, arch_mem_regions) =
arch_memory_regions(mem_size, KERNEL_LOAD_ADDR, KERNEL_SIZE);
arch_memory_regions(mem_size, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
let gm = GuestMemoryMmap::from_ranges(&arch_mem_regions).unwrap();
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();

// Now assigning some memory that is equal to the start of the 32bit memory hole.
let mem_size = 3328 << 20;
let (arch_mem_info, arch_mem_regions) =
arch_memory_regions(mem_size, KERNEL_LOAD_ADDR, KERNEL_SIZE);
arch_memory_regions(mem_size, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
let gm = GuestMemoryMmap::from_ranges(&arch_mem_regions).unwrap();
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();

// Now assigning some memory that falls after the 32bit memory hole.
let mem_size = 3330 << 20;
let (arch_mem_info, arch_mem_regions) =
arch_memory_regions(mem_size, KERNEL_LOAD_ADDR, KERNEL_SIZE);
arch_memory_regions(mem_size, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
let gm = GuestMemoryMmap::from_ranges(&arch_mem_regions).unwrap();
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();
}
Expand Down
57 changes: 48 additions & 9 deletions src/libkrun/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use std::env;
use std::ffi::CStr;
#[cfg(target_os = "linux")]
use std::ffi::CString;
#[cfg(all(not(feature = "efi"), not(feature = "tee")))]
#[cfg(all(target_arch = "x86_64", not(feature = "efi"), not(feature = "tee")))]
use std::fs::File;
#[cfg(not(feature = "efi"))]
#[cfg(all(target_arch = "x86_64", not(feature = "efi")))]
use std::os::fd::AsRawFd;
use std::os::fd::RawFd;
use std::path::PathBuf;
Expand Down Expand Up @@ -1033,8 +1033,8 @@ fn create_virtio_net(ctx_cfg: &mut ContextConfig, backend: VirtioNetBackend) {
.expect("Failed to create network interface");
}

#[cfg(all(not(feature = "efi"), not(feature = "tee")))]
fn map_kernel(ctx_id: u32, kernel_path: &str) -> i32 {
#[cfg(all(target_arch = "x86_64", not(feature = "efi"), not(feature = "tee")))]
fn map_kernel(ctx_id: u32, kernel_path: &PathBuf) -> i32 {
let file = match File::options().read(true).write(false).open(kernel_path) {
Ok(file) => file,
Err(err) => {
Expand Down Expand Up @@ -1095,9 +1095,11 @@ pub unsafe extern "C" fn krun_set_kernel(
ctx_id: u32,
c_kernel_path: *const c_char,
kernel_format: u32,
c_initramfs_path: *const c_char,
c_cmdline: *const c_char,
) -> i32 {
let kernel_path = match CStr::from_ptr(c_kernel_path).to_str() {
Ok(path) => path,
let path = match CStr::from_ptr(c_kernel_path).to_str() {
Ok(path) => PathBuf::from(path),
Err(e) => {
error!("Error parsing kernel_path: {:?}", e);
return -libc::EINVAL;
Expand All @@ -1107,8 +1109,8 @@ pub unsafe extern "C" fn krun_set_kernel(
let format = match kernel_format {
// For raw kernels, we map the kernel into the process
// and treat it as a bundled kernel.
#[cfg(all(not(feature = "efi"), not(feature = "tee")))]
0 => return map_kernel(ctx_id, kernel_path),
#[cfg(all(target_arch = "x86_64", not(feature = "efi"), not(feature = "tee")))]
0 => return map_kernel(ctx_id, &path),
1 => KernelFormat::Elf,
2 => KernelFormat::PeGz,
3 => KernelFormat::ImageBz2,
Expand All @@ -1119,9 +1121,46 @@ pub unsafe extern "C" fn krun_set_kernel(
}
};

let (initramfs_path, initramfs_size) = if !c_initramfs_path.is_null() {
match CStr::from_ptr(c_initramfs_path).to_str() {
Ok(path) => {
let path = PathBuf::from(path);
let size = match std::fs::metadata(&path) {
Ok(metadata) => metadata.len(),
Err(e) => {
error!("Can't read initramfs metadata: {:?}", e);
return -libc::EINVAL;
}
};
(Some(path), size)
}
Err(e) => {
error!("Error parsing initramfs path: {:?}", e);
return -libc::EINVAL;
}
}
} else {
(None, 0)
};

let cmdline = if !c_cmdline.is_null() {
match CStr::from_ptr(c_cmdline).to_str() {
Ok(cmdline) => Some(cmdline.to_string()),
Err(e) => {
error!("Error parsing kernel cmdline: {:?}", e);
return -libc::EINVAL;
}
}
} else {
None
};

let external_kernel = ExternalKernel {
path: PathBuf::from(kernel_path),
path,
format,
initramfs_path,
initramfs_size,
cmdline,
};

match CTX_MAP.lock().unwrap().entry(ctx_id) {
Expand Down
Loading

0 comments on commit beb5379

Please sign in to comment.