• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019-2021 Alibaba Cloud. All rights reserved.
2 // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
3 //
4 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 //
6 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE-BSD-Google file.
9 
10 //! Common traits and structs for vhost-user backend drivers.
11 
12 use base::{RawDescriptor, INVALID_DESCRIPTOR};
13 use std::cell::RefCell;
14 use std::sync::RwLock;
15 
16 use base::Event;
17 
18 use super::Result;
19 
20 /// Maximum number of memory regions supported.
21 pub const VHOST_MAX_MEMORY_REGIONS: usize = 255;
22 
23 /// Vring configuration data.
24 pub struct VringConfigData {
25     /// Maximum queue size supported by the driver.
26     pub queue_max_size: u16,
27     /// Actual queue size negotiated by the driver.
28     pub queue_size: u16,
29     /// Bitmask of vring flags.
30     pub flags: u32,
31     /// Descriptor table address.
32     pub desc_table_addr: u64,
33     /// Used ring buffer address.
34     pub used_ring_addr: u64,
35     /// Available ring buffer address.
36     pub avail_ring_addr: u64,
37     /// Optional address for logging.
38     pub log_addr: Option<u64>,
39 }
40 
41 impl VringConfigData {
42     /// Check whether the log (flag, address) pair is valid.
is_log_addr_valid(&self) -> bool43     pub fn is_log_addr_valid(&self) -> bool {
44         if self.flags & 0x1 != 0 && self.log_addr.is_none() {
45             return false;
46         }
47 
48         true
49     }
50 
51     /// Get the log address, default to zero if not available.
get_log_addr(&self) -> u6452     pub fn get_log_addr(&self) -> u64 {
53         if self.flags & 0x1 != 0 && self.log_addr.is_some() {
54             self.log_addr.unwrap()
55         } else {
56             0
57         }
58     }
59 }
60 
61 /// Memory region configuration data.
62 #[derive(Clone, Copy)]
63 pub struct VhostUserMemoryRegionInfo {
64     /// Guest physical address of the memory region.
65     pub guest_phys_addr: u64,
66     /// Size of the memory region.
67     pub memory_size: u64,
68     /// Virtual address in the current process.
69     pub userspace_addr: u64,
70     /// Optional offset where region starts in the mapped memory.
71     pub mmap_offset: u64,
72     /// Optional file descriptor for mmap.
73     pub mmap_handle: RawDescriptor,
74 }
75 
76 // We cannot derive default because windows Handle does not implement a default.
77 impl Default for VhostUserMemoryRegionInfo {
default() -> Self78     fn default() -> Self {
79         VhostUserMemoryRegionInfo {
80             guest_phys_addr: u64::default(),
81             memory_size: u64::default(),
82             userspace_addr: u64::default(),
83             mmap_offset: u64::default(),
84             mmap_handle: INVALID_DESCRIPTOR,
85         }
86     }
87 }
88 
89 /// An interface for setting up vhost-based backend drivers with interior mutability.
90 ///
91 /// Vhost devices are subset of virtio devices, which improve virtio device's performance by
92 /// delegating data plane operations to dedicated IO service processes. Vhost devices use the
93 /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to
94 /// virtio devices.
95 ///
96 /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the
97 /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service
98 /// processes, and slow path for device configuration are still handled by the VMM process. It may
99 /// also be used to control access permissions of virtio backend devices.
100 pub trait VhostBackend: std::marker::Sized {
101     /// Get a bitmask of supported virtio/vhost features.
get_features(&self) -> Result<u64>102     fn get_features(&self) -> Result<u64>;
103 
104     /// Inform the vhost subsystem which features to enable.
105     /// This should be a subset of supported features from get_features().
106     ///
107     /// # Arguments
108     /// * `features` - Bitmask of features to set.
set_features(&self, features: u64) -> Result<()>109     fn set_features(&self, features: u64) -> Result<()>;
110 
111     /// Set the current process as the owner of the vhost backend.
112     /// This must be run before any other vhost commands.
set_owner(&self) -> Result<()>113     fn set_owner(&self) -> Result<()>;
114 
115     /// Used to be sent to request disabling all rings
116     /// This is no longer used.
reset_owner(&self) -> Result<()>117     fn reset_owner(&self) -> Result<()>;
118 
119     /// Set the guest memory mappings for vhost to use.
set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>120     fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>;
121 
122     /// Set base address for page modification logging.
set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>123     fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>;
124 
125     /// Specify an event file descriptor to signal on log write.
set_log_fd(&self, fd: RawDescriptor) -> Result<()>126     fn set_log_fd(&self, fd: RawDescriptor) -> Result<()>;
127 
128     /// Set the number of descriptors in the vring.
129     ///
130     /// # Arguments
131     /// * `queue_index` - Index of the queue to set descriptor count for.
132     /// * `num` - Number of descriptors in the queue.
set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>133     fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>;
134 
135     /// Set the addresses for a given vring.
136     ///
137     /// # Arguments
138     /// * `queue_index` - Index of the queue to set addresses for.
139     /// * `config_data` - Configuration data for a vring.
set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>140     fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>;
141 
142     /// Set the first index to look for available descriptors.
143     ///
144     /// # Arguments
145     /// * `queue_index` - Index of the queue to modify.
146     /// * `num` - Index where available descriptors start.
set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>147     fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>;
148 
149     /// Get the available vring base offset.
get_vring_base(&self, queue_index: usize) -> Result<u32>150     fn get_vring_base(&self, queue_index: usize) -> Result<u32>;
151 
152     /// Set the event to trigger when buffers have been used by the host.
153     ///
154     /// # Arguments
155     /// * `queue_index` - Index of the queue to modify.
156     /// * `event` - Event to trigger.
set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>157     fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>;
158 
159     /// Set the event that will be signaled by the guest when buffers are
160     /// available for the host to process.
161     ///
162     /// # Arguments
163     /// * `queue_index` - Index of the queue to modify.
164     /// * `event` - Event that will be signaled from guest.
set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>165     fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>;
166 
167     /// Set the event that will be signaled by the guest when error happens.
168     ///
169     /// # Arguments
170     /// * `queue_index` - Index of the queue to modify.
171     /// * `event` - Event that will be signaled from guest.
set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>172     fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>;
173 }
174 
175 /// An interface for setting up vhost-based backend drivers.
176 ///
177 /// Vhost devices are subset of virtio devices, which improve virtio device's performance by
178 /// delegating data plane operations to dedicated IO service processes. Vhost devices use the
179 /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to
180 /// virtio devices.
181 ///
182 /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the
183 /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service
184 /// processes, and slow path for device configuration are still handled by the VMM process. It may
185 /// also be used to control access permissions of virtio backend devices.
186 pub trait VhostBackendMut: std::marker::Sized {
187     /// Get a bitmask of supported virtio/vhost features.
get_features(&mut self) -> Result<u64>188     fn get_features(&mut self) -> Result<u64>;
189 
190     /// Inform the vhost subsystem which features to enable.
191     /// This should be a subset of supported features from get_features().
192     ///
193     /// # Arguments
194     /// * `features` - Bitmask of features to set.
set_features(&mut self, features: u64) -> Result<()>195     fn set_features(&mut self, features: u64) -> Result<()>;
196 
197     /// Set the current process as the owner of the vhost backend.
198     /// This must be run before any other vhost commands.
set_owner(&mut self) -> Result<()>199     fn set_owner(&mut self) -> Result<()>;
200 
201     /// Used to be sent to request disabling all rings
202     /// This is no longer used.
reset_owner(&mut self) -> Result<()>203     fn reset_owner(&mut self) -> Result<()>;
204 
205     /// Set the guest memory mappings for vhost to use.
set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>206     fn set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>;
207 
208     /// Set base address for page modification logging.
set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>209     fn set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>;
210 
211     /// Specify an event file descriptor to signal on log write.
set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>212     fn set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>;
213 
214     /// Set the number of descriptors in the vring.
215     ///
216     /// # Arguments
217     /// * `queue_index` - Index of the queue to set descriptor count for.
218     /// * `num` - Number of descriptors in the queue.
set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>219     fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>;
220 
221     /// Set the addresses for a given vring.
222     ///
223     /// # Arguments
224     /// * `queue_index` - Index of the queue to set addresses for.
225     /// * `config_data` - Configuration data for a vring.
set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()>226     fn set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()>;
227 
228     /// Set the first index to look for available descriptors.
229     ///
230     /// # Arguments
231     /// * `queue_index` - Index of the queue to modify.
232     /// * `num` - Index where available descriptors start.
set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>233     fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>;
234 
235     /// Get the available vring base offset.
get_vring_base(&mut self, queue_index: usize) -> Result<u32>236     fn get_vring_base(&mut self, queue_index: usize) -> Result<u32>;
237 
238     /// Set the event to trigger when buffers have been used by the host.
239     ///
240     /// # Arguments
241     /// * `queue_index` - Index of the queue to modify.
242     /// * `event` - Event to trigger.
set_vring_call(&mut self, queue_index: usize, event: &Event) -> Result<()>243     fn set_vring_call(&mut self, queue_index: usize, event: &Event) -> Result<()>;
244 
245     /// Set the event that will be signaled by the guest when buffers are
246     /// available for the host to process.
247     ///
248     /// # Arguments
249     /// * `queue_index` - Index of the queue to modify.
250     /// * `event` - Event that will be signaled from guest.
set_vring_kick(&mut self, queue_index: usize, event: &Event) -> Result<()>251     fn set_vring_kick(&mut self, queue_index: usize, event: &Event) -> Result<()>;
252 
253     /// Set the event that will be signaled by the guest when error happens.
254     ///
255     /// # Arguments
256     /// * `queue_index` - Index of the queue to modify.
257     /// * `event` - Event that will be signaled from guest.
set_vring_err(&mut self, queue_index: usize, event: &Event) -> Result<()>258     fn set_vring_err(&mut self, queue_index: usize, event: &Event) -> Result<()>;
259 }
260 
261 impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
get_features(&self) -> Result<u64>262     fn get_features(&self) -> Result<u64> {
263         self.write().unwrap().get_features()
264     }
265 
set_features(&self, features: u64) -> Result<()>266     fn set_features(&self, features: u64) -> Result<()> {
267         self.write().unwrap().set_features(features)
268     }
269 
set_owner(&self) -> Result<()>270     fn set_owner(&self) -> Result<()> {
271         self.write().unwrap().set_owner()
272     }
273 
reset_owner(&self) -> Result<()>274     fn reset_owner(&self) -> Result<()> {
275         self.write().unwrap().reset_owner()
276     }
277 
set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>278     fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
279         self.write().unwrap().set_mem_table(regions)
280     }
281 
set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>282     fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
283         self.write().unwrap().set_log_base(base, fd)
284     }
285 
set_log_fd(&self, fd: RawDescriptor) -> Result<()>286     fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> {
287         self.write().unwrap().set_log_fd(fd)
288     }
289 
set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>290     fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
291         self.write().unwrap().set_vring_num(queue_index, num)
292     }
293 
set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>294     fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
295         self.write()
296             .unwrap()
297             .set_vring_addr(queue_index, config_data)
298     }
299 
set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>300     fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
301         self.write().unwrap().set_vring_base(queue_index, base)
302     }
303 
get_vring_base(&self, queue_index: usize) -> Result<u32>304     fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
305         self.write().unwrap().get_vring_base(queue_index)
306     }
307 
set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>308     fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
309         self.write().unwrap().set_vring_call(queue_index, event)
310     }
311 
set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>312     fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
313         self.write().unwrap().set_vring_kick(queue_index, event)
314     }
315 
set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>316     fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
317         self.write().unwrap().set_vring_err(queue_index, event)
318     }
319 }
320 
321 impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
get_features(&self) -> Result<u64>322     fn get_features(&self) -> Result<u64> {
323         self.borrow_mut().get_features()
324     }
325 
set_features(&self, features: u64) -> Result<()>326     fn set_features(&self, features: u64) -> Result<()> {
327         self.borrow_mut().set_features(features)
328     }
329 
set_owner(&self) -> Result<()>330     fn set_owner(&self) -> Result<()> {
331         self.borrow_mut().set_owner()
332     }
333 
reset_owner(&self) -> Result<()>334     fn reset_owner(&self) -> Result<()> {
335         self.borrow_mut().reset_owner()
336     }
337 
set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>338     fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
339         self.borrow_mut().set_mem_table(regions)
340     }
341 
set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>342     fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
343         self.borrow_mut().set_log_base(base, fd)
344     }
345 
set_log_fd(&self, fd: RawDescriptor) -> Result<()>346     fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> {
347         self.borrow_mut().set_log_fd(fd)
348     }
349 
set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>350     fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
351         self.borrow_mut().set_vring_num(queue_index, num)
352     }
353 
set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>354     fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
355         self.borrow_mut().set_vring_addr(queue_index, config_data)
356     }
357 
set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>358     fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
359         self.borrow_mut().set_vring_base(queue_index, base)
360     }
361 
get_vring_base(&self, queue_index: usize) -> Result<u32>362     fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
363         self.borrow_mut().get_vring_base(queue_index)
364     }
365 
set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>366     fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
367         self.borrow_mut().set_vring_call(queue_index, event)
368     }
369 
set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>370     fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
371         self.borrow_mut().set_vring_kick(queue_index, event)
372     }
373 
set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>374     fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
375         self.borrow_mut().set_vring_err(queue_index, event)
376     }
377 }
378 #[cfg(test)]
379 mod tests {
380     use super::*;
381 
382     struct MockBackend {}
383 
384     impl VhostBackendMut for MockBackend {
get_features(&mut self) -> Result<u64>385         fn get_features(&mut self) -> Result<u64> {
386             Ok(0x1)
387         }
388 
set_features(&mut self, features: u64) -> Result<()>389         fn set_features(&mut self, features: u64) -> Result<()> {
390             assert_eq!(features, 0x1);
391             Ok(())
392         }
393 
set_owner(&mut self) -> Result<()>394         fn set_owner(&mut self) -> Result<()> {
395             Ok(())
396         }
397 
reset_owner(&mut self) -> Result<()>398         fn reset_owner(&mut self) -> Result<()> {
399             Ok(())
400         }
401 
set_mem_table(&mut self, _regions: &[VhostUserMemoryRegionInfo]) -> Result<()>402         fn set_mem_table(&mut self, _regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
403             Ok(())
404         }
405 
set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>406         fn set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
407             assert_eq!(base, 0x100);
408             #[allow(clippy::unnecessary_cast)]
409             let rd = 100 as RawDescriptor;
410             assert_eq!(fd, Some(rd));
411             Ok(())
412         }
413 
set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>414         fn set_log_fd(&mut self, fd: RawDescriptor) -> Result<()> {
415             #[allow(clippy::unnecessary_cast)]
416             let rd = 100 as RawDescriptor;
417             assert_eq!(fd, rd);
418             Ok(())
419         }
420 
set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>421         fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()> {
422             assert_eq!(queue_index, 1);
423             assert_eq!(num, 256);
424             Ok(())
425         }
426 
set_vring_addr( &mut self, queue_index: usize, _config_data: &VringConfigData, ) -> Result<()>427         fn set_vring_addr(
428             &mut self,
429             queue_index: usize,
430             _config_data: &VringConfigData,
431         ) -> Result<()> {
432             assert_eq!(queue_index, 1);
433             Ok(())
434         }
435 
set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>436         fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()> {
437             assert_eq!(queue_index, 1);
438             assert_eq!(base, 2);
439             Ok(())
440         }
441 
get_vring_base(&mut self, queue_index: usize) -> Result<u32>442         fn get_vring_base(&mut self, queue_index: usize) -> Result<u32> {
443             assert_eq!(queue_index, 1);
444             Ok(2)
445         }
446 
set_vring_call(&mut self, queue_index: usize, _event: &Event) -> Result<()>447         fn set_vring_call(&mut self, queue_index: usize, _event: &Event) -> Result<()> {
448             assert_eq!(queue_index, 1);
449             Ok(())
450         }
451 
set_vring_kick(&mut self, queue_index: usize, _event: &Event) -> Result<()>452         fn set_vring_kick(&mut self, queue_index: usize, _event: &Event) -> Result<()> {
453             assert_eq!(queue_index, 1);
454             Ok(())
455         }
456 
set_vring_err(&mut self, queue_index: usize, _event: &Event) -> Result<()>457         fn set_vring_err(&mut self, queue_index: usize, _event: &Event) -> Result<()> {
458             assert_eq!(queue_index, 1);
459             Ok(())
460         }
461     }
462 
463     #[test]
test_vring_backend_mut()464     fn test_vring_backend_mut() {
465         let b = RwLock::new(MockBackend {});
466 
467         assert_eq!(b.get_features().unwrap(), 0x1);
468         b.set_features(0x1).unwrap();
469         b.set_owner().unwrap();
470         b.reset_owner().unwrap();
471         b.set_mem_table(&[]).unwrap();
472 
473         #[allow(clippy::unnecessary_cast)]
474         let rd = 100 as RawDescriptor;
475         b.set_log_base(0x100, Some(rd)).unwrap();
476         b.set_log_fd(rd).unwrap();
477         b.set_vring_num(1, 256).unwrap();
478 
479         let config = VringConfigData {
480             queue_max_size: 0x1000,
481             queue_size: 0x2000,
482             flags: 0x0,
483             desc_table_addr: 0x4000,
484             used_ring_addr: 0x5000,
485             avail_ring_addr: 0x6000,
486             log_addr: None,
487         };
488         b.set_vring_addr(1, &config).unwrap();
489 
490         b.set_vring_base(1, 2).unwrap();
491         assert_eq!(b.get_vring_base(1).unwrap(), 2);
492 
493         let event = Event::new().unwrap();
494         b.set_vring_call(1, &event).unwrap();
495         b.set_vring_kick(1, &event).unwrap();
496         b.set_vring_err(1, &event).unwrap();
497     }
498 
499     #[test]
test_vring_config_data()500     fn test_vring_config_data() {
501         let mut config = VringConfigData {
502             queue_max_size: 0x1000,
503             queue_size: 0x2000,
504             flags: 0x0,
505             desc_table_addr: 0x4000,
506             used_ring_addr: 0x5000,
507             avail_ring_addr: 0x6000,
508             log_addr: None,
509         };
510 
511         assert!(config.is_log_addr_valid());
512         assert_eq!(config.get_log_addr(), 0);
513 
514         config.flags = 0x1;
515         assert!(!config.is_log_addr_valid());
516         assert_eq!(config.get_log_addr(), 0);
517 
518         config.log_addr = Some(0x7000);
519         assert!(config.is_log_addr_valid());
520         assert_eq!(config.get_log_addr(), 0x7000);
521 
522         config.flags = 0x0;
523         assert!(config.is_log_addr_valid());
524         assert_eq!(config.get_log_addr(), 0);
525     }
526 }
527