blob: 309f9677bdd7a2b4ed76bd8be8b7c8616930ed9a [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;
27pub use common::{MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE};
Yi-De Wu725bd922023-04-24 16:26:52 +080028pub use geniezone::GeniezoneError;
29use geniezone::GeniezoneHypervisor;
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070030use gunyah::GunyahHypervisor;
Andrew Walbran9afab672023-04-17 14:26:23 +000031pub use kvm::KvmError;
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000032use kvm::{ProtectedKvmHypervisor, RegularKvmHypervisor};
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070033use once_cell::race::OnceBox;
Andrew Walbranf44f1602023-05-30 14:59:19 +000034use smccc::hvc64;
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070035use uuid::Uuid;
Alice Wang31329112023-04-13 09:02:36 +000036
37enum HypervisorBackend {
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000038 RegularKvm,
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070039 Gunyah,
Yi-De Wu725bd922023-04-24 16:26:52 +080040 Geniezone,
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000041 ProtectedKvm,
Alice Wang0bdc3f62023-03-15 10:46:12 +000042}
43
Alice Wang31329112023-04-13 09:02:36 +000044impl HypervisorBackend {
45 fn get_hypervisor(&self) -> &'static dyn Hypervisor {
46 match self {
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000047 Self::RegularKvm => &RegularKvmHypervisor,
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070048 Self::Gunyah => &GunyahHypervisor,
Yi-De Wu725bd922023-04-24 16:26:52 +080049 Self::Geniezone => &GeniezoneHypervisor,
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000050 Self::ProtectedKvm => &ProtectedKvmHypervisor,
Alice Wang31329112023-04-13 09:02:36 +000051 }
52 }
Alice Wang0bdc3f62023-03-15 10:46:12 +000053}
54
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070055impl TryFrom<Uuid> for HypervisorBackend {
56 type Error = Error;
57
58 fn try_from(uuid: Uuid) -> Result<HypervisorBackend> {
59 match uuid {
Yi-De Wu725bd922023-04-24 16:26:52 +080060 GeniezoneHypervisor::UUID => Ok(HypervisorBackend::Geniezone),
Srivatsa Vaddagiricb5959e2023-04-20 05:27:16 -070061 GunyahHypervisor::UUID => Ok(HypervisorBackend::Gunyah),
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000062 RegularKvmHypervisor::UUID => {
Pierre-Clément Tosicf215852023-07-11 13:33:14 +000063 // Protected KVM has the same UUID as "regular" KVM so issue an HVC that is assumed
64 // to only be supported by pKVM: if it returns SUCCESS, deduce that this is pKVM
65 // and if it returns NOT_SUPPORTED assume that it is "regular" KVM.
66 match ProtectedKvmHypervisor.as_mmio_guard().unwrap().granule() {
Pierre-Clément Tosibd98d922023-06-29 14:17:25 +000067 Ok(_) => Ok(HypervisorBackend::ProtectedKvm),
68 Err(Error::KvmError(KvmError::NotSupported, _)) => {
69 Ok(HypervisorBackend::RegularKvm)
70 }
71 Err(e) => Err(e),
72 }
73 }
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -070074 u => Err(Error::UnsupportedHypervisorUuid(u)),
75 }
76 }
77}
78
79const ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: u32 = 0x8600ff01;
80
81fn query_vendor_hyp_call_uid() -> Uuid {
82 let args = [0u64; 17];
83 let res = hvc64(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, args);
84
85 // KVM's UUID of "28b46fb6-2ec5-11e9-a9ca-4b564d003a74" is generated by
86 // Uuid::from_u128() from an input value of
87 // 0x28b46fb6_2ec511e9_a9ca4b56_4d003a74. ARM's SMC calling convention
88 // (Document number ARM DEN 0028E) describes the UUID register mapping such
89 // that W0 contains bytes 0..3 of UUID, with byte 0 in lower order bits. In
90 // the KVM example, byte 0 of KVM's UUID (0x28) will be returned in the low
91 // 8-bits of W0, while byte 15 (0x74) will be returned in bits 31-24 of W3.
92 //
93 // `uuid` value derived below thus need to be byte-reversed before
94 // being used in Uuid::from_u128(). Alternately use Uuid::from_u128_le()
95 // to achieve the same.
96
97 let uuid = ((res[3] as u32 as u128) << 96)
98 | ((res[2] as u32 as u128) << 64)
99 | ((res[1] as u32 as u128) << 32)
100 | (res[0] as u32 as u128);
101
102 Uuid::from_u128_le(uuid)
103}
104
105fn detect_hypervisor() -> HypervisorBackend {
Pierre-Clément Tosicf215852023-07-11 13:33:14 +0000106 query_vendor_hyp_call_uid().try_into().expect("Failed to detect hypervisor")
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -0700107}
108
Alice Wang31329112023-04-13 09:02:36 +0000109/// Gets the hypervisor singleton.
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000110fn get_hypervisor() -> &'static dyn Hypervisor {
Srivatsa Vaddagiri353f5d02023-04-18 23:49:01 -0700111 static HYPERVISOR: OnceBox<HypervisorBackend> = OnceBox::new();
112
113 HYPERVISOR.get_or_init(|| Box::new(detect_hypervisor())).get_hypervisor()
Alice Wang0bdc3f62023-03-15 10:46:12 +0000114}
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000115
116/// Gets the MMIO_GUARD hypervisor singleton, if any.
117pub fn get_mmio_guard() -> Option<&'static dyn MmioGuardedHypervisor> {
118 get_hypervisor().as_mmio_guard()
119}
120
121/// Gets the dynamic memory sharing hypervisor singleton, if any.
122pub fn get_mem_sharer() -> Option<&'static dyn MemSharingHypervisor> {
123 get_hypervisor().as_mem_sharer()
124}