Skip to content

Commit 8cd315c

Browse files
committed
Improve UEFI sys documentation
Add more comments to help anyone interested in checking out the internal implementation. Signed-off-by: Ayush <ayushsingh1325@gmail.com>
1 parent 88c615c commit 8cd315c

File tree

12 files changed

+148
-100
lines changed

12 files changed

+148
-100
lines changed

library/std/src/os/uefi/env.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub fn get_runtime_services() -> Option<NonNull<RuntimeServices>> {
4949
}
5050

5151
#[unstable(feature = "uefi_std", issue = "none")]
52+
/// Open Protocol on a handle
53+
/// Implemented using `EFI_BOOT_SERVICES.OpenProtocol()`
5254
pub fn open_protocol<T>(
5355
handle: NonNull<c_void>,
5456
mut protocol_guid: Guid,
@@ -79,6 +81,8 @@ pub fn open_protocol<T>(
7981
}
8082

8183
#[unstable(feature = "uefi_std", issue = "none")]
84+
// Locate handles with a particula protocol Guid
85+
/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`
8286
pub fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<c_void>>> {
8387
fn inner(
8488
guid: &mut Guid,

library/std/src/os/uefi/ffi.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ pub trait OsStrExt: Sealed {
1111
/// Note: The returned string is NULL terminated.
1212
/// Note: The supplied should not contain NULL.
1313
fn to_ffi_string(&self) -> Vec<u16> {
14-
let mut v: Vec<u16> = self.to_ucs2().map(u16::from).collect();
14+
let mut v: Vec<u16> = self
15+
.to_ucs2()
16+
.map(|x| match x {
17+
Ok(c) => c,
18+
Err(_) => ucs2::Ucs2Char::REPLACEMENT_CHARACTER,
19+
})
20+
.map(u16::from)
21+
.collect();
1522
v.push(0);
1623
v.shrink_to_fit();
1724
v

library/std/src/sys/uefi/alloc.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
//! Global Allocator for UEFI.
2+
//! Uses `EFI_BOOT_SERVICES.AllocatePool()` and `EFI_BOOT_SERVICES.FreePool()`.
3+
//! Takes a lot of inspiration from Windows allocator for Alignment > 8.
4+
15
use crate::alloc::{GlobalAlloc, Layout, System};
26
use crate::os::uefi;
37

48
const POOL_ALIGNMENT: usize = 8;
9+
// FIXME: Maybe allow chaing the MEMORY_TYPE. However, since allocation is done even before main,
10+
// there will be a few allocations with the default MEMORY_TYPE.
511
const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA;
612

713
#[stable(feature = "alloc_system_type", since = "1.28.0")]
@@ -80,7 +86,7 @@ unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
8086
// SAFETY: Because the size and alignment of a header is <= `MIN_ALIGN` and `aligned`
8187
// is aligned to at least `MIN_ALIGN` and has at least `MIN_ALIGN` bytes of padding before
8288
// it, it is safe to write a header directly before it.
83-
unsafe { core::ptr::write((aligned as *mut Header).offset(-1), Header(ptr)) };
89+
unsafe { crate::ptr::write((aligned as *mut Header).offset(-1), Header(ptr)) };
8490

8591
aligned
8692
} else {
@@ -93,7 +99,7 @@ unsafe fn unalign_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
9399
if align > POOL_ALIGNMENT {
94100
// SAFETY: Because of the contract of `System`, `ptr` is guaranteed to be non-null
95101
// and have a header readable directly before it.
96-
unsafe { core::ptr::read((ptr as *mut Header).offset(-1)).0 }
102+
unsafe { crate::ptr::read((ptr as *mut Header).offset(-1)).0 }
97103
} else {
98104
ptr
99105
}

library/std/src/sys/uefi/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Args related functionality for UEFI. Takes a lot of inspiration of Windows args
2+
13
use super::common;
24
use crate::ffi::OsString;
35
use crate::fmt;
@@ -11,6 +13,8 @@ pub struct Args {
1113
parsed_args_list: vec::IntoIter<OsString>,
1214
}
1315

16+
// Get the Supplied arguments for loaded image.
17+
// Uses EFI_LOADED_IMAGE_PROTOCOL
1418
pub fn args() -> Args {
1519
use r_efi::efi::protocols::loaded_image;
1620

library/std/src/sys/uefi/fs.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Implemented using File Protocol
1+
//! File System functionality for UEFI
22
33
use crate::ffi::{OsStr, OsString};
44
use crate::fmt;
@@ -9,7 +9,6 @@ use crate::sys::time::{SystemTime, UNIX_EPOCH};
99
use crate::sys::unsupported;
1010
use r_efi::protocols::file;
1111

12-
// FIXME: Do not store FileProtocol Instead store Handle
1312
pub struct File {
1413
ptr: uefi_fs::FileProtocol,
1514
path: PathBuf,
@@ -149,6 +148,7 @@ impl Iterator for ReadDir {
149148
fn next(&mut self) -> Option<io::Result<DirEntry>> {
150149
let dir_entry = self.inner.read_dir_entry(self.path.as_path());
151150
if let Some(Ok(ref x)) = dir_entry {
151+
// Ignore `.` and `..`
152152
if x.file_name().as_os_str() == OsStr::new(".")
153153
|| x.file_name().as_os_str() == OsStr::new("..")
154154
{
@@ -382,6 +382,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
382382
Ok(ReadDir { inner, path: abs_path })
383383
}
384384

385+
// Just Delete the file since symlinks are not supported
385386
pub fn unlink(p: &Path) -> io::Result<()> {
386387
let open_mode = file::MODE_READ | file::MODE_WRITE;
387388
let attr = 0;
@@ -431,14 +432,17 @@ pub fn try_exists(path: &Path) -> io::Result<bool> {
431432
}
432433
}
433434

435+
// Symlink not supported
434436
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
435437
unsupported()
436438
}
437439

440+
// Symlink not supported
438441
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
439442
unsupported()
440443
}
441444

445+
// Symlink not supported
442446
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
443447
unsupported()
444448
}
@@ -459,7 +463,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
459463
stat(p)
460464
}
461465

462-
// Not sure how to implement. Tryied doing a round conversion from EFI_DEVICE_PATH protocol but
466+
// Not sure how to implement. Tried doing a round conversion from EFI_DEVICE_PATH protocol but
463467
// that doesn't work either.
464468
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
465469
unsupported()
@@ -533,6 +537,9 @@ mod uefi_fs {
533537
FileProtocol { inner }
534538
}
535539

540+
// Can open any file as long as it is possible to convert path to EFI_DEVICE_PATH_PROTOCOL
541+
// using `EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL.ConvertTextToDevicePath()`.
542+
// If relative path is provided, then opens the file in the EFI_LOADED_IMAGE_DEVICE_PATH
536543
pub fn from_path(path: &Path, open_mode: u64, attr: u64) -> io::Result<Self> {
537544
match path.prefix() {
538545
None => {
@@ -559,6 +566,7 @@ mod uefi_fs {
559566
}
560567
}
561568

569+
// Open the volume on the device_handle the image was loaded from.
562570
fn get_rootfs() -> io::Result<FileProtocol> {
563571
use r_efi::protocols::loaded_image;
564572

@@ -581,6 +589,7 @@ mod uefi_fs {
581589
Self::get_volume(device_handle)
582590
}
583591

592+
// Open a volume having a particular prefix.
584593
fn get_volume_from_prefix(prefix: &OsStr) -> io::Result<Self> {
585594
use r_efi::protocols::{device_path, simple_file_system};
586595

@@ -608,6 +617,7 @@ mod uefi_fs {
608617
Err(io::error::const_io_error!(io::ErrorKind::NotFound, "Volume Not Found"))
609618
}
610619

620+
// Open volume on device_handle using SIMPLE_FILE_SYSTEM_PROTOCOL
611621
fn get_volume(device_handle: NonNull<crate::ffi::c_void>) -> io::Result<Self> {
612622
use r_efi::protocols::simple_file_system;
613623

@@ -636,6 +646,7 @@ mod uefi_fs {
636646
}
637647
}
638648

649+
// Open a file from current EFI_FILE_PATH_PROTOCOL
639650
pub fn open(&self, path: &Path, open_mode: u64, attr: u64) -> io::Result<FileProtocol> {
640651
let mut file_opened: MaybeUninit<*mut file::Protocol> = MaybeUninit::uninit();
641652
unsafe {
@@ -684,6 +695,7 @@ mod uefi_fs {
684695
unsafe { Self::flush_raw(self.inner.as_ptr()) }
685696
}
686697

698+
// Read a Directory.
687699
pub fn read_dir_entry(&self, base_path: &Path) -> Option<io::Result<DirEntry>> {
688700
let mut buf_size = 0usize;
689701
if let Err(e) = unsafe {
@@ -718,6 +730,7 @@ mod uefi_fs {
718730
Some(Ok(DirEntry { attr, name, path }))
719731
}
720732

733+
// Get current file info
721734
pub fn get_file_info(&self) -> io::Result<uefi::raw::VariableSizeType<file::Info>> {
722735
let mut buf_size = 0usize;
723736
match unsafe {
@@ -749,6 +762,7 @@ mod uefi_fs {
749762
}
750763
}
751764

765+
// Set file size. Useful for truncation
752766
pub fn set_file_size(&self, file_size: u64) -> io::Result<()> {
753767
use r_efi::efi::Time;
754768

@@ -771,6 +785,7 @@ mod uefi_fs {
771785
}
772786
}
773787

788+
// Set file attributes
774789
pub fn set_file_attr(&self, attribute: u64) -> io::Result<()> {
775790
use r_efi::efi::Time;
776791

@@ -793,6 +808,8 @@ mod uefi_fs {
793808
}
794809
}
795810

811+
// Change file name. It seems possible to provide a relative path as file name. Thus it
812+
// also acts as move
796813
pub fn set_file_name(&self, file_name: &OsStr) -> io::Result<()> {
797814
use r_efi::efi::Time;
798815

@@ -825,7 +842,10 @@ mod uefi_fs {
825842
}
826843
}
827844

845+
// Delete a file.
828846
pub fn delete(self) -> io::Result<()> {
847+
// Deleting the file makes the pointer invalid. Thus calling drop on it later will
848+
// cause UB
829849
let file = crate::mem::ManuallyDrop::new(self);
830850
unsafe { Self::delete_raw(file.inner.as_ptr()) }
831851
}

library/std/src/sys/uefi/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
7777
}
7878

7979
pub fn abort_internal() -> ! {
80+
// First try to use EFI_BOOT_SERVICES.Exit()
8081
if let (Some(boot_services), Some(handle)) =
8182
(uefi::env::get_boot_services(), uefi::env::get_system_handle())
8283
{

library/std/src/sys/uefi/os.rs

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::os::uefi::ffi::OsStrExt;
99
use crate::os::uefi::io::status_to_io_error;
1010
use crate::path::{self, PathBuf};
1111

12+
// Return EFI_ABORTED as Status
1213
pub fn errno() -> i32 {
1314
r_efi::efi::Status::ABORTED.as_usize() as i32
1415
}
@@ -18,6 +19,7 @@ pub fn error_string(errno: i32) -> String {
1819
status_to_io_error(r).to_string()
1920
}
2021

22+
// Implemented using EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL
2123
pub fn getcwd() -> io::Result<PathBuf> {
2224
let mut p = current_exe()?;
2325
p.pop();
@@ -65,6 +67,7 @@ impl StdError for JoinPathsError {
6567
}
6668
}
6769

70+
// Implemented using EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL
6871
pub fn current_exe() -> io::Result<PathBuf> {
6972
use r_efi::efi::protocols::{device_path, loaded_image_device_path};
7073

@@ -102,7 +105,7 @@ pub fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> {
102105
unsetenv(key)
103106
} else {
104107
unsafe {
105-
uefi_vars::set_variable_raw(
108+
uefi_vars::set_variable(
106109
key.to_ffi_string().as_mut_ptr(),
107110
val.len(),
108111
val.bytes().as_ptr() as *mut crate::ffi::c_void,
@@ -113,7 +116,7 @@ pub fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> {
113116

114117
pub fn unsetenv(key: &OsStr) -> io::Result<()> {
115118
match unsafe {
116-
uefi_vars::set_variable_raw(key.to_ffi_string().as_mut_ptr(), 0, crate::ptr::null_mut())
119+
uefi_vars::set_variable(key.to_ffi_string().as_mut_ptr(), 0, crate::ptr::null_mut())
117120
} {
118121
Ok(_) => Ok(()),
119122
Err(e) => match e.kind() {
@@ -138,20 +141,23 @@ pub fn exit(code: i32) -> ! {
138141
Err(_) => r_efi::efi::Status::ABORTED,
139142
};
140143

144+
// First try to use EFI_BOOT_SERVICES.Exit()
141145
if let (Some(boot_services), Some(handle)) =
142146
(uefi::env::get_boot_services(), uefi::env::get_system_handle())
143147
{
144148
let _ =
145149
unsafe { ((*boot_services.as_ptr()).exit)(handle.as_ptr(), code, 0, [0].as_mut_ptr()) };
146150
}
147151

152+
// If exit is not possible, the call abort
148153
crate::intrinsics::abort()
149154
}
150155

151156
pub fn getpid() -> u32 {
152157
panic!("no pids on this platform")
153158
}
154159

160+
// Implement variables using Variable Services in EFI_RUNTIME_SERVICES
155161
pub(crate) mod uefi_vars {
156162
// It is possible to directly store and use UTF-8 data. So no need to convert to and from UCS-2
157163
use super::super::common;
@@ -171,7 +177,7 @@ pub(crate) mod uefi_vars {
171177
&[0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2],
172178
);
173179

174-
pub(crate) unsafe fn set_variable_raw(
180+
pub(crate) unsafe fn set_variable(
175181
variable_name: *mut u16,
176182
data_size: usize,
177183
data: *mut crate::ffi::c_void,
@@ -192,40 +198,42 @@ pub(crate) mod uefi_vars {
192198
}
193199

194200
pub(crate) fn get_variable(key: &OsStr) -> Option<OsString> {
195-
let runtime_services = uefi::env::get_runtime_services()?;
196201
let mut buf_size = 0;
197-
let mut guid = SHELL_VARIABLE_GUID;
198-
let r = unsafe {
199-
((*runtime_services.as_ptr()).get_variable)(
200-
key.to_ffi_string().as_mut_ptr(),
201-
&mut guid,
202-
crate::ptr::null_mut(),
203-
&mut buf_size,
204-
crate::ptr::null_mut(),
205-
)
206-
};
207-
208-
if r.is_error() && r != r_efi::efi::Status::BUFFER_TOO_SMALL {
209-
return None;
202+
let mut key_buf = key.to_ffi_string();
203+
204+
if let Err(e) =
205+
unsafe { get_vaiable_raw(key_buf.as_mut_ptr(), &mut buf_size, crate::ptr::null_mut()) }
206+
{
207+
if e.kind() != io::ErrorKind::FileTooLarge {
208+
return None;
209+
}
210210
}
211211

212212
let mut buf: Vec<u8> = Vec::with_capacity(buf_size);
213+
unsafe { get_vaiable_raw(key_buf.as_mut_ptr(), &mut buf_size, buf.as_mut_ptr().cast()) }
214+
.ok()?;
215+
216+
unsafe { buf.set_len(buf_size) };
217+
Some(OsString::from(String::from_utf8(buf).ok()?))
218+
}
219+
220+
unsafe fn get_vaiable_raw(
221+
key: *mut u16,
222+
data_size: &mut usize,
223+
data: *mut crate::ffi::c_void,
224+
) -> io::Result<()> {
225+
let runtime_services =
226+
uefi::env::get_runtime_services().ok_or(common::RUNTIME_SERVICES_ERROR)?;
213227
let mut guid = SHELL_VARIABLE_GUID;
214228
let r = unsafe {
215229
((*runtime_services.as_ptr()).get_variable)(
216-
key.to_ffi_string().as_mut_ptr(),
230+
key,
217231
&mut guid,
218232
crate::ptr::null_mut(),
219-
&mut buf_size,
220-
buf.as_mut_ptr().cast(),
233+
data_size,
234+
data,
221235
)
222236
};
223-
224-
if r.is_error() {
225-
None
226-
} else {
227-
unsafe { buf.set_len(buf_size) };
228-
Some(OsString::from(String::from_utf8(buf).ok()?))
229-
}
237+
if r.is_error() { Err(status_to_io_error(r)) } else { Ok(()) }
230238
}
231239
}

library/std/src/sys/uefi/pipe.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! An implementation of Pipes using UEFI variables
2+
13
use crate::os::uefi::ffi::OsStrExt;
24
use crate::{
35
ffi::OsStr,

0 commit comments

Comments
 (0)