summaryrefslogtreecommitdiffstats
path: root/vendor/r-efi/examples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/r-efi/examples
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/r-efi/examples')
-rw-r--r--vendor/r-efi/examples/freestanding.rs34
-rw-r--r--vendor/r-efi/examples/gop-query.rs188
-rw-r--r--vendor/r-efi/examples/hello-world.rs55
-rw-r--r--vendor/r-efi/examples/uefi-cross-compile.rs41
4 files changed, 318 insertions, 0 deletions
diff --git a/vendor/r-efi/examples/freestanding.rs b/vendor/r-efi/examples/freestanding.rs
new file mode 100644
index 000000000..1c4e3aaf4
--- /dev/null
+++ b/vendor/r-efi/examples/freestanding.rs
@@ -0,0 +1,34 @@
+// Example: Freestanding
+//
+// This example is a plain UEFI application without any external requirements
+// but `core`. It immediately returns control to the caller upon execution,
+// yielding the exit code 0.
+//
+// The `main` function serves as entry-point. Depending on your
+// target-configuration, it must be exported with a pre-configured name so the
+// linker will correctly mark it as entry-point. The target configurations
+// shipped with upstream rust-lang use `efi_main` as symbol name.
+//
+// Additionally, a panic handler is provided. This is executed by rust on
+// panic. For simplicity, we simply end up in an infinite loop. For real
+// applications, this method should probably call into
+// `SystemTable->boot_services->exit()` to exit the UEFI application. Note,
+// however, that UEFI applications are likely to run in the same address space
+// as the entire firmware. Hence, halting the machine might be a viable
+// alternative. All that is out-of-scope for this example, though.
+//
+// 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.
+
+#![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
+}
diff --git a/vendor/r-efi/examples/gop-query.rs b/vendor/r-efi/examples/gop-query.rs
new file mode 100644
index 000000000..b4ab4c370
--- /dev/null
+++ b/vendor/r-efi/examples/gop-query.rs
@@ -0,0 +1,188 @@
+// Example: Graphics Query
+//
+// This is a slightly more complex UEFI application than `hello-world`. It
+// locates the graphics-output-protocol, queries its current mode and prints
+// the current resolution to the UEFI console.
+//
+// This example should make everyone aware that UEFI programing in Rust really
+// asks for helper layers. While the C/FFI/Spec API can be used directly, it
+// is quite cumbersome. Especially the error handling is overly difficult.
+//
+// Nevertheless, this example shows how to find UEFI protocol and invoke
+// their member functions.
+//
+// Like all the other r-efi examples, it is a standalone example. That is, no
+// UTF-16 helpers are pulled in, nor any allocators or panic frameworks. For
+// real world scenarios, you really should choose such helpers.
+
+#![no_main]
+#![no_std]
+
+use r_efi::efi;
+
+#[panic_handler]
+fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
+
+fn fail(_r: efi::Status) -> ! {
+ panic!();
+}
+
+// A simple `itoa()`-ish function that takes a u32 and turns it into a UTF-16
+// string. It always prints exactly 10 characters, so leading zeroes are used
+// for small numbers.
+fn utoa(mut u: u32, a: &mut [u16]) {
+ for i in 0..10 {
+ a[9 - i] = 0x0030u16 + ((u % 10) as u16);
+ u = u / 10;
+ }
+}
+
+// A simple helper that takes two integers and prints them to the UEFI console
+// with a short prefix. It uses a UTF-16 buffer and fills in the numbers before
+// printing the entire buffer.
+fn print_xy(st: *mut efi::SystemTable, x: u32, y: u32) {
+ let mut s = [
+ 0x0058u16, 0x0059u16, 0x003au16, // "XY:"
+ 0x0020u16, // " "
+ 0x0020u16, 0x0020u16, 0x0020u16, 0x0020u16, // " "
+ 0x0020u16, 0x0020u16, 0x0020u16, 0x0020u16, // " "
+ 0x0020u16, 0x0020u16, // " "
+ 0x0078u16, // "x"
+ 0x0020u16, 0x0020u16, 0x0020u16, 0x0020u16, // " "
+ 0x0020u16, 0x0020u16, 0x0020u16, 0x0020u16, // " "
+ 0x0020u16, 0x0020u16, // " "
+ 0x000au16, // "\n"
+ 0x0000u16, // NUL
+ ];
+
+ utoa(x, &mut s[4..14]);
+ utoa(y, &mut s[15..25]);
+
+ unsafe {
+ let r = ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16);
+ if r.is_error() {
+ fail(r);
+ }
+ }
+}
+
+// This function locates singleton UEFI protocols. Those protocols do not
+// require to register listener handles, but are globally available to all
+// UEFI applications. It takes a GUID of the protocol to locate and returns
+// the protocol pointer on success.
+fn locate_singleton(
+ st: *mut efi::SystemTable,
+ guid: *const efi::Guid,
+) -> Result<*mut core::ffi::c_void, efi::Status> {
+ let mut interface: *mut core::ffi::c_void = core::ptr::null_mut();
+ let mut handles: *mut efi::Handle = core::ptr::null_mut();
+ let mut n_handles: usize = 0;
+ let mut r: efi::Status;
+
+ // Use `locate_handle_buffer()` to find all handles that support the
+ // specified protocol.
+ unsafe {
+ if (*st).hdr.revision < efi::SYSTEM_TABLE_REVISION_1_10 {
+ // We use `LocateHandleBuffer`, which was introduced in 1.10.
+ return Err(efi::Status::UNSUPPORTED);
+ }
+
+ let r = ((*(*st).boot_services).locate_handle_buffer)(
+ efi::BY_PROTOCOL,
+ guid as *mut _,
+ core::ptr::null_mut(),
+ &mut n_handles,
+ &mut handles,
+ );
+ match r {
+ efi::Status::SUCCESS => {}
+ efi::Status::NOT_FOUND => return Err(r),
+ efi::Status::OUT_OF_RESOURCES => return Err(r),
+ _ => panic!(),
+ };
+ }
+
+ // Now that we have all handles with the specified protocol, query it for
+ // the protocol interface. We loop here, even though every item should
+ // succeed. Lets be on the safe side.
+ // Secondly, we use `handle_protocol()` here, but really should be using
+ // `open_protocol()`. But for singleton protocols, this does not matter,
+ // so lets use the simple path for now.
+ unsafe {
+ r = efi::Status::NOT_FOUND;
+ for i in 0..n_handles {
+ r = ((*(*st).boot_services).handle_protocol)(
+ *handles.offset(core::convert::TryFrom::<usize>::try_from(i).unwrap()),
+ guid as *mut _,
+ &mut interface,
+ );
+ match r {
+ efi::Status::SUCCESS => break,
+ efi::Status::UNSUPPORTED => continue,
+ _ => panic!(),
+ };
+ }
+ }
+
+ // Free the allocated buffer memory of `handles`. This was allocated on the
+ // pool by `locate_handle_buffer()`.
+ unsafe {
+ let r = ((*(*st).boot_services).free_pool)(handles as *mut core::ffi::c_void);
+ assert!(!r.is_error());
+ }
+
+ // In case we found nothing, return `NOT_FOUND`, otherwise return the
+ // interface identifier.
+ match r {
+ efi::Status::SUCCESS => Ok(interface),
+ _ => Err(efi::Status::NOT_FOUND),
+ }
+}
+
+// A simple helper that queries the current mode of the GraphicsOutputProtocol
+// and returns the x and y dimensions on success.
+fn query_gop(
+ gop: *mut efi::protocols::graphics_output::Protocol,
+) -> Result<(u32, u32), efi::Status> {
+ let mut info: *mut efi::protocols::graphics_output::ModeInformation = core::ptr::null_mut();
+ let mut z_info: usize = 0;
+
+ unsafe {
+ // We could just look at `gop->mode->info`, but lets query the mode
+ // instead to show how to query other modes than the active one.
+ let r = ((*gop).query_mode)(gop, (*(*gop).mode).mode, &mut z_info, &mut info);
+ match r {
+ efi::Status::SUCCESS => {}
+ efi::Status::DEVICE_ERROR => return Err(r),
+ _ => panic!(),
+ };
+ if z_info < core::mem::size_of_val(&*info) {
+ return Err(efi::Status::UNSUPPORTED);
+ }
+
+ Ok(((*info).horizontal_resolution, (*info).vertical_resolution))
+ }
+}
+
+// This is the UEFI application entrypoint. We use it to locate the GOP
+// pointer, query the current mode, and then print it to the system console.
+#[export_name = "efi_main"]
+pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status {
+ let r = locate_singleton(st, &efi::protocols::graphics_output::PROTOCOL_GUID);
+ let gop = match r {
+ Ok(v) => v,
+ Err(r) => fail(r),
+ };
+
+ let r = query_gop(gop as _);
+ let v = match r {
+ Ok(v) => v,
+ Err(r) => fail(r),
+ };
+
+ print_xy(st, v.0, v.1);
+
+ efi::Status::SUCCESS
+}
diff --git a/vendor/r-efi/examples/hello-world.rs b/vendor/r-efi/examples/hello-world.rs
new file mode 100644
index 000000000..25b5243ac
--- /dev/null
+++ b/vendor/r-efi/examples/hello-world.rs
@@ -0,0 +1,55 @@
+// 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 UEFI protocol
+// definitions.
+//
+// This example builds upon the `freestanding.rs` example, using the same setup
+// and rust integration. See there for details on the panic-handler and entry
+// point configuration.
+//
+// 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.
+
+#![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
+}
diff --git a/vendor/r-efi/examples/uefi-cross-compile.rs b/vendor/r-efi/examples/uefi-cross-compile.rs
new file mode 100644
index 000000000..f99870a21
--- /dev/null
+++ b/vendor/r-efi/examples/uefi-cross-compile.rs
@@ -0,0 +1,41 @@
+// Bare UEFI Compilation
+//
+// This is a copy of a cross-compile test from the upstream rust repository. It
+// is used to verify cross-compilation of UEFI targets works. It is included
+// verbatim here to make sure we can run tests against it and get notifications
+// when it breaks.
+
+// -----------------------------------------------------------------------------
+// COPY FROM `rust-lang/rust/src/test/codegen/uefi-cross-compile.rs`
+// -----------------------------------------------------------------------------
+
+// Checks whether UEFI targets cross-compile successfully.
+//
+// This test contains a simple UEFI program that simply exits with return code
+// 0. It can be easily run from the UEFI shell (but any other UEFI environment
+// works as well). This program is not run as part of the test. The test merely
+// verifies the cross-compilation does not fail and an entry-point is emitted.
+//
+// The imported definitions from the UEFI specification are intentionally left
+// incomplete. Only the bits that are actually used by this test are defined.
+
+// min-llvm-version 9.0
+
+// compile-flags: --target x86_64-unknown-uefi
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![no_main]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "freeze"]
+pub trait Freeze {}
+#[lang = "copy"]
+pub trait Copy {}
+
+// CHECK: define win64cc i64 @efi_main{{.*}}
+#[export_name = "efi_main"]
+pub extern "efiapi" fn main(_h: *mut usize, _st: *mut usize) -> usize {
+ return 0;
+}