4
4
#![ allow( dead_code) ]
5
5
6
6
use alloc:: vec:: Vec ;
7
+ use core:: ptr:: NonNull ;
7
8
use core:: sync:: atomic:: { fence, Ordering } ;
8
9
use core:: { mem, ptr} ;
9
10
11
+ use volatile:: { map_field, VolatileRef } ;
12
+
10
13
#[ cfg( all( not( feature = "rtl8139" ) , any( feature = "tcp" , feature = "udp" ) ) ) ]
11
14
use crate :: arch:: kernel:: interrupts:: * ;
12
15
use crate :: arch:: memory_barrier;
@@ -385,61 +388,77 @@ impl UniCapsColl {
385
388
pub struct ComCfg {
386
389
/// References the raw structure in PCI memory space. Is static as
387
390
/// long as the device is present, which is mandatory in order to let this code work.
388
- com_cfg : & ' static mut ComCfgRaw ,
391
+ com_cfg : VolatileRef < ' static , ComCfgRaw > ,
389
392
/// Preferences of the device for this config. From 1 (highest) to 2^7-1 (lowest)
390
393
rank : u8 ,
391
394
}
392
395
393
396
// Private interface of ComCfg
394
397
impl ComCfg {
395
- fn new ( raw : & ' static mut ComCfgRaw , rank : u8 ) -> Self {
398
+ fn new ( raw : VolatileRef < ' static , ComCfgRaw > , rank : u8 ) -> Self {
396
399
ComCfg { com_cfg : raw, rank }
397
400
}
398
401
}
399
402
403
+ // TODO: Create type for queue selected invariant to get rid of `self.select_queue()` everywhere.
400
404
pub struct VqCfgHandler < ' a > {
401
405
vq_index : u16 ,
402
- raw : & ' a mut ComCfgRaw ,
406
+ raw : VolatileRef < ' a , ComCfgRaw > ,
403
407
}
404
408
405
409
impl < ' a > VqCfgHandler < ' a > {
410
+ fn select_queue ( & mut self ) {
411
+ let raw = self . raw . as_mut_ptr ( ) ;
412
+ map_field ! ( raw. queue_select) . write ( self . vq_index ) ;
413
+ }
414
+
406
415
/// Sets the size of a given virtqueue. In case the provided size exceeds the maximum allowed
407
416
/// size, the size is set to this maximum instead. Else size is set to the provided value.
408
417
///
409
418
/// Returns the set size in form of a `u16`.
410
419
pub fn set_vq_size ( & mut self , size : u16 ) -> u16 {
411
- self . raw . queue_select = self . vq_index ;
420
+ self . select_queue ( ) ;
421
+
422
+ let raw = self . raw . as_mut_ptr ( ) ;
423
+ let queue_size = map_field ! ( raw. queue_size) ;
424
+
425
+ let old = queue_size. read ( ) ;
412
426
413
- if self . raw . queue_size >= size {
414
- self . raw . queue_size = size;
427
+ if old > size {
428
+ queue_size. write ( size) ;
415
429
}
416
430
417
- self . raw . queue_size
431
+ old . min ( size )
418
432
}
419
433
420
434
pub fn set_ring_addr ( & mut self , addr : PhysAddr ) {
421
- self . raw . queue_select = self . vq_index ;
422
- self . raw . queue_desc = addr. as_u64 ( ) ;
435
+ self . select_queue ( ) ;
436
+ let raw = self . raw . as_mut_ptr ( ) ;
437
+ map_field ! ( raw. queue_desc) . write ( addr. as_u64 ( ) ) ;
423
438
}
424
439
425
440
pub fn set_drv_ctrl_addr ( & mut self , addr : PhysAddr ) {
426
- self . raw . queue_select = self . vq_index ;
427
- self . raw . queue_driver = addr. as_u64 ( ) ;
441
+ self . select_queue ( ) ;
442
+ let raw = self . raw . as_mut_ptr ( ) ;
443
+ map_field ! ( raw. queue_driver) . write ( addr. as_u64 ( ) ) ;
428
444
}
429
445
430
446
pub fn set_dev_ctrl_addr ( & mut self , addr : PhysAddr ) {
431
- self . raw . queue_select = self . vq_index ;
432
- self . raw . queue_device = addr. as_u64 ( ) ;
447
+ self . select_queue ( ) ;
448
+ let raw = self . raw . as_mut_ptr ( ) ;
449
+ map_field ! ( raw. queue_device) . write ( addr. as_u64 ( ) ) ;
433
450
}
434
451
435
452
pub fn notif_off ( & mut self ) -> u16 {
436
- self . raw . queue_select = self . vq_index ;
437
- self . raw . queue_notify_off
453
+ self . select_queue ( ) ;
454
+ let raw = self . raw . as_mut_ptr ( ) ;
455
+ map_field ! ( raw. queue_notify_off) . read ( )
438
456
}
439
457
440
458
pub fn enable_queue ( & mut self ) {
441
- self . raw . queue_select = self . vq_index ;
442
- self . raw . queue_enable = 1 ;
459
+ self . select_queue ( ) ;
460
+ let raw = self . raw . as_mut_ptr ( ) ;
461
+ map_field ! ( raw. queue_enable) . write ( 1 ) ;
443
462
}
444
463
}
445
464
@@ -450,57 +469,65 @@ impl ComCfg {
450
469
///
451
470
/// INFO: The queue size is automatically bounded by constant `src::config:VIRTIO_MAX_QUEUE_SIZE`.
452
471
pub fn select_vq ( & mut self , index : u16 ) -> Option < VqCfgHandler < ' _ > > {
453
- self . com_cfg . queue_select = index ;
472
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
454
473
455
- if self . com_cfg . queue_size == 0 {
474
+ map_field ! ( com_cfg. queue_select) . write ( index) ;
475
+
476
+ if map_field ! ( com_cfg. queue_size) . read ( ) == 0 {
456
477
None
457
478
} else {
458
479
Some ( VqCfgHandler {
459
480
vq_index : index,
460
- raw : self . com_cfg ,
481
+ raw : self . com_cfg . borrow_mut ( ) ,
461
482
} )
462
483
}
463
484
}
464
485
465
486
/// Returns the device status field.
466
487
pub fn dev_status ( & self ) -> u8 {
467
- self . com_cfg . device_status
488
+ let com_cfg = self . com_cfg . as_ptr ( ) ;
489
+ map_field ! ( com_cfg. device_status) . read ( )
468
490
}
469
491
470
492
/// Resets the device status field to zero.
471
493
pub fn reset_dev ( & mut self ) {
472
494
memory_barrier ( ) ;
473
- self . com_cfg . device_status = 0 ;
495
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
496
+ map_field ! ( com_cfg. device_status) . write ( 0 ) ;
474
497
}
475
498
476
499
/// Sets the device status field to FAILED.
477
500
/// A driver MUST NOT initialize and use the device any further after this.
478
501
/// A driver MAY use the device again after a proper reset of the device.
479
502
pub fn set_failed ( & mut self ) {
480
503
memory_barrier ( ) ;
481
- self . com_cfg . device_status = u8:: from ( device:: Status :: FAILED ) ;
504
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
505
+ map_field ! ( com_cfg. device_status) . write ( u8:: from ( device:: Status :: FAILED ) ) ;
482
506
}
483
507
484
508
/// Sets the ACKNOWLEDGE bit in the device status field. This indicates, the
485
509
/// OS has notived the device
486
510
pub fn ack_dev ( & mut self ) {
487
511
memory_barrier ( ) ;
488
- self . com_cfg . device_status |= u8:: from ( device:: Status :: ACKNOWLEDGE ) ;
512
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
513
+ map_field ! ( com_cfg. device_status) . update ( |s| s | u8:: from ( device:: Status :: ACKNOWLEDGE ) ) ;
489
514
}
490
515
491
516
/// Sets the DRIVER bit in the device status field. This indicates, the OS
492
517
/// know how to run this device.
493
518
pub fn set_drv ( & mut self ) {
494
519
memory_barrier ( ) ;
495
- self . com_cfg . device_status |= u8:: from ( device:: Status :: DRIVER ) ;
520
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
521
+ map_field ! ( com_cfg. device_status) . update ( |s| s | u8:: from ( device:: Status :: DRIVER ) ) ;
496
522
}
497
523
498
524
/// Sets the FEATURES_OK bit in the device status field.
499
525
///
500
526
/// Drivers MUST NOT accept new features after this step.
501
527
pub fn features_ok ( & mut self ) {
502
528
memory_barrier ( ) ;
503
- self . com_cfg . device_status |= u8:: from ( device:: Status :: FEATURES_OK ) ;
529
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
530
+ map_field ! ( com_cfg. device_status) . update ( |s| s | u8:: from ( device:: Status :: FEATURES_OK ) ) ;
504
531
}
505
532
506
533
/// In order to correctly check feature negotiaten, this function
@@ -511,7 +538,8 @@ impl ComCfg {
511
538
/// otherwise, the device does not support our subset of features and the device is unusable.
512
539
pub fn check_features ( & self ) -> bool {
513
540
memory_barrier ( ) ;
514
- self . com_cfg . device_status & u8:: from ( device:: Status :: FEATURES_OK )
541
+ let com_cfg = self . com_cfg . as_ptr ( ) ;
542
+ map_field ! ( com_cfg. device_status) . read ( ) & u8:: from ( device:: Status :: FEATURES_OK )
515
543
== u8:: from ( device:: Status :: FEATURES_OK )
516
544
}
517
545
@@ -520,54 +548,59 @@ impl ComCfg {
520
548
/// After this call, the device is "live"!
521
549
pub fn drv_ok ( & mut self ) {
522
550
memory_barrier ( ) ;
523
- self . com_cfg . device_status |= u8:: from ( device:: Status :: DRIVER_OK ) ;
551
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
552
+ map_field ! ( com_cfg. device_status) . update ( |s| s | u8:: from ( device:: Status :: DRIVER_OK ) ) ;
524
553
}
525
554
526
555
/// Returns the features offered by the device. Coded in a 64bit value.
527
556
pub fn dev_features ( & mut self ) -> u64 {
528
- let device_feature_select = ptr:: from_mut ( & mut self . com_cfg . device_feature_select ) ;
529
- let device_feature = ptr:: from_mut ( & mut self . com_cfg . device_feature ) ;
557
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
558
+ let device_feature_select = map_field ! ( com_cfg. device_feature_select) ;
559
+ let device_feature = map_field ! ( com_cfg. device_feature_select) ;
560
+
530
561
// Indicate device to show high 32 bits in device_feature field.
531
562
// See Virtio specification v1.1. - 4.1.4.3
532
563
memory_barrier ( ) ;
533
- unsafe { device_feature_select. write_volatile ( 1 ) } ;
564
+ device_feature_select. write ( 1 ) ;
534
565
memory_barrier ( ) ;
535
566
536
567
// read high 32 bits of device features
537
- let mut dev_feat = u64:: from ( unsafe { device_feature. read_volatile ( ) } ) << 32 ;
568
+ let mut dev_feat = u64:: from ( device_feature. read ( ) ) << 32 ;
538
569
539
570
// Indicate device to show low 32 bits in device_feature field.
540
571
// See Virtio specification v1.1. - 4.1.4.3
541
- unsafe { device_feature_select. write_volatile ( 0 ) } ;
572
+ device_feature_select. write ( 0 ) ;
542
573
memory_barrier ( ) ;
543
574
544
575
// read low 32 bits of device features
545
- dev_feat |= u64:: from ( unsafe { device_feature. read_volatile ( ) } ) ;
576
+ dev_feat |= u64:: from ( device_feature. read ( ) ) ;
546
577
547
578
dev_feat
548
579
}
549
580
550
581
/// Write selected features into driver_select field.
551
582
pub fn set_drv_features ( & mut self , feats : u64 ) {
583
+ let com_cfg = self . com_cfg . as_mut_ptr ( ) ;
584
+
552
585
let high: u32 = ( feats >> 32 ) as u32 ;
553
586
let low: u32 = feats as u32 ;
554
587
555
588
// Indicate to device that driver_features field shows low 32 bits.
556
589
// See Virtio specification v1.1. - 4.1.4.3
557
590
memory_barrier ( ) ;
558
- self . com_cfg . driver_feature_select = 0 ;
591
+ map_field ! ( com_cfg. driver_feature_select) . write ( 0 ) ;
559
592
memory_barrier ( ) ;
560
593
561
594
// write low 32 bits of device features
562
- self . com_cfg . driver_feature = low;
595
+ map_field ! ( com_cfg. driver_feature) . write ( low) ;
563
596
564
597
// Indicate to device that driver_features field shows high 32 bits.
565
598
// See Virtio specification v1.1. - 4.1.4.3
566
- self . com_cfg . driver_feature_select = 1 ;
599
+ map_field ! ( com_cfg. driver_feature_select) . write ( 1 ) ;
567
600
memory_barrier ( ) ;
568
601
569
602
// write high 32 bits of device features
570
- self . com_cfg . driver_feature = high;
603
+ map_field ! ( com_cfg. driver_feature) . write ( high) ;
571
604
}
572
605
}
573
606
@@ -603,7 +636,7 @@ struct ComCfgRaw {
603
636
impl ComCfgRaw {
604
637
/// Returns a boxed [ComCfgRaw] structure. The box points to the actual structure inside the
605
638
/// PCI devices memory space.
606
- fn map ( cap : & PciCap ) -> Option < & ' static mut ComCfgRaw > {
639
+ fn map ( cap : & PciCap ) -> Option < VolatileRef < ' static , ComCfgRaw > > {
607
640
if cap. bar . length < u64:: from ( cap. length + cap. offset ) {
608
641
error ! ( "Common config of with id {} of device {:x}, does not fit into memory specified by bar {:x}!" ,
609
642
cap. id,
@@ -621,10 +654,13 @@ impl ComCfgRaw {
621
654
}
622
655
623
656
let virt_addr_raw = cap. bar . mem_addr + cap. offset ;
657
+ let ptr = NonNull :: new ( ptr:: from_exposed_addr_mut :: < ComCfgRaw > (
658
+ virt_addr_raw. into ( ) ,
659
+ ) )
660
+ . unwrap ( ) ;
624
661
625
662
// Create mutable reference to the PCI structure in PCI memory
626
- let com_cfg_raw: & mut ComCfgRaw =
627
- unsafe { & mut * ( ptr:: from_exposed_addr_mut ( virt_addr_raw. into ( ) ) ) } ;
663
+ let com_cfg_raw = unsafe { VolatileRef :: new ( ptr) } ;
628
664
629
665
Some ( com_cfg_raw)
630
666
}
0 commit comments