88use crossbeam_channel:: { unbounded, Receiver , Sender , TryRecvError } ;
99use libc:: { c_int, c_void, siginfo_t} ;
1010use std:: cell:: Cell ;
11+ use std:: cmp:: max;
1112use std:: fmt:: { Display , Formatter } ;
1213use std:: io;
1314use std:: os:: fd:: RawFd ;
1415
1516#[ cfg( feature = "tee" ) ]
1617use std:: os:: unix:: io:: RawFd ;
1718
19+ use kvm_ioctls:: VcpuExit :: Unsupported ;
1820use std:: result;
1921use std:: sync:: atomic:: { fence, Ordering } ;
2022#[ cfg( not( test) ) ]
@@ -48,8 +50,10 @@ use kvm_bindings::{
4850 KVM_MAX_CPUID_ENTRIES , KVM_PIT_SPEAKER_DUMMY ,
4951} ;
5052use 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 ,
5357} ;
5458use kvm_ioctls:: * ;
5559use utils:: eventfd:: EventFd ;
@@ -65,6 +69,9 @@ use sev::launch::sev as sev_launch;
6569#[ cfg( feature = "amd-sev" ) ]
6670use sev:: launch:: snp;
6771
72+ #[ cfg( feature = "cca" ) ]
73+ use cca:: Realm ;
74+
6875/// Signal number (SIGRTMIN) used to kick Vcpus.
6976pub ( crate ) const VCPU_RTSIG_OFFSET : i32 = 0 ;
7077
@@ -483,11 +490,14 @@ pub struct Vm {
483490
484491 #[ cfg( feature = "amd-sev" ) ]
485492 pub tee : Tee ,
493+
494+ #[ cfg( feature = "cca" ) ]
495+ pub realm : Realm ,
486496}
487497
488498impl Vm {
489499 /// Constructs a new `Vm` using the given `Kvm` instance.
490- #[ cfg( not( feature = "tee" ) ) ]
500+ #[ cfg( all ( not( feature = "tee" ) , not ( feature = "cca" ) ) ) ]
491501 pub fn new ( kvm : & Kvm ) -> Result < Self > {
492502 //create fd for interacting with kvm-vm specific functions
493503 let vm_fd = kvm. create_vm ( ) . map_err ( Error :: VmFd ) ?;
@@ -511,6 +521,26 @@ impl Vm {
511521 } )
512522 }
513523
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+
514544 #[ cfg( feature = "amd-sev" ) ]
515545 pub fn new ( kvm : & Kvm , tee_config : & TeeConfig ) -> Result < Self > {
516546 //create fd for interacting with kvm-vm specific functions
@@ -581,7 +611,7 @@ impl Vm {
581611 . create_guest_memfd ( gmem)
582612 . map_err ( Error :: CreateGuestMemfd ) ?;
583613
584- let memory_region = kvm_userspace_memory_region2 {
614+ let memory_region: kvm_userspace_memory_region2 = kvm_userspace_memory_region2 {
585615 slot : index as u32 ,
586616 flags : KVM_MEM_GUEST_MEMFD ,
587617 guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
@@ -600,6 +630,17 @@ impl Vm {
600630 . set_user_memory_region2 ( memory_region)
601631 . map_err ( Error :: SetUserMemoryRegion2 ) ?;
602632 } ;
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 ( ) ;
603644 } else {
604645 let memory_region = kvm_userspace_memory_region {
605646 slot : index as u32 ,
@@ -808,7 +849,7 @@ type VcpuCell = Cell<Option<*mut Vcpu>>;
808849
809850/// A wrapper around creating and using a kvm-based VCPU.
810851pub struct Vcpu {
811- fd : VcpuFd ,
852+ pub fd : VcpuFd ,
812853 id : u8 ,
813854 mmio_bus : Option < devices:: Bus > ,
814855 #[ allow( dead_code) ]
@@ -1267,19 +1308,39 @@ impl Vcpu {
12671308 info ! ( "Received KVM_EXIT_SHUTDOWN signal" ) ;
12681309 Ok ( VcpuEmulation :: Stopped )
12691310 }
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+ }
12701325 // Documentation specifies that below kvm exits are considered
12711326 // errors.
12721327 VcpuExit :: FailEntry ( reason, vcpu) => {
12731328 error ! ( "Received KVM_EXIT_FAIL_ENTRY signal: reason={reason}, vcpu={vcpu}" ) ;
12741329 Err ( Error :: VcpuUnhandledKvmExit )
12751330 }
1331+ // TODO: to remove this
1332+ Unsupported ( 39 ) => {
1333+ println ! ( "memory fault!" ) ;
1334+ Ok ( VcpuEmulation :: Handled )
1335+ }
12761336 VcpuExit :: InternalError => {
12771337 error ! ( "Received KVM_EXIT_INTERNAL_ERROR signal" ) ;
12781338 Err ( Error :: VcpuUnhandledKvmExit )
12791339 }
12801340 r => {
12811341 // TODO: Are we sure we want to finish running a vcpu upon
12821342 // receiving a vm exit that is not necessarily an error?
1343+ println ! ( "error! {:?}" , r) ;
12831344 error ! ( "Unexpected exit reason on vcpu run: {:?}" , r) ;
12841345 Err ( Error :: VcpuUnhandledKvmExit )
12851346 }
@@ -1605,7 +1666,9 @@ mod tests {
16051666
16061667 // Create valid memory region and test that the initialization is successful.
16071668 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( ) ) ;
16091672
16101673 // Set the maximum number of memory slots to 1 in KvmContext to check the error
16111674 // path of memory_init. Create 2 non-overlapping memory slots.
@@ -1615,7 +1678,9 @@ mod tests {
16151678 ( GuestAddress ( 0x1001 ) , 0x2000 ) ,
16161679 ] )
16171680 . 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( ) ) ;
16191684 }
16201685
16211686 #[ cfg( target_arch = "x86_64" ) ]
0 commit comments