-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
151 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
//! Implementation for UEFI using EFI_RNG_PROTOCOL | ||
use crate::Error; | ||
use core::{ | ||
mem::MaybeUninit, | ||
ptr::{self, null_mut, NonNull}, | ||
sync::atomic::{AtomicPtr, Ordering::Relaxed}, | ||
}; | ||
use r_efi::{ | ||
efi::{BootServices, Handle}, | ||
protocols::rng, | ||
}; | ||
|
||
extern crate std; | ||
|
||
pub use crate::util::{inner_u32, inner_u64}; | ||
|
||
#[cfg(not(target_os = "uefi"))] | ||
compile_error!("`efi_rng` backend can be enabled only for UEFI targets!"); | ||
|
||
static RNG_PROTOCOL: AtomicPtr<rng::Protocol> = AtomicPtr::new(null_mut()); | ||
|
||
fn init() -> Result<NonNull<rng::Protocol>, Error> { | ||
const HANDLE_SIZE: usize = size_of::<Handle>(); | ||
|
||
let boot_services = std::os::uefi::env::boot_services() | ||
.ok_or(Error::BOOT_SERVICES_UNAVAILABLE)? | ||
.cast::<BootServices>(); | ||
|
||
let mut handles = [ptr::null_mut(); 16]; | ||
// `locate_handle` operates with length in bytes | ||
let mut buf_size = handles.len() * HANDLE_SIZE; | ||
let mut guid = rng::PROTOCOL_GUID; | ||
let ret = unsafe { | ||
((*boot_services.as_ptr()).locate_handle)( | ||
r_efi::efi::BY_PROTOCOL, | ||
&mut guid, | ||
null_mut(), | ||
&mut buf_size, | ||
handles.as_mut_ptr(), | ||
) | ||
}; | ||
|
||
if ret.is_error() { | ||
return Err(Error::TEMP_EFI_ERROR); | ||
} | ||
|
||
let handles_len = buf_size / HANDLE_SIZE; | ||
let handles = handles.get(..handles_len).ok_or(Error::UNEXPECTED)?; | ||
|
||
let system_handle = std::os::uefi::env::image_handle(); | ||
for &handle in handles { | ||
let mut protocol: MaybeUninit<*mut rng::Protocol> = MaybeUninit::uninit(); | ||
|
||
let mut protocol_guid = rng::PROTOCOL_GUID; | ||
let ret = unsafe { | ||
((*boot_services.as_ptr()).open_protocol)( | ||
handle, | ||
&mut protocol_guid, | ||
protocol.as_mut_ptr().cast(), | ||
system_handle.as_ptr(), | ||
ptr::null_mut(), | ||
r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL, | ||
) | ||
}; | ||
|
||
let protocol = if ret.is_error() { | ||
continue; | ||
} else { | ||
let protocol = unsafe { protocol.assume_init() }; | ||
NonNull::new(protocol).ok_or(Error::UNEXPECTED)? | ||
}; | ||
|
||
// Try to use the acquired protocol handle | ||
let mut buf = [0u8; 8]; | ||
let ret = unsafe { | ||
((*protocol.as_ptr()).get_rng)( | ||
protocol.as_ptr(), | ||
ptr::null_mut(), | ||
buf.len(), | ||
buf.as_mut_ptr(), | ||
) | ||
}; | ||
|
||
if ret.is_error() { | ||
continue; | ||
} | ||
|
||
RNG_PROTOCOL.store(protocol.as_ptr(), Relaxed); | ||
return Ok(protocol); | ||
} | ||
Err(Error::NO_RNG_HANDLE) | ||
} | ||
|
||
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { | ||
let protocol = match NonNull::new(RNG_PROTOCOL.load(Relaxed)) { | ||
Some(p) => p, | ||
None => init()?, | ||
}; | ||
|
||
let ret = unsafe { | ||
((*protocol.as_ptr()).get_rng)( | ||
protocol.as_ptr(), | ||
ptr::null_mut(), | ||
dest.len(), | ||
dest.as_mut_ptr().cast::<u8>(), | ||
) | ||
}; | ||
|
||
if ret.is_error() { | ||
Err(Error::TEMP_EFI_ERROR) | ||
} else { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl Error { | ||
pub(crate) const BOOT_SERVICES_UNAVAILABLE: Error = Self::new_internal(10); | ||
pub(crate) const NO_RNG_HANDLE: Error = Self::new_internal(11); | ||
pub(crate) const TEMP_EFI_ERROR: Error = Self::new_internal(12); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters