Skip to content

Commit 07a2ebe

Browse files
committed
libkrun: support external kernels on aarch64
Introduce initial support for external kernels by dealing with the easier case: raw images on aarch64. This commit adds a new function, "krun_set_kernel", which receives a path to the external kernel. Future commits will add support for more image formats and x86_64. Signed-off-by: Sergio Lopez <[email protected]>
1 parent 69dd61b commit 07a2ebe

File tree

3 files changed

+108
-18
lines changed

3 files changed

+108
-18
lines changed

include/libkrun.h

+13
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,19 @@ int32_t krun_set_exec(uint32_t ctx_id,
403403
const char *const argv[],
404404
const char *const envp[]);
405405

406+
/**
407+
* Sets the path to the kernel to be loaded in the microVM.
408+
*
409+
* Arguments:
410+
* "ctx_id" - the configuration context ID.
411+
* "kernel_path" - the path to the kernel, relative to the host's filesystem.
412+
*
413+
* Returns:
414+
* Zero on success or a negative error number on failure.
415+
*/
416+
int32_t krun_set_kernel(uint32_t ctx_id,
417+
const char *kernel_path);
418+
406419
/**
407420
* Sets environment variables to be configured in the context of the executable.
408421
*

src/libkrun/src/lib.rs

+95-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use std::env;
88
use std::ffi::CStr;
99
#[cfg(target_os = "linux")]
1010
use std::ffi::CString;
11-
#[cfg(target_os = "linux")]
11+
#[cfg(all(target_arch = "aarch64", not(feature = "efi")))]
12+
use std::fs::File;
13+
#[cfg(not(feature = "efi"))]
1214
use std::os::fd::AsRawFd;
1315
use std::os::fd::RawFd;
1416
use std::path::PathBuf;
@@ -55,10 +57,10 @@ const MAX_ARGS: usize = 4096;
5557

5658
// krunfw library name for each context
5759
#[cfg(all(target_os = "linux", not(feature = "amd-sev")))]
58-
const KRUNKW_NAME: &str = "libkrunfw.so.4";
60+
const KRUNFW_NAME: &str = "libkrunfw.so.4";
5961
#[cfg(all(target_os = "linux", feature = "amd-sev"))]
6062
const KRUNFW_NAME: &str = "libkrunfw-sev.so.4";
61-
#[cfg(target_os = "macos")]
63+
#[cfg(all(target_os = "macos", not(feature = "efi")))]
6264
const KRUNFW_NAME: &str = "libkrunfw.4.dylib";
6365

6466
// Path to the init binary to be executed inside the VM.
@@ -106,6 +108,8 @@ struct ContextConfig {
106108
gpu_shm_size: Option<usize>,
107109
enable_snd: bool,
108110
console_output: Option<PathBuf>,
111+
#[cfg(not(feature = "efi"))]
112+
external_kernel: bool,
109113
}
110114

111115
impl ContextConfig {
@@ -1029,6 +1033,77 @@ fn create_virtio_net(ctx_cfg: &mut ContextConfig, backend: VirtioNetBackend) {
10291033
.expect("Failed to create network interface");
10301034
}
10311035

1036+
#[cfg(any(target_arch = "x86_64", feature = "tee", feature = "efi"))]
1037+
#[allow(clippy::format_collect)]
1038+
#[allow(clippy::missing_safety_doc)]
1039+
#[no_mangle]
1040+
pub unsafe extern "C" fn krun_set_kernel(_ctx_id: u32, _c_kernel_path: *const c_char) -> i32 {
1041+
-libc::EOPNOTSUPP
1042+
}
1043+
1044+
#[cfg(all(target_arch = "aarch64", not(feature = "efi")))]
1045+
#[allow(clippy::format_collect)]
1046+
#[allow(clippy::missing_safety_doc)]
1047+
#[no_mangle]
1048+
pub unsafe extern "C" fn krun_set_kernel(ctx_id: u32, c_kernel_path: *const c_char) -> i32 {
1049+
let kernel_path = match CStr::from_ptr(c_kernel_path).to_str() {
1050+
Ok(path) => path,
1051+
Err(e) => {
1052+
error!("Error parsing kernel_path: {:?}", e);
1053+
return -libc::EINVAL;
1054+
}
1055+
};
1056+
1057+
let file = match File::options().read(true).write(false).open(kernel_path) {
1058+
Ok(file) => file,
1059+
Err(err) => {
1060+
error!("Error opening external kernel: {err}");
1061+
return -libc::EINVAL;
1062+
}
1063+
};
1064+
1065+
let kernel_size = file.metadata().unwrap().len();
1066+
1067+
let kernel_host_addr = unsafe {
1068+
libc::mmap(
1069+
std::ptr::null_mut(),
1070+
kernel_size as usize,
1071+
libc::PROT_READ,
1072+
libc::MAP_SHARED,
1073+
file.as_raw_fd(),
1074+
0_i64,
1075+
)
1076+
};
1077+
if kernel_host_addr == libc::MAP_FAILED {
1078+
error!("Can't load kernel into process map");
1079+
return -libc::EINVAL;
1080+
}
1081+
1082+
let kernel_bundle = KernelBundle {
1083+
host_addr: kernel_host_addr as u64,
1084+
guest_addr: 0x8000_0000,
1085+
entry_addr: 0x8000_0000,
1086+
size: kernel_size as usize,
1087+
};
1088+
1089+
match CTX_MAP.lock().unwrap().entry(ctx_id) {
1090+
Entry::Occupied(mut ctx_cfg) => {
1091+
let ctx_cfg = ctx_cfg.get_mut();
1092+
if ctx_cfg.external_kernel {
1093+
error!("An extenal kernel was already configured");
1094+
return -libc::EINVAL;
1095+
} else {
1096+
ctx_cfg.external_kernel = true;
1097+
}
1098+
ctx_cfg.vmr.set_kernel_bundle(kernel_bundle).unwrap()
1099+
}
1100+
Entry::Vacant(_) => return -libc::ENOENT,
1101+
}
1102+
1103+
KRUN_SUCCESS
1104+
}
1105+
1106+
#[cfg(not(feature = "efi"))]
10321107
unsafe fn load_krunfw_payload(
10331108
krunfw: &libloading::Library,
10341109
vmr: &mut VmResources,
@@ -1072,15 +1147,15 @@ unsafe fn load_krunfw_payload(
10721147
host_addr: qboot_host_addr as u64,
10731148
size: qboot_size,
10741149
};
1075-
ctx_cfg.vmr.set_qboot_bundle(qboot_bundle).unwrap();
1150+
vmr.set_qboot_bundle(qboot_bundle).unwrap();
10761151

10771152
let mut initrd_size: usize = 0;
10781153
let initrd_host_addr = unsafe { krunfw_get_initrd(&mut initrd_size as *mut usize) };
10791154
let initrd_bundle = InitrdBundle {
10801155
host_addr: initrd_host_addr as u64,
10811156
size: initrd_size,
10821157
};
1083-
ctx_cfg.vmr.set_initrd_bundle(initrd_bundle).unwrap();
1158+
vmr.set_initrd_bundle(initrd_bundle).unwrap();
10841159
}
10851160

10861161
Ok(())
@@ -1110,18 +1185,24 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
11101185
None => return -libc::ENOENT,
11111186
};
11121187

1113-
// The reference to the dynamically loaded library must be kept alive.
1114-
let krunfw = match unsafe { libloading::Library::new(KRUNKW_NAME) } {
1115-
Ok(lib) => lib,
1116-
Err(err) => {
1117-
eprintln!("Can't load libkrunfw: {err}");
1188+
#[cfg(not(feature = "efi"))]
1189+
let _krunfw = if !ctx_cfg.external_kernel {
1190+
// The reference to the dynamically loaded library must be kept alive.
1191+
let krunfw = match unsafe { libloading::Library::new(KRUNFW_NAME) } {
1192+
Ok(lib) => lib,
1193+
Err(err) => {
1194+
eprintln!("Can't load libkrunfw: {err}");
1195+
return -libc::ENOENT;
1196+
}
1197+
};
1198+
if let Err(err) = unsafe { load_krunfw_payload(&krunfw, &mut ctx_cfg.vmr) } {
1199+
eprintln!("Can't load libkrunfw symbols: {err}");
11181200
return -libc::ENOENT;
11191201
}
1202+
Some(krunfw)
1203+
} else {
1204+
None
11201205
};
1121-
if let Err(err) = unsafe { load_krunfw_payload(&krunfw, &mut ctx_cfg.vmr) } {
1122-
eprintln!("Can't load libkrunfw symbols: {err}");
1123-
return -libc::ENOENT;
1124-
}
11251206

11261207
#[cfg(feature = "blk")]
11271208
for block_cfg in ctx_cfg.get_block_cfg() {

src/vmm/src/resources.rs

-4
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,6 @@ impl VmResources {
199199
return Err(KernelBundleError::InvalidGuestAddress);
200200
}
201201

202-
if kernel_bundle.size & (page_size - 1) != 0 {
203-
return Err(KernelBundleError::InvalidSize);
204-
}
205-
206202
self.kernel_bundle = Some(kernel_bundle);
207203
Ok(())
208204
}

0 commit comments

Comments
 (0)