@@ -9,12 +9,8 @@ use std::cmp::min;
9
9
use std:: num:: Wrapping ;
10
10
use std:: sync:: atomic:: { fence, Ordering } ;
11
11
12
- use utils:: usize_to_u64;
13
-
14
12
use crate :: logger:: error;
15
- use crate :: vstate:: memory:: {
16
- Address , Bitmap , ByteValued , Bytes , GuestAddress , GuestMemory , GuestMemoryMmap ,
17
- } ;
13
+ use crate :: vstate:: memory:: { Address , Bitmap , ByteValued , GuestAddress , GuestMemory } ;
18
14
19
15
pub const VIRTQ_DESC_F_NEXT : u16 = 0x1 ;
20
16
pub const VIRTQ_DESC_F_WRITE : u16 = 0x2 ;
@@ -72,14 +68,12 @@ unsafe impl ByteValued for UsedElement {}
72
68
73
69
/// A virtio descriptor chain.
74
70
#[ derive( Debug , Copy , Clone ) ]
75
- pub struct DescriptorChain < ' a , M : GuestMemory = GuestMemoryMmap > {
76
- desc_table : GuestAddress ,
71
+ pub struct DescriptorChain {
72
+ desc_table_ptr : * const Descriptor ,
73
+
77
74
queue_size : u16 ,
78
75
ttl : u16 , // used to prevent infinite chain cycles
79
76
80
- /// Reference to guest memory
81
- pub mem : & ' a M ,
82
-
83
77
/// Index into the descriptor table
84
78
pub index : u16 ,
85
79
@@ -97,38 +91,20 @@ pub struct DescriptorChain<'a, M: GuestMemory = GuestMemoryMmap> {
97
91
pub next : u16 ,
98
92
}
99
93
100
- impl < ' a , M : GuestMemory > DescriptorChain < ' a , M > {
94
+ impl DescriptorChain {
101
95
/// Creates a new `DescriptorChain` from the given memory and descriptor table.
102
96
///
103
97
/// Note that the desc_table and queue_size are assumed to be validated by the caller.
104
- fn checked_new (
105
- mem : & ' a M ,
106
- desc_table : GuestAddress ,
107
- queue_size : u16 ,
108
- index : u16 ,
109
- ) -> Option < Self > {
110
- if index >= queue_size {
98
+ fn checked_new ( desc_table_ptr : * const Descriptor , queue_size : u16 , index : u16 ) -> Option < Self > {
99
+ if queue_size <= index {
111
100
return None ;
112
101
}
113
102
114
- // There's no need for checking as we already validated the descriptor table and index
115
- // bounds.
116
- let desc_head = desc_table. unchecked_add ( u64:: from ( index) * 16 ) ;
117
-
118
- // These reads can't fail unless Guest memory is hopelessly broken.
119
- let desc = match mem. read_obj :: < Descriptor > ( desc_head) {
120
- Ok ( ret) => ret,
121
- Err ( err) => {
122
- error ! (
123
- "Failed to read virtio descriptor from memory at address {:#x}: {}" ,
124
- desc_head. 0 , err
125
- ) ;
126
- return None ;
127
- }
128
- } ;
103
+ // SAFETY:
104
+ // index is in 0..queue_size bounds
105
+ let desc = unsafe { desc_table_ptr. add ( usize:: from ( index) ) . read_volatile ( ) } ;
129
106
let chain = DescriptorChain {
130
- mem,
131
- desc_table,
107
+ desc_table_ptr,
132
108
queue_size,
133
109
ttl : queue_size,
134
110
index,
@@ -168,7 +144,7 @@ impl<'a, M: GuestMemory> DescriptorChain<'a, M> {
168
144
/// the head of the next _available_ descriptor chain.
169
145
pub fn next_descriptor ( & self ) -> Option < Self > {
170
146
if self . has_next ( ) {
171
- DescriptorChain :: checked_new ( self . mem , self . desc_table , self . queue_size , self . next ) . map (
147
+ DescriptorChain :: checked_new ( self . desc_table_ptr , self . queue_size , self . next ) . map (
172
148
|mut c| {
173
149
c. ttl = self . ttl - 1 ;
174
150
c
@@ -181,19 +157,19 @@ impl<'a, M: GuestMemory> DescriptorChain<'a, M> {
181
157
}
182
158
183
159
#[ derive( Debug ) ]
184
- pub struct DescriptorIterator < ' a > ( Option < DescriptorChain < ' a > > ) ;
160
+ pub struct DescriptorIterator ( Option < DescriptorChain > ) ;
185
161
186
- impl < ' a > IntoIterator for DescriptorChain < ' a > {
187
- type Item = DescriptorChain < ' a > ;
188
- type IntoIter = DescriptorIterator < ' a > ;
162
+ impl IntoIterator for DescriptorChain {
163
+ type Item = DescriptorChain ;
164
+ type IntoIter = DescriptorIterator ;
189
165
190
166
fn into_iter ( self ) -> Self :: IntoIter {
191
167
DescriptorIterator ( Some ( self ) )
192
168
}
193
169
}
194
170
195
- impl < ' a > Iterator for DescriptorIterator < ' a > {
196
- type Item = DescriptorChain < ' a > ;
171
+ impl Iterator for DescriptorIterator {
172
+ type Item = DescriptorChain ;
197
173
198
174
fn next ( & mut self ) -> Option < Self :: Item > {
199
175
self . 0 . take ( ) . map ( |desc| {
@@ -524,7 +500,7 @@ impl Queue {
524
500
}
525
501
526
502
/// Pop the first available descriptor chain from the avail ring.
527
- pub fn pop < ' b , M : GuestMemory > ( & mut self , mem : & ' b M ) -> Option < DescriptorChain < ' b , M > > {
503
+ pub fn pop < M : GuestMemory > ( & mut self , mem : & M ) -> Option < DescriptorChain > {
528
504
debug_assert ! ( self . is_valid( mem) ) ;
529
505
530
506
let len = self . len ( ) ;
@@ -548,15 +524,15 @@ impl Queue {
548
524
return None ;
549
525
}
550
526
551
- self . do_pop_unchecked ( mem )
527
+ self . do_pop_unchecked ( )
552
528
}
553
529
554
530
/// Try to pop the first available descriptor chain from the avail ring.
555
531
/// If no descriptor is available, enable notifications.
556
- pub fn pop_or_enable_notification < ' b , M : GuestMemory > (
532
+ pub fn pop_or_enable_notification < M : GuestMemory > (
557
533
& mut self ,
558
- mem : & ' b M ,
559
- ) -> Option < DescriptorChain < ' b , M > > {
534
+ mem : & M ,
535
+ ) -> Option < DescriptorChain > {
560
536
if !self . uses_notif_suppression {
561
537
return self . pop ( mem) ;
562
538
}
@@ -565,18 +541,15 @@ impl Queue {
565
541
return None ;
566
542
}
567
543
568
- self . do_pop_unchecked ( mem )
544
+ self . do_pop_unchecked ( )
569
545
}
570
546
571
547
/// Pop the first available descriptor chain from the avail ring.
572
548
///
573
549
/// # Important
574
550
/// This is an internal method that ASSUMES THAT THERE ARE AVAILABLE DESCRIPTORS. Otherwise it
575
551
/// will retrieve a descriptor that contains garbage data (obsolete/empty).
576
- fn do_pop_unchecked < ' b , M : GuestMemory > (
577
- & mut self ,
578
- mem : & ' b M ,
579
- ) -> Option < DescriptorChain < ' b , M > > {
552
+ fn do_pop_unchecked ( & mut self ) -> Option < DescriptorChain > {
580
553
// This fence ensures all subsequent reads see the updated driver writes.
581
554
fence ( Ordering :: Acquire ) ;
582
555
@@ -592,11 +565,12 @@ impl Queue {
592
565
// index is bound by the queue size
593
566
let desc_index = unsafe { self . avail_ring_ring_get ( usize:: from ( idx) ) } ;
594
567
595
- DescriptorChain :: checked_new ( mem , self . desc_table_address , self . actual_size ( ) , desc_index)
596
- . map ( |dc| {
568
+ DescriptorChain :: checked_new ( self . desc_table_ptr , self . actual_size ( ) , desc_index) . map (
569
+ |dc| {
597
570
self . next_avail += Wrapping ( 1 ) ;
598
571
dc
599
- } )
572
+ } ,
573
+ )
600
574
}
601
575
602
576
/// Undo the effects of the last `self.pop()` call.
@@ -1175,12 +1149,8 @@ mod verification {
1175
1149
let ProofContext ( queue, mem) = ProofContext :: bounded_queue ( ) ;
1176
1150
1177
1151
let index = kani:: any ( ) ;
1178
- let maybe_chain = DescriptorChain :: checked_new (
1179
- & mem,
1180
- queue. desc_table_address ,
1181
- queue. actual_size ( ) ,
1182
- index,
1183
- ) ;
1152
+ let maybe_chain =
1153
+ DescriptorChain :: checked_new ( queue. desc_table_ptr , queue. actual_size ( ) , index) ;
1184
1154
1185
1155
if index >= queue. actual_size ( ) {
1186
1156
assert ! ( maybe_chain. is_none( ) )
@@ -1210,6 +1180,8 @@ mod verification {
1210
1180
#[ cfg( test) ]
1211
1181
mod tests {
1212
1182
1183
+ use vm_memory:: Bytes ;
1184
+
1213
1185
pub use super :: * ;
1214
1186
use crate :: devices:: virtio:: queue:: QueueError :: DescIndexOutOfBounds ;
1215
1187
use crate :: devices:: virtio:: test_utils:: { default_mem, VirtQueue } ;
@@ -1230,14 +1202,13 @@ mod tests {
1230
1202
fn test_checked_new_descriptor_chain ( ) {
1231
1203
let m = & multi_region_mem ( & [ ( GuestAddress ( 0 ) , 0x10000 ) , ( GuestAddress ( 0x20000 ) , 0x2000 ) ] ) ;
1232
1204
let vq = VirtQueue :: new ( GuestAddress ( 0 ) , m, 16 ) ;
1205
+ let mut q = vq. create_queue ( ) ;
1206
+ q. initialize ( m) . unwrap ( ) ;
1233
1207
1234
1208
assert ! ( vq. end( ) . 0 < 0x1000 ) ;
1235
1209
1236
1210
// index >= queue_size
1237
- assert ! ( DescriptorChain :: checked_new( m, vq. dtable_start( ) , 16 , 16 ) . is_none( ) ) ;
1238
-
1239
- // desc_table address is way off
1240
- assert ! ( DescriptorChain :: checked_new( m, GuestAddress ( 0x00ff_ffff_ffff ) , 16 , 0 ) . is_none( ) ) ;
1211
+ assert ! ( DescriptorChain :: checked_new( q. desc_table_ptr, 16 , 16 ) . is_none( ) ) ;
1241
1212
1242
1213
// Let's create an invalid chain.
1243
1214
{
@@ -1248,18 +1219,17 @@ mod tests {
1248
1219
// .. but the index of the next descriptor is too large
1249
1220
vq. dtable [ 0 ] . next . set ( 16 ) ;
1250
1221
1251
- assert ! ( DescriptorChain :: checked_new( m , vq . dtable_start ( ) , 16 , 0 ) . is_none( ) ) ;
1222
+ assert ! ( DescriptorChain :: checked_new( q . desc_table_ptr , 16 , 0 ) . is_none( ) ) ;
1252
1223
}
1253
1224
1254
1225
// Finally, let's test an ok chain.
1255
1226
{
1256
1227
vq. dtable [ 0 ] . next . set ( 1 ) ;
1257
1228
vq. dtable [ 1 ] . set ( 0x2000 , 0x1000 , 0 , 0 ) ;
1258
1229
1259
- let c = DescriptorChain :: checked_new ( m , vq . dtable_start ( ) , 16 , 0 ) . unwrap ( ) ;
1230
+ let c = DescriptorChain :: checked_new ( q . desc_table_ptr , 16 , 0 ) . unwrap ( ) ;
1260
1231
1261
- assert_eq ! ( c. mem as * const GuestMemoryMmap , m as * const GuestMemoryMmap ) ;
1262
- assert_eq ! ( c. desc_table, vq. dtable_start( ) ) ;
1232
+ assert_eq ! ( c. desc_table_ptr, q. desc_table_ptr) ;
1263
1233
assert_eq ! ( c. queue_size, 16 ) ;
1264
1234
assert_eq ! ( c. ttl, c. queue_size) ;
1265
1235
assert_eq ! ( c. index, 0 ) ;
0 commit comments