1 // Copyright 2024, 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 // This is an example implementation of the libavb rust wrapper backend in the EFI environment. It
16 // is mainly for use by the boot demo. Eventually, these backends will be implemented from the
17 // `GblOps` interface in libgbl, where EFI services will be one level lower as its backend instead.
18
19 use crate::utils::EfiMultiBlockDevices;
20 use avb::{IoError, IoResult, Ops, PublicKeyForPartitionInfo};
21 use core::ffi::CStr;
22 use gbl_storage::AsMultiBlockDevices;
23 use uuid::Uuid;
24
25 extern crate avb_sysdeps;
26
27 pub struct GblEfiAvbOps<'a, 'b> {
28 gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
29 preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
30 }
31
32 impl<'a, 'b> GblEfiAvbOps<'a, 'b> {
new( gpt_dev: &'b mut EfiMultiBlockDevices<'a>, preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>, ) -> Self33 pub fn new(
34 gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
35 preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
36 ) -> Self {
37 Self { gpt_dev, preloaded_partitions }
38 }
39 }
40
41 /// A helper function for converting CStr to str
cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E>42 fn cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E> {
43 Ok(s.to_str().map_err(|_| err)?)
44 }
45
46 impl<'b> Ops<'b> for GblEfiAvbOps<'_, 'b> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>47 fn read_from_partition(
48 &mut self,
49 partition: &CStr,
50 offset: i64,
51 buffer: &mut [u8],
52 ) -> IoResult<usize> {
53 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
54 let partition_size: u64 = self
55 .gpt_dev
56 .find_partition(part_str)
57 .and_then(|v| v.size())
58 .map_err(|_| IoError::NoSuchPartition)?
59 .try_into()
60 .map_err(|_| IoError::Oom)?;
61 let read_off: u64 = match offset < 0 {
62 true => {
63 partition_size.checked_sub(offset.abs() as u64).ok_or(IoError::InvalidValueSize)?
64 }
65 _ => offset.try_into().map_err(|_| IoError::InvalidValueSize)?,
66 };
67 self.gpt_dev.read_gpt_partition(part_str, read_off, buffer).map_err(|_| IoError::Io)?;
68 Ok(buffer.len())
69 }
70
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'b [u8]>71 fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'b [u8]> {
72 let part_str = cstr_to_str(partition, IoError::NotImplemented)?;
73 Ok(self
74 .preloaded_partitions
75 .ok_or(IoError::NotImplemented)?
76 .iter()
77 .find(|(name, _)| *name == part_str)
78 .ok_or(IoError::NotImplemented)?
79 .1)
80 }
81
validate_vbmeta_public_key( &mut self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>82 fn validate_vbmeta_public_key(
83 &mut self,
84 _public_key: &[u8],
85 _public_key_metadata: Option<&[u8]>,
86 ) -> IoResult<bool> {
87 // Not supported until we add our GBL specific EFI protocol that does this.
88 Ok(true)
89 }
90
read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64>91 fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> {
92 // Not supported until we add our GBL specific EFI protocol that does this.
93 Ok(0)
94 }
95
write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> IoResult<()>96 fn write_rollback_index(
97 &mut self,
98 _rollback_index_location: usize,
99 _index: u64,
100 ) -> IoResult<()> {
101 // Not supported until we add our GBL specific EFI protocol that does this.
102 Ok(())
103 }
104
read_is_device_unlocked(&mut self) -> IoResult<bool>105 fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
106 // Not supported until we add our GBL specific EFI protocol that does this.
107 // For now always consider unlocked.
108 Ok(true)
109 }
110
get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid>111 fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid> {
112 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
113 let ptn = self.gpt_dev.find_partition(part_str).map_err(|_| IoError::NoSuchPartition)?;
114 Ok(Uuid::from_bytes(ptn.gpt_entry().guid))
115 }
116
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>117 fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
118 match self.get_preloaded_partition(partition) {
119 Ok(img) => Ok(img.len().try_into().unwrap()),
120 _ => {
121 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
122 Ok(self
123 .gpt_dev
124 .find_partition(part_str)
125 .and_then(|v| v.size())
126 .map_err(|_| IoError::NoSuchPartition)?
127 .try_into()
128 .map_err(|_| IoError::NoSuchPartition)?)
129 }
130 }
131 }
132
read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize>133 fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
134 // Not supported until we add our GBL specific EFI protocol that does this.
135 unimplemented!();
136 }
137
write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()>138 fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
139 // Not supported until we add our GBL specific EFI protocol that does this.
140 unimplemented!();
141 }
142
erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()>143 fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
144 // Not supported until we add our GBL specific EFI protocol that does this.
145 unimplemented!();
146 }
147
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>148 fn validate_public_key_for_partition(
149 &mut self,
150 _partition: &CStr,
151 _public_key: &[u8],
152 _public_key_metadata: Option<&[u8]>,
153 ) -> IoResult<PublicKeyForPartitionInfo> {
154 // Not supported until we add our GBL specific EFI protocol that does this.
155 unimplemented!();
156 }
157 }
158