Skip to content

Commit e789b3f

Browse files
committed
libkrun: load libkrunfw as a dynamic library
Instead of linking statically against libkrunfw, load it as a dynamic library. This will enable us to make its presence optional, which will come handy when we support loading external payloads. Signed-off-by: Sergio Lopez <[email protected]>
1 parent e29be7e commit e789b3f

File tree

4 files changed

+117
-94
lines changed

4 files changed

+117
-94
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/libkrun/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ virgl_resource_map2 = []
1919
crossbeam-channel = "0.5"
2020
env_logger = "0.9.0"
2121
libc = ">=0.2.39"
22+
libloading = "0.8"
2223
log = "0.4.0"
2324
once_cell = "1.4.1"
2425

src/libkrun/build.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
fn main() {
22
#[cfg(target_os = "macos")]
33
println!("cargo:rustc-link-lib=framework=Hypervisor");
4-
#[cfg(target_os = "macos")]
5-
println!("cargo:rustc-link-search=/opt/homebrew/lib");
6-
#[cfg(all(not(feature = "tee"), not(feature = "efi")))]
7-
println!("cargo:rustc-link-lib=krunfw");
8-
#[cfg(feature = "tee")]
9-
println!("cargo:rustc-link-lib=krunfw-sev");
104
}

src/libkrun/src/lib.rs

Lines changed: 115 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use std::os::fd::RawFd;
1414
use std::path::PathBuf;
1515
use std::slice;
1616
use std::sync::atomic::{AtomicI32, Ordering};
17+
#[cfg(not(feature = "efi"))]
18+
use std::sync::LazyLock;
1719
use std::sync::Mutex;
1820

1921
#[cfg(target_os = "macos")]
@@ -48,17 +50,60 @@ use vmm::vmm_config::machine_config::VmConfig;
4850
use vmm::vmm_config::net::NetworkInterfaceConfig;
4951
use vmm::vmm_config::vsock::VsockDeviceConfig;
5052

51-
// Minimum krunfw version we require.
52-
#[cfg(not(feature = "efi"))]
53-
const KRUNFW_MIN_VERSION: u32 = 4;
5453
// Value returned on success. We use libc's errors otherwise.
5554
const KRUN_SUCCESS: i32 = 0;
5655
// Maximum number of arguments/environment variables we allow
5756
const MAX_ARGS: usize = 4096;
5857

58+
// krunfw library name for each context
59+
#[cfg(all(target_os = "linux", not(feature = "amd-sev")))]
60+
const KRUNFW_NAME: &str = "libkrunfw.so.4";
61+
#[cfg(all(target_os = "linux", feature = "amd-sev"))]
62+
const KRUNFW_NAME: &str = "libkrunfw-sev.so.4";
63+
#[cfg(target_os = "macos")]
64+
const KRUNFW_NAME: &str = "libkrunfw.4.dylib";
65+
5966
// Path to the init binary to be executed inside the VM.
6067
const INIT_PATH: &str = "/init.krun";
6168

