@@ -14,6 +14,8 @@ use std::os::fd::RawFd;
14
14
use std:: path:: PathBuf ;
15
15
use std:: slice;
16
16
use std:: sync:: atomic:: { AtomicI32 , Ordering } ;
17
+ #[ cfg( not( feature = "efi" ) ) ]
18
+ use std:: sync:: LazyLock ;
17
19
use std:: sync:: Mutex ;
18
20
19
21
#[ cfg( target_os = "macos" ) ]
@@ -48,17 +50,60 @@ use vmm::vmm_config::machine_config::VmConfig;
48
50
use vmm:: vmm_config:: net:: NetworkInterfaceConfig ;
49
51
use vmm:: vmm_config:: vsock:: VsockDeviceConfig ;
50
52
51
- // Minimum krunfw version we require.
52
- #[ cfg( not( feature = "efi" ) ) ]
53
- const KRUNFW_MIN_VERSION : u32 = 4 ;
54
53
// Value returned on success. We use libc's errors otherwise.
55
54
const KRUN_SUCCESS : i32 = 0 ;
56
55
// Maximum number of arguments/environment variables we allow
57
56
const MAX_ARGS : usize = 4096 ;
58
57
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
+
59
66
// Path to the init binary to be executed inside the VM.
60
67
const INIT_PATH : & str = "/init.krun" ;
61
68
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
+
62
107
#[ derive( Default ) ]
63
108
struct TsiConfig {
64
109
port_map : Option < HashMap < u16 , u16 > > ,
@@ -79,6 +124,8 @@ impl Default for NetworkConfig {
79
124
80
125
#[ derive( Default ) ]
81
126
struct ContextConfig {
127
+ #[ cfg( not( feature = "efi" ) ) ]
128
+ krunfw : Option < KrunfwBindings > ,
82
129
vmr : VmResources ,
83
130
workdir : Option < String > ,
84
131
exec_path : Option < String > ,
@@ -242,30 +289,6 @@ impl ContextConfig {
242
289
static CTX_MAP : Lazy < Mutex < HashMap < u32 , ContextConfig > > > = Lazy :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
243
290
static CTX_IDS : AtomicI32 = AtomicI32 :: new ( 0 ) ;
244
291
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
-
269
292
#[ no_mangle]
270
293
pub extern "C" fn krun_set_log_level ( level : u32 ) -> i32 {
271
294
let log_level = match level {
@@ -281,70 +304,20 @@ pub extern "C" fn krun_set_log_level(level: u32) -> i32 {
281
304
}
282
305
283
306
#[ no_mangle]
284
- #[ cfg( not( feature = "efi" ) ) ]
285
307
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
328
313
} ;
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
- }
341
314
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
+ }
348
321
} ;
349
322
350
323
let ctx_id = CTX_IDS . fetch_add ( 1 , Ordering :: SeqCst ) ;
@@ -1104,6 +1077,50 @@ fn create_virtio_net(ctx_cfg: &mut ContextConfig, backend: VirtioNetBackend) {
1104
1077
. expect ( "Failed to create network interface" ) ;
1105
1078
}
1106
1079
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
+
1107
1124
#[ no_mangle]
1108
1125
pub extern "C" fn krun_start_enter ( ctx_id : u32 ) -> i32 {
1109
1126
#[ cfg( target_os = "linux" ) ]
@@ -1128,6 +1145,16 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
1128
1145
None => return -libc:: ENOENT ,
1129
1146
} ;
1130
1147
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
+
1131
1158
#[ cfg( feature = "blk" ) ]
1132
1159
for block_cfg in ctx_cfg. get_block_cfg ( ) {
1133
1160
if ctx_cfg. vmr . add_block_device ( block_cfg) . is_err ( ) {
0 commit comments