Skip to content

Commit 6791b62

Browse files
authored
Merge branch 'main' into bishop-cstr8-display
2 parents d8a4723 + 8bcd3bb commit 6791b62

File tree

5 files changed

+97
-8
lines changed

5 files changed

+97
-8
lines changed

.github/workflows/qa.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ jobs:
77
steps:
88
- uses: actions/checkout@v4
99
# Executes "typos ."
10-
- uses: crate-ci/[email protected].7
10+
- uses: crate-ci/[email protected].9

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

uefi-test-runner/src/boot/misc.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn test() {
1717
info!("Testing events...");
1818
test_check_event();
1919
test_callback_with_ctx();
20+
test_signal_event();
2021
info!("Testing watchdog...");
2122
test_watchdog();
2223
info!("Testing protocol handler services...");
@@ -92,6 +93,38 @@ fn test_callback_with_ctx() {
9293
assert_eq!(data, 456);
9394
}
9495

96+
fn test_signal_event() {
97+
let mut data = 123u32;
98+
99+
extern "efiapi" fn callback(_event: Event, ctx: Option<NonNull<c_void>>) {
100+
info!("Inside the signal event callback");
101+
// Safety: this callback is run within the parent function's
102+
// scope, so the context pointer is still valid.
103+
unsafe {
104+
let ctx = ctx.unwrap().as_ptr().cast::<u32>();
105+
*ctx = 456;
106+
}
107+
}
108+
109+
let ctx: *mut u32 = &mut data;
110+
let ctx = NonNull::new(ctx.cast::<c_void>()).unwrap();
111+
112+
let event = unsafe {
113+
boot::create_event(
114+
EventType::NOTIFY_SIGNAL,
115+
Tpl::CALLBACK,
116+
Some(callback),
117+
Some(ctx),
118+
)
119+
.expect("Failed to create event with context")
120+
};
121+
122+
boot::signal_event(&event).expect("Failed to signal event");
123+
124+
// Check that `data` was updated inside the event callback.
125+
assert_eq!(data, 456);
126+
}
127+
95128
fn test_watchdog() {
96129
// There's no way to check the watchdog timer value, so just test setting it.
97130

uefi/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# uefi - [Unreleased]
22

3+
## Added
4+
- Added `boot::signal_event`.
5+
36
## Changed
47
- **Breaking:** Removed `BootPolicyError` as `BootPolicy` construction is no
58
longer fallible. `BootPolicy` now tightly integrates the new `Boolean` type
@@ -11,6 +14,9 @@
1114
Previously it incorrectly added the header size to the buffer length, which
1215
could cause the firmware to read past the end of the buffer.
1316
- The `Display` impl for `CStr8` now excludes the trailing null character.
17+
- `boot::allocate_pages` no longer panics if the allocation is at address
18+
zero. The allocation is retried instead, and in all failure cases an error is
19+
returned rather than panicking.
1420

1521

1622
# uefi - 0.34.1 (2025-02-07)

uefi/src/boot.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,40 @@ pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Res
134134
let bt = boot_services_raw_panicking();
135135
let bt = unsafe { bt.as_ref() };
136136

137-
let (ty, mut addr) = match ty {
137+
let (ty, initial_addr) = match ty {
138138
AllocateType::AnyPages => (0, 0),
139139
AllocateType::MaxAddress(addr) => (1, addr),
140140
AllocateType::Address(addr) => (2, addr),
141141
};
142-
let addr =
143-
unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr) }.to_result_with_val(|| addr)?;
144-
let ptr = addr as *mut u8;
145-
Ok(NonNull::new(ptr).expect("allocate_pages must not return a null pointer if successful"))
142+
143+
let mut addr1 = initial_addr;
144+
unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr1) }.to_result()?;
145+
146+
// The UEFI spec allows `allocate_pages` to return a valid allocation at
147+
// address zero. Rust does not allow writes through a null pointer (which
148+
// Rust defines as address zero), so this is not very useful. Only return
149+
// the allocation if the address is non-null.
150+
if let Some(ptr) = NonNull::new(addr1 as *mut u8) {
151+
return Ok(ptr);
152+
}
153+
154+
// Attempt a second allocation. The first allocation (at address zero) has
155+
// not yet been freed, so if this allocation succeeds it should be at a
156+
// non-zero address.
157+
let mut addr2 = initial_addr;
158+
let r = unsafe { (bt.allocate_pages)(ty, mem_ty, count, &mut addr2) }.to_result();
159+
160+
// Free the original allocation (ignoring errors).
161+
let _unused = unsafe { (bt.free_pages)(addr1, count) };
162+
163+
// Return an error if the second allocation failed, or if it is still at
164+
// address zero. Otherwise, return a pointer to the second allocation.
165+
r?;
166+
if let Some(ptr) = NonNull::new(addr2 as *mut u8) {
167+
Ok(ptr)
168+
} else {
169+
Err(Status::OUT_OF_RESOURCES.into())
170+
}
146171
}
147172

148173
/// Frees memory pages allocated by [`allocate_pages`].
@@ -467,6 +492,31 @@ pub fn check_event(event: Event) -> Result<bool> {
467492
}
468493
}
469494

495+
/// Places the supplied `event` in the signaled state. If `event` is already in
496+
/// the signaled state, the function returns successfully. If `event` is of type
497+
/// [`NOTIFY_SIGNAL`], the event's notification function is scheduled to be
498+
/// invoked at the event's notification task priority level.
499+
///
500+
/// This function may be invoked from any task priority level.
501+
///
502+
/// If `event` is part of an event group, then all of the events in the event
503+
/// group are also signaled and their notification functions are scheduled.
504+
///
505+
/// When signaling an event group, it is possible to create an event in the
506+
/// group, signal it and then close the event to remove it from the group.
507+
///
508+
/// # Errors
509+
///
510+
/// The specification does not list any errors.
511+
///
512+
/// [`NOTIFY_SIGNAL`]: EventType::NOTIFY_SIGNAL
513+
pub fn signal_event(event: &Event) -> Result {
514+
let bt = boot_services_raw_panicking();
515+
let bt = unsafe { bt.as_ref() };
516+
517+
unsafe { (bt.signal_event)(event.as_ptr()) }.to_result()
518+
}
519+
470520
/// Removes `event` from any event group to which it belongs and closes it.
471521
///
472522
/// If `event` was registered with [`register_protocol_notify`], then the

0 commit comments

Comments
 (0)