8
8
use crossbeam_channel:: { unbounded, Receiver , Sender , TryRecvError } ;
9
9
use libc:: { c_int, c_void, siginfo_t} ;
10
10
use std:: cell:: Cell ;
11
+ use std:: cmp:: max;
11
12
use std:: fmt:: { Display , Formatter } ;
12
13
use std:: io;
13
14
use std:: os:: fd:: RawFd ;
14
15
15
16
#[ cfg( feature = "tee" ) ]
16
17
use std:: os:: unix:: io:: RawFd ;
17
18
19
+ use kvm_ioctls:: VcpuExit :: Unsupported ;
18
20
use std:: result;
19
21
use std:: sync:: atomic:: { fence, Ordering } ;
20
22
#[ cfg( not( test) ) ]
@@ -48,8 +50,10 @@ use kvm_bindings::{
48
50
KVM_MAX_CPUID_ENTRIES , KVM_PIT_SPEAKER_DUMMY ,
49
51
} ;
50
52
use kvm_bindings:: {
51
- kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2,
52
- KVM_API_VERSION , KVM_MEM_GUEST_MEMFD ,
53
+ kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region,
54
+ kvm_userspace_memory_region2, KVM_API_VERSION , KVM_MEMORY_ATTRIBUTE_PRIVATE ,
55
+ KVM_MEMORY_EXIT_FLAG_PRIVATE , KVM_MEM_GUEST_MEMFD , KVM_VM_TYPE_ARM_IPA_SIZE_MASK ,
56
+ KVM_VM_TYPE_ARM_REALM ,
53
57
} ;
54
58
use kvm_ioctls:: * ;
55
59
use utils:: eventfd:: EventFd ;
@@ -65,6 +69,9 @@ use sev::launch::sev as sev_launch;
65
69
#[ cfg( feature = "amd-sev" ) ]
66
70
use sev:: launch:: snp;
67
71
72
+ #[ cfg( feature = "cca" ) ]
73
+ use cca:: Realm ;
74
+
68
75
/// Signal number (SIGRTMIN) used to kick Vcpus.
69
76
pub ( crate ) const VCPU_RTSIG_OFFSET : i32 = 0 ;
70
77
@@ -483,11 +490,14 @@ pub struct Vm {
483
490
484
491
#[ cfg( feature = "amd-sev" ) ]
485
492
pub tee : Tee ,
493
+
494
+ #[ cfg( feature = "cca" ) ]
495
+ pub realm : Realm ,
486
496
}
487
497
488
498
impl Vm {
489
499
/// Constructs a new `Vm` using the given `Kvm` instance.
490
- #[ cfg( not( feature = "tee" ) ) ]
500
+ #[ cfg( all ( not( feature = "tee" ) , not ( feature = "cca" ) ) ) ]
491
501
pub fn new ( kvm : & Kvm ) -> Result < Self > {
492
502
//create fd for interacting with kvm-vm specific functions
493
503
let vm_fd = kvm. create_vm ( ) . map_err ( Error :: VmFd ) ?;
@@ -511,6 +521,26 @@ impl Vm {
511
521
} )
512
522
}
513
523
524
+ #[ cfg( feature = "cca" ) ]
525
+ pub fn new ( kvm : & Kvm , max_ipa : usize ) -> Result < Self > {
526
+ //create fd for interacting with kvm-vm specific functions
527
+ let ipa_bits = max ( 64u32 - max_ipa. leading_zeros ( ) - 1 , 32 ) + 1 ;
528
+ let vm_fd = kvm
529
+ . create_vm_with_type (
530
+ ( KVM_VM_TYPE_ARM_REALM | ( ipa_bits & KVM_VM_TYPE_ARM_IPA_SIZE_MASK ) ) . into ( ) ,
531
+ )
532
+ . map_err ( Error :: VmFd ) ?;
533
+
534
+ let realm = Realm :: new ( ) . unwrap ( ) ;
535
+
536
+ Ok ( Vm {
537
+ fd : vm_fd,
538
+ #[ cfg( target_arch = "aarch64" ) ]
539
+ irqchip_handle : None ,
540
+ realm,
541
+ } )
542
+ }
543
+
514
544
#[ cfg( feature = "amd-sev" ) ]
515
545
pub fn new ( kvm : & Kvm , tee_config : & TeeConfig ) -> Result < Self > {
516
546
//create fd for interacting with kvm-vm specific functions
@@ -581,7 +611,7 @@ impl Vm {
581
611
. create_guest_memfd ( gmem)
582
612
. map_err ( Error :: CreateGuestMemfd ) ?;
583
613
584
- let memory_region = kvm_userspace_memory_region2 {
614
+ let memory_region: kvm_userspace_memory_region2 = kvm_userspace_memory_region2 {
585
615
slot : index as u32 ,
586
616
flags : KVM_MEM_GUEST_MEMFD ,
587
617
guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
@@ -600,6 +630,17 @@ impl Vm {
600
630
. set_user_memory_region2 ( memory_region)
601
631
. map_err ( Error :: SetUserMemoryRegion2 ) ?;
602
632
} ;
633
+
634
+ // set private by default when using guestmemfd
635
+ // this imitates QEMU behavior
636
+ let attr = kvm_memory_attributes {
637
+ address : region. start_addr ( ) . raw_value ( ) ,
638
+ size : region. len ( ) ,
639
+ attributes : KVM_MEMORY_ATTRIBUTE_PRIVATE as u64 ,
640
+ flags : 0 ,
641
+ } ;
642
+
643
+ self . fd . set_memory_attributes ( attr) . unwrap ( ) ;
603
644
} else {
604
645
let memory_region = kvm_userspace_memory_region {
605
646
slot : index as u32 ,
@@ -808,7 +849,7 @@ type VcpuCell = Cell<Option<*mut Vcpu>>;
808
849
809
850
/// A wrapper around creating and using a kvm-based VCPU.
810
851
pub struct Vcpu {
811
- fd : VcpuFd ,
852
+ pub fd : VcpuFd ,
812
853
id : u8 ,
813
854
mmio_bus : Option < devices:: Bus > ,
814
855
#[ allow( dead_code) ]
@@ -1267,19 +1308,39 @@ impl Vcpu {
1267
1308
info ! ( "Received KVM_EXIT_SHUTDOWN signal" ) ;
1268
1309
Ok ( VcpuEmulation :: Stopped )
1269
1310
}
1311
+ VcpuExit :: MemoryFault {
1312
+ flags,
1313
+ gpa : _,
1314
+ size : _,
1315
+ } => {
1316
+ // TODO: flags can be private or shared
1317
+ if flags & !KVM_MEMORY_EXIT_FLAG_PRIVATE as u64 != 0 {
1318
+ error ! ( "KVM_EXIT_MEMORY_FAULT: Unknown flag {}" , flags) ;
1319
+ Err ( Error :: VcpuUnhandledKvmExit )
1320
+ } else {
1321
+ // TODO: to transition from shared to private
1322
+ Ok ( VcpuEmulation :: Handled )
1323
+ }
1324
+ }
1270
1325
// Documentation specifies that below kvm exits are considered
1271
1326
// errors.
1272
1327
VcpuExit :: FailEntry ( reason, vcpu) => {
1273
1328
error ! ( "Received KVM_EXIT_FAIL_ENTRY signal: reason={reason}, vcpu={vcpu}" ) ;
1274
1329
Err ( Error :: VcpuUnhandledKvmExit )
1275
1330
}
1331
+ // TODO: to remove this
1332
+ Unsupported ( 39 ) => {
1333
+ println ! ( "memory fault!" ) ;
1334
+ Ok ( VcpuEmulation :: Handled )
1335
+ }
1276
1336
VcpuExit :: InternalError => {
1277
1337
error ! ( "Received KVM_EXIT_INTERNAL_ERROR signal" ) ;
1278
1338
Err ( Error :: VcpuUnhandledKvmExit )
1279
1339
}
1280
1340
r => {
1281
1341
// TODO: Are we sure we want to finish running a vcpu upon
1282
1342
// receiving a vm exit that is not necessarily an error?
1343
+ println ! ( "error! {:?}" , r) ;
1283
1344
error ! ( "Unexpected exit reason on vcpu run: {:?}" , r) ;
1284
1345
Err ( Error :: VcpuUnhandledKvmExit )
1285
1346
}
@@ -1605,7 +1666,9 @@ mod tests {
1605
1666
1606
1667
// Create valid memory region and test that the initialization is successful.
1607
1668
let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x1000 ) ] ) . unwrap ( ) ;
1608
- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_ok( ) ) ;
1669
+ assert ! ( vm
1670
+ . memory_init( & gm, kvm_context. max_memslots( ) , false )
1671
+ . is_ok( ) ) ;
1609
1672
1610
1673
// Set the maximum number of memory slots to 1 in KvmContext to check the error
1611
1674
// path of memory_init. Create 2 non-overlapping memory slots.
@@ -1615,7 +1678,9 @@ mod tests {
1615
1678
( GuestAddress ( 0x1001 ) , 0x2000 ) ,
1616
1679
] )
1617
1680
. unwrap ( ) ;
1618
- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_err( ) ) ;
1681
+ assert ! ( vm
1682
+ . memory_init( & gm, kvm_context. max_memslots( ) , false )
1683
+ . is_err( ) ) ;
1619
1684
}
1620
1685
1621
1686
#[ cfg( target_arch = "x86_64" ) ]
0 commit comments