devices/register_space/
mod.rs

1// Copyright 2018 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::collections::btree_map::BTreeMap;
6
7#[macro_use]
8mod register;
9
10pub use self::register::*;
11
12/// Register space repesents a set of registers. It can handle read/write operations.
13pub struct RegisterSpace {
14    regs: BTreeMap<RegisterRange, Box<dyn RegisterInterface>>,
15}
16
17impl RegisterSpace {
18    /// Creates a new empty RegisterSpace.
19    pub fn new() -> RegisterSpace {
20        RegisterSpace {
21            regs: BTreeMap::new(),
22        }
23    }
24
25    /// Add a register to register space.
26    pub fn add_register<T: RegisterInterface + 'static>(&mut self, reg: T) {
27        let range = reg.range();
28        debug_assert!(self.get_register(range.from).is_none());
29        if cfg!(debug_assertions) {
30            if let Some(r) = self.first_before(range.to) {
31                debug_assert!(r.range().to < range.to);
32            }
33        }
34
35        let insert_result = self.regs.insert(range, Box::new(reg)).is_none();
36        debug_assert!(insert_result);
37    }
38
39    /// Add an array of registers.
40    pub fn add_register_array<T: RegisterValue>(&mut self, regs: &[Register<T>]) {
41        for r in regs {
42            self.add_register(r.clone());
43        }
44    }
45
46    /// Read range.
47    pub fn read(&self, addr: RegisterOffset, data: &mut [u8]) {
48        let mut current_addr: RegisterOffset = addr;
49        while current_addr < addr + data.len() as RegisterOffset {
50            if let Some(r) = self.get_register(current_addr) {
51                // Next addr to read is.
52                current_addr = r.range().to + 1;
53                r.read(addr, data);
54            } else {
55                // TODO(jkwang) Add logging for debug here.
56                current_addr += 1;
57            }
58        }
59    }
60
61    /// Write range. If the targeted register has a callback, it will be invoked with the new
62    /// value.
63    pub fn write(&self, addr: RegisterOffset, data: &[u8]) {
64        let mut current_addr: RegisterOffset = addr;
65        while current_addr < addr + data.len() as RegisterOffset {
66            if let Some(r) = self.get_register(current_addr) {
67                // Next addr to read is, range is inclusive.
68                current_addr = r.range().to + 1;
69                r.write(addr, data);
70            } else {
71                current_addr += 1;
72            }
73        }
74    }
75
76    /// Get first register before this addr.
77    fn first_before(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface> {
78        for (range, r) in self.regs.iter().rev() {
79            if range.from <= addr {
80                return Some(r.as_ref());
81            }
82        }
83        None
84    }
85
86    /// Get register at this addr.
87    fn get_register(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface> {
88        let r = self.first_before(addr)?;
89        let range = r.range();
90        if addr <= range.to {
91            Some(r)
92        } else {
93            None
94        }
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use std::sync::Arc;
101
102    use sync::Mutex;
103
104    use super::*;
105
106    #[test]
107    fn regs_no_reg() {
108        let regs = RegisterSpace::new();
109        let mut data: [u8; 4] = [4, 3, 2, 1];
110        // Read should be no op cause no register.
111        regs.read(0, &mut data);
112        assert_eq!([4, 3, 2, 1], data);
113        // Write should be no op.
114        regs.write(0, &[0, 0, 0, 0]);
115        regs.read(0, &mut data);
116        assert_eq!([4, 3, 2, 1], data);
117    }
118
119    #[test]
120    #[should_panic]
121    #[cfg(debug_assertions)]
122    fn regs_reg_overlap() {
123        let mut regs = RegisterSpace::new();
124        regs.add_register(static_register!(
125        ty: u32,
126        offset: 4,
127        value: 11,
128        ));
129
130        regs.add_register(static_register!(
131        ty: u16,
132        offset: 7,
133        value: 11,
134        ));
135    }
136
137    #[test]
138    fn regs_static_reg() {
139        let mut regs = RegisterSpace::new();
140        regs.add_register(static_register!(
141            ty: u8,
142            offset: 0,
143            value: 11,
144        ));
145        let mut data: [u8; 4] = [4, 3, 2, 1];
146        regs.read(0, &mut data);
147        assert_eq!([11, 3, 2, 1], data);
148        // Write should be no op.
149        regs.write(0, &[0, 0, 0, 0]);
150        let mut data: [u8; 4] = [4, 3, 2, 1];
151        regs.read(0, &mut data);
152        assert_eq!([11, 3, 2, 1], data);
153    }
154
155    #[test]
156    fn regs_static_reg_offset() {
157        let mut regs = RegisterSpace::new();
158        regs.add_register(static_register!(
159            ty: u32,
160            offset: 2,
161            value: 0xaabbccdd,
162        ));
163        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
164        regs.read(0, &mut data);
165        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
166        // Write should be no op.
167        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
168        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
169        regs.read(0, &mut data);
170        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
171    }
172
173    #[test]
174    fn regs_reg_write() {
175        let mut regs = RegisterSpace::new();
176        regs.add_register(register!(
177            name: "",
178            ty: u32,
179            offset: 2,
180            reset_value: 0xaabbccdd,
181        ));
182        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
183        regs.read(0, &mut data);
184        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
185        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
186        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
187        regs.read(0, &mut data);
188        assert_eq!([8, 7, 0, 0, 0, 0, 2, 1], data);
189    }
190
191    #[test]
192    fn regs_reg_writeable() {
193        let mut regs = RegisterSpace::new();
194        regs.add_register(register!(
195            name: "",
196            ty: u32,
197            offset: 2,
198            reset_value: 0xaabbccdd,
199            guest_writeable_mask: 0x00f0000f,
200            guest_write_1_to_clear_mask: 0,
201        ));
202        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
203        regs.read(0, &mut data);
204        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
205        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
206        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
207        regs.read(0, &mut data);
208        assert_eq!([8, 7, 0xd0, 0xcc, 0x0b, 0xaa, 2, 1], data);
209    }
210
211    #[test]
212    fn regs_reg_writeable_callback() {
213        let state = Arc::new(Mutex::new(0u32));
214        let mut regs = RegisterSpace::new();
215        let reg = register!(
216            name: "",
217            ty: u32,
218            offset: 2,
219            reset_value: 0xaabbccdd,
220            guest_writeable_mask: 0x00f0000f,
221            guest_write_1_to_clear_mask: 0,
222        );
223        regs.add_register(reg.clone());
224        let state_clone = state.clone();
225        reg.set_write_cb(move |val: u32| {
226            *state_clone.lock() = val;
227            val
228        });
229
230        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
231        regs.read(0, &mut data);
232        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
233        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
234        assert_eq!(0xaa0bccd0, *state.lock());
235    }
236
237    #[test]
238    fn regs_reg_write_to_clear() {
239        let mut regs = RegisterSpace::new();
240        regs.add_register(register!(
241        name: "",
242        ty: u32,
243        offset: 2,
244        reset_value: 0xaabbccdd,
245        guest_writeable_mask: 0xfff0000f,
246        guest_write_1_to_clear_mask: 0xf0000000,
247        ));
248        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
249        regs.read(0, &mut data);
250        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
251        regs.write(0, &[0, 0, 0, 0, 0, 0xad, 0, 0]);
252        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
253        regs.read(0, &mut data);
254        assert_eq!([8, 7, 0xd0, 0xcc, 0x0b, 0x0d, 2, 1], data);
255    }
256
257    #[test]
258    fn regs_reg_array() {
259        let mut regs = RegisterSpace::new();
260        regs.add_register_array(&register_array!(
261            name: "",
262            ty: u8,
263            cnt: 8,
264            base_offset: 10,
265            stride: 2,
266            reset_value: 0xff,
267            guest_writeable_mask: !0,
268            guest_write_1_to_clear_mask: 0,
269        ));
270        let mut data: [u8; 8] = [0; 8];
271        regs.read(8, &mut data);
272        assert_eq!([0, 0, 0xff, 0, 0xff, 0, 0xff, 0], data);
273    }
274
275    #[test]
276    fn regs_reg_multi_array() {
277        let mut regs = RegisterSpace::new();
278        regs.add_register_array(&register_array!(
279        name: "",
280        ty: u8,
281        cnt: 8,
282        base_offset: 10,
283        stride: 2,
284        reset_value: 0xff,
285        guest_writeable_mask: !0,
286        guest_write_1_to_clear_mask: 0,
287        ));
288        regs.add_register_array(&register_array!(
289        name: "",
290        ty: u8,
291        cnt: 8,
292        base_offset: 11,
293        stride: 2,
294        reset_value: 0xee,
295        guest_writeable_mask: !0,
296        guest_write_1_to_clear_mask: 0,
297        ));
298        let mut data: [u8; 8] = [0; 8];
299        regs.read(8, &mut data);
300        assert_eq!([0, 0, 0xff, 0xee, 0xff, 0xee, 0xff, 0xee], data);
301    }
302}