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