Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/cros_fdt/src/propval.rs
5392 views
1
// Copyright 2023 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
//! This module implements FDT property value conversions as defined by the device tree format.
6
7
use std::mem::size_of_val;
8
9
use crate::fdt::c_str_to_string;
10
use crate::fdt::Error;
11
use crate::fdt::Result;
12
use crate::fdt::SIZE_U32;
13
use crate::fdt::SIZE_U64;
14
15
/// Conversion into an FDT property value.
16
///
17
/// Implementing `ToFdtPropval` for a type defines its conversion to a raw
18
/// FDT property value (a byte vector).
19
pub trait ToFdtPropval {
20
// Convert the type to its byte representation as an FDT property.
21
fn to_propval(self) -> Result<Vec<u8>>;
22
}
23
24
#[inline]
25
fn u32_to_bytes(value: &[u32]) -> Vec<u8> {
26
let mut bytes = Vec::with_capacity(size_of_val(value));
27
for val in value {
28
bytes.extend_from_slice(&val.to_be_bytes())
29
}
30
bytes
31
}
32
33
#[inline]
34
fn u64_to_bytes(value: &[u64]) -> Vec<u8> {
35
let mut bytes = Vec::with_capacity(size_of_val(value));
36
for val in value {
37
bytes.extend_from_slice(&val.to_be_bytes())
38
}
39
bytes
40
}
41
42
impl ToFdtPropval for () {
43
fn to_propval(self) -> Result<Vec<u8>> {
44
Ok(vec![])
45
}
46
}
47
48
impl ToFdtPropval for &[u8] {
49
fn to_propval(self) -> Result<Vec<u8>> {
50
Ok(self.into())
51
}
52
}
53
54
impl<const N: usize> ToFdtPropval for &[u8; N] {
55
fn to_propval(self) -> Result<Vec<u8>> {
56
Ok(self.to_vec())
57
}
58
}
59
60
impl ToFdtPropval for Vec<u8> {
61
fn to_propval(self) -> Result<Vec<u8>> {
62
Ok(self)
63
}
64
}
65
66
impl ToFdtPropval for u32 {
67
fn to_propval(self) -> Result<Vec<u8>> {
68
Ok(u32_to_bytes(std::slice::from_ref(&self)))
69
}
70
}
71
72
impl ToFdtPropval for &[u32] {
73
fn to_propval(self) -> Result<Vec<u8>> {
74
Ok(u32_to_bytes(self))
75
}
76
}
77
78
impl<const N: usize> ToFdtPropval for &[u32; N] {
79
fn to_propval(self) -> Result<Vec<u8>> {
80
Ok(u32_to_bytes(self))
81
}
82
}
83
84
impl ToFdtPropval for Vec<u32> {
85
fn to_propval(self) -> Result<Vec<u8>> {
86
Ok(u32_to_bytes(self.as_slice()))
87
}
88
}
89
90
impl ToFdtPropval for u64 {
91
fn to_propval(self) -> Result<Vec<u8>> {
92
Ok(u64_to_bytes(std::slice::from_ref(&self)))
93
}
94
}
95
96
impl ToFdtPropval for &[u64] {
97
fn to_propval(self) -> Result<Vec<u8>> {
98
Ok(u64_to_bytes(self))
99
}
100
}
101
102
impl<const N: usize> ToFdtPropval for &[u64; N] {
103
fn to_propval(self) -> Result<Vec<u8>> {
104
Ok(u64_to_bytes(self))
105
}
106
}
107
108
impl ToFdtPropval for Vec<u64> {
109
fn to_propval(self) -> Result<Vec<u8>> {
110
Ok(u64_to_bytes(self.as_slice()))
111
}
112
}
113
114
#[inline]
115
fn is_valid_string_property(val: &str) -> bool {
116
// Although the devicetree spec says string properties should be printable, neither libfdt nor
117
// the kernel device tree API verify that, so only check for zero bytes.
118
!val.contains('\0')
119
}
120
121
#[inline]
122
fn str_to_bytes<T: AsRef<str>>(value: &[T]) -> Result<Vec<u8>> {
123
let total_length = value.iter().map(|s| s.as_ref().len() + 1).sum();
124
let mut bytes = Vec::with_capacity(total_length);
125
for s in value {
126
let s = s.as_ref();
127
if !is_valid_string_property(s) {
128
return Err(Error::InvalidString(s.to_owned()));
129
}
130
bytes.extend_from_slice(s.as_bytes());
131
bytes.push(0);
132
}
133
Ok(bytes)
134
}
135
136
impl ToFdtPropval for &str {
137
fn to_propval(self) -> Result<Vec<u8>> {
138
str_to_bytes(std::slice::from_ref(&self))
139
}
140
}
141
142
impl ToFdtPropval for &[&str] {
143
fn to_propval(self) -> Result<Vec<u8>> {
144
str_to_bytes(self)
145
}
146
}
147
148
impl<const N: usize> ToFdtPropval for &[&str; N] {
149
fn to_propval(self) -> Result<Vec<u8>> {
150
str_to_bytes(self)
151
}
152
}
153
154
impl ToFdtPropval for String {
155
fn to_propval(self) -> Result<Vec<u8>> {
156
if !is_valid_string_property(&self) {
157
Err(Error::InvalidString(self))
158
} else {
159
let mut bytes = self.into_bytes();
160
bytes.push(0);
161
Ok(bytes)
162
}
163
}
164
}
165
166
impl ToFdtPropval for Vec<String> {
167
fn to_propval(self) -> Result<Vec<u8>> {
168
str_to_bytes(&self)
169
}
170
}
171
172
/// Conversion from an FDT property value.
173
///
174
/// Implementing `FromFdtPropval` for a type defines its construction from a raw
175
/// FDT property value (a byte slice).
176
pub trait FromFdtPropval {
177
// Try to convert FDT property bytes to `Self`, return `None` if impossible.
178
fn from_propval(propval: &[u8]) -> Option<Self>
179
where
180
Self: Sized;
181
}
182
183
impl FromFdtPropval for () {
184
fn from_propval(propval: &[u8]) -> Option<Self> {
185
propval.is_empty().then_some(())
186
}
187
}
188
189
impl FromFdtPropval for Vec<u8> {
190
fn from_propval(propval: &[u8]) -> Option<Self> {
191
Some(propval.into())
192
}
193
}
194
195
impl FromFdtPropval for u32 {
196
fn from_propval(propval: &[u8]) -> Option<Self> {
197
if propval.len() == SIZE_U32 {
198
Some(u32::from_be_bytes(propval.try_into().unwrap()))
199
} else {
200
None
201
}
202
}
203
}
204
205
impl FromFdtPropval for Vec<u32> {
206
fn from_propval(propval: &[u8]) -> Option<Self> {
207
if propval.len() % SIZE_U32 != 0 {
208
None
209
} else {
210
Some(
211
propval
212
.chunks(SIZE_U32)
213
.map(|v| u32::from_be_bytes(v.try_into().unwrap()))
214
.collect(),
215
)
216
}
217
}
218
}
219
220
impl FromFdtPropval for u64 {
221
fn from_propval(propval: &[u8]) -> Option<Self> {
222
if propval.len() == SIZE_U64 {
223
Some(u64::from_be_bytes(propval.try_into().unwrap()))
224
} else {
225
None
226
}
227
}
228
}
229
230
impl FromFdtPropval for Vec<u64> {
231
fn from_propval(propval: &[u8]) -> Option<Self> {
232
if propval.len() % SIZE_U64 != 0 {
233
None
234
} else {
235
Some(
236
propval
237
.chunks(SIZE_U64)
238
.map(|v| u64::from_be_bytes(v.try_into().unwrap()))
239
.collect(),
240
)
241
}
242
}
243
}
244
245
impl FromFdtPropval for String {
246
fn from_propval(propval: &[u8]) -> Option<Self> {
247
c_str_to_string(propval)
248
}
249
}
250
251
impl FromFdtPropval for Vec<String> {
252
fn from_propval(propval: &[u8]) -> Option<Self> {
253
if Some(&0) == propval.last() {
254
Some(
255
propval
256
.split(|&b| b == 0u8)
257
.take_while(|s| !s.is_empty())
258
.filter_map(|b| String::from_utf8(b.into()).ok())
259
.collect(),
260
)
261
} else {
262
None
263
}
264
}
265
}
266
267
#[cfg(test)]
268
mod tests {
269
use super::*;
270
271
#[test]
272
fn fdt_as_propval() {
273
assert_eq!(().to_propval().unwrap(), []);
274
assert_eq!([0u8, 1u8, 2u8].to_propval().unwrap(), [0u8, 1u8, 2u8]);
275
assert_eq!(0x1u32.to_propval().unwrap(), [0u8, 0, 0, 1]);
276
assert_eq!(
277
0x12345678u32.to_propval().unwrap(),
278
[0x12u8, 0x34, 0x56, 0x78]
279
);
280
assert_eq!(
281
0x12345678ABCDu64.to_propval().unwrap(),
282
[0x00u8, 0x00, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD]
283
);
284
assert_eq!(
285
[0x1u32, 0xABCDu32].to_propval().unwrap(),
286
[0x00u8, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD]
287
);
288
assert_eq!(
289
[0x1u64, 0xABCD00000000u64].to_propval().unwrap(),
290
[
291
0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD, 0x00,
292
0x00, 0x00, 0x00,
293
]
294
);
295
assert_eq!(
296
"abc def".to_propval().unwrap(),
297
[0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00,]
298
);
299
assert_eq!(
300
["abc def", "ghi jkl", "mno pqr"].to_propval().unwrap(),
301
[
302
0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68, 0x69, 0x20, 0x6A,
303
0x6B, 0x6C, 0x00, 0x6Du8, 0x6E, 0x6F, 0x20, 0x70, 0x71, 0x72, 0x00,
304
]
305
);
306
"abc\0def".to_propval().expect_err("invalid string");
307
}
308
309
#[test]
310
fn fdt_from_propval() {
311
assert_eq!(Vec::<u8>::from_propval(&[]).unwrap(), []);
312
assert_eq!(u32::from_propval(&[0, 0, 0, 1]).unwrap(), 1u32);
313
assert_eq!(
314
u32::from_propval(&[0x12u8, 0x34, 0x56, 0x78]).unwrap(),
315
0x12345678u32
316
);
317
assert_eq!(
318
u64::from_propval(&[0x00u8, 0x00, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD]).unwrap(),
319
0x12345678ABCDu64
320
);
321
assert_eq!(
322
Vec::<u32>::from_propval(&[0x00u8, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD]).unwrap(),
323
[0x1u32, 0xABCDu32]
324
);
325
assert_eq!(
326
Vec::<u64>::from_propval(&[
327
0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xAB, 0xCD, 0x00,
328
0x00, 0x00, 0x00
329
])
330
.unwrap(),
331
[0x1u64, 0xABCD00000000u64]
332
);
333
assert_eq!(
334
String::from_propval(&[0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00]).unwrap(),
335
"abc def"
336
);
337
assert_eq!(
338
Vec::<String>::from_propval(&[
339
0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68, 0x69, 0x20, 0x6A,
340
0x6B, 0x6C, 0x00, 0x6Du8, 0x6E, 0x6F, 0x20, 0x70, 0x71, 0x72, 0x00,
341
])
342
.unwrap(),
343
["abc def", "ghi jkl", "mno pqr"],
344
);
345
346
assert!(Vec::<String>::from_propval(&[
347
0x61u8, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00, 0x67u8, 0x68,
348
])
349
.is_none());
350
assert!(String::from_propval(&[0x61u8, 0x62, 0x63]).is_none());
351
assert!(u32::from_propval(&[0x61u8, 0x62]).is_none());
352
assert!(u64::from_propval(&[0x61u8, 0x62, 0x61u8, 0x62, 0x61u8, 0x62]).is_none());
353
}
354
}
355
356