blob: c9c45fb883e1add6b96dfece5b1d968f9a232c0a [file] [log] [blame]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
Balint Dobszaya5846852025-02-26 15:38:53 +01004//! Implementation of the FF-A Boot information protocol.
5//!
6//! An SP or SPMC could rely on boot information for their initialization e.g. a flattened device
7//! tree with nodes to describe the devices and memory regions assigned to the SP or SPMC. FF-A
8//! specifies a protocol that can be used by a producer to pass boot information to a consumer at a
9//! Secure FF-A instance. The Framework assumes that the boot information protocol is used by a
10//! producer and consumer pair that reside at adjacent exception levels as listed below.
11//! - SPMD (producer) and an SPMC (consumer) in either S-EL1 or S-EL2.
12//! - An SPMC (producer) and SP (consumer) pair listed below.
13//! - EL3 SPMC and a Logical S-EL1 SP.
14//! - S-EL2 SPMC and Physical S-EL1 SP.
15//! - EL3 SPMC and a S-EL0 SP.
16//! - S-EL2 SPMC and a S-EL0 SP.
17//! - S-EL1 SPMC and a S-EL0 SP.
18
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010019use crate::{
20 ffa_v1_1::{boot_info_descriptor, boot_info_header},
21 Version,
22};
23use core::ffi::CStr;
24use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020025use uuid::Uuid;
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010026use zerocopy::{FromBytes, IntoBytes};
Balint Dobszay5bf492f2024-07-29 17:21:32 +020027
Balint Dobszaya5846852025-02-26 15:38:53 +010028/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
29/// with the `FFA_ERROR` interface.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010030#[derive(Debug, Error)]
31pub enum Error {
32 #[error("Invalid standard type {0}")]
33 InvalidStdType(u8),
34 #[error("Invalid type {0}")]
35 InvalidType(u8),
36 #[error("Invalid contents format {0}")]
37 InvalidContentsFormat(u16),
38 #[error("Invalid name format {0}")]
39 InvalidNameFormat(u16),
40 #[error("Invalid name")]
41 InvalidName,
42 #[error("Invalid flags {0}")]
43 InvalidFlags(u16),
44 #[error("Invalid header size or alignment")]
45 InvalidHeader,
46 #[error("Invalid buffer size")]
47 InvalidBufferSize,
48 #[error("Invalid signature")]
49 InvalidSignature,
50 #[error("Invalid version {0}")]
51 InvalidVersion(Version),
52 #[error("Malformed descriptor")]
53 MalformedDescriptor,
54}
55
56impl From<Error> for crate::FfaError {
57 fn from(_value: Error) -> Self {
58 Self::InvalidParameters
59 }
60}
61
Balint Dobszaya5846852025-02-26 15:38:53 +010062/// Name of boot information descriptor.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010063#[derive(Clone, Debug, PartialEq, Eq)]
64pub enum BootInfoName<'a> {
65 NullTermString(&'a CStr),
Balint Dobszay5bf492f2024-07-29 17:21:32 +020066 Uuid(Uuid),
67}
68
Balint Dobszaya5846852025-02-26 15:38:53 +010069/// ID for supported standard boot information types.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010070#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71#[repr(u8)]
72pub enum BootInfoStdId {
73 Fdt = Self::FDT,
74 Hob = Self::HOB,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020075}
76
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010077impl TryFrom<u8> for BootInfoStdId {
78 type Error = Error;
79
80 fn try_from(value: u8) -> Result<Self, Self::Error> {
81 match value {
82 Self::FDT => Ok(BootInfoStdId::Fdt),
83 Self::HOB => Ok(BootInfoStdId::Hob),
84 _ => Err(Error::InvalidStdType(value)),
85 }
86 }
87}
88
89impl BootInfoStdId {
90 const FDT: u8 = 0;
91 const HOB: u8 = 1;
92}
93
Balint Dobszaya5846852025-02-26 15:38:53 +010094/// ID for implementation defined boot information type.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010095#[derive(Clone, Copy, Debug, PartialEq, Eq)]
96pub struct BootInfoImpdefId(pub u8);
97
98impl From<u8> for BootInfoImpdefId {
99 fn from(value: u8) -> Self {
100 Self(value)
101 }
102}
103
Balint Dobszaya5846852025-02-26 15:38:53 +0100104/// Boot information type.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200106pub enum BootInfoType {
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100107 Std(BootInfoStdId),
108 Impdef(BootInfoImpdefId),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200109}
110
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100111impl TryFrom<u8> for BootInfoType {
112 type Error = Error;
113
114 fn try_from(value: u8) -> Result<Self, Self::Error> {
115 match (value >> Self::TYPE_SHIFT) & Self::TYPE_MASK {
116 Self::TYPE_STANDARD => Ok(BootInfoType::Std((value & Self::ID_MASK).try_into()?)),
117 Self::TYPE_IMPDEF => Ok(BootInfoType::Impdef((value & Self::ID_MASK).into())),
118 _ => Err(Error::InvalidType(value)),
119 }
120 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200121}
122
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100123impl From<BootInfoType> for u8 {
124 fn from(value: BootInfoType) -> Self {
125 match value {
126 BootInfoType::Std(std_type) => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100127 std_type as u8 | (BootInfoType::TYPE_STANDARD << BootInfoType::TYPE_SHIFT)
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100128 }
129 BootInfoType::Impdef(impdef_type) => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100130 impdef_type.0 | (BootInfoType::TYPE_IMPDEF << BootInfoType::TYPE_SHIFT)
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100131 }
132 }
133 }
134}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200135
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100136impl BootInfoType {
137 // This field contains the boot info type at bit[7] and the boot info identifier in bits[6:0]
138 const TYPE_SHIFT: usize = 7;
139 const TYPE_MASK: u8 = 0b1;
140 const TYPE_STANDARD: u8 = 0b0;
141 const TYPE_IMPDEF: u8 = 0b1;
142 // Mask for boot info identifier in bits[6:0]
143 const ID_MASK: u8 = 0b0111_1111;
144}
145
Balint Dobszaya5846852025-02-26 15:38:53 +0100146/// Boot information contents.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148pub enum BootInfoContents<'a> {
149 Address { content_buf: &'a [u8] },
150 Value { val: u64, len: usize },
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq)]
154#[repr(u16)]
155enum BootInfoContentsFormat {
156 Address = Self::ADDRESS << Self::SHIFT,
157 Value = Self::VALUE << Self::SHIFT,
158}
159
160impl TryFrom<u16> for BootInfoContentsFormat {
161 type Error = Error;
162
163 fn try_from(value: u16) -> Result<Self, Self::Error> {
164 match (value >> Self::SHIFT) & Self::MASK {
165 Self::ADDRESS => Ok(BootInfoContentsFormat::Address),
166 Self::VALUE => Ok(BootInfoContentsFormat::Value),
167 _ => Err(Error::InvalidContentsFormat(value)),
168 }
169 }
170}
171
172impl BootInfoContentsFormat {
173 const SHIFT: usize = 2;
174 const MASK: u16 = 0b11;
175 const ADDRESS: u16 = 0b00;
176 const VALUE: u16 = 0b01;
177}
178
179#[derive(Clone, Copy, Debug, PartialEq, Eq)]
180#[repr(u16)]
181enum BootInfoNameFormat {
182 String = Self::STRING << Self::SHIFT,
183 Uuid = Self::UUID << Self::SHIFT,
184}
185
186impl TryFrom<u16> for BootInfoNameFormat {
187 type Error = Error;
188
189 fn try_from(value: u16) -> Result<Self, Self::Error> {
190 match (value >> Self::SHIFT) & Self::MASK {
191 Self::STRING => Ok(BootInfoNameFormat::String),
192 Self::UUID => Ok(BootInfoNameFormat::Uuid),
193 _ => Err(Error::InvalidNameFormat(value)),
194 }
195 }
196}
197
198impl BootInfoNameFormat {
199 const SHIFT: usize = 0;
200 const MASK: u16 = 0b11;
201 const STRING: u16 = 0b00;
202 const UUID: u16 = 0b01;
203}
204
205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206struct BootInfoFlags {
207 contents_format: BootInfoContentsFormat,
208 name_format: BootInfoNameFormat,
209}
210
211impl TryFrom<u16> for BootInfoFlags {
212 type Error = Error;
213
214 fn try_from(value: u16) -> Result<Self, Self::Error> {
215 // bits[15:4]: Reserved (MBZ)
216 if value >> 4 == 0 {
217 Ok(Self {
218 contents_format: BootInfoContentsFormat::try_from(value)?,
219 name_format: BootInfoNameFormat::try_from(value)?,
220 })
221 } else {
222 Err(Error::InvalidFlags(value))
223 }
224 }
225}
226
227impl From<BootInfoFlags> for u16 {
228 fn from(value: BootInfoFlags) -> Self {
229 value.contents_format as u16 | value.name_format as u16
230 }
231}
232
Balint Dobszaya5846852025-02-26 15:38:53 +0100233/// Boot information descriptor.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100234#[derive(Clone, Debug, PartialEq, Eq)]
235pub struct BootInfo<'a> {
236 pub name: BootInfoName<'a>,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200237 pub typ: BootInfoType,
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100238 pub contents: BootInfoContents<'a>,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200239}
240
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100241impl BootInfo<'_> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100242 /// Serialize a list of boot information descriptors into a buffer. The `mapped_addr` parameter
243 /// should contain the address of the buffer in the consumers translation regime (typically a
244 /// virtual address where the buffer is mapped to). This is necessary since there are
245 /// self-references within the serialized data structure which must be described with an
246 /// absolute address according to the FF-A spec.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100247 pub fn pack(descriptors: &[BootInfo], buf: &mut [u8], mapped_addr: Option<usize>) {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200248 // Offset from the base of the header to the first element in the boot info descriptor array
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100249 // Must be 8 byte aligned, but otherwise we're free to choose any value here.
Balint Dobszaya5846852025-02-26 15:38:53 +0100250 // Let's just pack the array right after the header.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100251 const DESC_ARRAY_OFFSET: usize = size_of::<boot_info_header>().next_multiple_of(8);
252 const DESC_SIZE: usize = size_of::<boot_info_descriptor>();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200253
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100254 assert!(buf.len() <= u32::MAX as usize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200255
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200256 let desc_cnt = descriptors.len();
257
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100258 // Add the already known fields, later we have to add the sizes referenced by the individual
259 // descriptors
260
261 // The Size of boot information blob field specifies the size of the blob that spans one or
262 // more contiguous 4K pages used by the producer to populate it. It is calculated by adding
263 // the following values:
264 // 1. Boot information descriptor array offset
265 // 2. Product of Boot information descriptor count and Boot information descriptor size.
266 // 3. Total size of all boot information referenced by boot information descriptors.
267 // This is determined by adding the values in the Size field of each boot information
268 // descriptor whose Contents field contains an address.
269 // 4. Any padding between,
270 // 1. The boot information descriptor array and the boot information referenced from it.
271 // 2. Distinct instances of boot information referenced from the boot information
272 // descriptor array.
273 let mut total_offset = 0usize;
274
275 // No. 1 from the "Size of boot information blob" list
276 total_offset = total_offset.checked_add(DESC_ARRAY_OFFSET).unwrap();
277
278 // No. 2 from the "Size of boot information blob" list
279 total_offset = total_offset
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200280 .checked_add(desc_cnt.checked_mul(DESC_SIZE).unwrap())
281 .unwrap();
282
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100283 // Fail early if the buffer is too small
284 assert!(total_offset <= buf.len());
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200285
286 // Fill the boot info descriptor array, all offset based from DESC_ARRAY_OFFSET
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100287 let mut desc_array_offset = DESC_ARRAY_OFFSET;
288
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200289 for desc in descriptors {
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100290 let mut desc_raw = boot_info_descriptor::default();
291
292 let name_format = match &desc.name {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200293 BootInfoName::NullTermString(name) => {
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100294 // count_bytes() doesn't include nul terminator
295 let name_len = name.count_bytes().min(15);
296 desc_raw.name[..name_len].copy_from_slice(&name.to_bytes()[..name_len]);
297 // Add nul terminator and zero fill the rest
298 desc_raw.name[name_len..].fill(0);
299
300 BootInfoNameFormat::String
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200301 }
302 BootInfoName::Uuid(uuid) => {
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100303 desc_raw.name.copy_from_slice(&uuid.to_bytes_le());
304 BootInfoNameFormat::Uuid
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200305 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200306 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200307
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100308 let contents_format = match desc.contents {
309 BootInfoContents::Address { content_buf } => {
310 // We have to copy the contents referenced by the boot info descriptor into the
311 // boot info blob. At this offset we're after the boot info header and all of
312 // the boot info descriptors. The contents referenced from the individual boot
313 // info descriptors will get copied to this starting address. The 8 byte
314 // alignment is not explicitly mentioned by the spec, but it's better to have it
315 // anyway.
316 // No. 4 from the "Size of boot information blob" list
317 total_offset = total_offset.next_multiple_of(8);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200318
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100319 // The mapped_addr argument contains the address where buf is mapped to in the
320 // consumer's translation regime. If it's None, we assume identity mapping is
321 // used, so the buffer's address stays the same.
322 let buf_addr = mapped_addr.unwrap_or(buf.as_ptr() as usize);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200323
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100324 // The content's address in the consumer's translation regime will be the
325 // buffer's address in the consumer's translation regime plus the offset of the
326 // content within the boot info blob.
327 let content_addr = buf_addr.checked_add(total_offset).unwrap();
328
329 // Check if the content fits before copying
330 let content_len = content_buf.len();
331 total_offset.checked_add(content_len).unwrap();
332
333 // Do the copy and increase the total size
334 // No. 3 from the "Size of boot information blob" list
335 buf[total_offset..total_offset + content_len].copy_from_slice(content_buf);
336 total_offset += content_len;
337
338 desc_raw.contents = content_addr as u64;
339 desc_raw.size = content_len as u32;
340
341 BootInfoContentsFormat::Address
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200342 }
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100343 BootInfoContents::Value { val, len } => {
344 assert!((1..=8).contains(&len));
345 desc_raw.contents = val;
346 desc_raw.size = len as u32;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200347
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100348 BootInfoContentsFormat::Value
349 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200350 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200351
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100352 let flags = BootInfoFlags {
353 contents_format,
354 name_format,
355 };
356
357 desc_raw.flags = flags.into();
358 desc_raw.typ = desc.typ.into();
359
360 desc_raw
361 .write_to_prefix(&mut buf[desc_array_offset..])
362 .unwrap();
363 desc_array_offset += DESC_SIZE;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200364 }
365
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100366 let header_raw = boot_info_header {
367 signature: 0x0ffa,
368 version: Version(1, 1).into(),
369 boot_info_blob_size: total_offset as u32,
370 boot_info_desc_size: DESC_SIZE as u32,
371 boot_info_desc_count: desc_cnt as u32,
372 boot_info_array_offset: DESC_ARRAY_OFFSET as u32,
373 reserved: 0,
374 };
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200375
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100376 header_raw.write_to_prefix(buf).unwrap();
377 }
378
379 /// Validate and return the boot information header
380 fn get_header(buf: &[u8]) -> Result<&boot_info_header, Error> {
381 let (header_raw, _) =
382 boot_info_header::ref_from_prefix(buf).map_err(|_| Error::InvalidHeader)?;
383
384 if header_raw.signature != 0x0ffa {
385 return Err(Error::InvalidSignature);
386 }
387
388 let version = Version::from(header_raw.version);
389 if version != Version(1, 1) {
390 return Err(Error::InvalidVersion(version));
391 }
392
393 Ok(header_raw)
394 }
395
Balint Dobszaya5846852025-02-26 15:38:53 +0100396 /// Get the size of the boot information blob spanning contiguous memory. This enables a
397 /// consumer to map all of the boot information blob in its translation regime or copy it to
398 /// another memory location without parsing each element in the boot information descriptor
399 /// array.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100400 pub fn get_blob_size(buf: &[u8]) -> Result<usize, Error> {
401 let header_raw = Self::get_header(buf)?;
402
403 Ok(header_raw.boot_info_blob_size as usize)
404 }
405}
406
Balint Dobszaya5846852025-02-26 15:38:53 +0100407/// Iterator of boot information descriptors.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100408pub struct BootInfoIterator<'a> {
409 buf: &'a [u8],
410 offset: usize,
411 desc_count: usize,
412 desc_size: usize,
413}
414
415impl<'a> BootInfoIterator<'a> {
Balint Dobszaya5846852025-02-26 15:38:53 +0100416 /// Create an iterator of boot information descriptors from a buffer.
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100417 pub fn new(buf: &'a [u8]) -> Result<Self, Error> {
418 let header_raw = BootInfo::get_header(buf)?;
419
420 if buf.len() < header_raw.boot_info_blob_size as usize {
421 return Err(Error::InvalidBufferSize);
422 }
423
424 if header_raw.boot_info_desc_size as usize != size_of::<boot_info_descriptor>() {
425 return Err(Error::MalformedDescriptor);
426 }
427
428 let Some(total_desc_size) = header_raw
429 .boot_info_desc_count
430 .checked_mul(header_raw.boot_info_desc_size)
431 .and_then(|x| x.checked_add(header_raw.boot_info_array_offset))
432 else {
433 return Err(Error::InvalidBufferSize);
434 };
435
436 if buf.len() < total_desc_size as usize {
437 return Err(Error::InvalidBufferSize);
438 }
439
440 Ok(Self {
441 buf,
442 offset: header_raw.boot_info_array_offset as usize,
443 desc_count: header_raw.boot_info_desc_count as usize,
444 desc_size: header_raw.boot_info_desc_size as usize,
445 })
446 }
447}
448
449impl<'a> Iterator for BootInfoIterator<'a> {
450 type Item = Result<BootInfo<'a>, Error>;
451
452 fn next(&mut self) -> Option<Self::Item> {
453 if self.desc_count > 0 {
454 let desc_offset = self.offset;
455 self.offset += self.desc_size;
456 self.desc_count -= 1;
457
458 let Ok(desc_raw) = boot_info_descriptor::ref_from_bytes(
459 &self.buf[desc_offset..desc_offset + self.desc_size],
460 ) else {
461 return Some(Err(Error::MalformedDescriptor));
462 };
463
464 if desc_raw.reserved != 0 {
465 return Some(Err(Error::MalformedDescriptor));
466 }
467
468 let typ: BootInfoType = match desc_raw.typ.try_into() {
469 Ok(v) => v,
470 Err(e) => return Some(Err(e)),
471 };
472
473 let flags: BootInfoFlags = match desc_raw.flags.try_into() {
474 Ok(v) => v,
475 Err(e) => return Some(Err(e)),
476 };
477
478 let name = match flags.name_format {
479 BootInfoNameFormat::String => {
480 let Ok(name_str) = CStr::from_bytes_with_nul(desc_raw.name.as_bytes()) else {
481 return Some(Err(Error::InvalidName));
482 };
483 BootInfoName::NullTermString(name_str)
484 }
485 BootInfoNameFormat::Uuid => BootInfoName::Uuid(Uuid::from_bytes_le(desc_raw.name)),
486 };
487
488 let contents = match flags.contents_format {
489 BootInfoContentsFormat::Address => {
490 let contents = desc_raw.contents as usize;
491 let contents_size = desc_raw.size as usize;
492
493 let Some(offset) = contents.checked_sub(self.buf.as_ptr() as usize) else {
494 return Some(Err(Error::InvalidBufferSize));
495 };
496
497 let Some(offset_end) = offset.checked_add(contents_size) else {
498 return Some(Err(Error::InvalidBufferSize));
499 };
500
501 if self.buf.len() < offset_end {
502 return Some(Err(Error::InvalidBufferSize));
503 }
504
505 BootInfoContents::Address {
506 content_buf: &self.buf[offset..offset_end],
507 }
508 }
509
510 BootInfoContentsFormat::Value => BootInfoContents::Value {
511 val: desc_raw.contents,
512 len: desc_raw.size as usize,
513 },
514 };
515
516 return Some(Ok(BootInfo {
517 name,
518 typ,
519 contents,
520 }));
521 }
522
523 None
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200524 }
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200530 use uuid::uuid;
531
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100532 // TODO: add tests with a known correct boot info blob
533
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200534 #[test]
535 fn boot_info() {
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100536 let desc1 = BootInfo {
537 name: BootInfoName::NullTermString(c"test1234test123"),
538 typ: BootInfoType::Impdef(BootInfoImpdefId(0x2b)),
539 contents: BootInfoContents::Value {
540 val: 0xdeadbeef,
541 len: 4,
542 },
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200543 };
544
545 let fdt = [0u8; 0xff];
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100546 let desc2 = BootInfo {
547 name: BootInfoName::Uuid(uuid!("12345678-abcd-dcba-1234-123456789abc")),
548 typ: BootInfoType::Std(BootInfoStdId::Fdt),
549 contents: BootInfoContents::Address { content_buf: &fdt },
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200550 };
551
552 let mut buf = [0u8; 0x1ff];
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100553 let buf_addr = buf.as_ptr() as usize;
554 BootInfo::pack(&[desc1.clone(), desc2.clone()], &mut buf, Some(buf_addr));
555 let mut descriptors = BootInfoIterator::new(&buf).unwrap();
556 let desc1_check = descriptors.next().unwrap().unwrap();
557 let desc2_check = descriptors.next().unwrap().unwrap();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200558
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +0100559 assert_eq!(desc1, desc1_check);
560 assert_eq!(desc2, desc2_check);
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200561 }
562}