Alice Wang | 0bdc3f6 | 2023-03-15 10:46:12 +0000 | [diff] [blame] | 1 | // Copyright 2023, The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | //! Wrappers around hypervisor back-ends. |
| 16 | |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 17 | extern crate alloc; |
| 18 | |
Alice Wang | 3132911 | 2023-04-13 09:02:36 +0000 | [diff] [blame] | 19 | mod common; |
Yi-De Wu | 725bd92 | 2023-04-24 16:26:52 +0800 | [diff] [blame] | 20 | mod geniezone; |
Srivatsa Vaddagiri | cb5959e | 2023-04-20 05:27:16 -0700 | [diff] [blame] | 21 | mod gunyah; |
Alice Wang | 0bdc3f6 | 2023-03-15 10:46:12 +0000 | [diff] [blame] | 22 | mod kvm; |
| 23 | |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 24 | use crate::error::{Error, Result}; |
| 25 | use alloc::boxed::Box; |
Pierre-Clément Tosi | d643cfe | 2023-06-29 09:30:51 +0000 | [diff] [blame] | 26 | use common::Hypervisor; |
Jaewan Kim | fb24bdd | 2023-11-27 17:25:02 +0900 | [diff] [blame] | 27 | pub use common::{ |
| 28 | DeviceAssigningHypervisor, MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE, |
| 29 | }; |
Yi-De Wu | 725bd92 | 2023-04-24 16:26:52 +0800 | [diff] [blame] | 30 | pub use geniezone::GeniezoneError; |
| 31 | use geniezone::GeniezoneHypervisor; |
Srivatsa Vaddagiri | cb5959e | 2023-04-20 05:27:16 -0700 | [diff] [blame] | 32 | use gunyah::GunyahHypervisor; |
Andrew Walbran | 9afab67 | 2023-04-17 14:26:23 +0000 | [diff] [blame] | 33 | pub use kvm::KvmError; |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 34 | use kvm::{ProtectedKvmHypervisor, RegularKvmHypervisor}; |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 35 | use once_cell::race::OnceBox; |
Andrew Walbran | f44f160 | 2023-05-30 14:59:19 +0000 | [diff] [blame] | 36 | use smccc::hvc64; |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 37 | use uuid::Uuid; |
Alice Wang | 3132911 | 2023-04-13 09:02:36 +0000 | [diff] [blame] | 38 | |
| 39 | enum HypervisorBackend { |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 40 | RegularKvm, |
Srivatsa Vaddagiri | cb5959e | 2023-04-20 05:27:16 -0700 | [diff] [blame] | 41 | Gunyah, |
Yi-De Wu | 725bd92 | 2023-04-24 16:26:52 +0800 | [diff] [blame] | 42 | Geniezone, |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 43 | ProtectedKvm, |
Alice Wang | 0bdc3f6 | 2023-03-15 10:46:12 +0000 | [diff] [blame] | 44 | } |
| 45 | |
Alice Wang | 3132911 | 2023-04-13 09:02:36 +0000 | [diff] [blame] | 46 | impl HypervisorBackend { |
| 47 | fn get_hypervisor(&self) -> &'static dyn Hypervisor { |
| 48 | match self { |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 49 | Self::RegularKvm => &RegularKvmHypervisor, |
Srivatsa Vaddagiri | cb5959e | 2023-04-20 05:27:16 -0700 | [diff] [blame] | 50 | Self::Gunyah => &GunyahHypervisor, |
Yi-De Wu | 725bd92 | 2023-04-24 16:26:52 +0800 | [diff] [blame] | 51 | Self::Geniezone => &GeniezoneHypervisor, |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 52 | Self::ProtectedKvm => &ProtectedKvmHypervisor, |
Alice Wang | 3132911 | 2023-04-13 09:02:36 +0000 | [diff] [blame] | 53 | } |
| 54 | } |
Alice Wang | 0bdc3f6 | 2023-03-15 10:46:12 +0000 | [diff] [blame] | 55 | } |
| 56 | |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 57 | impl TryFrom<Uuid> for HypervisorBackend { |
| 58 | type Error = Error; |
| 59 | |
| 60 | fn try_from(uuid: Uuid) -> Result<HypervisorBackend> { |
| 61 | match uuid { |
Yi-De Wu | 725bd92 | 2023-04-24 16:26:52 +0800 | [diff] [blame] | 62 | GeniezoneHypervisor::UUID => Ok(HypervisorBackend::Geniezone), |
Srivatsa Vaddagiri | cb5959e | 2023-04-20 05:27:16 -0700 | [diff] [blame] | 63 | GunyahHypervisor::UUID => Ok(HypervisorBackend::Gunyah), |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 64 | RegularKvmHypervisor::UUID => { |
Pierre-Clément Tosi | cf21585 | 2023-07-11 13:33:14 +0000 | [diff] [blame] | 65 | // Protected KVM has the same UUID as "regular" KVM so issue an HVC that is assumed |
| 66 | // to only be supported by pKVM: if it returns SUCCESS, deduce that this is pKVM |
| 67 | // and if it returns NOT_SUPPORTED assume that it is "regular" KVM. |
| 68 | match ProtectedKvmHypervisor.as_mmio_guard().unwrap().granule() { |
Pierre-Clément Tosi | bd98d92 | 2023-06-29 14:17:25 +0000 | [diff] [blame] | 69 | Ok(_) => Ok(HypervisorBackend::ProtectedKvm), |
| 70 | Err(Error::KvmError(KvmError::NotSupported, _)) => { |
| 71 | Ok(HypervisorBackend::RegularKvm) |
| 72 | } |
| 73 | Err(e) => Err(e), |
| 74 | } |
| 75 | } |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 76 | u => Err(Error::UnsupportedHypervisorUuid(u)), |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | const ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: u32 = 0x8600ff01; |
| 82 | |
| 83 | fn query_vendor_hyp_call_uid() -> Uuid { |
| 84 | let args = [0u64; 17]; |
| 85 | let res = hvc64(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, args); |
| 86 | |
| 87 | // KVM's UUID of "28b46fb6-2ec5-11e9-a9ca-4b564d003a74" is generated by |
| 88 | // Uuid::from_u128() from an input value of |
| 89 | // 0x28b46fb6_2ec511e9_a9ca4b56_4d003a74. ARM's SMC calling convention |
| 90 | // (Document number ARM DEN 0028E) describes the UUID register mapping such |
| 91 | // that W0 contains bytes 0..3 of UUID, with byte 0 in lower order bits. In |
| 92 | // the KVM example, byte 0 of KVM's UUID (0x28) will be returned in the low |
| 93 | // 8-bits of W0, while byte 15 (0x74) will be returned in bits 31-24 of W3. |
| 94 | // |
| 95 | // `uuid` value derived below thus need to be byte-reversed before |
| 96 | // being used in Uuid::from_u128(). Alternately use Uuid::from_u128_le() |
| 97 | // to achieve the same. |
| 98 | |
| 99 | let uuid = ((res[3] as u32 as u128) << 96) |
| 100 | | ((res[2] as u32 as u128) << 64) |
| 101 | | ((res[1] as u32 as u128) << 32) |
| 102 | | (res[0] as u32 as u128); |
| 103 | |
| 104 | Uuid::from_u128_le(uuid) |
| 105 | } |
| 106 | |
| 107 | fn detect_hypervisor() -> HypervisorBackend { |
Pierre-Clément Tosi | cf21585 | 2023-07-11 13:33:14 +0000 | [diff] [blame] | 108 | query_vendor_hyp_call_uid().try_into().expect("Failed to detect hypervisor") |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Alice Wang | 3132911 | 2023-04-13 09:02:36 +0000 | [diff] [blame] | 111 | /// Gets the hypervisor singleton. |
Pierre-Clément Tosi | d643cfe | 2023-06-29 09:30:51 +0000 | [diff] [blame] | 112 | fn get_hypervisor() -> &'static dyn Hypervisor { |
Srivatsa Vaddagiri | 353f5d0 | 2023-04-18 23:49:01 -0700 | [diff] [blame] | 113 | static HYPERVISOR: OnceBox<HypervisorBackend> = OnceBox::new(); |
| 114 | |
| 115 | HYPERVISOR.get_or_init(|| Box::new(detect_hypervisor())).get_hypervisor() |
Alice Wang | 0bdc3f6 | 2023-03-15 10:46:12 +0000 | [diff] [blame] | 116 | } |
Pierre-Clément Tosi | d643cfe | 2023-06-29 09:30:51 +0000 | [diff] [blame] | 117 | |
| 118 | /// Gets the MMIO_GUARD hypervisor singleton, if any. |
| 119 | pub fn get_mmio_guard() -> Option<&'static dyn MmioGuardedHypervisor> { |
| 120 | get_hypervisor().as_mmio_guard() |
| 121 | } |
| 122 | |
| 123 | /// Gets the dynamic memory sharing hypervisor singleton, if any. |
| 124 | pub fn get_mem_sharer() -> Option<&'static dyn MemSharingHypervisor> { |
| 125 | get_hypervisor().as_mem_sharer() |
| 126 | } |
Jaewan Kim | d9095f8 | 2023-11-13 11:04:27 +0900 | [diff] [blame] | 127 | |
| 128 | /// Gets the device assigning hypervisor singleton, if any. |
| 129 | pub fn get_device_assigner() -> Option<&'static dyn DeviceAssigningHypervisor> { |
| 130 | get_hypervisor().as_device_assigner() |
| 131 | } |