69+
#[cfg(not(feature = "efi"))]
70+
static KRUNFW: LazyLock<libloading::Library> =
71+
LazyLock::new(|| unsafe { libloading::Library::new(KRUNFW_NAME).unwrap() });
72+
73+
#[cfg(not(feature = "efi"))]
74+
pub struct KrunfwBindings {
75+
get_kernel: libloading::Symbol<
76+
'static,
77+
unsafe extern "C" fn(*mut u64, *mut u64, *mut size_t) -> *mut c_char,
78+
>,
79+
#[cfg(feature = "tee")]
80+
get_initrd: libloading::Symbol<'static, unsafe extern "C" fn(*mut size_t) -> *mut c_char>,
81+
#[cfg(feature = "tee")]
82+
get_qboot: libloading::Symbol<'static, unsafe extern "C" fn(*mut size_t) -> *mut c_char>,
83+
}
84+
85+
#[cfg(not(feature = "efi"))]
86+
impl KrunfwBindings {
87+
fn load_bindings() -> Result<KrunfwBindings, libloading::Error> {
88+
Ok(unsafe {
89+
KrunfwBindings {
90+
get_kernel: KRUNFW.get(b"krunfw_get_kernel")?,
91+
#[cfg(feature = "tee")]
92+
get_initrd: KRUNFW.get(b"krunfw_get_initrd")?,
93+
#[cfg(feature = "tee")]
94+
get_qboot: KRUNFW.get(b"krunfw_get_qboot")?,
95+
}
96+
})
97+
}
98+
99+
pub fn new() -> Option<Self> {
100+
match Self::load_bindings() {
101+
Ok(bindings) => Some(bindings),
102+
Err(_) => None,
103+
}
104+
}
105+
}
106+
62107
#[derive(Default)]
63108
struct TsiConfig {
64109
port_map: Option<HashMap<u16, u16>>,
@@ -79,6 +124,8 @@ impl Default for NetworkConfig {
79124

80125
#[derive(Default)]
81126
struct ContextConfig {
127+
#[cfg(not(feature = "efi"))]
128+
krunfw: Option<KrunfwBindings>,
82129
vmr: VmResources,
83130
workdir: Option<String>,
84131
exec_path: Option<String>,
@@ -242,30 +289,6 @@ impl ContextConfig {
242289
static CTX_MAP: Lazy<Mutex<HashMap<u32, ContextConfig>>> = Lazy::new(|| Mutex::new(HashMap::new()));
243290
static CTX_IDS: AtomicI32 = AtomicI32::new(0);
244291

245-
#[cfg(all(not(feature = "tee"), not(feature = "efi")))]
246-
#[link(name = "krunfw")]
247-
extern "C" {
248-
fn krunfw_get_kernel(
249-
load_addr: *mut u64,
250-
entry_addr: *mut u64,
251-
size: *mut size_t,
252-
) -> *mut c_char;
253-
fn krunfw_get_version() -> u32;
254-
}
255-
256-
#[cfg(feature = "tee")]
257-
#[link(name = "krunfw-sev")]
258-
extern "C" {
259-
fn krunfw_get_qboot(size: *mut size_t) -> *mut c_char;
260-
fn krunfw_get_initrd(size: *mut size_t) -> *mut c_char;
261-
fn krunfw_get_kernel(
262-
load_addr: *mut u64,
263-
entry_addr: *mut u64,
264-
size: *mut size_t,
265-
) -> *mut c_char;
266-
fn krunfw_get_version() -> u32;
267-
}
268-
269292
#[no_mangle]
270293
pub extern "C" fn krun_set_log_level(level: u32) -> i32 {
271294
let log_level = match level {
@@ -281,70 +304,20 @@ pub extern "C" fn krun_set_log_level(level: u32) -> i32 {
281304
}
282305

283306
#[no_mangle]
284-
#[cfg(not(feature = "efi"))]
285307
pub extern "C" fn krun_create_ctx() -> i32 {
286-
let krunfw_version = unsafe { krunfw_get_version() };
287-
if krunfw_version < KRUNFW_MIN_VERSION {
288-
eprintln!("Unsupported libkrunfw version: {krunfw_version}");
289-
return -libc::EINVAL;
290-
}
291-
292-
let mut kernel_guest_addr: u64 = 0;
293-
let mut kernel_entry_addr: u64 = 0;
294-
let mut kernel_size: usize = 0;
295-
let kernel_host_addr = unsafe {
296-
krunfw_get_kernel(
297-
&mut kernel_guest_addr as *mut u64,
298-
&mut kernel_entry_addr as *mut u64,
299-
&mut kernel_size as *mut usize,
300-
)
301-
};
302-
303-
let mut ctx_cfg = ContextConfig::default();
304-
305-
let kernel_bundle = KernelBundle {
306-
host_addr: kernel_host_addr as u64,
307-
guest_addr: kernel_guest_addr,
308-
entry_addr: kernel_entry_addr,
309-
size: kernel_size,
310-
};
311-
ctx_cfg.vmr.set_kernel_bundle(kernel_bundle).unwrap();
312-
313-
#[cfg(feature = "tee")]
314-
{
315-
let mut qboot_size: usize = 0;
316-
let qboot_host_addr = unsafe { krunfw_get_qboot(&mut qboot_size as *mut usize) };
317-
let qboot_bundle = QbootBundle {
318-
host_addr: qboot_host_addr as u64,
319-
size: qboot_size,
320-
};
321-
ctx_cfg.vmr.set_qboot_bundle(qboot_bundle).unwrap();
322-
323-
let mut initrd_size: usize = 0;
324-
let initrd_host_addr = unsafe { krunfw_get_initrd(&mut initrd_size as *mut usize) };
325-
let initrd_bundle = InitrdBundle {
326-
host_addr: initrd_host_addr as u64,
327-
size: initrd_size,
308+
let ctx_cfg = {
309+
let shutdown_efd = if cfg!(feature = "tee") {
310+
Some(EventFd::new(utils::eventfd::EFD_NONBLOCK).unwrap())
311+
} else {
312+
None
328313
};
329-
ctx_cfg.vmr.set_initrd_bundle(initrd_bundle).unwrap();
330-
}
331-
332-
let ctx_id = CTX_IDS.fetch_add(1, Ordering::SeqCst);
333-
if ctx_id == i32::MAX || CTX_MAP.lock().unwrap().contains_key(&(ctx_id as u32)) {
334-
// libkrun is not intended to be used as a daemon for managing VMs.
335-
panic!("Context ID namespace exhausted");
336-
}
337-
CTX_MAP.lock().unwrap().insert(ctx_id as u32, ctx_cfg);
338-
339-
ctx_id
340-
}
341314

342-
#[no_mangle]
343-
#[cfg(feature = "efi")]
344-
pub extern "C" fn krun_create_ctx() -> i32 {
345-
let ctx_cfg = ContextConfig {
346-
shutdown_efd: Some(EventFd::new(utils::eventfd::EFD_NONBLOCK).unwrap()),
347-
..Default::default()
315+
ContextConfig {
316+
#[cfg(not(feature = "efi"))]
317+
krunfw: KrunfwBindings::new(),
318+
shutdown_efd,
319+
..Default::default()
320+
}
348321
};
349322

350323
let ctx_id = CTX_IDS.fetch_add(1, Ordering::SeqCst);
@@ -1104,6 +1077,50 @@ fn create_virtio_net(ctx_cfg: &mut ContextConfig, backend: VirtioNetBackend) {
11041077
.expect("Failed to create network interface");
11051078
}
11061079

1080+
unsafe fn load_krunfw_payload(
1081+
krunfw: &KrunfwBindings,
1082+
vmr: &mut VmResources,
1083+
) -> Result<(), libloading::Error> {
1084+
let mut kernel_guest_addr: u64 = 0;
1085+
let mut kernel_entry_addr: u64 = 0;
1086+
let mut kernel_size: usize = 0;
1087+
let kernel_host_addr = unsafe {
1088+
(krunfw.get_kernel)(
1089+
&mut kernel_guest_addr as *mut u64,
1090+
&mut kernel_entry_addr as *mut u64,
1091+
&mut kernel_size as *mut usize,
1092+
)
1093+
};
1094+
let kernel_bundle = KernelBundle {
1095+
host_addr: kernel_host_addr as u64,
1096+
guest_addr: kernel_guest_addr,
1097+
entry_addr: kernel_entry_addr,
1098+
size: kernel_size,
1099+
};
1100+
vmr.set_kernel_bundle(kernel_bundle).unwrap();
1101+
1102+
#[cfg(feature = "tee")]
1103+
{
1104+
let mut qboot_size: usize = 0;
1105+
let qboot_host_addr = unsafe { (krunfw.get_qboot)(&mut qboot_size as *mut usize) };
1106+
let qboot_bundle = QbootBundle {
1107+
host_addr: qboot_host_addr as u64,
1108+
size: qboot_size,
1109+
};
1110+
ctx_cfg.vmr.set_qboot_bundle(qboot_bundle).unwrap();
1111+
1112+
let mut initrd_size: usize = 0;
1113+
let initrd_host_addr = unsafe { (krunfw.get_initrd)(&mut initrd_size as *mut usize) };
1114+
let initrd_bundle = InitrdBundle {
1115+
host_addr: initrd_host_addr as u64,
1116+
size: initrd_size,
1117+
};
1118+
ctx_cfg.vmr.set_initrd_bundle(initrd_bundle).unwrap();
1119+
}
1120+
1121+
Ok(())
1122+
}
1123+
11071124
#[no_mangle]
11081125
pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
11091126
#[cfg(target_os = "linux")]
@@ -1128,6 +1145,16 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
11281145
None => return -libc::ENOENT,
11291146
};
11301147

1148+
if let Some(ref krunfw) = ctx_cfg.krunfw {
1149+
if let Err(err) = unsafe { load_krunfw_payload(krunfw, &mut ctx_cfg.vmr) } {
1150+
eprintln!("Can't load libkrunfw symbols: {err}");
1151+
return -libc::ENOENT;
1152+
}
1153+
} else {
1154+
eprintln!("Couldn't find or load {}", KRUNFW_NAME);
1155+
return -libc::ENOENT;
1156+
}
1157+
11311158
#[cfg(feature = "blk")]
11321159
for block_cfg in ctx_cfg.get_block_cfg() {
11331160
if ctx_cfg.vmr.add_block_device(block_cfg).is_err() {

0 commit comments

Comments
 (0)