@@ -9,6 +9,7 @@ use crate::proto::device_path::DevicePath;
9
9
use crate :: proto:: loaded_image:: LoadedImage ;
10
10
use crate :: proto:: media:: fs:: SimpleFileSystem ;
11
11
use crate :: proto:: { Protocol , ProtocolPointer } ;
12
+ use crate :: runtime:: { self , ResetType } ;
12
13
use crate :: table:: Revision ;
13
14
use crate :: util:: opt_nonnull_to_ptr;
14
15
use core:: ffi:: c_void;
@@ -1070,6 +1071,99 @@ pub unsafe fn exit(
1070
1071
)
1071
1072
}
1072
1073
1074
+ /// Get the current memory map and exit boot services.
1075
+ unsafe fn get_memory_map_and_exit_boot_services ( buf : & mut [ u8 ] ) -> Result < MemoryMapMeta > {
1076
+ let bt = boot_services_raw_panicking ( ) ;
1077
+ let bt = unsafe { bt. as_ref ( ) } ;
1078
+
1079
+ // Get the memory map.
1080
+ let memory_map = get_memory_map ( buf) ?;
1081
+
1082
+ // Try to exit boot services using the memory map key. Note that after
1083
+ // the first call to `exit_boot_services`, there are restrictions on
1084
+ // what boot services functions can be called. In UEFI 2.8 and earlier,
1085
+ // only `get_memory_map` and `exit_boot_services` are allowed. Starting
1086
+ // in UEFI 2.9 other memory allocation functions may also be called.
1087
+ ( bt. exit_boot_services ) ( image_handle ( ) . as_ptr ( ) , memory_map. map_key . 0 )
1088
+ . to_result_with_val ( || memory_map)
1089
+ }
1090
+
1091
+ /// Exit UEFI boot services.
1092
+ ///
1093
+ /// After this function completes, UEFI hands over control of the hardware
1094
+ /// to the executing OS loader, which implies that the UEFI boot services
1095
+ /// are shut down and cannot be used anymore. Only UEFI configuration tables
1096
+ /// and run-time services can be used.
1097
+ ///
1098
+ /// The memory map at the time of exiting boot services returned. The map is
1099
+ /// backed by a pool allocation of the given `memory_type`. Since the boot
1100
+ /// services function to free that memory is no longer available after calling
1101
+ /// `exit_boot_services`, the allocation will not be freed on drop.
1102
+ ///
1103
+ /// Note that once the boot services are exited, associated loggers and
1104
+ /// allocators can't use the boot services anymore. For the corresponding
1105
+ /// abstractions provided by this crate (see the [`helpers`] module),
1106
+ /// invoking this function will automatically disable them. If the
1107
+ /// `global_allocator` feature is enabled, attempting to use the allocator
1108
+ /// after exiting boot services will panic.
1109
+ ///
1110
+ /// # Safety
1111
+ ///
1112
+ /// The caller is responsible for ensuring that no references to
1113
+ /// boot-services data remain. A non-exhaustive list of resources to check:
1114
+ ///
1115
+ /// * All protocols will be invalid after exiting boot services. This
1116
+ /// includes the [`Output`] protocols attached to stdout/stderr. The
1117
+ /// caller must ensure that no protocol references remain.
1118
+ /// * The pool allocator is not usable after exiting boot services. Types
1119
+ /// such as [`PoolString`] which call [`free_pool`] on drop
1120
+ /// must be cleaned up before calling `exit_boot_services`, or leaked to
1121
+ /// avoid drop ever being called.
1122
+ /// * All data in the memory map marked as
1123
+ /// [`MemoryType::BOOT_SERVICES_CODE`] and
1124
+ /// [`MemoryType::BOOT_SERVICES_DATA`] will become free memory.
1125
+ ///
1126
+ /// # Errors
1127
+ ///
1128
+ /// This function will fail if it is unable to allocate memory for
1129
+ /// the memory map, if it fails to retrieve the memory map, or if
1130
+ /// exiting boot services fails (with up to one retry).
1131
+ ///
1132
+ /// All errors are treated as unrecoverable because the system is
1133
+ /// now in an undefined state. Rather than returning control to the
1134
+ /// caller, the system will be reset.
1135
+ ///
1136
+ /// [`helpers`]: crate::helpers
1137
+ /// [`Output`]: crate::proto::console::text::Output
1138
+ /// [`PoolString`]: crate::proto::device_path::text::PoolString
1139
+ #[ must_use]
1140
+ pub unsafe fn exit_boot_services ( memory_type : MemoryType ) -> MemoryMapOwned {
1141
+ crate :: helpers:: exit ( ) ;
1142
+
1143
+ let mut buf = MemoryMapBackingMemory :: new ( memory_type) . expect ( "Failed to allocate memory" ) ;
1144
+
1145
+ // Calling `exit_boot_services` can fail if the memory map key is not
1146
+ // current. Retry a second time if that occurs. This matches the
1147
+ // behavior of the Linux kernel:
1148
+ // https://github.com/torvalds/linux/blob/e544a0743/drivers/firmware/efi/libstub/efi-stub-helper.c#L375
1149
+ let mut status = Status :: ABORTED ;
1150
+ for _ in 0 ..2 {
1151
+ match unsafe { get_memory_map_and_exit_boot_services ( buf. as_mut_slice ( ) ) } {
1152
+ Ok ( memory_map) => {
1153
+ return MemoryMapOwned :: from_initialized_mem ( buf, memory_map) ;
1154
+ }
1155
+ Err ( err) => {
1156
+ log:: error!( "Error retrieving the memory map for exiting the boot services" ) ;
1157
+ status = err. status ( )
1158
+ }
1159
+ }
1160
+ }
1161
+
1162
+ // Failed to exit boot services.
1163
+ log:: warn!( "Resetting the machine" ) ;
1164
+ runtime:: reset ( ResetType :: COLD , status, None ) ;
1165
+ }
1166
+
1073
1167
/// Adds, updates, or removes a configuration table entry
1074
1168
/// from the EFI System Table.
1075
1169
///
0 commit comments