1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Example: Hello World!
//
// This example extends the Hello-World example from the `r-efi` crate. The
// main entry-point now installs a global rust allocator and calls into the
// `efi_run()` function. The latter then prints the string "Hello World!\n" to
// console-out, waits for any key-input, and returns.
//
// Unlike the original example, here we make use of the global allocator by
// using the types from rust's `alloc::*` crate. These needs dynamic
// allocations, and we can now serve them by providing the allocator from
// `r-efi-alloc`.
//
// To integrate the allocator with rust, we need to provide a global variable
// annotated as `#[global_allocator]`. It must implement the `GlobalAlloc`
// trait. We use the `Bridge` type from our crate to serve this.
extern crate alloc;
use String;
use Vec;
use efi;
static GLOBAL_ALLOCATOR: Bridge = new;
!
// This is the wrapped entry-point of this Hello-World UEFI Application. The
// caller provides us with an extended environment, by guaranteeing us a global
// rust allocator. Hence, we can now make use of all the `alloc::*` objects.
//
// Similar to the Hello-World example from `r-efi`, this example just prints
// "Hello World!\n" to standard-output, waits for any key input, then exits.
//
// With `alloc::*` to our disposal, we use normal rust strings, and convert
// them to UTF-16 vectors before passing them to UEFI.
// This is the main UEFI entry point, called by the UEFI environment when the
// application is spawned. We use it to create an allocator and attach it to
// the global allocator bridge. Then we invoke the `efi_run()` function as if
// it was the main entry-point. Since the attachment is dropped after
// `efi_run()` returns, the allocator is available throughout the entire
// runtime.
//
// Note that both calls here require unsafe code:
//
// * Allocator::from_system_table(): We must guarantee `SystemTable` survives
// longer than the allocator object we create. This is trivially true
// here, since we pass in the system-table from the UEFI core, which is
// guaranteed to outlive us. However, we must make sure not to call
// ExitBootServices() and friends, obviously.
//
// * Bridge::attach(): This function is unsafe, since it requires the caller
// to guarantee that all memory allocations are released before it is
// detached. Since we do not perform allocations ourselves here, we know
// that they must be released before `efi_run()` returns. Hence, we are
// safe as well.
//
// Lastly, we use the `LoaderData` annotation for all memory allocations.
// Depending on your UEFI application type you might want different allocators
// for different operations. The rust global allocator is a fixed type, so you
// need to use custom-allocators for all allocations that need to be put in
// different memory regions.
pub extern "C"