blob: c53b88671ced5ba371b1ab7b7482978d90cf9c50 [file] [log] [blame]
Alice Wang0bdc3f62023-03-15 10:46:12 +00001// 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 Vaddagiri353f5d02023-04-18 23:49:01 -070017extern crate alloc;
18
Alice Wang31329112023-04-13 09:02:36 +000019mod common;
Yi-De Wu725bd922023-04-24 16:26:52 +080020mod geniezone;
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070021mod gunyah;
Alice Wang0bdc3f62023-03-15 10:46:12 +000022mod kvm;
23
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070024use crate::error::{Error, Result};
25use alloc::boxed::Box;
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +000026use common::Hypervisor;
Jaewan Kimfb24bdd2023-11-27 17:25:02 +090027pub use common::{
28 DeviceAssigningHypervisor, MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE,
29};
Yi-De Wu725bd922023-04-24 16:26:52 +080030pub use geniezone::GeniezoneError;
31use geniezone::GeniezoneHypervisor;
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070032use gunyah::GunyahHypervisor;
Andrew Walbran9afab672023-04-17 14:26:23 +000033pub use kvm::KvmError;
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000034use kvm::{ProtectedKvmHypervisor, RegularKvmHypervisor};
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070035use once_cell::race::OnceBox;
Andrew Walbranf44f1602023-05-30 14:59:19 +000036use smccc::hvc64;
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070037use uuid::Uuid;
Alice Wang31329112023-04-13 09:02:36 +000038
39enum HypervisorBackend {
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000040 RegularKvm,
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070041 Gunyah,
Yi-De Wu725bd922023-04-24 16:26:52 +080042 Geniezone,
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000043 ProtectedKvm,
Alice Wang0bdc3f62023-03-15 10:46:12 +000044}
45
Alice Wang31329112023-04-13 09:02:36 +000046impl HypervisorBackend {
47 fn get_hypervisor(&self) -> &'static dyn Hypervisor {
48 match self {
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000049 Self::RegularKvm => &RegularKvmHypervisor,
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070050 Self::Gunyah => &GunyahHypervisor,
Yi-De Wu725bd922023-04-24 16:26:52 +080051 Self::Geniezone => &GeniezoneHypervisor,
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000052 Self::ProtectedKvm => &ProtectedKvmHypervisor,
Alice Wang31329112023-04-13 09:02:36 +000053 }
54 }
Alice Wang0bdc3f62023-03-15 10:46:12 +000055}
56
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070057impl TryFrom<Uuid> for HypervisorBackend {
58 type Error = Error;
59
60 fn try_from(uuid: Uuid) -> Result<HypervisorBackend> {
61 match uuid {
Yi-De Wu725bd922023-04-24 16:26:52 +080062 GeniezoneHypervisor::UUID => Ok(HypervisorBackend::Geniezone),
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070063 GunyahHypervisor::UUID => Ok(HypervisorBackend::Gunyah),
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000064 RegularKvmHypervisor::UUID => {
Pierre-Clément Tosicf215852023-07-11 13:33:14 +000065 // 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 Tosibd98d922023-06-29 14:17:25 +000069 Ok(_) => Ok(HypervisorBackend::ProtectedKvm),
70 Err(Error::KvmError(KvmError::NotSupported, _)) => {
71 Ok(HypervisorBackend::RegularKvm)
72 }
73 Err(e) => Err(e),
74 }
75 }
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070076 u => Err(Error::UnsupportedHypervisorUuid(u)),
77 }
78 }
79}
80
81const ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: u32 = 0x8600ff01;
82
83fn 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
107fn detect_hypervisor() -> HypervisorBackend {
Pierre-Clément Tosicf215852023-07-11 13:33:14 +0000108 query_vendor_hyp_call_uid().try_into().expect("Failed to detect hypervisor")
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -0700109}
110
Alice Wang31329112023-04-13 09:02:36 +0000111/// Gets the hypervisor singleton.
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000112fn get_hypervisor() -> &'static dyn Hypervisor {
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -0700113 static HYPERVISOR: OnceBox<HypervisorBackend> = OnceBox::new();
114
115 HYPERVISOR.get_or_init(|| Box::new(detect_hypervisor())).get_hypervisor()
Alice Wang0bdc3f62023-03-15 10:46:12 +0000116}
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000117
118/// Gets the MMIO_GUARD hypervisor singleton, if any.
119pub 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.
124pub fn get_mem_sharer() -> Option<&'static dyn MemSharingHypervisor> {
125 get_hypervisor().as_mem_sharer()
126}
Jaewan Kimd9095f82023-11-13 11:04:27 +0900127
128/// Gets the device assigning hypervisor singleton, if any.
129pub fn get_device_assigner() -> Option<&'static dyn DeviceAssigningHypervisor> {
130 get_hypervisor().as_device_assigner()
131}