summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-11-10 21:22:29 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-11-10 21:22:29 +0000
commit7db62a2704bfb57abc5be94508101b2fd57d8189 (patch)
treed9e74aacb8f18d24502e2cbcce08a94a82537a49
parent46301d5a3e67627f9d4989edf210e3764aa1dfed (diff)
parent50cd8a032fa03bd5559d110efca660aca1f4a58c (diff)
downloadlibbootloader-7db62a2704bfb57abc5be94508101b2fd57d8189.tar.gz
Merge "Support EfiRiscvBootProtocol" into main am: 9b0ae388b7 am: 4225163405 am: 50cd8a032f
Original change: https://android-review.googlesource.com/c/platform/bootable/libbootloader/+/2824956 Change-Id: Ibcb028304dfbd05f03aaa97dec26b2b6466be72f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--gbl/libefi/BUILD1
-rw-r--r--gbl/libefi/defs/efi.h1
-rw-r--r--gbl/libefi/defs/protocols/riscv_efi_boot_protocol.h32
-rw-r--r--gbl/libefi/src/lib.rs23
-rw-r--r--gbl/libefi/src/protocol.rs81
5 files changed, 122 insertions, 16 deletions
diff --git a/gbl/libefi/BUILD b/gbl/libefi/BUILD
index aa134d7..7507ddc 100644
--- a/gbl/libefi/BUILD
+++ b/gbl/libefi/BUILD
@@ -28,6 +28,7 @@ cc_library(
"defs/protocols/block_io_protocol.h",
"defs/protocols/device_path_protocol.h",
"defs/protocols/loaded_image_protocol.h",
+ "defs/protocols/riscv_efi_boot_protocol.h",
"defs/protocols/simple_text_output_protocol.h",
"defs/system_table.h",
"defs/types.h",
diff --git a/gbl/libefi/defs/efi.h b/gbl/libefi/defs/efi.h
index 0fcaed5..2162768 100644
--- a/gbl/libefi/defs/efi.h
+++ b/gbl/libefi/defs/efi.h
@@ -29,6 +29,7 @@
#include "protocols/block_io_protocol.h"
#include "protocols/device_path_protocol.h"
#include "protocols/loaded_image_protocol.h"
+#include "protocols/riscv_efi_boot_protocol.h"
#include "protocols/simple_text_output_protocol.h"
#endif // __EFI_H__
diff --git a/gbl/libefi/defs/protocols/riscv_efi_boot_protocol.h b/gbl/libefi/defs/protocols/riscv_efi_boot_protocol.h
new file mode 100644
index 0000000..528844b
--- /dev/null
+++ b/gbl/libefi/defs/protocols/riscv_efi_boot_protocol.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.
+ *
+ */
+
+#ifndef __RISCV_EFI_BOOT_PROTOCOL_H__
+#define __RISCV_EFI_BOOT_PROTOCOL_H__
+
+#include <stddef.h>
+
+#include "types.h"
+
+// Source: https://github.com/riscv-non-isa/riscv-uefi
+struct EfiRiscvBootProtocol {
+ uint64_t revision;
+
+ EfiStatus (*get_boot_hartid)(struct EfiRiscvBootProtocol* self, size_t* boot_hartid);
+};
+
+#endif // __RISCV_EFI_BOOT_PROTOCOL_H__
diff --git a/gbl/libefi/src/lib.rs b/gbl/libefi/src/lib.rs
index dabb1c7..c337e5d 100644
--- a/gbl/libefi/src/lib.rs
+++ b/gbl/libefi/src/lib.rs
@@ -73,6 +73,7 @@ pub use protocol::DevicePathToTextProtocol;
pub use protocol::LoadedImageProtocol;
pub use protocol::Protocol;
pub use protocol::ProtocolInfo;
+pub use protocol::RiscvBootProtocol;
pub use protocol::SimpleTextOutputProtocol;
mod error {
@@ -199,11 +200,17 @@ impl<'a> SystemTable<'a> {
/// Gets the `EFI_SYSTEM_TABLE.ConOut` field.
pub fn con_out(&self) -> EfiResult<Protocol<'a, SimpleTextOutputProtocol>> {
- Ok(Protocol::<SimpleTextOutputProtocol>::new(
- DeviceHandle(null_mut()), // No device handle. This protocol is a permanent reference.
- self.table.con_out,
- self.efi_entry,
- ))
+ // SAFETY: `EFI_SYSTEM_TABLE.ConOut` is a pointer to EfiSimpleTextOutputProtocol structure
+ // by definition. It lives until ExitBootService and thus as long as `self.efi_entry` or,
+ // 'a
+ Ok(unsafe {
+ Protocol::<SimpleTextOutputProtocol>::new(
+ // No device handle. This protocol is a permanent reference.
+ DeviceHandle(null_mut()),
+ self.table.con_out,
+ self.efi_entry,
+ )
+ })
}
/// Gets the `EFI_SYSTEM_TABLE.ConfigurationTable` array.
@@ -268,8 +275,10 @@ impl<'a> BootServices<'a> {
EFI_OPEN_PROTOCOL_ATTRIBUTE_BY_HANDLE_PROTOCOL
)?;
}
-
- Ok(Protocol::<T>::new(handle, out_handle as *mut _, self.efi_entry))
+ // SAFETY: `EFI_SYSTEM_TABLE.OpenProtocol` returns a valid pointer to `T::InterfaceType`
+ // on success. The pointer remains valid until closed by
+ // `EFI_BOOT_SERVICES.CloseProtocol()` when Protocol goes out of scope.
+ Ok(unsafe { Protocol::<T>::new(handle, out_handle as *mut _, self.efi_entry) })
}
/// Wrapper of `EFI_BOOT_SERVICES.CloseProtocol()`.
diff --git a/gbl/libefi/src/protocol.rs b/gbl/libefi/src/protocol.rs
index 327ccf8..b24de7b 100644
--- a/gbl/libefi/src/protocol.rs
+++ b/gbl/libefi/src/protocol.rs
@@ -40,7 +40,15 @@ pub struct Protocol<'a, T: ProtocolInfo> {
/// Protocol<T> will have additional implementation based on type `T`.
impl<'a, T: ProtocolInfo> Protocol<'a, T> {
/// Create a new instance with the given device handle, interface pointer and `EfiEntry` data.
- pub(crate) fn new(
+ ///
+ /// # Safety
+ ///
+ /// Caller needs to ensure that
+ ///
+ /// * `interface` points to a valid object of type T::InterfaceType.
+ ///
+ /// * Object pointed to by `interface` must live as long as the create `Protocol` or 'a.
+ pub(crate) unsafe fn new(
device: DeviceHandle,
interface: *mut T::InterfaceType,
efi_entry: &'a EfiEntry,
@@ -108,7 +116,11 @@ impl ProtocolInfo for BlockIoProtocol {
impl Protocol<'_, BlockIoProtocol> {
/// Wrapper of `EFI_BLOCK_IO_PROTOCOL.read_blocks()`
pub fn read_blocks(&self, lba: u64, buffer: &mut [u8]) -> EfiResult<()> {
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees self.interface is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
+ // `buffer` remains valid during the call.
unsafe {
efi_call!(
self.interface()?.read_blocks,
@@ -123,7 +135,11 @@ impl Protocol<'_, BlockIoProtocol> {
/// Wrapper of `EFI_BLOCK_IO_PROTOCOL.write_blocks()`
pub fn write_blocks(&self, lba: u64, buffer: &[u8]) -> EfiResult<()> {
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees self.interface is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
+ // `buffer` remains valid during the call.
unsafe {
efi_call!(
self.interface()?.write_blocks,
@@ -138,13 +154,19 @@ impl Protocol<'_, BlockIoProtocol> {
/// Wrapper of `EFI_BLOCK_IO_PROTOCOL.flush_blocks()`
pub fn flush_blocks(&self) -> EfiResult<()> {
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
unsafe { efi_call!(self.interface()?.flush_blocks, self.interface) }
}
/// Wrapper of `EFI_BLOCK_IO_PROTOCOL.reset()`
pub fn reset(&self, extended_verification: bool) -> EfiResult<()> {
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
unsafe { efi_call!(self.interface()?.reset, self.interface, extended_verification) }
}
@@ -169,7 +191,10 @@ impl ProtocolInfo for SimpleTextOutputProtocol {
impl Protocol<'_, SimpleTextOutputProtocol> {
/// Wrapper of `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString()`
pub fn output_string(&self, msg: *mut char16_t) -> EfiResult<()> {
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
unsafe { efi_call!(self.interface()?.output_string, self.interface, msg) }
}
}
@@ -234,7 +259,10 @@ impl<'a> Protocol<'a, DevicePathToTextProtocol> {
.convert_device_path_to_text
.as_ref()
.ok_or_else::<EfiError, _>(|| EFI_STATUS_NOT_FOUND.into())?;
- // SAFETY: EFI protocol method call.
+ // SAFETY:
+ // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
let res = unsafe { f(device_path.interface_ptr(), display_only, allow_shortcuts) };
Ok(DevicePathText::new(res, self.efi_entry))
}
@@ -313,6 +341,35 @@ impl<'a> Protocol<'a, LoadedImageProtocol> {
}
}
+/// RISCV_EFI_BOOT_PROTOCOL
+pub struct RiscvBootProtocol;
+
+impl ProtocolInfo for RiscvBootProtocol {
+ type InterfaceType = EfiRiscvBootProtocol;
+
+ const GUID: EfiGuid =
+ EfiGuid::new(0xccd15fec, 0x6f73, 0x4eec, [0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf]);
+}
+
+impl<'a> Protocol<'a, RiscvBootProtocol> {
+ pub fn get_boot_hartid(&self) -> EfiResult<usize> {
+ let mut boot_hart_id: usize = 0;
+ // SAFETY:
+ // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
+ // established by `Protocol::new()`.
+ // `self.interface` is input parameter and will not be retained. It outlives the call.
+ // `&mut boot_hart_id` is output parameter and will not be retained. It outlives the call.
+ unsafe {
+ efi_call!(self.interface()?.get_boot_hartid, self.interface, &mut boot_hart_id)?;
+ }
+ Ok(boot_hart_id)
+ }
+
+ pub fn revision(&self) -> EfiResult<u64> {
+ Ok(self.interface()?.revision)
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -322,8 +379,14 @@ mod test {
fn test_dont_close_protocol_without_device_handle() {
run_test(|image_handle, systab_ptr| {
let efi_entry = EfiEntry { image_handle, systab_ptr };
- {
- Protocol::<BlockIoProtocol>::new(DeviceHandle(null_mut()), 2 as *mut _, &efi_entry);
+ let mut block_io: EfiBlockIoProtocol = Default::default();
+ // SAFETY: `block_io` is a EfiBlockIoProtocol and out lives the created Protocol.
+ unsafe {
+ Protocol::<BlockIoProtocol>::new(
+ DeviceHandle(null_mut()),
+ &mut block_io as *mut _,
+ &efi_entry,
+ );
}
efi_call_traces().with(|traces| {
assert_eq!(traces.borrow_mut().close_protocol_trace.inputs.len(), 0);