4
4
#![ allow( dead_code) ]
5
5
6
6
use crate :: arch:: mm:: PhysAddr ;
7
- use core:: arch:: x86_64:: _mm_mfence;
8
7
use core:: convert:: TryInto ;
9
- use core:: ptr:: read_volatile;
8
+ use core:: ptr:: { read_volatile, write_volatile } ;
10
9
use core:: result:: Result ;
10
+ use core:: sync:: atomic:: fence;
11
+ use core:: sync:: atomic:: Ordering ;
11
12
use core:: u8;
12
13
13
14
use crate :: drivers:: error:: DriverError ;
@@ -141,24 +142,22 @@ impl ComCfg {
141
142
142
143
/// Returns the device status field.
143
144
pub fn dev_status ( & self ) -> u8 {
144
- self . com_cfg . status . try_into ( ) . unwrap ( )
145
+ unsafe { read_volatile ( & self . com_cfg . status ) . try_into ( ) . unwrap ( ) }
145
146
}
146
147
147
148
/// Resets the device status field to zero.
148
149
pub fn reset_dev ( & mut self ) {
149
- self . com_cfg . status = 0 ;
150
150
unsafe {
151
- _mm_mfence ( ) ;
151
+ write_volatile ( & mut self . com_cfg . status , 0u32 ) ;
152
152
}
153
153
}
154
154
155
155
/// Sets the device status field to FAILED.
156
156
/// A driver MUST NOT initialize and use the device any further after this.
157
157
/// A driver MAY use the device again after a proper reset of the device.
158
158
pub fn set_failed ( & mut self ) {
159
- self . com_cfg . status = u32:: from ( device:: Status :: FAILED ) ;
160
159
unsafe {
161
- _mm_mfence ( ) ;
160
+ write_volatile ( & mut self . com_cfg . status , u32 :: from ( device :: Status :: FAILED ) ) ;
162
161
}
163
162
}
164
163
@@ -167,8 +166,10 @@ impl ComCfg {
167
166
pub fn ack_dev ( & mut self ) {
168
167
unsafe {
169
168
let status = read_volatile ( & self . com_cfg . status ) ;
170
- _mm_mfence ( ) ;
171
- self . com_cfg . status = status | u32:: from ( device:: Status :: ACKNOWLEDGE ) ;
169
+ write_volatile (
170
+ & mut self . com_cfg . status ,
171
+ status | u32:: from ( device:: Status :: ACKNOWLEDGE ) ,
172
+ ) ;
172
173
}
173
174
}
174
175
@@ -177,8 +178,10 @@ impl ComCfg {
177
178
pub fn set_drv ( & mut self ) {
178
179
unsafe {
179
180
let status = read_volatile ( & self . com_cfg . status ) ;
180
- _mm_mfence ( ) ;
181
- self . com_cfg . status = status | u32:: from ( device:: Status :: DRIVER ) ;
181
+ write_volatile (
182
+ & mut self . com_cfg . status ,
183
+ status | u32:: from ( device:: Status :: DRIVER ) ,
184
+ ) ;
182
185
}
183
186
}
184
187
@@ -188,8 +191,10 @@ impl ComCfg {
188
191
pub fn features_ok ( & mut self ) {
189
192
unsafe {
190
193
let status = read_volatile ( & self . com_cfg . status ) ;
191
- _mm_mfence ( ) ;
192
- self . com_cfg . status = status | u32:: from ( device:: Status :: FEATURES_OK ) ;
194
+ write_volatile (
195
+ & mut self . com_cfg . status ,
196
+ status | u32:: from ( device:: Status :: FEATURES_OK ) ,
197
+ ) ;
193
198
}
194
199
}
195
200
@@ -202,7 +207,6 @@ impl ComCfg {
202
207
pub fn check_features ( & self ) -> bool {
203
208
unsafe {
204
209
let status = read_volatile ( & self . com_cfg . status ) ;
205
- _mm_mfence ( ) ;
206
210
status & u32:: from ( device:: Status :: FEATURES_OK )
207
211
== u32:: from ( device:: Status :: FEATURES_OK )
208
212
}
@@ -214,8 +218,10 @@ impl ComCfg {
214
218
pub fn drv_ok ( & mut self ) {
215
219
unsafe {
216
220
let status = read_volatile ( & self . com_cfg . status ) ;
217
- _mm_mfence ( ) ;
218
- self . com_cfg . status = status | u32:: from ( device:: Status :: DRIVER_OK ) ;
221
+ write_volatile (
222
+ & mut self . com_cfg . status ,
223
+ status | u32:: from ( device:: Status :: DRIVER_OK ) ,
224
+ ) ;
219
225
}
220
226
}
221
227
@@ -314,24 +320,21 @@ impl IsrStatus {
314
320
pub fn is_interrupt ( & self ) -> bool {
315
321
unsafe {
316
322
let status = read_volatile ( & self . raw . interrupt_status ) ;
317
- _mm_mfence ( ) ;
318
323
status & 0x1 == 0x1
319
324
}
320
325
}
321
326
322
327
pub fn is_cfg_change ( & self ) -> bool {
323
328
unsafe {
324
329
let status = read_volatile ( & self . raw . interrupt_status ) ;
325
- _mm_mfence ( ) ;
326
330
status & 0x2 == 0x2
327
331
}
328
332
}
329
333
330
334
pub fn acknowledge ( & mut self ) {
331
335
unsafe {
332
336
let status = read_volatile ( & self . raw . interrupt_status ) ;
333
- _mm_mfence ( ) ;
334
- self . raw . interrupt_ack = status;
337
+ write_volatile ( & mut self . raw . interrupt_ack , status) ;
335
338
}
336
339
}
337
340
}
@@ -440,149 +443,130 @@ pub struct MmioRegisterLayout {
440
443
441
444
impl MmioRegisterLayout {
442
445
pub fn get_magic_value ( & self ) -> u32 {
443
- self . magic_value
446
+ unsafe { read_volatile ( & self . magic_value ) }
444
447
}
445
448
446
449
pub fn get_version ( & self ) -> u32 {
447
- self . version
450
+ unsafe { read_volatile ( & self . version ) }
448
451
}
449
452
450
453
pub fn get_device_id ( & self ) -> DevId {
451
- self . device_id
454
+ unsafe { read_volatile ( & self . device_id ) }
452
455
}
453
456
454
457
pub fn enable_queue ( & mut self , sel : u32 ) {
455
- self . queue_sel = sel;
456
458
unsafe {
457
- _mm_mfence ( ) ;
459
+ write_volatile ( & mut self . queue_sel , sel) ;
460
+ write_volatile ( & mut self . queue_ready , 1u32 ) ;
458
461
}
459
- self . queue_ready = 1 ;
460
462
}
461
463
462
464
pub fn get_max_queue_size ( & mut self , sel : u32 ) -> u32 {
463
- self . queue_sel = sel;
464
465
unsafe {
465
- _mm_mfence ( ) ;
466
+ write_volatile ( & mut self . queue_sel , sel) ;
467
+ read_volatile ( & self . queue_num_max )
466
468
}
467
- self . queue_num_max
468
469
}
469
470
470
471
pub fn set_queue_size ( & mut self , sel : u32 , size : u32 ) -> u32 {
471
- self . queue_sel = sel;
472
472
unsafe {
473
- _mm_mfence ( ) ;
474
- }
475
- let num_max = self . queue_num_max ;
473
+ write_volatile ( & mut self . queue_sel , sel) ;
476
474
477
- if num_max >= size {
478
- self . queue_num = size;
479
- size
480
- } else {
481
- self . queue_num = num_max;
482
- num_max
475
+ let num_max = read_volatile ( & self . queue_num_max ) ;
476
+
477
+ if num_max >= size {
478
+ write_volatile ( & mut self . queue_num , size) ;
479
+ size
480
+ } else {
481
+ write_volatile ( & mut self . queue_num , num_max) ;
482
+ num_max
483
+ }
483
484
}
484
485
}
485
486
486
487
pub fn set_ring_addr ( & mut self , sel : u32 , addr : PhysAddr ) {
487
- self . queue_sel = sel;
488
488
unsafe {
489
- _mm_mfence ( ) ;
489
+ write_volatile ( & mut self . queue_sel , sel) ;
490
+ write_volatile ( & mut self . queue_desc_low , addr. as_u64 ( ) as u32 ) ;
491
+ write_volatile ( & mut self . queue_desc_high , ( addr. as_u64 ( ) >> 32 ) as u32 ) ;
490
492
}
491
- self . queue_desc_low = addr. as_u64 ( ) as u32 ;
492
- self . queue_desc_high = ( addr. as_u64 ( ) >> 32 ) as u32 ;
493
493
}
494
494
495
495
pub fn set_drv_ctrl_addr ( & mut self , sel : u32 , addr : PhysAddr ) {
496
- self . queue_sel = sel;
497
496
unsafe {
498
- _mm_mfence ( ) ;
497
+ write_volatile ( & mut self . queue_sel , sel) ;
498
+ write_volatile ( & mut self . queue_driver_low , addr. as_u64 ( ) as u32 ) ;
499
+ write_volatile ( & mut self . queue_driver_high , ( addr. as_u64 ( ) >> 32 ) as u32 ) ;
499
500
}
500
- self . queue_driver_low = addr. as_u64 ( ) as u32 ;
501
- self . queue_driver_high = ( addr. as_u64 ( ) >> 32 ) as u32 ;
502
501
}
503
502
504
503
pub fn set_dev_ctrl_addr ( & mut self , sel : u32 , addr : PhysAddr ) {
505
- self . queue_sel = sel;
506
504
unsafe {
507
- _mm_mfence ( ) ;
505
+ write_volatile ( & mut self . queue_sel , sel) ;
506
+ write_volatile ( & mut self . queue_device_low , addr. as_u64 ( ) as u32 ) ;
507
+ write_volatile ( & mut self . queue_device_high , ( addr. as_u64 ( ) >> 32 ) as u32 ) ;
508
508
}
509
- self . queue_device_low = addr. as_u64 ( ) as u32 ;
510
- self . queue_device_high = ( addr. as_u64 ( ) >> 32 ) as u32 ;
511
509
}
512
510
513
511
pub fn is_queue_ready ( & mut self , sel : u32 ) -> bool {
514
- self . queue_sel = sel;
515
512
unsafe {
516
- _mm_mfence ( ) ;
513
+ write_volatile ( & mut self . queue_sel , sel) ;
514
+ read_volatile ( & self . queue_ready ) != 0
517
515
}
518
- self . queue_ready != 0
519
516
}
520
517
521
518
pub fn dev_features ( & mut self ) -> u64 {
522
519
// Indicate device to show high 32 bits in device_feature field.
523
520
// See Virtio specification v1.1. - 4.1.4.3
524
- self . device_features_sel = 1 ;
525
521
unsafe {
526
- _mm_mfence ( ) ;
527
- }
522
+ write_volatile ( & mut self . device_features_sel , 1u32 ) ;
528
523
529
- // read high 32 bits of device features
530
- let mut dev_feat = u64:: from ( self . device_features ) << 32 ;
531
- unsafe {
532
- _mm_mfence ( ) ;
533
- }
524
+ // read high 32 bits of device features
525
+ let mut dev_feat = u64:: from ( read_volatile ( & self . device_features ) ) << 32 ;
534
526
535
- // Indicate device to show low 32 bits in device_feature field.
536
- // See Virtio specification v1.1. - 4.1.4.3
537
- self . device_features_sel = 0 ;
538
- unsafe {
539
- _mm_mfence ( ) ;
540
- }
527
+ // Indicate device to show low 32 bits in device_feature field.
528
+ // See Virtio specification v1.1. - 4.1.4.3
529
+ write_volatile ( & mut self . device_features_sel , 0u32 ) ;
541
530
542
- // read low 32 bits of device features
543
- dev_feat |= u64:: from ( self . device_features ) ;
531
+ // read low 32 bits of device features
532
+ dev_feat |= u64:: from ( read_volatile ( & self . device_features ) ) ;
544
533
545
- dev_feat
534
+ dev_feat
535
+ }
546
536
}
547
537
548
538
/// Write selected features into driver_select field.
549
539
pub fn set_drv_features ( & mut self , feats : u64 ) {
550
540
let high: u32 = ( feats >> 32 ) as u32 ;
551
541
let low: u32 = feats as u32 ;
552
542
553
- // Indicate to device that driver_features field shows low 32 bits.
554
- // See Virtio specification v1.1. - 4.1.4.3
555
- self . driver_features_sel = 0 ;
556
543
unsafe {
557
- _mm_mfence ( ) ;
558
- }
544
+ // Indicate to device that driver_features field shows low 32 bits.
545
+ // See Virtio specification v1.1. - 4.1.4.3
546
+ write_volatile ( & mut self . driver_features_sel , 0u32 ) ;
559
547
560
- // write low 32 bits of device features
561
- self . driver_features = low;
562
- unsafe {
563
- _mm_mfence ( ) ;
564
- }
548
+ // write low 32 bits of device features
549
+ write_volatile ( & mut self . driver_features , low) ;
565
550
566
- // Indicate to device that driver_features field shows high 32 bits.
567
- // See Virtio specification v1.1. - 4.1.4.3
568
- self . driver_features_sel = 1 ;
569
- unsafe {
570
- _mm_mfence ( ) ;
571
- }
551
+ // Indicate to device that driver_features field shows high 32 bits.
552
+ // See Virtio specification v1.1. - 4.1.4.3
553
+ write_volatile ( & mut self . driver_features_sel , 1u32 ) ;
572
554
573
- // write high 32 bits of device features
574
- self . driver_features = high;
555
+ // write high 32 bits of device features
556
+ write_volatile ( & mut self . driver_features , high) ;
557
+ }
575
558
}
576
559
577
560
pub fn get_config ( & mut self ) -> [ u32 ; 3 ] {
578
561
// see Virtio specification v1.1 - 2.4.1
579
562
unsafe {
580
563
loop {
581
564
let before = read_volatile ( & self . config_generation ) ;
582
- _mm_mfence ( ) ;
565
+ fence ( Ordering :: SeqCst ) ;
583
566
let config = read_volatile ( & self . config ) ;
584
- _mm_mfence ( ) ;
567
+ fence ( Ordering :: SeqCst ) ;
585
568
let after = read_volatile ( & self . config_generation ) ;
569
+ fence ( Ordering :: SeqCst ) ;
586
570
587
571
if before == after {
588
572
return config;
@@ -594,12 +578,20 @@ impl MmioRegisterLayout {
594
578
pub fn print_information ( & mut self ) {
595
579
infoheader ! ( " MMIO RREGISTER LAYOUT INFORMATION " ) ;
596
580
597
- infoentry ! ( "Device version" , "{:#X}" , self . version) ;
598
- infoentry ! ( "Device ID" , "{:?}" , self . device_id) ;
599
- infoentry ! ( "Vendor ID" , "{:#X}" , self . vendor_id) ;
581
+ infoentry ! ( "Device version" , "{:#X}" , self . get_version( ) ) ;
582
+ infoentry ! ( "Device ID" , "{:?}" , unsafe {
583
+ read_volatile( & self . device_id)
584
+ } ) ;
585
+ infoentry ! ( "Vendor ID" , "{:#X}" , unsafe {
586
+ read_volatile( & self . vendor_id)
587
+ } ) ;
600
588
infoentry ! ( "Device Features" , "{:#X}" , self . dev_features( ) ) ;
601
- infoentry ! ( "Interrupt status" , "{:#X}" , self . interrupt_status) ;
602
- infoentry ! ( "Device status" , "{:#X}" , self . status) ;
589
+ infoentry ! ( "Interrupt status" , "{:#X}" , unsafe {
590
+ read_volatile( & self . interrupt_status)
591
+ } ) ;
592
+ infoentry ! ( "Device status" , "{:#X}" , unsafe {
593
+ read_volatile( & self . status)
594
+ } ) ;
603
595
infoentry ! ( "Configuration space" , "{:#X?}" , self . get_config( ) ) ;
604
596
605
597
infofooter ! ( ) ;
0 commit comments