xref: /aosp_15_r20/external/crosvm/devices/src/register_space/mod.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
5 use std::collections::btree_map::BTreeMap;
6 
7 #[macro_use]
8 mod register;
9 
10 pub use self::register::*;
11 
12 /// Register space repesents a set of registers. It can handle read/write operations.
13 pub struct RegisterSpace {
14     regs: BTreeMap<RegisterRange, Box<dyn RegisterInterface>>,
15 }
16 
17 impl RegisterSpace {
18     /// Creates a new empty RegisterSpace.
new() -> RegisterSpace19     pub fn new() -> RegisterSpace {
20         RegisterSpace {
21             regs: BTreeMap::new(),
22         }
23     }
24 
25     /// Add a register to register space.
add_register<T: RegisterInterface + 'static>(&mut self, reg: T)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.
add_register_array<T: RegisterValue>(&mut self, regs: &[Register<T>])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.
read(&self, addr: RegisterOffset, data: &mut [u8])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.
write(&self, addr: RegisterOffset, data: &[u8])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.
first_before(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface>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.
get_register(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface>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)]
99 mod tests {
100     use std::sync::Arc;
101 
102     use sync::Mutex;
103 
104     use super::*;
105 
106     #[test]
regs_no_reg()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)]
regs_reg_overlap()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]
regs_static_reg()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]
regs_static_reg_offset()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]
regs_reg_write()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]
regs_reg_writeable()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]
regs_reg_writeable_callback()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]
regs_reg_write_to_clear()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]
regs_reg_array()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]
regs_reg_multi_array()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 }
303