Skip to content

Commit a33ddbd

Browse files
bors[bot]stlankes
andauthored
Merge #303
303: using write_volatile to guarantee that the data is written to the I/O device r=mkroening a=stlankes `@simonschoening` reports that the current implementation doesn't work on RISC-V. By using `write_volatile` we should get a more platform independent solution. Co-authored-by: Stefan Lankes <[email protected]>
2 parents 396bd67 + 449c035 commit a33ddbd

File tree

1 file changed

+88
-96
lines changed
  • src/drivers/virtio/transport

1 file changed

+88
-96
lines changed

src/drivers/virtio/transport/mmio.rs

Lines changed: 88 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
#![allow(dead_code)]
55

66
use crate::arch::mm::PhysAddr;
7-
use core::arch::x86_64::_mm_mfence;
87
use core::convert::TryInto;
9-
use core::ptr::read_volatile;
8+
use core::ptr::{read_volatile, write_volatile};
109
use core::result::Result;
10+
use core::sync::atomic::fence;
11+
use core::sync::atomic::Ordering;
1112
use core::u8;
1213

1314
use crate::drivers::error::DriverError;
@@ -141,24 +142,22 @@ impl ComCfg {
141142

142143
/// Returns the device status field.
143144
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() }
145146
}
146147

147148
/// Resets the device status field to zero.
148149
pub fn reset_dev(&mut self) {
149-
self.com_cfg.status = 0;
150150
unsafe {
151-
_mm_mfence();
151+
write_volatile(&mut self.com_cfg.status, 0u32);
152152
}
153153
}
154154

155155
/// Sets the device status field to FAILED.
156156
/// A driver MUST NOT initialize and use the device any further after this.
157157
/// A driver MAY use the device again after a proper reset of the device.
158158
pub fn set_failed(&mut self) {
159-
self.com_cfg.status = u32::from(device::Status::FAILED);
160159
unsafe {
161-
_mm_mfence();
160+
write_volatile(&mut self.com_cfg.status, u32::from(device::Status::FAILED));
162161
}
163162
}
164163

@@ -167,8 +166,10 @@ impl ComCfg {
167166
pub fn ack_dev(&mut self) {
168167
unsafe {
169168
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+
);
172173
}
173174
}
174175

@@ -177,8 +178,10 @@ impl ComCfg {
177178
pub fn set_drv(&mut self) {
178179
unsafe {
179180
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+
);
182185
}
183186
}
184187

@@ -188,8 +191,10 @@ impl ComCfg {
188191
pub fn features_ok(&mut self) {
189192
unsafe {
190193
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+
);
193198
}
194199
}
195200

@@ -202,7 +207,6 @@ impl ComCfg {
202207
pub fn check_features(&self) -> bool {
203208
unsafe {
204209
let status = read_volatile(&self.com_cfg.status);
205-
_mm_mfence();
206210
status & u32::from(device::Status::FEATURES_OK)
207211
== u32::from(device::Status::FEATURES_OK)
208212
}
@@ -214,8 +218,10 @@ impl ComCfg {
214218
pub fn drv_ok(&mut self) {
215219
unsafe {
216220
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+
);
219225
}
220226
}
221227

@@ -314,24 +320,21 @@ impl IsrStatus {
314320
pub fn is_interrupt(&self) -> bool {
315321
unsafe {
316322
let status = read_volatile(&self.raw.interrupt_status);
317-
_mm_mfence();
318323
status & 0x1 == 0x1
319324
}
320325
}
321326

322327
pub fn is_cfg_change(&self) -> bool {
323328
unsafe {
324329
let status = read_volatile(&self.raw.interrupt_status);
325-
_mm_mfence();
326330
status & 0x2 == 0x2
327331
}
328332
}
329333

330334
pub fn acknowledge(&mut self) {
331335
unsafe {
332336
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);
335338
}
336339
}
337340
}
@@ -440,149 +443,130 @@ pub struct MmioRegisterLayout {
440443

441444
impl MmioRegisterLayout {
442445
pub fn get_magic_value(&self) -> u32 {
443-
self.magic_value
446+
unsafe { read_volatile(&self.magic_value) }
444447
}
445448

446449
pub fn get_version(&self) -> u32 {
447-
self.version
450+
unsafe { read_volatile(&self.version) }
448451
}
449452

450453
pub fn get_device_id(&self) -> DevId {
451-
self.device_id
454+
unsafe { read_volatile(&self.device_id) }
452455
}
453456

454457
pub fn enable_queue(&mut self, sel: u32) {
455-
self.queue_sel = sel;
456458
unsafe {
457-
_mm_mfence();
459+
write_volatile(&mut self.queue_sel, sel);
460+
write_volatile(&mut self.queue_ready, 1u32);
458461
}
459-
self.queue_ready = 1;
460462
}
461463

462464
pub fn get_max_queue_size(&mut self, sel: u32) -> u32 {
463-
self.queue_sel = sel;
464465
unsafe {
465-
_mm_mfence();
466+
write_volatile(&mut self.queue_sel, sel);
467+
read_volatile(&self.queue_num_max)
466468
}
467-
self.queue_num_max
468469
}
469470

470471
pub fn set_queue_size(&mut self, sel: u32, size: u32) -> u32 {
471-
self.queue_sel = sel;
472472
unsafe {
473-
_mm_mfence();
474-
}
475-
let num_max = self.queue_num_max;
473+
write_volatile(&mut self.queue_sel, sel);
476474

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+
}
483484
}
484485
}
485486

486487
pub fn set_ring_addr(&mut self, sel: u32, addr: PhysAddr) {
487-
self.queue_sel = sel;
488488
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);
490492
}
491-
self.queue_desc_low = addr.as_u64() as u32;
492-
self.queue_desc_high = (addr.as_u64() >> 32) as u32;
493493
}
494494

