dbs_address_space/
layout.rs

1// Copyright (C) 2021 Alibaba Cloud. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use lazy_static::lazy_static;
5
6use crate::{AddressSpaceRegion, AddressSpaceRegionType};
7
8// Max retry times for reading /proc
9const PROC_READ_RETRY: u64 = 5;
10
11lazy_static! {
12    /// Upper bound of host memory.
13    pub static ref USABLE_END: u64 = {
14        for _ in 0..PROC_READ_RETRY {
15            if let Ok(buf) = std::fs::read("/proc/meminfo") {
16                let content = String::from_utf8_lossy(&buf);
17                for line in content.lines() {
18                    if line.starts_with("MemTotal:") {
19                        if let Some(end) = line.find(" kB") {
20                            if let Ok(size) = line[9..end].trim().parse::<u64>() {
21                                return (size << 10) - 1;
22                            }
23                        }
24                    }
25                }
26            }
27        }
28        panic!("Exceed max retry times. Cannot get total mem size from /proc/meminfo");
29    };
30}
31
32/// Address space layout configuration.
33///
34/// The layout configuration must guarantee that `mem_start` <= `mem_end` <= `phys_end`.
35/// Non-memory region should be arranged into the range [mem_end, phys_end).
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct AddressSpaceLayout {
38    /// end of guest physical address
39    pub phys_end: u64,
40    /// start of guest memory address
41    pub mem_start: u64,
42    /// end of guest memory address
43    pub mem_end: u64,
44    /// end of usable memory address
45    pub usable_end: u64,
46}
47
48impl AddressSpaceLayout {
49    /// Create a new instance of `AddressSpaceLayout`.
50    pub fn new(phys_end: u64, mem_start: u64, mem_end: u64) -> Self {
51        AddressSpaceLayout {
52            phys_end,
53            mem_start,
54            mem_end,
55            usable_end: *USABLE_END,
56        }
57    }
58
59    /// Check whether an region is valid with the constraints of the layout.
60    pub fn is_region_valid(&self, region: &AddressSpaceRegion) -> bool {
61        let region_end = match region.base.0.checked_add(region.size) {
62            None => return false,
63            Some(v) => v,
64        };
65
66        match region.ty {
67            AddressSpaceRegionType::DefaultMemory => {
68                if region.base.0 < self.mem_start || region_end > self.mem_end {
69                    return false;
70                }
71            }
72            AddressSpaceRegionType::DeviceMemory | AddressSpaceRegionType::DAXMemory => {
73                if region.base.0 < self.mem_end || region_end > self.phys_end {
74                    return false;
75                }
76            }
77        }
78
79        true
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use vm_memory::GuestAddress;
87
88    #[test]
89    fn test_is_region_valid() {
90        let layout = AddressSpaceLayout::new(0x1_0000_0000, 0x1000_0000, 0x2000_0000);
91
92        let region = AddressSpaceRegion::new(
93            AddressSpaceRegionType::DefaultMemory,
94            GuestAddress(0x0),
95            0x1_0000,
96        );
97        assert!(!layout.is_region_valid(&region));
98        let region = AddressSpaceRegion::new(
99            AddressSpaceRegionType::DefaultMemory,
100            GuestAddress(0x2000_0000),
101            0x1_0000,
102        );
103        assert!(!layout.is_region_valid(&region));
104        let region = AddressSpaceRegion::new(
105            AddressSpaceRegionType::DefaultMemory,
106            GuestAddress(0x1_0000),
107            0x2000_0000,
108        );
109        assert!(!layout.is_region_valid(&region));
110        let region = AddressSpaceRegion::new(
111            AddressSpaceRegionType::DefaultMemory,
112            GuestAddress(u64::MAX),
113            0x1_0000_0000,
114        );
115        assert!(!layout.is_region_valid(&region));
116        let region = AddressSpaceRegion::new(
117            AddressSpaceRegionType::DefaultMemory,
118            GuestAddress(0x1000_0000),
119            0x1_0000,
120        );
121        assert!(layout.is_region_valid(&region));
122
123        let region = AddressSpaceRegion::new(
124            AddressSpaceRegionType::DeviceMemory,
125            GuestAddress(0x1000_0000),
126            0x1_0000,
127        );
128        assert!(!layout.is_region_valid(&region));
129        let region = AddressSpaceRegion::new(
130            AddressSpaceRegionType::DeviceMemory,
131            GuestAddress(0x1_0000_0000),
132            0x1_0000,
133        );
134        assert!(!layout.is_region_valid(&region));
135        let region = AddressSpaceRegion::new(
136            AddressSpaceRegionType::DeviceMemory,
137            GuestAddress(0x1_0000),
138            0x1_0000_0000,
139        );
140        assert!(!layout.is_region_valid(&region));
141        let region = AddressSpaceRegion::new(
142            AddressSpaceRegionType::DeviceMemory,
143            GuestAddress(u64::MAX),
144            0x1_0000_0000,
145        );
146        assert!(!layout.is_region_valid(&region));
147        let region = AddressSpaceRegion::new(
148            AddressSpaceRegionType::DeviceMemory,
149            GuestAddress(0x8000_0000),
150            0x1_0000,
151        );
152        assert!(layout.is_region_valid(&region));
153    }
154}