@@ -12,15 +12,18 @@ use core::marker::PhantomData;
12
12
use core:: mem:: MaybeUninit ;
13
13
use core:: num:: NonZeroUsize ;
14
14
use core:: ptr;
15
- use core:: ptr:: { NonNull , slice_from_raw_parts } ;
15
+ use core:: ptr:: NonNull ;
16
16
use core:: time:: Duration ;
17
17
use log:: debug;
18
18
use uefi:: proto:: pci:: PciIoMode ;
19
19
use uefi:: proto:: pci:: root_bridge:: io_access:: IoAccessType ;
20
20
use uefi_macros:: unsafe_protocol;
21
- use uefi_raw:: protocol:: pci:: resource:: QWordAddressSpaceDescriptor ;
22
21
use uefi_raw:: Status ;
23
- use uefi_raw:: protocol:: pci:: root_bridge:: { PciRootBridgeIoAccess , PciRootBridgeIoProtocol , PciRootBridgeIoProtocolAttribute , PciRootBridgeIoProtocolOperation , PciRootBridgeIoProtocolWidth } ;
22
+ use uefi_raw:: protocol:: pci:: resource:: QWordAddressSpaceDescriptor ;
23
+ use uefi_raw:: protocol:: pci:: root_bridge:: {
24
+ PciRootBridgeIoAccess , PciRootBridgeIoProtocol , PciRootBridgeIoProtocolAttribute ,
25
+ PciRootBridgeIoProtocolOperation ,
26
+ } ;
24
27
use uefi_raw:: table:: boot:: { AllocateType , MemoryType , PAGE_SIZE } ;
25
28
26
29
#[ cfg( doc) ]
@@ -191,9 +194,10 @@ impl PciRootBridgeIo {
191
194
///
192
195
/// # Returns
193
196
/// [`Ok`] on successful copy.
197
+ ///
194
198
/// [`Err`] otherwise.
195
- /// * [`Status::INVALID_PARAMETER`]: Width is invalid for this PCI root bridge.
196
- /// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
199
+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
200
+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
197
201
/// # Question
198
202
/// Should this support other types than just primitives?
199
203
#[ cfg( feature = "alloc" ) ]
@@ -219,15 +223,16 @@ impl PciRootBridgeIo {
219
223
///
220
224
/// # Returns
221
225
/// [`Ok`] when it successfully retrieved current configuration.
226
+ ///
222
227
/// [`Err`] when it failed to retrieve current configuration.
223
- /// * Status value will be [`Status::UNSUPPORTED`]
228
+ /// - Its Status value will be [`Status::UNSUPPORTED`]
224
229
///
225
230
/// # Panic
226
231
/// It may panic if pci devices or drivers for those provided by boot service misbehave.
227
232
/// There are multiple verifications put in place, and they will panic if invariants
228
233
/// are broken, such as when invalid enum variant value was received
229
234
/// or reserved bits are not 0
230
- pub fn configuration ( & self ) -> crate :: Result < & ' static [ QWordAddressSpaceDescriptor ] > {
235
+ pub fn configuration ( & self ) -> crate :: Result < & [ QWordAddressSpaceDescriptor ] > {
231
236
let mut configuration_address = 0u64 ;
232
237
let configuration_status = unsafe {
233
238
( self . 0 . configuration ) (
@@ -249,8 +254,10 @@ impl PciRootBridgeIo {
249
254
cursor_ref. verify ( ) ;
250
255
count += 1 ;
251
256
if count >= 1024 {
252
- panic ! ( "Timed out while fetching configurations:\
253
- There are more than 1024 configuration spaces") ;
257
+ panic ! (
258
+ "Timed out while fetching configurations:\
259
+ There are more than 1024 configuration spaces"
260
+ ) ;
254
261
}
255
262
}
256
263
0x79 => {
@@ -271,7 +278,7 @@ impl PciRootBridgeIo {
271
278
}
272
279
} ;
273
280
let list: & [ QWordAddressSpaceDescriptor ] =
274
- unsafe { slice_from_raw_parts ( head, count) . as_ref ( ) . unwrap ( ) } ;
281
+ unsafe { ptr :: slice_from_raw_parts ( head, count) . as_ref ( ) . unwrap ( ) } ;
275
282
Ok ( list)
276
283
}
277
284
e => Err ( e. into ( ) ) ,
@@ -282,77 +289,170 @@ impl PciRootBridgeIo {
282
289
/// The criteria in question is met when value read from provided reference
283
290
/// equals to provided value when masked:
284
291
/// `(*to_poll) & mask == value`
285
- /// /// Refer to [`Self::poll_io`] for polling io port instead.
292
+ ///
293
+ /// Refer to [`Self::poll_io`] for polling io port instead.
286
294
///
287
295
/// # Returns
288
296
/// [`Ok`]: Criteria was met before timeout.
297
+ ///
289
298
/// [`Err`]: One of below error happened:
290
- /// * [`Status::TIMEOUT`]: Delay expired before a match occurred.
291
- /// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
299
+ /// - [`Status::TIMEOUT`]: Delay expired before a match occurred.
300
+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
301
+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
292
302
///
293
303
/// # Panic
294
304
/// Panics when delay is too large (longer than 58494 years).
295
- pub fn poll_mem < U : PciIoUnit > ( & self , to_poll : & U , mask : U , value : U , delay : Duration ) -> crate :: Result < ( ) , U > {
296
- let mut result = U :: default ( ) ;
305
+ pub fn poll_mem < U : PciIoUnit > (
306
+ & self ,
307
+ to_poll : & U ,
308
+ mask : U ,
309
+ value : U ,
310
+ delay : Duration ,
311
+ ) -> crate :: Result < ( ) , u64 > {
312
+ let mut result = 0u64 ;
297
313
let delay = delay. as_nanos ( ) . div_ceil ( 100 ) . try_into ( ) . unwrap ( ) ;
298
314
let status = unsafe {
299
315
( self . 0 . poll_mem ) (
300
316
ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
301
317
encode_io_mode_and_unit :: < U > ( PciIoMode :: Normal ) ,
302
318
ptr:: from_ref ( to_poll) . addr ( ) as u64 ,
303
319
mask. into ( ) ,
304
- value,
320
+ value. into ( ) ,
305
321
delay,
306
- & mut result
322
+ & mut result,
307
323
)
308
324
} ;
309
325
310
- match status {
311
- Status :: SUCCESS => {
312
- Ok ( ( ) )
313
- }
314
- e => Err ( e. into ( ) ) ,
315
- }
326
+ status. to_result_with_err ( |_| result)
316
327
}
317
328
318
329
/// Polls a same io port until criteria is met.
319
330
/// The criteria in question is met when value read from provided reference
320
331
/// equals to provided value when masked:
321
332
/// `(*to_poll) & mask == value`
333
+ ///
322
334
/// Refer to [`Self::poll_mem`] for polling memory instead.
323
335
///
324
336
/// # Returns
325
337
/// [`Ok`]: Criteria was met before timeout.
338
+ ///
326
339
/// [`Err`]: One of below error happened:
327
- /// * [`Status::TIMEOUT`]: Delay expired before a match occurred.
328
- /// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
340
+ /// - [`Status::TIMEOUT`]: Delay expired before a match occurred.
341
+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
342
+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
329
343
///
330
344
/// # Panic
331
345
/// Panics when delay is too large (longer than 58494 years).
332
- pub fn poll_io < U : PciIoUnit > ( & self , to_poll : & U , mask : U , value : U , delay : Duration ) -> crate :: Result < ( ) , U > {
333
- let mut result = U :: default ( ) ;
346
+ pub fn poll_io < U : PciIoUnit > (
347
+ & self ,
348
+ to_poll : & U ,
349
+ mask : U ,
350
+ value : U ,
351
+ delay : Duration ,
352
+ ) -> crate :: Result < ( ) , u64 > {
353
+ let mut result = 0u64 ;
334
354
let delay = delay. as_nanos ( ) . div_ceil ( 100 ) . try_into ( ) . unwrap ( ) ;
335
355
let status = unsafe {
336
356
( self . 0 . poll_io ) (
337
357
ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
338
358
encode_io_mode_and_unit :: < U > ( PciIoMode :: Normal ) ,
339
359
ptr:: from_ref ( to_poll) . addr ( ) as u64 ,
340
360
mask. into ( ) ,
341
- value,
361
+ value. into ( ) ,
342
362
delay,
343
- & mut result
363
+ & mut result,
364
+ )
365
+ } ;
366
+
367
+ status. to_result_with_err ( |_| result)
368
+ }
369
+
370
+ /// Returns available and used attributes of this root bridge.
371
+ ///
372
+ /// # Returns
373
+ /// Both supported and used attribute will be returned in struct [`AttributeReport`]
374
+ pub fn get_attributes ( & self ) -> AttributeReport {
375
+ let mut supports = PciRootBridgeIoProtocolAttribute :: empty ( ) ;
376
+ let mut attributes = PciRootBridgeIoProtocolAttribute :: empty ( ) ;
377
+ let status = unsafe {
378
+ ( self . 0 . get_attributes ) (
379
+ & self . 0 ,
380
+ ptr:: from_mut ( & mut supports) . cast ( ) ,
381
+ ptr:: from_mut ( & mut attributes) . cast ( ) ,
382
+ )
383
+ } ;
384
+
385
+ match status {
386
+ Status :: SUCCESS => AttributeReport {
387
+ supported : supports,
388
+ used : attributes,
389
+ } ,
390
+ Status :: INVALID_PARAMETER => unreachable ! ( ) ,
391
+ e => panic ! ( "Unexpected error occurred: {:?}" , e) ,
392
+ }
393
+ }
394
+
395
+ /// Sets attributes to use for this root bridge.
396
+ /// Specified attributes must be supported. Otherwise, it will return error.
397
+ /// Supported attributes can be requested with [`Self::get_attributes`]
398
+ ///
399
+ /// # Returns
400
+ /// [`Ok`]: Optional resource range. It will only be available when resource
401
+ /// parameter is Some and one of:
402
+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_WRITE_COMBINE`]
403
+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_CACHED`]
404
+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_DISABLE`]
405
+ /// is set.
406
+ ///
407
+ /// [`Err`]: Possible error cases:
408
+ /// - [`Status::UNSUPPORTED`]: A bit is set in Attributes that is not supported by the PCI Root Bridge.
409
+ /// The supported attribute bits are reported by [`Self::get_attributes`]
410
+ /// - [`Status::INVALID_PARAMETER`]: More than one attribute bit is set in Attributes that requires a resource parameter.
411
+ /// - [`Status::OUT_OF_RESOURCES`]: There are not enough resources to set the attributes on the resource range specified by resource parameter.
412
+ pub fn set_attributes < ' a , ' p > (
413
+ & ' p self ,
414
+ attributes : PciRootBridgeIoProtocolAttribute ,
415
+ resource : Option < & ' a [ u64 ] > ,
416
+ ) -> crate :: Result < Option < & ' a [ u64 ] > >
417
+ where
418
+ ' p : ' a ,
419
+ {
420
+ let ( mut base, mut length) = match resource {
421
+ Some ( v) => {
422
+ let ptr: * const [ u64 ] = v;
423
+ let base = ptr. addr ( ) as u64 ;
424
+ let length = ptr. len ( ) as u64 ;
425
+ ( base, length)
426
+ }
427
+ None => ( 0 , 0 ) ,
428
+ } ;
429
+ let status = unsafe {
430
+ ( self . 0 . set_attributes ) (
431
+ ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
432
+ attributes. bits ( ) ,
433
+ & mut base,
434
+ & mut length,
344
435
)
345
436
} ;
346
437
347
438
match status {
348
439
Status :: SUCCESS => {
349
- Ok ( ( ) )
440
+ let to_return = if length != 0 {
441
+ unsafe {
442
+ Some (
443
+ ptr:: slice_from_raw_parts ( base as * const u64 , length as usize )
444
+ . as_ref ( )
445
+ . unwrap ( ) ,
446
+ )
447
+ }
448
+ } else {
449
+ None
450
+ } ;
451
+ Ok ( to_return)
350
452
}
351
453
e => Err ( e. into ( ) ) ,
352
454
}
353
455
}
354
-
355
- // TODO: get/set attributes
356
456
}
357
457
358
458
/// Struct for performing PCI I/O operations on a root bridge.
@@ -575,3 +675,15 @@ impl<T: IoAccessType> PciIoAccessPci<'_, T> {
575
675
}
576
676
}
577
677
}
678
+
679
+ /// Struct containing return value for [`PciRootBridgeIo::get_attributes`]
680
+ /// This is to minimize confusion by giving both of them names.
681
+ #[ derive( Debug ) ]
682
+ pub struct AttributeReport {
683
+ /// Attributes supported by this bridge.
684
+ /// Only attributes in this set can be used as parameter for [`PciRootBridgeIo::set_attributes`]
685
+ pub supported : PciRootBridgeIoProtocolAttribute ,
686
+
687
+ /// Attributes currently being used.
688
+ pub used : PciRootBridgeIoProtocolAttribute ,
689
+ }
0 commit comments