dfu/
memory_layout.rs

1use crate::error::Error;
2use serde::{Serialize, Serializer};
3use std::fmt;
4use std::str::FromStr;
5#[derive(Debug, Serialize)]
6pub struct Page {
7    #[serde(serialize_with = "to_hex32_string")]
8    pub(crate) address: u32,
9    pub(crate) size: u32,
10}
11
12fn to_hex32_string<S>(value: &u32, s: S) -> Result<S::Ok, S::Error>
13where
14    S: Serializer,
15{
16    s.serialize_str(&format!("0x{:08X}", value))
17}
18
19#[derive(Debug, Serialize)]
20pub struct MemoryLayout {
21    pages: Vec<Page>,
22}
23
24impl FromStr for MemoryLayout {
25    type Err = Error;
26    fn from_str(s: &str) -> Result<Self, Error> {
27        let s = &s.replace("0x", "");
28        let mut sp = s.split('/');
29        let address = sp.nth(1).ok_or_else(|| Error::MemoryLayout(s.into()))?;
30        let mut address =
31            u32::from_str_radix(&address, 16).map_err(|_| Error::MemoryLayout(s.into()))?;
32        let mut pages = Vec::new();
33        for p in sp
34            .next()
35            .ok_or_else(|| Error::MemoryLayout(format!("Missing pages in {}", s)))?
36            .split(',')
37        {
38            let mut keyval = p.split('*');
39            let page_count: u32 = keyval
40                .next()
41                .ok_or_else(|| Error::MemoryLayout(p.into()))?
42                .parse()
43                .map_err(|_| Error::MemoryLayout(p.into()))?;
44            let valprefix = keyval.next().ok_or_else(|| Error::MemoryLayout(p.into()))?;
45            let size = valprefix.trim_matches(char::is_alphabetic);
46            let prefix = valprefix.trim_matches(char::is_numeric);
47            let mut size: u32 = size.parse().map_err(|_| Error::MemoryLayout(size.into()))?;
48            match &prefix[0..1] {
49                "K" => size *= 1024,
50                "M" => size *= 1024 * 1024,
51                _ => {
52                    return Err(Error::MemoryLayout(format!("Invalid prefix {}", prefix)));
53                }
54            }
55            for _ in 0..page_count {
56                pages.push(Page { address, size });
57                address += size;
58            }
59        }
60        Ok(Self { pages })
61    }
62}
63
64impl fmt::Display for MemoryLayout {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        writeln!(f, "Show memory layout:")?;
67        writeln!(f)?;
68        for (i, p) in self.pages.iter().enumerate() {
69            writeln!(
70                f,
71                "{}: Start: 0x{:08X} Size: {} bytes",
72                i, p.address, p.size
73            )?;
74        }
75
76        write!(f, "")
77    }
78}
79
80impl MemoryLayout {
81    pub fn pages(&self) -> &Vec<Page> {
82        &self.pages
83    }
84
85    /// Return num_pages in region specified
86    pub fn num_pages(&self, mut address: u32, length: u32) -> Result<usize, Error> {
87        let mut pages = 0;
88        let end = address + length;
89        while address < end {
90            let p = self.address(address)?;
91            address += p.size;
92            pages += 1;
93        }
94        Ok(pages)
95    }
96
97    pub fn address(&self, address: u32) -> Result<Page, Error> {
98        for p in &self.pages {
99            if address >= p.address && address < p.address + p.size {
100                return Ok(Page {
101                    address: p.address,
102                    size: p.size,
103                });
104            }
105        }
106        Err(Error::Address(address))
107    }
108}
109
110mod tests {
111    #[test]
112    fn test_memory_address() {
113        use super::MemoryLayout;
114        use std::str::FromStr;
115        // 0: 0x0801_0000 to 0801_3FFF 16K
116        // 1: 0x0801_4000 to 0801_7FFF 16K
117        // 2: 0x0801_8000 to 0802_7FFF 64K
118        let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K").unwrap();
119        assert_eq!(true, m.address(0x0800_0000).is_err());
120        let p = m.address(0x0801_0100).unwrap();
121        assert_eq!(0x0801_0000, p.address);
122        assert_eq!(0x4000, p.size);
123        let p = m.address(0x0801_4000).unwrap();
124        assert_eq!(0x0801_4000, p.address);
125        assert_eq!(0x4000, p.size);
126
127        let p = m.address(0x0801_8001).unwrap();
128        assert_eq!(0x0801_8000, p.address);
129        assert_eq!(0x10000, p.size);
130        assert_eq!(true, m.address(0x0802_7FFF).is_ok());
131
132        assert_eq!(true, m.address(0x0802_8000).is_err());
133    }
134    #[test]
135    fn test_memory_num_pages() {
136        use super::MemoryLayout;
137        use std::str::FromStr;
138        // 0: 0x0801_0000 to 0801_3FFF 16K
139        // 1: 0x0801_4000 to 0801_7FFF 16K
140        // 2: 0x0801_8000 to 0802_7FFF 64K
141        let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K").unwrap();
142        assert_eq!(true, m.num_pages(0x0800_0000, 0xFFFF).is_err());
143        let n = m.num_pages(0x0801_0000, 0xFFFF).unwrap();
144        assert_eq!(3, n);
145
146        let n = m.num_pages(0x0801_0000, 0x2000).unwrap();
147        assert_eq!(1, n);
148
149        let n = m.num_pages(0x0801_0000, 0x4000).unwrap();
150        assert_eq!(1, n);
151
152        let n = m.num_pages(0x0801_0000, 0x4001).unwrap();
153        assert_eq!(2, n);
154
155        let n = m.num_pages(0x0801_4000, 0x2000).unwrap();
156        assert_eq!(1, n);
157
158        let n = m.num_pages(0x0801_4000, 0x8000).unwrap();
159        assert_eq!(2, n);
160    }
161    #[test]
162    fn test_memory_from() {
163        use super::MemoryLayout;
164        use std::str::FromStr;
165        assert_eq!(true, MemoryLayout::from_str("/").is_err());
166        let m = MemoryLayout::from_str("/0x08008000");
167        assert_eq!(true, m.is_err());
168
169        let m = MemoryLayout::from_str("/0x08001000/02*16K");
170        assert_eq!(true, m.is_ok());
171        let m = m.unwrap();
172        let p = m.pages();
173        assert_eq!(2, p.len());
174        assert_eq!(16384, p.iter().nth(0).unwrap().size);
175        assert_eq!(16384, p.iter().nth(1).unwrap().size);
176
177        let m = MemoryLayout::from_str("/0x08010000/02*16K,01*64K");
178        assert_eq!(true, m.is_ok());
179        let m = m.unwrap();
180        let p = m.pages();
181        assert_eq!(3, p.len());
182        assert_eq!(16384, p.iter().nth(0).unwrap().size);
183        assert_eq!(16384, p.iter().nth(1).unwrap().size);
184        assert_eq!(65536, p.iter().nth(2).unwrap().size);
185    }
186}