• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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