@@ -120,42 +120,83 @@ pub unsafe fn raise_tpl(tpl: Tpl) -> TplGuard {
120
120
}
121
121
}
122
122
123
- /// Allocates memory pages from the system.
123
+ /// Allocates a consecutive set of memory pages using the UEFI allocator.
124
+ ///
125
+ /// The caller is responsible to free the memory using [`free_pages`].
124
126
///
125
127
/// UEFI OS loaders should allocate memory of the type `LoaderData`.
126
128
///
129
+ /// # Example
130
+ ///```rust,no_run
131
+ /// use uefi::boot::{self, AllocateType};
132
+ /// use uefi_raw::table::boot::MemoryType;
133
+ ///
134
+ /// let num_pages = 3;
135
+ /// let mut ptr = boot::allocate_pages(
136
+ /// AllocateType::AnyPages,
137
+ /// MemoryType::LOADER_DATA,
138
+ /// num_pages
139
+ /// ).unwrap();
140
+ ///
141
+ /// // ⚠️ Creating the reference is safe, but reading the uninitialized memory
142
+ /// // causes Undefined Behavior (UB)! Please make sure to initialize the memory
143
+ /// // first by:
144
+ /// // - using `core::ptr::write`,
145
+ /// // - directly writing to slice indices,
146
+ /// // - zeroing the memory,
147
+ /// // - using `.copy_from_slice()`,
148
+ /// // - or a similar operation.
149
+ /// let buffer: &mut [u8] = unsafe { ptr.as_mut() };
150
+ /// // Now initialize the content of the buffer, cast it, etc.
151
+ /// // Please follow Rust guidelines on safety and UB! ⚠️
152
+ ///
153
+ /// // free the allocation
154
+ /// unsafe { boot::free_pages(ptr.cast(), num_pages) }.unwrap();
155
+ /// ```
156
+ ///
157
+ /// # Safety
158
+ /// Using this function is safe but reading on initialized memory is not.
159
+ /// Please look into the example code.
160
+ ///
127
161
/// # Errors
128
162
///
129
163
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
130
164
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`],
131
165
/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`.
132
166
/// * [`Status::NOT_FOUND`]: the requested pages could not be found.
133
- pub fn allocate_pages ( ty : AllocateType , mem_ty : MemoryType , count : usize ) -> Result < NonNull < u8 > > {
167
+ pub fn allocate_pages (
168
+ allocation_type : AllocateType ,
169
+ memory_type : MemoryType ,
170
+ count : usize ,
171
+ ) -> Result < NonNull < [ u8 ] > > {
134
172
let bt = boot_services_raw_panicking ( ) ;
135
173
let bt = unsafe { bt. as_ref ( ) } ;
136
174
137
- let ( ty , initial_addr ) = match ty {
175
+ let ( allocation_type_efi , start_address ) = match allocation_type {
138
176
AllocateType :: AnyPages => ( 0 , 0 ) ,
139
177
AllocateType :: MaxAddress ( addr) => ( 1 , addr) ,
140
178
AllocateType :: Address ( addr) => ( 2 , addr) ,
141
179
} ;
142
180
143
- let mut addr1 = initial_addr;
144
- unsafe { ( bt. allocate_pages ) ( ty, mem_ty, count, & mut addr1) } . to_result ( ) ?;
181
+ let mut addr1 = start_address;
182
+ unsafe { ( bt. allocate_pages ) ( allocation_type_efi, memory_type, count, & mut addr1) }
183
+ . to_result ( ) ?;
145
184
146
185
// The UEFI spec allows `allocate_pages` to return a valid allocation at
147
186
// address zero. Rust does not allow writes through a null pointer (which
148
187
// Rust defines as address zero), so this is not very useful. Only return
149
188
// the allocation if the address is non-null.
150
189
if let Some ( ptr) = NonNull :: new ( addr1 as * mut u8 ) {
151
- return Ok ( ptr) ;
190
+ let slice = NonNull :: slice_from_raw_parts ( ptr, count * PAGE_SIZE ) ;
191
+ return Ok ( slice) ;
152
192
}
153
193
154
194
// Attempt a second allocation. The first allocation (at address zero) has
155
195
// not yet been freed, so if this allocation succeeds it should be at a
156
196
// non-zero address.
157
- let mut addr2 = initial_addr;
158
- let r = unsafe { ( bt. allocate_pages ) ( ty, mem_ty, count, & mut addr2) } . to_result ( ) ;
197
+ let mut addr2 = start_address;
198
+ let r = unsafe { ( bt. allocate_pages ) ( allocation_type_efi, memory_type, count, & mut addr2) }
199
+ . to_result ( ) ;
159
200
160
201
// Free the original allocation (ignoring errors).
161
202
let _unused = unsafe { ( bt. free_pages ) ( addr1, count) } ;
@@ -164,7 +205,8 @@ pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Res
164
205
// address zero. Otherwise, return a pointer to the second allocation.
165
206
r?;
166
207
if let Some ( ptr) = NonNull :: new ( addr2 as * mut u8 ) {
167
- Ok ( ptr)
208
+ let slice = NonNull :: slice_from_raw_parts ( ptr, count * PAGE_SIZE ) ;
209
+ Ok ( slice)
168
210
} else {
169
211
Err ( Status :: OUT_OF_RESOURCES . into ( ) )
170
212
}
0 commit comments