Skip to content

Commit 8e56b33

Browse files
committed
Fixes from PR
Signed-off-by: Ayush Singh <[email protected]>
1 parent 48c6ae0 commit 8e56b33

File tree

6 files changed

+70
-59
lines changed

6 files changed

+70
-59
lines changed

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! UEFI-specific extensions to the primitives in `std::env` module
22
3+
#![unstable(feature = "uefi_std", issue = "100499")]
4+
35
use crate::ffi::c_void;
46
use crate::ptr::NonNull;
57
use crate::sync::atomic::{AtomicPtr, Ordering};
@@ -22,21 +24,18 @@ static GLOBALS: OnceLock<(AtomicPtr<c_void>, AtomicPtr<c_void>)> = OnceLock::new
2224
/// standard library is loaded.
2325
///
2426
/// This function must not be called more than once.
25-
#[unstable(feature = "uefi_std", issue = "100499")]
2627
pub unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
2728
GLOBALS.set((AtomicPtr::new(system_table.as_ptr()), AtomicPtr::new(handle.as_ptr()))).unwrap()
2829
}
2930

3031
/// Get the SystemTable Pointer.
31-
/// Note: This function panics if the System Table and Image Handle is Not initialized
32-
#[unstable(feature = "uefi_std", issue = "100499")]
32+
/// Note: This function panics if the System Table or Image Handle is not initialized
3333
pub fn system_table() -> NonNull<c_void> {
3434
try_system_table().unwrap()
3535
}
3636

37-
/// Get the SystemHandle Pointer.
38-
/// Note: This function panics if the System Table and Image Handle is Not initialized
39-
#[unstable(feature = "uefi_std", issue = "100499")]
37+
/// Get the ImageHandle Pointer.
38+
/// Note: This function panics if the System Table or Image Handle is not initialized
4039
pub fn image_handle() -> NonNull<c_void> {
4140
try_image_handle().unwrap()
4241
}

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

+4-8
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,16 @@ unsafe impl GlobalAlloc for System {
1313
Some(x) => x.as_ptr() as *mut _,
1414
};
1515

16-
if layout.size() > 0 {
17-
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
18-
} else {
19-
layout.dangling().as_ptr()
20-
}
16+
// The caller must ensure non-0 layout
17+
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
2118
}
2219

2320
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
2421
let system_table = match crate::os::uefi::env::try_system_table() {
2522
None => handle_alloc_error(layout),
2623
Some(x) => x.as_ptr() as *mut _,
2724
};
28-
if layout.size() > 0 {
29-
unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
30-
}
25+
// The caller must ensure non-0 layout
26+
unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
3127
}
3228
}

library/std/src/sys/uefi/common.rs renamed to library/std/src/sys/uefi/helpers.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
//! Contains most of the shared UEFI specific stuff. Some of this might be moved to `std::os::uefi`
22
//! if needed but no point in adding extra public API when there is not Std support for UEFI in the
33
//! first place
4+
//!
5+
//! Some Nomenclature
6+
//! * Protocol:
7+
//! - Protocols serve to enable communication between separately built modules, including drivers.
8+
//! - Every protocol has a GUID associated with it. The GUID serves as the name for the protocol.
9+
//! - Protocols are produced and consumed.
10+
//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
411
512
use r_efi::efi::Guid;
613

714
use crate::io::{self, const_io_error};
8-
use crate::mem::MaybeUninit;
15+
use crate::mem::{size_of, MaybeUninit};
916
use crate::os::uefi;
1017
use crate::ptr::NonNull;
1118

