1 // Copyright 2022, 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 calls to the KVM hypervisor.
16
17 use core::fmt::{self, Display, Formatter};
18
19 use super::{DeviceAssigningHypervisor, Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor};
20 use crate::{
21 hyp::{Error, Result},
22 memory::page_4kb_of,
23 };
24
25 use smccc::{
26 error::{positive_or_error_64, success_or_error_32, success_or_error_64},
27 hvc64,
28 };
29 use uuid::{uuid, Uuid};
30
31 /// Error from a KVM HVC call.
32 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
33 pub enum KvmError {
34 /// The call is not supported by the implementation.
35 NotSupported,
36 /// One of the call parameters has a non-supported value.
37 InvalidParameter,
38 /// There was an unexpected return value.
39 Unknown(i64),
40 }
41
42 impl From<i64> for KvmError {
from(value: i64) -> Self43 fn from(value: i64) -> Self {
44 match value {
45 -1 => KvmError::NotSupported,
46 -3 => KvmError::InvalidParameter,
47 _ => KvmError::Unknown(value),
48 }
49 }
50 }
51
52 impl From<i32> for KvmError {
from(value: i32) -> Self53 fn from(value: i32) -> Self {
54 i64::from(value).into()
55 }
56 }
57
58 impl Display for KvmError {
fmt(&self, f: &mut Formatter) -> fmt::Result59 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
60 match self {
61 Self::NotSupported => write!(f, "KVM call not supported"),
62 Self::InvalidParameter => write!(f, "KVM call received non-supported value"),
63 Self::Unknown(e) => write!(f, "Unknown return value from KVM {} ({0:#x})", e),
64 }
65 }
66 }
67
68 const ARM_SMCCC_KVM_FUNC_HYP_MEMINFO: u32 = 0xc6000002;
69 const ARM_SMCCC_KVM_FUNC_MEM_SHARE: u32 = 0xc6000003;
70 const ARM_SMCCC_KVM_FUNC_MEM_UNSHARE: u32 = 0xc6000004;
71
72 const VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID: u32 = 0xc6000005;
73 const VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID: u32 = 0xc6000006;
74 const VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID: u32 = 0xc6000007;
75 const VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID: u32 = 0xc6000008;
76
77 const VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID: u32 = 0xc6000012;
78 const VENDOR_HYP_KVM_DEV_REQ_DMA_FUNC_ID: u32 = 0xc6000013;
79
80 pub(super) struct RegularKvmHypervisor;
81
82 impl RegularKvmHypervisor {
83 // Based on ARM_SMCCC_VENDOR_HYP_UID_KVM_REG values listed in Linux kernel source:
84 // https://github.com/torvalds/linux/blob/master/include/linux/arm-smccc.h
85 pub(super) const UUID: Uuid = uuid!("28b46fb6-2ec5-11e9-a9ca-4b564d003a74");
86 }
87
88 impl Hypervisor for RegularKvmHypervisor {}
89
90 pub(super) struct ProtectedKvmHypervisor;
91
92 impl Hypervisor for ProtectedKvmHypervisor {
as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor>93 fn as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor> {
94 Some(self)
95 }
96
as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor>97 fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
98 Some(self)
99 }
100
as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor>101 fn as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor> {
102 Some(self)
103 }
104 }
105
106 impl MmioGuardedHypervisor for ProtectedKvmHypervisor {
enroll(&self) -> Result<()>107 fn enroll(&self) -> Result<()> {
108 let args = [0u64; 17];
109 match success_or_error_64(hvc64(VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID, args)[0]) {
110 Ok(()) => Ok(()),
111 Err(KvmError::NotSupported) => Err(Error::MmioGuardNotSupported),
112 Err(e) => Err(Error::KvmError(e, VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID)),
113 }
114 }
115
map(&self, addr: usize) -> Result<()>116 fn map(&self, addr: usize) -> Result<()> {
117 let mut args = [0u64; 17];
118 args[0] = page_4kb_of(addr).try_into().unwrap();
119
120 if cfg!(feature = "compat_android_13") {
121 let res = hvc64(VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID, args)[0];
122 // pKVM returns i32 instead of the intended i64 in Android 13.
123 return success_or_error_32(res as u32)
124 .map_err(|e| Error::KvmError(e, VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID));
125 }
126
127 checked_hvc64_expect_zero(VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID, args)
128 }
129
unmap(&self, addr: usize) -> Result<()>130 fn unmap(&self, addr: usize) -> Result<()> {
131 let mut args = [0u64; 17];
132 args[0] = page_4kb_of(addr).try_into().unwrap();
133
134 if cfg!(feature = "compat_android_13") {
135 let res = hvc64(VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID, args)[0];
136 // pKVM returns NOT_SUPPORTED for SUCCESS in Android 13.
137 return match success_or_error_64(res) {
138 Err(KvmError::NotSupported) | Ok(_) => Ok(()),
139 Err(e) => Err(Error::KvmError(e, VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID)),
140 };
141 }
142
143 checked_hvc64_expect_zero(VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID, args)
144 }
145
granule(&self) -> Result<usize>146 fn granule(&self) -> Result<usize> {
147 let args = [0u64; 17];
148 let granule = checked_hvc64(VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID, args)?;
149 Ok(granule.try_into().unwrap())
150 }
151 }
152
153 impl MemSharingHypervisor for ProtectedKvmHypervisor {
share(&self, base_ipa: u64) -> Result<()>154 fn share(&self, base_ipa: u64) -> Result<()> {
155 let mut args = [0u64; 17];
156 args[0] = base_ipa;
157
158 checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_SHARE, args)
159 }
160
unshare(&self, base_ipa: u64) -> Result<()>161 fn unshare(&self, base_ipa: u64) -> Result<()> {
162 let mut args = [0u64; 17];
163 args[0] = base_ipa;
164
165 checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, args)
166 }
167
granule(&self) -> Result<usize>168 fn granule(&self) -> Result<usize> {
169 let args = [0u64; 17];
170 let granule = checked_hvc64(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, args)?;
171 Ok(granule.try_into().unwrap())
172 }
173 }
174
175 impl DeviceAssigningHypervisor for ProtectedKvmHypervisor {
get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> Result<u64>176 fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> Result<u64> {
177 let mut args = [0u64; 17];
178 args[0] = base_ipa;
179 args[1] = size;
180
181 let ret = checked_hvc64_expect_results(VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID, args)?;
182 Ok(ret[0])
183 }
184
get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> Result<(u64, u64)>185 fn get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> Result<(u64, u64)> {
186 let mut args = [0u64; 17];
187 args[0] = pviommu_id;
188 args[1] = vsid;
189
190 let ret = checked_hvc64_expect_results(VENDOR_HYP_KVM_DEV_REQ_DMA_FUNC_ID, args)?;
191 Ok((ret[0], ret[1]))
192 }
193 }
194
checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()>195 fn checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()> {
196 success_or_error_64(hvc64(function, args)[0]).map_err(|e| Error::KvmError(e, function))
197 }
198
checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64>199 fn checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64> {
200 positive_or_error_64(hvc64(function, args)[0]).map_err(|e| Error::KvmError(e, function))
201 }
202
checked_hvc64_expect_results(function: u32, args: [u64; 17]) -> Result<[u64; 17]>203 fn checked_hvc64_expect_results(function: u32, args: [u64; 17]) -> Result<[u64; 17]> {
204 let [ret, results @ ..] = hvc64(function, args);
205 success_or_error_64(ret).map_err(|e| Error::KvmError(e, function))?;
206 Ok(results)
207 }
208