495495
pub fn set_drv_ctrl_addr(&mut self, sel: u32, addr: PhysAddr) {
496-
self.queue_sel = sel;
497496
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);
499500
}
500-
self.queue_driver_low = addr.as_u64() as u32;
501-
self.queue_driver_high = (addr.as_u64() >> 32) as u32;
502501
}
503502

504503
pub fn set_dev_ctrl_addr(&mut self, sel: u32, addr: PhysAddr) {
505-
self.queue_sel = sel;
506504
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);
508508
}
509-
self.queue_device_low = addr.as_u64() as u32;
510-
self.queue_device_high = (addr.as_u64() >> 32) as u32;
511509
}
512510

513511
pub fn is_queue_ready(&mut self, sel: u32) -> bool {
514-
self.queue_sel = sel;
515512
unsafe {
516-
_mm_mfence();
513+
write_volatile(&mut self.queue_sel, sel);
514+
read_volatile(&self.queue_ready) != 0
517515
}
518-
self.queue_ready != 0
519516
}
520517

521518
pub fn dev_features(&mut self) -> u64 {
522519
// Indicate device to show high 32 bits in device_feature field.
523520
// See Virtio specification v1.1. - 4.1.4.3
524-
self.device_features_sel = 1;
525521
unsafe {
526-
_mm_mfence();
527-
}
522+
write_volatile(&mut self.device_features_sel, 1u32);
528523

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;
534526

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);
541530

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));
544533

545-
dev_feat
534+
dev_feat
535+
}
546536
}
547537

548538
/// Write selected features into driver_select field.
549539
pub fn set_drv_features(&mut self, feats: u64) {
550540
let high: u32 = (feats >> 32) as u32;
551541
let low: u32 = feats as u32;
552542

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;
556543
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);
559547

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);
565550

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);
572554

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+
}
575558
}
576559

577560
pub fn get_config(&mut self) -> [u32; 3] {
578561
// see Virtio specification v1.1 - 2.4.1
579562
unsafe {
580563
loop {
581564
let before = read_volatile(&self.config_generation);
582-
_mm_mfence();
565+
fence(Ordering::SeqCst);
583566
let config = read_volatile(&self.config);
584-
_mm_mfence();
567+
fence(Ordering::SeqCst);
585568
let after = read_volatile(&self.config_generation);
569+
fence(Ordering::SeqCst);
586570

587571
if before == after {
588572
return config;
@@ -594,12 +578,20 @@ impl MmioRegisterLayout {
594578
pub fn print_information(&mut self) {
595579
infoheader!(" MMIO RREGISTER LAYOUT INFORMATION ");
596580

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+
});
600588
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+
});
603595
infoentry!("Configuration space", "{:#X?}", self.get_config());
604596

605597
infofooter!();

0 commit comments

Comments
 (0)