mirror of https://github.com/rust-lang/rust.git
Auto merge of #99892 - JohnTitor:rollup-qi4fem8, r=JohnTitor
Rollup of 8 pull requests Successful merges: - #99686 (add suggestion when there is a impl of external trait on pointer with wrong coherence rules) - #99760 (doc/rustc: describe the uefi target platforms) - #99766 (Htmldocck: Substitute the doc channel when blessing) - #99781 (Use String::from_utf8_lossy in CStr demo) - #99803 (Update mentions to `rustc_metadata::rmeta::Lazy`) - #99845 (Remove `$` prefix for bash scripts in doc) - #99850 (rustdoc: Remove more Clean trait implementations) - #99872 (Clone the `src/llvm-project` submodule if profiling is enabled) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2f847b81a0
|
@ -83,7 +83,7 @@ pub(crate) struct CrateMetadata {
|
||||||
|
|
||||||
// --- Some data pre-decoded from the metadata blob, usually for performance ---
|
// --- Some data pre-decoded from the metadata blob, usually for performance ---
|
||||||
/// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
|
/// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
|
||||||
/// lifetime is only used behind `Lazy`, and therefore acts like a
|
/// lifetime is only used behind `LazyValue`, `LazyArray`, or `LazyTable`, and therefore acts like a
|
||||||
/// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
|
/// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
|
||||||
/// is being used to decode those values.
|
/// is being used to decode those values.
|
||||||
root: CrateRoot,
|
root: CrateRoot,
|
||||||
|
|
|
@ -66,13 +66,13 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V
|
||||||
///
|
///
|
||||||
/// Metadata is effective a tree, encoded in post-order,
|
/// Metadata is effective a tree, encoded in post-order,
|
||||||
/// and with the root's position written next to the header.
|
/// and with the root's position written next to the header.
|
||||||
/// That means every single `Lazy` points to some previous
|
/// That means every single `LazyValue` points to some previous
|
||||||
/// location in the metadata and is part of a larger node.
|
/// location in the metadata and is part of a larger node.
|
||||||
///
|
///
|
||||||
/// The first `Lazy` in a node is encoded as the backwards
|
/// The first `LazyValue` in a node is encoded as the backwards
|
||||||
/// distance from the position where the containing node
|
/// distance from the position where the containing node
|
||||||
/// starts and where the `Lazy` points to, while the rest
|
/// starts and where the `LazyValue` points to, while the rest
|
||||||
/// use the forward distance from the previous `Lazy`.
|
/// use the forward distance from the previous `LazyValue`.
|
||||||
/// Distances start at 1, as 0-byte nodes are invalid.
|
/// Distances start at 1, as 0-byte nodes are invalid.
|
||||||
/// Also invalid are nodes being referred in a different
|
/// Also invalid are nodes being referred in a different
|
||||||
/// order than they were encoded in.
|
/// order than they were encoded in.
|
||||||
|
@ -94,12 +94,12 @@ impl<T> LazyValue<T> {
|
||||||
|
|
||||||
/// A list of lazily-decoded values.
|
/// A list of lazily-decoded values.
|
||||||
///
|
///
|
||||||
/// Unlike `Lazy<Vec<T>>`, the length is encoded next to the
|
/// Unlike `LazyValue<Vec<T>>`, the length is encoded next to the
|
||||||
/// position, not at the position, which means that the length
|
/// position, not at the position, which means that the length
|
||||||
/// doesn't need to be known before encoding all the elements.
|
/// doesn't need to be known before encoding all the elements.
|
||||||
///
|
///
|
||||||
/// If the length is 0, no position is encoded, but otherwise,
|
/// If the length is 0, no position is encoded, but otherwise,
|
||||||
/// the encoding is that of `Lazy`, with the distinction that
|
/// the encoding is that of `LazyArray`, with the distinction that
|
||||||
/// the minimal distance the length of the sequence, i.e.
|
/// the minimal distance the length of the sequence, i.e.
|
||||||
/// it's assumed there's no 0-byte element in the sequence.
|
/// it's assumed there's no 0-byte element in the sequence.
|
||||||
struct LazyArray<T> {
|
struct LazyArray<T> {
|
||||||
|
@ -167,17 +167,17 @@ impl<I, T> Clone for LazyTable<I, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encoding / decoding state for `Lazy`.
|
/// Encoding / decoding state for `Lazy`s (`LazyValue`, `LazyArray`, and `LazyTable`).
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
enum LazyState {
|
enum LazyState {
|
||||||
/// Outside of a metadata node.
|
/// Outside of a metadata node.
|
||||||
NoNode,
|
NoNode,
|
||||||
|
|
||||||
/// Inside a metadata node, and before any `Lazy`.
|
/// Inside a metadata node, and before any `Lazy`s.
|
||||||
/// The position is that of the node itself.
|
/// The position is that of the node itself.
|
||||||
NodeStart(NonZeroUsize),
|
NodeStart(NonZeroUsize),
|
||||||
|
|
||||||
/// Inside a metadata node, with a previous `Lazy`.
|
/// Inside a metadata node, with a previous `Lazy`s.
|
||||||
/// The position is where that previous `Lazy` would start.
|
/// The position is where that previous `Lazy` would start.
|
||||||
Previous(NonZeroUsize),
|
Previous(NonZeroUsize),
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ fixed_size_enum! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We directly encode `DefPathHash` because a `Lazy` would encur a 25% cost.
|
// We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost.
|
||||||
impl FixedSizeEncoding for Option<DefPathHash> {
|
impl FixedSizeEncoding for Option<DefPathHash> {
|
||||||
type ByteArray = [u8; 16];
|
type ByteArray = [u8; 16];
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ impl FixedSizeEncoding for Option<DefPathHash> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We directly encode RawDefId because using a `Lazy` would incur a 50% overhead in the worst case.
|
// We directly encode RawDefId because using a `LazyValue` would incur a 50% overhead in the worst case.
|
||||||
impl FixedSizeEncoding for Option<RawDefId> {
|
impl FixedSizeEncoding for Option<RawDefId> {
|
||||||
type ByteArray = [u8; 8];
|
type ByteArray = [u8; 8];
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::{Diagnostic, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
|
@ -107,6 +107,7 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
Err(err) => emit_orphan_check_error(
|
Err(err) => emit_orphan_check_error(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
sp,
|
||||||
|
item.span,
|
||||||
tr.path.span,
|
tr.path.span,
|
||||||
trait_ref.self_ty(),
|
trait_ref.self_ty(),
|
||||||
impl_.self_ty.span,
|
impl_.self_ty.span,
|
||||||
|
@ -207,6 +208,7 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
fn emit_orphan_check_error<'tcx>(
|
fn emit_orphan_check_error<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
|
full_impl_span: Span,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
self_ty_span: Span,
|
self_ty_span: Span,
|
||||||
|
@ -247,8 +249,20 @@ fn emit_orphan_check_error<'tcx>(
|
||||||
ty::Slice(_) => (this, " because slices are always foreign"),
|
ty::Slice(_) => (this, " because slices are always foreign"),
|
||||||
ty::Array(..) => (this, " because arrays are always foreign"),
|
ty::Array(..) => (this, " because arrays are always foreign"),
|
||||||
ty::Tuple(..) => (this, " because tuples are always foreign"),
|
ty::Tuple(..) => (this, " because tuples are always foreign"),
|
||||||
|
ty::RawPtr(ptr_ty) => {
|
||||||
|
emit_newtype_suggestion_for_raw_ptr(
|
||||||
|
full_impl_span,
|
||||||
|
self_ty,
|
||||||
|
self_ty_span,
|
||||||
|
ptr_ty,
|
||||||
|
&mut err,
|
||||||
|
);
|
||||||
|
|
||||||
|
(format!("`{}`", ty), " because raw pointers are always foreign")
|
||||||
|
}
|
||||||
_ => (format!("`{}`", ty), ""),
|
_ => (format!("`{}`", ty), ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
|
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
|
||||||
if *is_target_ty {
|
if *is_target_ty {
|
||||||
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
|
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
|
||||||
|
@ -330,6 +344,27 @@ fn emit_orphan_check_error<'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_newtype_suggestion_for_raw_ptr(
|
||||||
|
full_impl_span: Span,
|
||||||
|
self_ty: Ty<'_>,
|
||||||
|
self_ty_span: Span,
|
||||||
|
ptr_ty: &ty::TypeAndMut<'_>,
|
||||||
|
diag: &mut Diagnostic,
|
||||||
|
) {
|
||||||
|
if !self_ty.needs_subst() {
|
||||||
|
let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" };
|
||||||
|
let msg_sugg = "consider introducing a new wrapper type".to_owned();
|
||||||
|
let sugg = vec![
|
||||||
|
(
|
||||||
|
full_impl_span.shrink_to_lo(),
|
||||||
|
format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
|
||||||
|
),
|
||||||
|
(self_ty_span, "WrapperType".to_owned()),
|
||||||
|
];
|
||||||
|
diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Lint impls of auto traits if they are likely to have
|
/// Lint impls of auto traits if they are likely to have
|
||||||
/// unsound or surprising effects on auto impls.
|
/// unsound or surprising effects on auto impls.
|
||||||
fn lint_auto_trait_impl<'tcx>(
|
fn lint_auto_trait_impl<'tcx>(
|
||||||
|
|
|
@ -65,9 +65,9 @@ use crate::str;
|
||||||
/// extern "C" { fn my_string() -> *const c_char; }
|
/// extern "C" { fn my_string() -> *const c_char; }
|
||||||
///
|
///
|
||||||
/// fn my_string_safe() -> String {
|
/// fn my_string_safe() -> String {
|
||||||
/// unsafe {
|
/// let cstr = unsafe { CStr::from_ptr(my_string()) };
|
||||||
/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
|
/// // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation
|
||||||
/// }
|
/// String::from_utf8_lossy(cstr.to_bytes()).to_string()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// println!("string: {}", my_string_safe());
|
/// println!("string: {}", my_string_safe());
|
||||||
|
|
|
@ -111,6 +111,11 @@ impl Step for Std {
|
||||||
|
|
||||||
builder.update_submodule(&Path::new("library").join("stdarch"));
|
builder.update_submodule(&Path::new("library").join("stdarch"));
|
||||||
|
|
||||||
|
// Profiler information requires LLVM's compiler-rt
|
||||||
|
if builder.config.profiler {
|
||||||
|
builder.update_submodule(&Path::new("src/llvm-project"));
|
||||||
|
}
|
||||||
|
|
||||||
let mut target_deps = builder.ensure(StartupObjects { compiler, target });
|
let mut target_deps = builder.ensure(StartupObjects { compiler, target });
|
||||||
|
|
||||||
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
|
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
|
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
|
||||||
- [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
|
- [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
|
||||||
- [*-unknown-openbsd](platform-support/openbsd.md)
|
- [*-unknown-openbsd](platform-support/openbsd.md)
|
||||||
|
- [\*-unknown-uefi](platform-support/unknown-uefi.md)
|
||||||
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
|
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
|
||||||
- [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
|
- [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
|
||||||
- [Targets](targets/index.md)
|
- [Targets](targets/index.md)
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
# `*-unknown-uefi`
|
||||||
|
|
||||||
|
**Tier: 3**
|
||||||
|
|
||||||
|
Unified Extensible Firmware Interface (UEFI) targets for application, driver,
|
||||||
|
and core UEFI binaries.
|
||||||
|
|
||||||
|
Available targets:
|
||||||
|
|
||||||
|
- `aarch64-unknown-uefi`
|
||||||
|
- `i686-unknown-uefi`
|
||||||
|
- `x86_64-unknown-uefi`
|
||||||
|
|
||||||
|
## Target maintainers
|
||||||
|
|
||||||
|
- David Rheinsberg ([@dvdhrm](https://github.com/dvdhrm))
|
||||||
|
- Nicholas Bishop ([@nicholasbishop](https://github.com/nicholasbishop))
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
All UEFI targets can be used as `no-std` environments via cross-compilation.
|
||||||
|
Support for `std` is missing, but actively worked on. `alloc` is supported if
|
||||||
|
an allocator is provided by the user. No host tools are supported.
|
||||||
|
|
||||||
|
The UEFI environment resembles the environment for Microsoft Windows, with some
|
||||||
|
minor differences. Therefore, cross-compiling for UEFI works with the same
|
||||||
|
tools as cross-compiling for Windows. The target binaries are PE32+ encoded,
|
||||||
|
the calling convention is different for each architecture, but matches what
|
||||||
|
Windows uses (if the architecture is supported by Windows). The special
|
||||||
|
`efiapi` Rust calling-convention chooses the right ABI for the target platform
|
||||||
|
(`extern "C"` is incorrect on Intel targets at least). The specification has an
|
||||||
|
elaborate section on the different supported calling-conventions, if more
|
||||||
|
details are desired.
|
||||||
|
|
||||||
|
MMX, SSE, and other FP-units are disabled by default, to allow for compilation
|
||||||
|
of core UEFI code that runs before they are set up. This can be overridden for
|
||||||
|
individual compilations via rustc command-line flags. Not all firmwares
|
||||||
|
correctly configure those units, though, so careful inspection is required.
|
||||||
|
|
||||||
|
As native to PE32+, binaries are position-dependent, but can be relocated at
|
||||||
|
runtime if their desired location is unavailable. The code must be statically
|
||||||
|
linked. Dynamic linking is not supported. Code is shared via UEFI interfaces,
|
||||||
|
rather than dynamic linking. Additionally, UEFI forbids running code on
|
||||||
|
anything but the boot CPU/thread, nor is interrupt-usage allowed (apart from
|
||||||
|
the timer interrupt). Device drivers are required to use polling methods.
|
||||||
|
|
||||||
|
UEFI uses a single address-space to run all code in. Multiple applications can
|
||||||
|
be loaded simultaneously and are dispatched via cooperative multitasking on a
|
||||||
|
single stack.
|
||||||
|
|
||||||
|
By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to
|
||||||
|
link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem
|
||||||
|
is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>`
|
||||||
|
to the linker. Similarly, the entry-point is to to `efi_main` but can be
|
||||||
|
changed via `/entry:<...>`. The panic-strategy is set to `abort`,
|
||||||
|
|
||||||
|
The UEFI specification is available online for free:
|
||||||
|
[UEFI Specification Directory](https://uefi.org/specifications)
|
||||||
|
|
||||||
|
## Building rust for UEFI targets
|
||||||
|
|
||||||
|
Rust can be built for the UEFI targets by enabling them in the `rustc` build
|
||||||
|
configuration. Note that you can only build the standard libraries. The
|
||||||
|
compiler and host tools currently cannot be compiled for UEFI targets. A sample
|
||||||
|
configuration would be:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build]
|
||||||
|
build-stage = 1
|
||||||
|
target = ["x86_64-unknown-uefi"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building Rust programs
|
||||||
|
|
||||||
|
Rust does not yet ship pre-compiled artifacts for this target. To compile for
|
||||||
|
this target, you will either need to build Rust with the target enabled (see
|
||||||
|
"Building rust for UEFI targets" above), or build your own copy of `core` by
|
||||||
|
using `build-std`, `cargo-buildx`, or similar.
|
||||||
|
|
||||||
|
A native build with the unstable `build-std`-feature can be achieved via:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo +nightly build \
|
||||||
|
-Zbuild-std=core,compiler_builtins \
|
||||||
|
-Zbuild-std-features=compiler-builtins-mem \
|
||||||
|
--target x86_64-unknown-uefi
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can install `cargo-xbuild` via
|
||||||
|
`cargo install --force cargo-xbuild` and build for the UEFI targets via:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo \
|
||||||
|
+nightly \
|
||||||
|
xbuild \
|
||||||
|
--target x86_64-unknown-uefi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
UEFI applications can be copied into the ESP on any UEFI system and executed
|
||||||
|
via the firmware boot menu. The qemu suite allows emulating UEFI systems and
|
||||||
|
executing UEFI applications as well. See its documentation for details.
|
||||||
|
|
||||||
|
The [uefi-run](https://github.com/Richard-W/uefi-run) rust tool is a simple
|
||||||
|
wrapper around `qemu` that can spawn UEFI applications in qemu. You can install
|
||||||
|
it via `cargo install uefi-run` and execute qemu applications as
|
||||||
|
`uefi-run ./application.efi`.
|
||||||
|
|
||||||
|
## Cross-compilation toolchains and C code
|
||||||
|
|
||||||
|
There are 3 common ways to compile native C code for UEFI targets:
|
||||||
|
|
||||||
|
- Use the official SDK by Intel:
|
||||||
|
[Tianocore/EDK2](https://github.com/tianocore/edk2). This supports a
|
||||||
|
multitude of platforms, comes with the full specification transposed into C,
|
||||||
|
lots of examples and build-system integrations. This is also the only
|
||||||
|
officially supported platform by Intel, and is used by many major firmware
|
||||||
|
implementations. Any code compiled via the SDK is compatible to rust binaries
|
||||||
|
compiled for the UEFI targets. You can link them directly into your rust
|
||||||
|
binaries, or call into each other via UEFI protocols.
|
||||||
|
- Use the **GNU-EFI** suite. This approach is used by many UEFI applications
|
||||||
|
in the Linux/OSS ecosystem. The GCC compiler is used to compile ELF binaries,
|
||||||
|
and linked with a pre-loader that converts the ELF binary to PE32+
|
||||||
|
**at runtime**. You can combine such binaries with the rust UEFI targets only
|
||||||
|
via UEFI protocols. Linking both into the same executable will fail, since
|
||||||
|
one is an ELF executable, and one a PE32+. If linking to **GNU-EFI**
|
||||||
|
executables is desired, you must compile your rust code natively for the same
|
||||||
|
GNU target as **GNU-EFI** and use their pre-loader. This requires careful
|
||||||
|
consideration about which calling-convention to use when calling into native
|
||||||
|
UEFI protocols, or calling into linked **GNU-EFI** code (similar to how these
|
||||||
|
differences need to be accounted for when writing **GNU-EFI** C code).
|
||||||
|
- Use native Windows targets. This means compiling your C code for the Windows
|
||||||
|
platform as if it was the UEFI platform. This works for static libraries, but
|
||||||
|
needs adjustments when linking into an UEFI executable. You can, however,
|
||||||
|
link such static libraries seemlessly into rust code compiled for UEFI
|
||||||
|
targets. Be wary of any includes that are not specifically suitable for UEFI
|
||||||
|
targets (especially the C standard library includes are not always
|
||||||
|
compatible). Freestanding compilations are recommended to avoid
|
||||||
|
incompatibilites.
|
||||||
|
|
||||||
|
## Ecosystem
|
||||||
|
|
||||||
|
The rust language has a long history of supporting UEFI targets. Many crates
|
||||||
|
have been developed to provide access to UEFI protocols and make UEFI
|
||||||
|
programming more ergonomic in rust. The following list is a short overview (in
|
||||||
|
alphabetical ordering):
|
||||||
|
|
||||||
|
- **efi**: *Ergonomic Rust bindings for writing UEFI applications*. Provides
|
||||||
|
_rustified_ access to UEFI protocols, implements allocators and a safe
|
||||||
|
environment to write UEFI applications.
|
||||||
|
- **r-efi**: *UEFI Reference Specification Protocol Constants and Definitions*.
|
||||||
|
A pure transpose of the UEFI specification into rust. This provides the raw
|
||||||
|
definitions from the specification, without any extended helpers or
|
||||||
|
_rustification_. It serves as baseline to implement any more elaborate rust
|
||||||
|
UEFI layers.
|
||||||
|
- **uefi-rs**: *Safe and easy-to-use wrapper for building UEFI apps*. An
|
||||||
|
elaborate library providing safe abstractions for UEFI protocols and
|
||||||
|
features. It implements allocators and provides an execution environment to
|
||||||
|
UEFI applications written in rust.
|
||||||
|
- **uefi-run**: *Run UEFI applications*. A small wrapper around _qemu_ to spawn
|
||||||
|
UEFI applications in an emulated `x86_64` machine.
|
||||||
|
|
||||||
|
## Example: Freestanding
|
||||||
|
|
||||||
|
The following code is a valid UEFI application returning immediately upon
|
||||||
|
execution with an exit code of 0. A panic handler is provided. This is executed
|
||||||
|
by rust on panic. For simplicity, we simply end up in an infinite loop.
|
||||||
|
|
||||||
|
Note that as of rust-1.31.0, all features used here are stabilized. No unstable
|
||||||
|
features are required, nor do we rely on nightly compilers. However, if you do
|
||||||
|
not compile rustc for the UEFI targets, you need a nightly compiler to support
|
||||||
|
the `-Z build-std` flag.
|
||||||
|
|
||||||
|
This example can be compiled as binary crate via `cargo`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo +nightly build \
|
||||||
|
-Zbuild-std=core,compiler_builtins \
|
||||||
|
-Zbuild-std-features=compiler-builtins-mem \
|
||||||
|
--target x86_64-unknown-uefi
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust,ignore (platform-specific,eh-personality-is-unstable)
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_name = "efi_main"]
|
||||||
|
pub extern "C" fn main(_h: *mut core::ffi::c_void, _st: *mut core::ffi::c_void) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: Hello World
|
||||||
|
|
||||||
|
This is an example UEFI application that prints "Hello World!", then waits for
|
||||||
|
key input before it exits. It serves as base example how to write UEFI
|
||||||
|
applications without any helper modules other than the standalone UEFI protocol
|
||||||
|
definitions provided by the `r-efi` crate.
|
||||||
|
|
||||||
|
This extends the "Freestanding" example and builds upon its setup. See there
|
||||||
|
for instruction how to compile this as binary crate.
|
||||||
|
|
||||||
|
Note that UEFI uses UTF-16 strings. Since rust literals are UTF-8, we have to
|
||||||
|
use an open-coded, zero-terminated, UTF-16 array as argument to
|
||||||
|
`output_string()`. Similarly to the panic handler, real applications should
|
||||||
|
rather use UTF-16 modules.
|
||||||
|
|
||||||
|
```rust,ignore (platform-specific,eh-personality-is-unstable)
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use r_efi::efi;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_name = "efi_main"]
|
||||||
|
pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status {
|
||||||
|
let s = [
|
||||||
|
0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello"
|
||||||
|
0x0020u16, // " "
|
||||||
|
0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World"
|
||||||
|
0x0021u16, // "!"
|
||||||
|
0x000au16, // "\n"
|
||||||
|
0x0000u16, // NUL
|
||||||
|
];
|
||||||
|
|
||||||
|
// Print "Hello World!".
|
||||||
|
let r =
|
||||||
|
unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) };
|
||||||
|
if r.is_error() {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for key input, by waiting on the `wait_for_key` event hook.
|
||||||
|
let r = unsafe {
|
||||||
|
let mut x: usize = 0;
|
||||||
|
((*(*st).boot_services).wait_for_event)(1, &mut (*(*st).con_in).wait_for_key, &mut x)
|
||||||
|
};
|
||||||
|
if r.is_error() {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
efi::Status::SUCCESS
|
||||||
|
}
|
||||||
|
```
|
|
@ -5,13 +5,13 @@ If you'd like to build for a target that is not yet supported by `rustc`, you ca
|
||||||
are JSON. To see the JSON for the host target, you can run:
|
are JSON. To see the JSON for the host target, you can run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ rustc +nightly -Z unstable-options --print target-spec-json
|
rustc +nightly -Z unstable-options --print target-spec-json
|
||||||
```
|
```
|
||||||
|
|
||||||
To see it for a different target, add the `--target` flag:
|
To see it for a different target, add the `--target` flag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json
|
rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json
|
||||||
```
|
```
|
||||||
|
|
||||||
To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`.
|
To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`.
|
||||||
|
|
|
@ -440,6 +440,7 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text):
|
||||||
|
|
||||||
if bless:
|
if bless:
|
||||||
with open(snapshot_path, 'w') as snapshot_file:
|
with open(snapshot_path, 'w') as snapshot_file:
|
||||||
|
actual_str = actual_str.replace(channel, "{{channel}}")
|
||||||
snapshot_file.write(actual_str)
|
snapshot_file.write(actual_str)
|
||||||
else:
|
else:
|
||||||
print('--- expected ---\n')
|
print('--- expected ---\n')
|
||||||
|
|
|
@ -17,7 +17,8 @@ use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
|
|
||||||
use crate::clean::{
|
use crate::clean::{
|
||||||
self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty,
|
self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty,
|
||||||
clean_ty_generics, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility,
|
clean_ty_generics, clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId,
|
||||||
|
Type, Visibility,
|
||||||
};
|
};
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::formats::item_type::ItemType;
|
use crate::formats::item_type::ItemType;
|
||||||
|
@ -134,7 +135,7 @@ pub(crate) fn try_inline(
|
||||||
);
|
);
|
||||||
if let Some(import_def_id) = import_def_id {
|
if let Some(import_def_id) = import_def_id {
|
||||||
// The visibility needs to reflect the one from the reexport and not from the "source" DefId.
|
// The visibility needs to reflect the one from the reexport and not from the "source" DefId.
|
||||||
item.visibility = cx.tcx.visibility(import_def_id).clean(cx);
|
item.visibility = clean_visibility(cx.tcx.visibility(import_def_id));
|
||||||
}
|
}
|
||||||
ret.push(item);
|
ret.push(item);
|
||||||
Some(ret)
|
Some(ret)
|
||||||
|
@ -599,7 +600,7 @@ fn build_macro(
|
||||||
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
|
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
|
||||||
LoadedMacro::MacroDef(item_def, _) => {
|
LoadedMacro::MacroDef(item_def, _) => {
|
||||||
if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
|
if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
|
||||||
let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id)).clean(cx);
|
let vis = clean_visibility(cx.tcx.visibility(import_def_id.unwrap_or(def_id)));
|
||||||
clean::MacroItem(clean::Macro {
|
clean::MacroItem(clean::Macro {
|
||||||
source: utils::display_macro_source(cx, name, def, def_id, vis),
|
source: utils::display_macro_source(cx, name, def, def_id, vis),
|
||||||
})
|
})
|
||||||
|
|
|
@ -1812,9 +1812,8 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Clean<'tcx, Visibility> for ty::Visibility {
|
pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
|
||||||
fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
|
match vis {
|
||||||
match *self {
|
|
||||||
ty::Visibility::Public => Visibility::Public,
|
ty::Visibility::Public => Visibility::Public,
|
||||||
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
|
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
|
||||||
// while rustdoc really does mean inherited. That means that for enum variants, such as
|
// while rustdoc really does mean inherited. That means that for enum variants, such as
|
||||||
|
@ -1823,21 +1822,15 @@ impl<'tcx> Clean<'tcx, Visibility> for ty::Visibility {
|
||||||
ty::Visibility::Invisible => Visibility::Inherited,
|
ty::Visibility::Invisible => Visibility::Inherited,
|
||||||
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
|
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Clean<'tcx, VariantStruct> for rustc_hir::VariantData<'tcx> {
|
fn clean_variant_data<'tcx>(
|
||||||
fn clean(&self, cx: &mut DocContext<'tcx>) -> VariantStruct {
|
variant: &hir::VariantData<'tcx>,
|
||||||
|
cx: &mut DocContext<'tcx>,
|
||||||
|
) -> VariantStruct {
|
||||||
VariantStruct {
|
VariantStruct {
|
||||||
struct_type: CtorKind::from_hir(self),
|
struct_type: CtorKind::from_hir(variant),
|
||||||
fields: self.fields().iter().map(|x| clean_field(x, cx)).collect(),
|
fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Clean<'tcx, Vec<Item>> for hir::VariantData<'tcx> {
|
|
||||||
fn clean(&self, cx: &mut DocContext<'tcx>) -> Vec<Item> {
|
|
||||||
self.fields().iter().map(|x| clean_field(x, cx)).collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1863,8 +1856,10 @@ impl<'tcx> Clean<'tcx, Item> for ty::VariantDef {
|
||||||
impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> {
|
impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> {
|
||||||
fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant {
|
fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant {
|
||||||
match self {
|
match self {
|
||||||
hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
|
hir::VariantData::Struct(..) => Variant::Struct(clean_variant_data(self, cx)),
|
||||||
hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)),
|
hir::VariantData::Tuple(..) => {
|
||||||
|
Variant::Tuple(self.fields().iter().map(|x| clean_field(x, cx)).collect())
|
||||||
|
}
|
||||||
hir::VariantData::Unit(..) => Variant::CLike,
|
hir::VariantData::Unit(..) => Variant::CLike,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1983,7 +1978,7 @@ fn clean_maybe_renamed_item<'tcx>(
|
||||||
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
|
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
|
||||||
}
|
}
|
||||||
ItemKind::Macro(ref macro_def, _) => {
|
ItemKind::Macro(ref macro_def, _) => {
|
||||||
let ty_vis = cx.tcx.visibility(def_id).clean(cx);
|
let ty_vis = clean_visibility(cx.tcx.visibility(def_id));
|
||||||
MacroItem(Macro {
|
MacroItem(Macro {
|
||||||
source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
|
source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
|
||||||
})
|
})
|
||||||
|
@ -2112,7 +2107,7 @@ fn clean_extern_crate<'tcx>(
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
attrs: Box::new(attrs.clean(cx)),
|
attrs: Box::new(attrs.clean(cx)),
|
||||||
item_id: crate_def_id.into(),
|
item_id: crate_def_id.into(),
|
||||||
visibility: ty_vis.clean(cx),
|
visibility: clean_visibility(ty_vis),
|
||||||
kind: box ExternCrateItem { src: orig_name },
|
kind: box ExternCrateItem { src: orig_name },
|
||||||
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
|
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
|
||||||
}]
|
}]
|
||||||
|
|
|
@ -37,7 +37,7 @@ use crate::clean::cfg::Cfg;
|
||||||
use crate::clean::external_path;
|
use crate::clean::external_path;
|
||||||
use crate::clean::inline::{self, print_inlined_const};
|
use crate::clean::inline::{self, print_inlined_const};
|
||||||
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
|
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
|
||||||
use crate::clean::Clean;
|
use crate::clean::{clean_visibility, Clean};
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
use crate::formats::item_type::ItemType;
|
use crate::formats::item_type::ItemType;
|
||||||
|
@ -499,7 +499,7 @@ impl Item {
|
||||||
let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) {
|
let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) {
|
||||||
Visibility::Public
|
Visibility::Public
|
||||||
} else {
|
} else {
|
||||||
cx.tcx.visibility(def_id).clean(cx)
|
clean_visibility(cx.tcx.visibility(def_id))
|
||||||
};
|
};
|
||||||
|
|
||||||
Item { item_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg }
|
Item { item_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg }
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Emit additional suggestion to correct the trait implementation
|
||||||
|
// on a pointer
|
||||||
|
use std::{fmt, marker};
|
||||||
|
|
||||||
|
struct LocalType;
|
||||||
|
|
||||||
|
impl fmt::Display for *mut LocalType {
|
||||||
|
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
//~| NOTE impl doesn't use only types from inside the current crate
|
||||||
|
//~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign
|
||||||
|
//~| NOTE define and implement a trait or new type instead
|
||||||
|
//~| HELP consider introducing a new wrapper type
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "This not compile")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> marker::Copy for *mut T {
|
||||||
|
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
//~| NOTE impl doesn't use only types from inside the current crate
|
||||||
|
//~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign
|
||||||
|
//~| NOTE define and implement a trait or new type instead
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
--> $DIR/issue-99572-impl-trait-on-pointer.rs:7:1
|
||||||
|
|
|
||||||
|
LL | impl fmt::Display for *mut LocalType {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^--------------
|
||||||
|
| | |
|
||||||
|
| | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign
|
||||||
|
| impl doesn't use only types from inside the current crate
|
||||||
|
|
|
||||||
|
= note: define and implement a trait or new type instead
|
||||||
|
help: consider introducing a new wrapper type
|
||||||
|
|
|
||||||
|
LL + struct WrapperType(*mut LocalType);
|
||||||
|
LL +
|
||||||
|
LL ~ impl fmt::Display for WrapperType {
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||||
|
--> $DIR/issue-99572-impl-trait-on-pointer.rs:18:1
|
||||||
|
|
|
||||||
|
LL | impl<T> marker::Copy for *mut T {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^------
|
||||||
|
| | |
|
||||||
|
| | `*mut T` is not defined in the current crate because raw pointers are always foreign
|
||||||
|
| impl doesn't use only types from inside the current crate
|
||||||
|
|
|
||||||
|
= note: define and implement a trait or new type instead
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0117`.
|
Loading…
Reference in New Issue