Skip to content

Commit 67f19fc

Browse files
committed
Support external initramfs and custom cmdline
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 <slp@redhat.com>
1 parent 71aaaf2 commit 67f19fc

File tree

8 files changed

+202
-115
lines changed

8 files changed

+202
-115
lines changed

include/libkrun.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,9 @@ int32_t krun_set_exec(uint32_t ctx_id,
423423
/* Supported disk image formats */
424424
int32_t krun_set_kernel(uint32_t ctx_id,
425425
const char *kernel_path,
426-
uint32_t kernel_format);
426+
uint32_t kernel_format,
427+
const char *initramfs,
428+
const char *cmdline);
427429

428430
/**
429431
* Sets environment variables to be configured in the context of the executable.

src/arch/src/aarch64/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ use crate::DeviceType;
4747

4848
/// Returns a Vec of the valid memory addresses for aarch64.
4949
/// See [`layout`](layout) module for a drawing of the specific memory model for this platform.
50-
pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
50+
pub fn arch_memory_regions(
51+
size: usize,
52+
initrd_size: u64,
53+
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
5154
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
5255
let dram_size = round_up(size, page_size);
5356
let ram_last_addr = layout::DRAM_MEM_START + (dram_size as u64);
@@ -57,6 +60,7 @@ pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, u
5760
ram_last_addr,
5861
shm_start_addr,
5962
page_size,
63+
initrd_addr: ram_last_addr - layout::FDT_MAX_SIZE as u64 - initrd_size,
6064
};
6165
let regions = if cfg!(feature = "efi") {
6266
vec![

src/arch/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub struct ArchMemoryInfo {
1212
pub ram_last_addr: u64,
1313
pub shm_start_addr: u64,
1414
pub page_size: usize,
15+
pub initrd_addr: u64,
1516
}
1617

1718
/// Module for aarch64 related functionality.

src/arch/src/x86_64/mod.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub fn arch_memory_regions(
6969
size: usize,
7070
kernel_load_addr: Option<u64>,
7171
kernel_size: usize,
72+
initrd_size: u64,
7273
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
7374
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
7475

@@ -136,6 +137,7 @@ pub fn arch_memory_regions(
136137
ram_last_addr,
137138
shm_start_addr,
138139
page_size,
140+
initrd_addr: ram_last_addr - initrd_size,
139141
};
140142
(info, regions)
141143
}
@@ -150,6 +152,7 @@ pub fn arch_memory_regions(
150152
size: usize,
151153
kernel_load_addr: Option<u64>,
152154
kernel_size: usize,
155+
_initrd_size: u64,
153156
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
154157
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
155158

@@ -195,6 +198,7 @@ pub fn arch_memory_regions(
195198
ram_last_addr,
196199
shm_start_addr,
197200
page_size,
201+
initrd_addr: layout::INITRD_SEV_START,
198202
};
199203
(info, regions)
200204
}
@@ -342,7 +346,8 @@ mod tests {
342346

343347
#[test]
344348
fn regions_lt_4gb() {
345-
let (_info, regions) = arch_memory_regions(1usize << 29, KERNEL_LOAD_ADDR, KERNEL_SIZE);
349+
let (_info, regions) =
350+
arch_memory_regions(1usize << 29, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
346351
assert_eq!(2, regions.len());
347352
assert_eq!(GuestAddress(0), regions[0].0);
348353
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
@@ -355,8 +360,12 @@ mod tests {
355360

356361
#[test]
357362
fn regions_gt_4gb() {
358-
let (_info, regions) =
359-
arch_memory_regions((1usize << 32) + 0x8000, KERNEL_LOAD_ADDR, KERNEL_SIZE);
363+
let (_info, regions) = arch_memory_regions(
364+
(1usize << 32) + 0x8000,
365+
Some(KERNEL_LOAD_ADDR),
366+
KERNEL_SIZE,
367+
0,
368+
);
360369
assert_eq!(3, regions.len());
361370
assert_eq!(GuestAddress(0), regions[0].0);
362371
assert_eq!(KERNEL_LOAD_ADDR as usize, regions[0].1);
@@ -383,21 +392,21 @@ mod tests {
383392
// Now assigning some memory that falls before the 32bit memory hole.
384393
let mem_size = 128 << 20;
385394
let (arch_mem_info, arch_mem_regions) =
386-
arch_memory_regions(mem_size, KERNEL_LOAD_ADDR, KERNEL_SIZE);
395+
arch_memory_regions(mem_size, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
387396
let gm = GuestMemoryMmap::from_ranges(&arch_mem_regions).unwrap();
388397
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();
389398

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

397406
// Now assigning some memory that falls after the 32bit memory hole.
398407
let mem_size = 3330 << 20;
399408
let (arch_mem_info, arch_mem_regions) =
400-
arch_memory_regions(mem_size, KERNEL_LOAD_ADDR, KERNEL_SIZE);
409+
arch_memory_regions(mem_size, Some(KERNEL_LOAD_ADDR), KERNEL_SIZE, 0);
401410
let gm = GuestMemoryMmap::from_ranges(&arch_mem_regions).unwrap();
402411
configure_system(&gm, &arch_mem_info, GuestAddress(0), 0, &None, no_vcpus).unwrap();
403412
}

src/libkrun/src/lib.rs

+44-5
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ fn create_virtio_net(ctx_cfg: &mut ContextConfig, backend: VirtioNetBackend) {
10341034
}
10351035

10361036
#[cfg(all(target_arch = "x86_64", not(feature = "tee")))]
1037-
fn map_kernel(ctx_id: u32, kernel_path: &str) -> i32 {
1037+
fn map_kernel(ctx_id: u32, kernel_path: &PathBuf) -> i32 {
10381038
let file = match File::options().read(true).write(false).open(kernel_path) {
10391039
Ok(file) => file,
10401040
Err(err) => {
@@ -1095,9 +1095,11 @@ pub unsafe extern "C" fn krun_set_kernel(
10951095
ctx_id: u32,
10961096
c_kernel_path: *const c_char,
10971097
kernel_format: u32,
1098+
c_initramfs_path: *const c_char,
1099+
c_cmdline: *const c_char,
10981100
) -> i32 {
1099-
let kernel_path = match CStr::from_ptr(c_kernel_path).to_str() {
1100-
Ok(path) => path,
1101+
let path = match CStr::from_ptr(c_kernel_path).to_str() {
1102+
Ok(path) => PathBuf::from(path),
11011103
Err(e) => {
11021104
error!("Error parsing kernel_path: {:?}", e);
11031105
return -libc::EINVAL;
@@ -1108,7 +1110,7 @@ pub unsafe extern "C" fn krun_set_kernel(
11081110
// For raw kernels in x86_64, we map the kernel into the
11091111
// process and treat it as a bundled kernel.
11101112
#[cfg(all(target_arch = "x86_64", not(feature = "tee")))]
1111-
0 => return map_kernel(ctx_id, kernel_path),
1113+
0 => return map_kernel(ctx_id, path),
11121114
#[cfg(target_arch = "aarch64")]
11131115
0 => KernelFormat::Raw,
11141116
1 => KernelFormat::Elf,
@@ -1121,9 +1123,46 @@ pub unsafe extern "C" fn krun_set_kernel(
11211123
}
11221124
};
11231125

1126+
let (initramfs_path, initramfs_size) = if !c_initramfs_path.is_null() {
1127+
match CStr::from_ptr(c_initramfs_path).to_str() {
1128+
Ok(path) => {
1129+
let path = PathBuf::from(path);
1130+
let size = match std::fs::metadata(&path) {
1131+
Ok(metadata) => metadata.len(),
1132+
Err(e) => {
1133+
error!("Can't read initramfs metadata: {:?}", e);
1134+
return -libc::EINVAL;
1135+
}
1136+
};
1137+
(Some(path), size)
1138+
}
1139+
Err(e) => {
1140+
error!("Error parsing initramfs path: {:?}", e);
1141+
return -libc::EINVAL;
1142+
}
1143+
}
1144+
} else {
1145+
(None, 0)
1146+
};
1147+
1148+
let cmdline = if !c_cmdline.is_null() {
1149+
match CStr::from_ptr(c_cmdline).to_str() {
1150+
Ok(cmdline) => Some(cmdline.to_string()),
1151+
Err(e) => {
1152+
error!("Error parsing kernel cmdline: {:?}", e);
1153+
return -libc::EINVAL;
1154+
}
1155+
}
1156+
} else {
1157+
None
1158+
};
1159+
11241160
let external_kernel = ExternalKernel {
1125-
path: PathBuf::from(kernel_path),
1161+
path,
11261162
format,
1163+
initramfs_path,
1164+
initramfs_size,
1165+
cmdline,
11271166
};
11281167

11291168
match CTX_MAP.lock().unwrap().entry(ctx_id) {

0 commit comments

Comments
 (0)