Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/register_space/mod.rs
5394 views
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.
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)]
99
mod 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
}
303
304