Skip to content

Commit b272b7e

Browse files
committed
efi: Defer reset_system activation until after ExitBootServices
EFI applications like shim call ResetSystem during early boot when MOK state import fails (set_variable returns UNSUPPORTED). The previous commit made reset_system write to Cloud Hypervisor's shutdown port and enter a halt loop, which caused VMs to either shut down (on CH) or hang (on QEMU) during boot. Split reset_system into two phases: - reset_system_boot: no-op during boot services (old behavior) - reset_system: activated after ExitBootServices with CH port I/O Also fix fixup_at_virtual to remap reset_system to its virtual address instead of not_available, so ResetSystem works after SetVirtualAddressMap (needed for Windows shutdown on CH). Signed-off-by: CMGS <ilskdw@gmail.com>
1 parent a76cafc commit b272b7e

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

src/efi/boot_services.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,9 @@ pub extern "efiapi" fn unload_image(_: Handle) -> Status {
453453
}
454454

455455
pub extern "efiapi" fn exit_boot_services(_: Handle, _: usize) -> Status {
456+
unsafe {
457+
super::runtime_services::swap_reset_system();
458+
}
456459
Status::SUCCESS
457460
}
458461

src/efi/runtime_services.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub static mut RS: SyncUnsafeCell<efi::RuntimeServices> =
3838
get_next_variable_name,
3939
set_variable,
4040
get_next_high_mono_count,
41-
reset_system,
41+
reset_system: reset_system_boot,
4242
update_capsule,
4343
query_capsule_capabilities,
4444
query_variable_info,
@@ -62,7 +62,11 @@ unsafe fn fixup_at_virtual(descriptors: &[MemoryDescriptor]) {
6262
rs.get_variable = transmute(ptr);
6363
rs.set_variable = transmute(ptr);
6464
rs.get_next_variable_name = transmute(ptr);
65-
rs.reset_system = transmute(ptr);
65+
let reset_ptr = ALLOCATOR
66+
.borrow()
67+
.convert_internal_pointer(descriptors, (reset_system as *const ()) as u64)
68+
.unwrap();
69+
rs.reset_system = transmute(reset_ptr);
6670
rs.update_capsule = transmute(ptr);
6771
rs.query_capsule_capabilities = transmute(ptr);
6872
rs.query_variable_info = transmute(ptr);
@@ -196,10 +200,24 @@ pub extern "efiapi" fn get_next_high_mono_count(_: *mut u32) -> Status {
196200
Status::DEVICE_ERROR
197201
}
198202

203+
// No-op used during boot services phase. EFI applications like shim may call
204+
// ResetSystem during early boot (e.g. on MOK import failure). Returning here
205+
// lets them continue, matching the original firmware behavior.
206+
pub extern "efiapi" fn reset_system_boot(
207+
_: ResetType,
208+
_: Status,
209+
_: usize,
210+
_: *mut c_void,
211+
) {
212+
}
213+
214+
// Activated after ExitBootServices via swap_reset_system(). Writes to Cloud
215+
// Hypervisor's AcpiShutdownDevice at IO port 0x600 to perform the actual
216+
// VM shutdown or reset. On non-CH platforms the port write is a no-op and
217+
// the function falls through to a halt loop.
199218
pub extern "efiapi" fn reset_system(_reset_type: ResetType, _: Status, _: usize, _: *mut c_void) {
200219
#[cfg(target_arch = "x86_64")]
201220
{
202-
// Cloud Hypervisor's AcpiShutdownDevice is at IO port 0x600.
203221
const SHUTDOWN_PORT: u16 = 0x600;
204222
const S5_SLEEP_VALUE: u8 = (5 << 2) | (1 << 5); // SLP_TYP=5, SLP_EN=1
205223
const REBOOT_VALUE: u8 = 1;
@@ -224,6 +242,14 @@ pub extern "efiapi" fn reset_system(_reset_type: ResetType, _: Status, _: usize,
224242
}
225243
}
226244

245+
/// Switch the runtime services table from the boot-phase no-op to the real
246+
/// reset_system implementation. Called from exit_boot_services.
247+
pub unsafe fn swap_reset_system() {
248+
#[allow(static_mut_refs)]
249+
let rs = RS.get_mut();
250+
rs.reset_system = reset_system;
251+
}
252+
227253
pub extern "efiapi" fn update_capsule(
228254
_: *mut *mut CapsuleHeader,
229255
_: usize,

0 commit comments

Comments
 (0)