blob: 5a800007bbccf64cb5846762411b98ad28f20467 [file] [log] [blame]
// Copyright 2024, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This is an example implementation of the libavb rust wrapper backend in the EFI environment. It
// is mainly for use by the boot demo. Eventually, these backends will be implemented from the
// `GblOps` interface in libgbl, where EFI services will be one level lower as its backend instead.
use crate::utils::EfiMultiBlockDevices;
use avb::{IoError, IoResult, Ops, PublicKeyForPartitionInfo};
use core::ffi::CStr;
use gbl_storage::AsMultiBlockDevices;
use uuid::Uuid;
extern crate avb_sysdeps;
pub struct GblEfiAvbOps<'a, 'b> {
gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
}
impl<'a, 'b> GblEfiAvbOps<'a, 'b> {
pub fn new(
gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
) -> Self {
Self { gpt_dev, preloaded_partitions }
}
}
/// A helper function for converting CStr to str
fn cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E> {
Ok(s.to_str().map_err(|_| err)?)
}
impl<'b> Ops<'b> for GblEfiAvbOps<'_, 'b> {
fn read_from_partition(
&mut self,
partition: &CStr,
offset: i64,
buffer: &mut [u8],
) -> IoResult<usize> {
let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
let partition_size: u64 = self
.gpt_dev
.find_partition(part_str)
.and_then(|v| v.size())
.map_err(|_| IoError::NoSuchPartition)?
.try_into()
.map_err(|_| IoError::Oom)?;
let read_off: u64 = match offset < 0 {
true => {
partition_size.checked_sub(offset.abs() as u64).ok_or(IoError::InvalidValueSize)?
}
_ => offset.try_into().map_err(|_| IoError::InvalidValueSize)?,
};
self.gpt_dev.read_gpt_partition(part_str, read_off, buffer).map_err(|_| IoError::Io)?;
Ok(buffer.len())
}
fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'b [u8]> {
let part_str = cstr_to_str(partition, IoError::NotImplemented)?;
Ok(self
.preloaded_partitions
.ok_or(IoError::NotImplemented)?
.iter()
.find(|(name, _)| *name == part_str)
.ok_or(IoError::NotImplemented)?
.1)
}
fn validate_vbmeta_public_key(
&mut self,
_public_key: &[u8],
_public_key_metadata: Option<&[u8]>,
) -> IoResult<bool> {
// Not supported until we add our GBL specific EFI protocol that does this.
Ok(true)
}
fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> {
// Not supported until we add our GBL specific EFI protocol that does this.
Ok(0)
}
fn write_rollback_index(
&mut self,
_rollback_index_location: usize,
_index: u64,
) -> IoResult<()> {
// Not supported until we add our GBL specific EFI protocol that does this.
Ok(())
}
fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
// Not supported until we add our GBL specific EFI protocol that does this.
// For now always consider unlocked.
Ok(true)
}
fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid> {
let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
let ptn = self.gpt_dev.find_partition(part_str).map_err(|_| IoError::NoSuchPartition)?;
Ok(Uuid::from_bytes(ptn.gpt_entry().guid))
}
fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
match self.get_preloaded_partition(partition) {
Ok(img) => Ok(img.len().try_into().unwrap()),
_ => {
let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
Ok(self
.gpt_dev
.find_partition(part_str)
.and_then(|v| v.size())
.map_err(|_| IoError::NoSuchPartition)?
.try_into()
.map_err(|_| IoError::NoSuchPartition)?)
}
}
}
fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
// Not supported until we add our GBL specific EFI protocol that does this.
unimplemented!();
}
fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
// Not supported until we add our GBL specific EFI protocol that does this.
unimplemented!();
}
fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
// Not supported until we add our GBL specific EFI protocol that does this.
unimplemented!();
}
fn validate_public_key_for_partition(
&mut self,
_partition: &CStr,
_public_key: &[u8],
_public_key_metadata: Option<&[u8]>,
) -> IoResult<PublicKeyForPartitionInfo> {
// Not supported until we add our GBL specific EFI protocol that does this.
unimplemented!();
}
}