diff options
author | Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> | 2023-11-10 21:22:29 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-11-10 21:22:29 +0000 |
commit | 7db62a2704bfb57abc5be94508101b2fd57d8189 (patch) | |
tree | d9e74aacb8f18d24502e2cbcce08a94a82537a49 | |
parent | 46301d5a3e67627f9d4989edf210e3764aa1dfed (diff) | |
parent | 50cd8a032fa03bd5559d110efca660aca1f4a58c (diff) | |
download | libbootloader-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/BUILD | 1 | ||||
-rw-r--r-- | gbl/libefi/defs/efi.h | 1 | ||||
-rw-r--r-- | gbl/libefi/defs/protocols/riscv_efi_boot_protocol.h | 32 | ||||
-rw-r--r-- | gbl/libefi/src/lib.rs | 23 | ||||
-rw-r--r-- | gbl/libefi/src/protocol.rs | 81 |
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); |