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 calls to the GenieZone hypervisor.
16
17 use super::{Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor};
18 use crate::{mem::page_4kb_of, Error, Result};
19
20 use smccc::{
21 error::{positive_or_error_64, success_or_error_64},
22 hvc64,
23 };
24 use thiserror::Error;
25 use uuid::{uuid, Uuid};
26
27 pub(super) struct GeniezoneHypervisor;
28
29 const ARM_SMCCC_GZVM_FUNC_HYP_MEMINFO: u32 = 0xc6000002;
30 const ARM_SMCCC_GZVM_FUNC_MEM_SHARE: u32 = 0xc6000003;
31 const ARM_SMCCC_GZVM_FUNC_MEM_UNSHARE: u32 = 0xc6000004;
32
33 const VENDOR_HYP_GZVM_MMIO_GUARD_INFO_FUNC_ID: u32 = 0xc6000005;
34 const VENDOR_HYP_GZVM_MMIO_GUARD_ENROLL_FUNC_ID: u32 = 0xc6000006;
35 const VENDOR_HYP_GZVM_MMIO_GUARD_MAP_FUNC_ID: u32 = 0xc6000007;
36 const VENDOR_HYP_GZVM_MMIO_GUARD_UNMAP_FUNC_ID: u32 = 0xc6000008;
37
38 impl GeniezoneHypervisor {
39 // We generate this uuid by ourselves to identify GenieZone hypervisor
40 // and share the same identification along with guest VMs.
41 // The previous uuid was removed due to duplication elsewhere.
42 pub const UUID: Uuid = uuid!("7e134ed0-3b82-488d-8cee-69c19211dbe7");
43 }
44
45 /// Error from a GenieZone HVC call.
46 #[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
47 pub enum GeniezoneError {
48 /// The call is not supported by the implementation.
49 #[error("GenieZone call not supported")]
50 NotSupported,
51 /// The call is not required to implement.
52 #[error("GenieZone call not required")]
53 NotRequired,
54 /// One of the call parameters has a invalid value.
55 #[error("GenieZone call received invalid value")]
56 InvalidParameter,
57 /// There was an unexpected return value.
58 #[error("Unknown return value from GenieZone {0} ({0:#x})")]
59 Unknown(i64),
60 }
61
62 impl From<i64> for GeniezoneError {
from(value: i64) -> Self63 fn from(value: i64) -> Self {
64 match value {
65 -1 => GeniezoneError::NotSupported,
66 -2 => GeniezoneError::NotRequired,
67 -3 => GeniezoneError::InvalidParameter,
68 _ => GeniezoneError::Unknown(value),
69 }
70 }
71 }
72
73 impl From<i32> for GeniezoneError {
from(value: i32) -> Self74 fn from(value: i32) -> Self {
75 i64::from(value).into()
76 }
77 }
78
79 impl Hypervisor for GeniezoneHypervisor {
as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor>80 fn as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor> {
81 Some(self)
82 }
83
as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor>84 fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
85 Some(self)
86 }
87
get_granule_size(&self) -> Option<usize>88 fn get_granule_size(&self) -> Option<usize> {
89 <Self as MemSharingHypervisor>::granule(self).ok()
90 }
91 }
92
93 impl MmioGuardedHypervisor for GeniezoneHypervisor {
enroll(&self) -> Result<()>94 fn enroll(&self) -> Result<()> {
95 let args = [0u64; 17];
96 match success_or_error_64(hvc64(VENDOR_HYP_GZVM_MMIO_GUARD_ENROLL_FUNC_ID, args)[0]) {
97 Ok(()) => Ok(()),
98 Err(GeniezoneError::NotSupported) | Err(GeniezoneError::NotRequired) => {
99 Err(Error::MmioGuardNotSupported)
100 }
101 Err(e) => Err(Error::GeniezoneError(e, VENDOR_HYP_GZVM_MMIO_GUARD_ENROLL_FUNC_ID)),
102 }
103 }
104
map(&self, addr: usize) -> Result<()>105 fn map(&self, addr: usize) -> Result<()> {
106 let mut args = [0u64; 17];
107 args[0] = page_4kb_of(addr).try_into().unwrap();
108
109 checked_hvc64_expect_zero(VENDOR_HYP_GZVM_MMIO_GUARD_MAP_FUNC_ID, args)
110 }
111
unmap(&self, addr: usize) -> Result<()>112 fn unmap(&self, addr: usize) -> Result<()> {
113 let mut args = [0u64; 17];
114 args[0] = page_4kb_of(addr).try_into().unwrap();
115
116 checked_hvc64_expect_zero(VENDOR_HYP_GZVM_MMIO_GUARD_UNMAP_FUNC_ID, args)
117 }
118
granule(&self) -> Result<usize>119 fn granule(&self) -> Result<usize> {
120 let args = [0u64; 17];
121 let granule = checked_hvc64(VENDOR_HYP_GZVM_MMIO_GUARD_INFO_FUNC_ID, args)?;
122 Ok(granule.try_into().unwrap())
123 }
124 }
125
126 impl MemSharingHypervisor for GeniezoneHypervisor {
share(&self, base_ipa: u64) -> Result<()>127 fn share(&self, base_ipa: u64) -> Result<()> {
128 let mut args = [0u64; 17];
129 args[0] = base_ipa;
130
131 checked_hvc64_expect_zero(ARM_SMCCC_GZVM_FUNC_MEM_SHARE, args)
132 }
133
unshare(&self, base_ipa: u64) -> Result<()>134 fn unshare(&self, base_ipa: u64) -> Result<()> {
135 let mut args = [0u64; 17];
136 args[0] = base_ipa;
137
138 checked_hvc64_expect_zero(ARM_SMCCC_GZVM_FUNC_MEM_UNSHARE, args)
139 }
140
granule(&self) -> Result<usize>141 fn granule(&self) -> Result<usize> {
142 let args = [0u64; 17];
143 let granule = checked_hvc64(ARM_SMCCC_GZVM_FUNC_HYP_MEMINFO, args)?;
144 Ok(granule.try_into().unwrap())
145 }
146 }
147
checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()>148 fn checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()> {
149 success_or_error_64(hvc64(function, args)[0]).map_err(|e| Error::GeniezoneError(e, function))
150 }
151
checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64>152 fn checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64> {
153 positive_or_error_64(hvc64(function, args)[0]).map_err(|e| Error::GeniezoneError(e, function))
154 }
155