12-
// Locate handles with a particular protocol GUID
19+
/// Locate Handles with a particular Protocol GUID
1320
/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`
21+
///
22+
/// Returns an array of [Handles](r_efi::efi::Handle) that support a specified protocol.
1423
pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ffi::c_void>>> {
1524
fn inner(
1625
guid: &mut Guid,
@@ -34,6 +43,8 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
3443
let boot_services = boot_services();
3544
let mut buf_len = 0usize;
3645

46+
// This should always fail since the size of buffer is 0. This call should update the buf_len
47+
// variable with the required buffer length
3748
match inner(&mut guid, boot_services, &mut buf_len, crate::ptr::null_mut()) {
3849
Ok(()) => unreachable!(),
3950
Err(e) => match e.kind() {
@@ -44,21 +55,23 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
4455

4556
// The returned buf_len is in bytes
4657
let mut buf: Vec<r_efi::efi::Handle> =
47-
Vec::with_capacity(buf_len / crate::mem::size_of::<r_efi::efi::Handle>());
58+
Vec::with_capacity(buf_len / size_of::<r_efi::efi::Handle>());
4859
match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) {
4960
Ok(()) => {
50-
// SAFETY: This is safe because the call will succeed only if buf_len >= required
51-
// length. Also, on success, the `buf_len` is updated with the size of bufferv (in
52-
// bytes) written
53-
unsafe { buf.set_len(buf_len / crate::mem::size_of::<r_efi::efi::Handle>()) };
54-
Ok(buf.iter().filter_map(|x| NonNull::new(*x)).collect())
61+
// This is safe because the call will succeed only if buf_len >= required length.
62+
// Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written
63+
unsafe { buf.set_len(buf_len / size_of::<r_efi::efi::Handle>()) };
64+
Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect())
5565
}
5666
Err(e) => Err(e),
5767
}
5868
}
5969

60-
/// Open Protocol on a handle
61-
/// Implemented using `EFI_BOOT_SERVICES.OpenProtocol()`
70+
/// Open Protocol on a handle.
71+
/// Internally just a call to `EFI_BOOT_SERVICES.OpenProtocol()`.
72+
///
73+
/// Queries a handle to determine if it supports a specified protocol. If the protocol is
74+
/// supported by the handle, it opens the protocol on behalf of the calling agent.
6275
pub(crate) fn open_protocol<T>(
6376
handle: NonNull<crate::ffi::c_void>,
6477
mut protocol_guid: Guid,
@@ -256,9 +269,7 @@ pub(crate) fn status_to_io_error(s: r_efi::efi::Status) -> io::Error {
256269

257270
/// Get the BootServices Pointer.
258271
pub(crate) fn boot_services() -> NonNull<r_efi::efi::BootServices> {
259-
let system_table: NonNull<r_efi::efi::SystemTable> = uefi::env::system_table().cast();
260-
let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
261-
NonNull::new(boot_services).unwrap()
272+
try_boot_services().unwrap()
262273
}
263274
/// Get the BootServices Pointer.
264275
/// This function is mostly intended for places where panic is not an option

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

+13-11
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub mod thread_local_key;
4747
#[path = "../unsupported/time.rs"]
4848
pub mod time;
4949

50-
pub(crate) mod common;
50+
pub(crate) mod helpers;
5151

5252
#[cfg(test)]
5353
mod tests;
@@ -60,18 +60,20 @@ pub mod memchr {
6060
pub use core::slice::memchr::{memchr, memrchr};
6161
}
6262

63-
// SAFETY: must be called only once during runtime initialization.
64-
// SAFETY: argc must be 2.
65-
// SAFETY: argv must be &[Handle, *mut SystemTable].
66-
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
63+
/// # SAFETY
64+
/// - must be called only once during runtime initialization.
65+
/// - argc must be 2.
66+
/// - argv must be &[Handle, *mut SystemTable].
67+
pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
6768
assert_eq!(argc, 2);
6869
let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() };
6970
let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() };
7071
unsafe { crate::os::uefi::env::init_globals(image_handle, system_table) };
7172
}
7273

73-
// SAFETY: must be called only once during runtime cleanup.
74-
// NOTE: this is not guaranteed to run, for example when the program aborts.
74+
/// # SAFETY
75+
/// this is not guaranteed to run, for example when the program aborts.
76+
/// - must be called only once during runtime cleanup.
7577
pub unsafe fn cleanup() {}
7678

7779
#[inline]
@@ -89,15 +91,15 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
8991
use r_efi::efi::Status;
9092

9193
if let Ok(code) = usize::try_from(code) {
92-
common::status_to_io_error(Status::from_usize(code)).kind()
94+
helpers::status_to_io_error(Status::from_usize(code)).kind()
9395
} else {
9496
ErrorKind::Uncategorized
9597
}
9698
}
9799

98100
pub fn abort_internal() -> ! {
99101
if let (Some(boot_services), Some(handle)) =
100-
(common::try_boot_services(), uefi::env::try_image_handle())
102+
(helpers::try_boot_services(), uefi::env::try_image_handle())
101103
{
102104
let _ = unsafe {
103105
((*boot_services.as_ptr()).exit)(
@@ -130,9 +132,9 @@ fn get_random() -> Option<(u64, u64)> {
130132
use r_efi::protocols::rng;
131133

132134
let mut buf = [0u8; 16];
133-
let handles = common::locate_handles(rng::PROTOCOL_GUID).ok()?;
135+
let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?;
134136
for handle in handles {
135-
if let Ok(protocol) = common::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
137+
if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
136138
let r = unsafe {
137139
((*protocol.as_ptr()).get_rng)(
138140
protocol.as_ptr(),

library/std/src/sys_common/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ cfg_if::cfg_if! {
4444

4545
cfg_if::cfg_if! {
4646
if #[cfg(any(target_os = "l4re",
47-
target_os = "hermit",
4847
target_os = "uefi",
4948
feature = "restricted-std",
5049
all(target_family = "wasm", not(target_os = "emscripten")),

src/doc/rustc/src/platform-support/unknown-uefi.md

+24-20
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Available targets:
1919
## Requirements
2020

2121
All UEFI targets can be used as `no-std` environments via cross-compilation.
22-
Support for `std` is present, but incomplete and extreamly new. `alloc` is supported if
22+
Support for `std` is present, but incomplete and extremely new. `alloc` is supported if
2323
an allocator is provided by the user or if using std. No host tools are supported.
2424

2525
The UEFI environment resembles the environment for Microsoft Windows, with some
@@ -238,44 +238,42 @@ This section contains information on how to use std on UEFI.
238238
The building std part is pretty much the same as the official [docs](https://rustc-dev-guide.rust-lang.org/getting-started.html).
239239
The linker that should be used is `rust-lld`. Here is a sample `config.toml`:
240240
```toml
241-
[llvm]
242-
download-ci-llvm = false
243241
[rust]
244242
lld = true
245-
[target.x86_64-unknown-uefi]
246-
linker = "rust-lld"
247243
```
248244
Then just build using `x.py`:
249245
```sh
250-
./x.py build --target x86_64-unknown-uefi
246+
./x.py build --target x86_64-unknown-uefi --stage 1
247+
```
248+
Alternatively, it is possible to use the `build-std` feature. However, you must use a toolchain which has the UEFI std patches.
249+
Then just build the project using the following command:
250+
```sh
251+
cargo build --target x86_64-unknown-uefi -Zbuild-std=std,panic_abort
251252
```
252253

253254
### Std Requirements
254255
The current std has a few basic requirements to function:
255-
1. Memory Allocation Services (`EFI_BOOT_SERVICES.AllocatePool()` and
256-
`EFI_BOOT_SERVICES.FreePool()`) are available.
256+
1. Memory Allocation Services (`EFI_BOOT_SERVICES.AllocatePool()` and `EFI_BOOT_SERVICES.FreePool()`) are available. This should be true in in the Driver Execution Environment or later.
257257
If the above requirement is satisfied, the Rust code will reach `main`.
258258
Now we will discuss what the different modules of std use in UEFI.
259259

260260
### Implemented features
261261
#### alloc
262262
- Implemented using `EFI_BOOT_SERVICES.AllocatePool()` and `EFI_BOOT_SERVICES.FreePool()`.
263263
- Passes all the tests.
264-
- Some Quirks:
265-
- Currently uses `EfiLoaderData` as the `EFI_ALLOCATE_POOL->PoolType`.
264+
- Currently uses `EfiLoaderData` as the `EFI_ALLOCATE_POOL->PoolType`.
266265
#### cmath
267266
- Provided by compiler-builtins.
268267
#### env
269-
- Just some global consants.
268+
- Just some global constants.
270269
#### locks
271-
- Uses `unsupported/locks`.
272-
- They should work for a platform without threads according to docs.
270+
- The provided locks should work on all standard single-threaded UEFI implementations.
273271
#### os_str
274-
- Uses WTF-8 from windows.
272+
- While the strings in UEFI should be valid UCS-2, in practice, many implementations just do not care and use UTF-16 strings.
273+
- Thus, the current implementation supports full UTF-16 strings.
275274

276275
## Example: Hello World With std
277-
The following code is a valid UEFI application showing stdio in UEFI. It also
278-
uses `alloc` type `OsString` and `Vec`.
276+
The following code features a valid UEFI application, including stdio and `alloc` (`OsString` and `Vec`):
279277

280278
This example can be compiled as binary crate via `cargo` using the toolchain
281279
compiled from the above source (named custom):
@@ -286,15 +284,21 @@ cargo +custom build --target x86_64-unknown-uefi
286284

287285
```rust,ignore (platform-specific)
288286
use r_efi::efi;
289-
use std::os::uefi::ffi::OsStrExt;
290-
use std::{ffi::OsString, panic};
287+
use std::{
288+
ffi::OsString,
289+
os::uefi::{env, ffi::OsStrExt}
290+
};
291291
292292
pub fn main() {
293-
let st = std::os::uefi::env::system_table().as_ptr() as *mut efi::SystemTable;
293+
let st = env::system_table().as_ptr() as *mut efi::SystemTable;
294294
let mut s: Vec<u16> = OsString::from("Hello World!\n").encode_wide().collect();
295295
s.push(0);
296296
let r =
297-
unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) };
297+
unsafe {
298+
let con_out: *mut simple_text_output::Protocol = (*st).con_out;
299+
let output_string: extern "efiapi" fn(_: *mut simple_text_output::Protocol, *mut u16) = (*con_out).output_string;
300+
output_string(con_out, s.as_ptr() as *mut efi::Char16)
301+
};
298302
assert!(!r.is_error())
299303
}
300304
```

0 commit comments

Comments
 (0)