1#![cfg_attr(not(any(feature = "std", test)), no_std)]
8#![forbid(unsafe_code)]
9use core::fmt;
12use log::debug;
13
14use chrono::Datelike;
15use enumset::{EnumSet, EnumSetType};
16use num_derive::FromPrimitive;
17
18use nom::{
19 branch::alt,
20 bytes::complete::{tag, take},
21 character::complete::u32 as c_u32,
22 combinator::{
23 all_consuming, flat_map, map, map_opt, map_parser, map_res, rest, value,
24 },
25 number::complete::{le_u16, le_u32, le_u8},
26 sequence::tuple,
27 IResult,
28};
29
30#[cfg(feature = "alloc")]
31use nom::multi::{count, length_count};
32
33extern crate pldm;
34
35pub mod fd;
37#[cfg(feature = "alloc")]
39pub mod pkg;
40#[cfg(feature = "std")]
42pub mod ua;
43
44use pldm::util::*;
45
46pub const PLDM_TYPE_FW: u8 = 5;
48
49pub const PLDM_FW_BASELINE_TRANSFER: usize = 32;
51
52#[cfg(not(feature = "alloc"))]
56const MAX_DESC_STRING: usize = 64;
57
58#[cfg(not(feature = "alloc"))]
63const MAX_VENDORDATA: usize = 64;
64
65#[derive(Debug, Eq, PartialEq, Hash)]
67pub struct ComponentId(pub u16);
68
69#[derive(Debug, PartialEq, Copy, Clone)]
71#[repr(u8)]
72pub enum PldmFDState {
73 Idle = 0,
74 LearnComponents = 1,
75 ReadyXfer = 2,
76 Download = 3,
77 Verify = 4,
78 Apply = 5,
79 Activate = 6,
80}
81
82impl TryFrom<u8> for PldmFDState {
83 type Error = &'static str;
84 fn try_from(value: u8) -> core::result::Result<Self, Self::Error> {
85 match value {
86 0 => Ok(Self::Idle),
87 1 => Ok(Self::LearnComponents),
88 2 => Ok(Self::ReadyXfer),
89 3 => Ok(Self::Download),
90 4 => Ok(Self::Verify),
91 5 => Ok(Self::Apply),
92 6 => Ok(Self::Activate),
93 _ => Err("unknown state!"),
94 }
95 }
96}
97
98impl PldmFDState {
99 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
101 map_res(le_u8, TryInto::<PldmFDState>::try_into)(buf)
102 }
103}
104
105#[allow(missing_docs)]
107#[derive(FromPrimitive, Debug, PartialEq, Copy, Clone)]
108#[repr(u8)]
109pub enum PldmIdleReason {
110 Init = 0,
111 Activate = 1,
112 Cancel = 2,
113 TimeoutLearn = 3,
114 TimeoutReadyXfer = 4,
115 TimeoutDownload = 5,
116 TimeoutVerify = 6,
117 TimeoutApply = 7,
118}
119
120#[allow(missing_docs)]
122#[derive(FromPrimitive, Debug, PartialEq)]
123#[repr(u8)]
124pub enum Cmd {
125 QueryDeviceIdentifiers = 0x01,
126 GetFirmwareParameters = 0x02,
127 QueryDownstreamDevices = 0x03,
128 QueryDownstreamIdentifiers = 0x04,
129 GetDownstreamFirmwareParameters = 0x05,
130 RequestUpdate = 0x10,
131 GetPackageData = 0x11,
132 GetDeviceMetaData = 0x12,
133 PassComponentTable = 0x13,
134 UpdateComponent = 0x14,
135 RequestFirmwareData = 0x15,
136 TransferComplete = 0x16,
137 VerifyComplete = 0x17,
138 ApplyComplete = 0x18,
139 GetMetaData = 0x19,
140 ActivateFirmware = 0x1A,
141 GetStatus = 0x1B,
142 CancelUpdateComponent = 0x1C,
143 CancelUpdate = 0x1D,
144 ActivatePendingComponentImageSet = 0x1E,
145 ActivatePendingComponentImage = 0x1F,
146 RequestDownstreamDeviceUpdate = 0x20,
147}
148
149impl Cmd {
150 pub const fn is_ua(&self) -> bool {
151 !self.is_fd()
152 }
153
154 pub const fn is_fd(&self) -> bool {
155 match self {
156 Self::GetPackageData
157 | Self::RequestFirmwareData
158 | Self::TransferComplete
159 | Self::VerifyComplete
160 | Self::ApplyComplete
161 | Self::GetMetaData => true,
162 _ => false,
163 }
164 }
165}
166
167#[allow(missing_docs)]
169#[repr(u8)]
170#[allow(non_camel_case_types)]
171#[derive(Debug, PartialEq)]
172pub enum FwCode {
173 NOT_IN_UPDATE_MODE = 0x80,
174 ALREADY_IN_UPDATE_MODE = 0x81,
175 DATA_OUT_OF_RANGE = 0x82,
176 INVALID_TRANSFER_LENGTH = 0x83,
177 INVALID_STATE_FOR_COMMAND = 0x84,
178 INCOMPLETE_UPDATE = 0x85,
179 BUSY_IN_BACKGROUND = 0x86,
180 CANCEL_PENDING = 0x87,
181 COMMAND_NOT_EXPECTED = 0x88,
182 RETRY_REQUEST_FW_DATA = 0x89,
183 UNABLE_TO_INITIATE_UPDATE = 0x8A,
184 ACTIVATION_NOT_REQUIRED = 0x8B,
185 SELF_CONTAINED_ACTIVATION_NOT_PERMITTED = 0x8C,
186 NO_DEVICE_METADATA = 0x8D,
187 RETRY_REQUEST_UPDATE = 0x8E,
188 NO_PACKAGE_DATA = 0x8F,
189 INVALID_TRANSFER_HANDLE = 0x90,
190 INVALID_TRANSFER_OPERATION = 0x91,
191 ACTIVATE_PENDING_IMAGE_NOT_PERMITTED = 0x92,
192 PACKAGE_DATA_ERROR = 0x93,
193}
194
195#[repr(u8)]
200#[derive(Debug, Copy, Clone, PartialEq)]
201#[non_exhaustive]
202pub enum TransferResult {
203 Success,
204 Corrupt,
205 VersionMismatch,
206 Aborted,
207 Timeout,
208 GenericError,
209 Other(u8),
210}
211
212impl From<u8> for TransferResult {
213 fn from(v: u8) -> Self {
214 match v {
215 0x00 => Self::Success,
216 0x01 => Self::Corrupt,
217 0x02 => Self::VersionMismatch,
218 0x03 => Self::Aborted,
219 0x09 => Self::Timeout,
220 0x0a => Self::GenericError,
221 v => Self::Other(v),
222 }
223 }
224}
225
226impl From<TransferResult> for u8 {
227 fn from(v: TransferResult) -> u8 {
228 match v {
229 TransferResult::Success => 0x00,
230 TransferResult::Corrupt => 0x01,
231 TransferResult::VersionMismatch => 0x02,
232 TransferResult::Aborted => 0x03,
233 TransferResult::Timeout => 0x09,
234 TransferResult::GenericError => 0x0a,
235 TransferResult::Other(v) => v,
236 }
237 }
238}
239
240#[allow(missing_docs)]
247#[derive(Debug, Copy, Clone, PartialEq)]
248pub enum VerifyResult {
249 Success,
250 Failure,
251 VersionMismatch,
252 SecurityChecksFailed,
253 IncompleteImage,
254 Timeout,
256 GenericError,
257 Other(u8),
258}
259
260impl From<u8> for VerifyResult {
261 fn from(v: u8) -> Self {
262 match v {
263 0x00 => Self::Success,
264 0x01 => Self::Failure,
265 0x02 => Self::VersionMismatch,
266 0x03 => Self::SecurityChecksFailed,
267 0x04 => Self::IncompleteImage,
268 0x09 => Self::Timeout,
269 0x0a => Self::GenericError,
270 v => Self::Other(v),
271 }
272 }
273}
274
275impl From<VerifyResult> for u8 {
276 fn from(v: VerifyResult) -> u8 {
277 match v {
278 VerifyResult::Success => 0x00,
279 VerifyResult::Failure => 0x01,
280 VerifyResult::VersionMismatch => 0x02,
281 VerifyResult::SecurityChecksFailed => 0x03,
282 VerifyResult::IncompleteImage => 0x04,
283 VerifyResult::Timeout => 0x09,
284 VerifyResult::GenericError => 0x0a,
285 VerifyResult::Other(v) => v,
286 }
287 }
288}
289
290#[allow(missing_docs)]
297#[derive(Debug, Copy, Clone, PartialEq)]
298pub enum ApplyResult {
299 Success,
300 SuccessModActivation,
301 FailedMemoryWrite,
302 Timeout,
303 GenericError,
304 Other(u8),
305}
306
307impl From<u8> for ApplyResult {
308 fn from(v: u8) -> Self {
309 match v {
310 0x00 => Self::Success,
311 0x01 => Self::SuccessModActivation,
312 0x02 => Self::FailedMemoryWrite,
313 0x09 => Self::Timeout,
314 0x0a => Self::GenericError,
315 v => Self::Other(v),
316 }
317 }
318}
319
320impl From<ApplyResult> for u8 {
321 fn from(v: ApplyResult) -> u8 {
322 match v {
323 ApplyResult::Success => 0x00,
324 ApplyResult::SuccessModActivation => 0x01,
325 ApplyResult::FailedMemoryWrite => 0x02,
326 ApplyResult::Timeout => 0x09,
327 ApplyResult::GenericError => 0x0a,
328 ApplyResult::Other(v) => v,
329 }
330 }
331}
332
333type VResult<I, O> = IResult<I, O>;
335
336#[derive(FromPrimitive, Debug, PartialEq)]
337#[repr(u8)]
338enum TransferFlag {
339 Start = 0x01,
340 Middle = 0x02,
341 End = 0x04,
342}
343
344#[cfg(feature = "alloc")]
345#[derive(Debug)]
346pub enum DescriptorString {
347 String(String),
348 Bytes(Vec<u8>),
349}
350
351#[cfg(not(feature = "alloc"))]
352#[derive(Debug)]
353pub enum DescriptorString {
354 String(heapless::String<MAX_DESC_STRING>),
355 Bytes(heapless::Vec<u8, MAX_DESC_STRING>),
356}
357
358impl fmt::Display for DescriptorString {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 let trim_chars = ['\0', ' '];
361 match self {
362 Self::String(s) => {
363 write!(
364 f,
365 "{}",
366 s.trim_end_matches(&trim_chars).escape_default()
367 )
368 }
369 Self::Bytes(bs) => {
370 for b in bs.iter() {
371 write!(f, "{:02x}", b)?;
372 }
373 Ok(())
374 }
375 }
376 }
377}
378
379impl DescriptorString {
380 pub fn empty() -> Self {
381 Self::Bytes(Default::default())
382 }
383
384 pub fn string_type(&self) -> u8 {
385 match self {
386 Self::Bytes(_) => 0,
387 Self::String(_) => 1,
388 }
389 }
390
391 fn as_bytes(&self) -> &[u8] {
392 match self {
393 Self::Bytes(b) => b,
394 Self::String(b) => b.as_bytes(),
395 }
396 }
397
398 fn bytes_len(&self) -> u8 {
399 self.as_bytes().len() as u8
400 }
401}
402
403#[cfg(feature = "alloc")]
404impl DescriptorString {
405 pub fn write_utf8_bytes(&self, v: &mut Vec<u8>) {
406 match self {
407 Self::String(s) => {
408 v.push(0x01);
409 v.push(s.len() as u8);
410 v.extend_from_slice(s.as_bytes());
411 }
412 Self::Bytes(b) => {
413 v.push(0x00);
414 v.push(b.len() as u8);
415 v.extend_from_slice(b);
416 }
417 }
418 }
419
420 pub fn new_utf8(v: &[u8]) -> Option<Self> {
421 if v.len() > 0xff {
422 return None;
423 }
424 let s = core::str::from_utf8(v).ok()?;
425 Some(Self::String(s.to_string()))
426 }
427
428 pub fn new_str(s: &str) -> Option<Self> {
429 if s.as_bytes().len() > 0xff {
430 return None;
431 }
432 Some(Self::String(s.to_string()))
433 }
434
435 pub fn new_bytes(v: &[u8]) -> Option<Self> {
436 if v.len() > 0xff {
437 return None;
438 }
439 Some(Self::Bytes(v.to_vec()))
440 }
441
442 }
455
456#[cfg(not(feature = "alloc"))]
457impl DescriptorString {
458 pub fn new_utf8(v: &[u8]) -> Option<Self> {
459 let s = core::str::from_utf8(v).ok()?;
460 Self::new_str(s)
461 }
462
463 pub fn new_str(s: &str) -> Option<Self> {
464 let s = heapless::String::try_from(s).ok()?;
465 Some(Self::String(s))
466 }
467
468 pub fn new_bytes(v: &[u8]) -> Option<Self> {
469 v.try_into().ok().map(|v| Self::Bytes(v))
470 }
471
472 }
479
480#[derive(Debug)]
482pub enum Descriptor {
483 PciVid(u16),
485 Iana(u32),
487 Uuid(uuid::Uuid),
489 PciDid(u16),
491 PciSubVid(u16),
493 PciSubDid(u16),
495 Vendor {
497 title: Option<DescriptorString>,
498 #[cfg(feature = "alloc")]
499 data: Vec<u8>,
500 #[cfg(not(feature = "alloc"))]
501 data: heapless::Vec<u8, MAX_VENDORDATA>,
502 },
503}
504
505pub fn parse_string<'a>(
507 typ: u8,
508 len: u8,
509) -> impl FnMut(&'a [u8]) -> VResult<&'a [u8], DescriptorString> {
510 map_opt(take(len), move |d: &[u8]| match typ {
511 0 => DescriptorString::new_bytes(d),
512 1 | 2 => DescriptorString::new_utf8(d),
514 _ => {
515 debug!("unimplemented string type {typ}");
516 None
517 }
518 })
519}
520
521pub fn parse_string_adjacent(buf: &[u8]) -> VResult<&[u8], DescriptorString> {
523 let (r, (typ, len)) = tuple((le_u8, le_u8))(buf)?;
524 parse_string(typ, len)(r)
525}
526
527impl Descriptor {
528 pub fn parse_pcivid(buf: &[u8]) -> VResult<&[u8], Self> {
529 map(le_u16, Self::PciVid)(buf)
530 }
531
532 pub fn parse_iana(buf: &[u8]) -> VResult<&[u8], Self> {
533 map(le_u32, Self::Iana)(buf)
534 }
535
536 pub fn parse_uuid(buf: &[u8]) -> VResult<&[u8], Self> {
537 map_res(take(16usize), |b| {
538 let u = uuid::Uuid::from_slice(b)?;
539 Ok::<Descriptor, uuid::Error>(Self::Uuid(u))
540 })(buf)
541 }
542
543 pub fn parse_pcidid(buf: &[u8]) -> VResult<&[u8], Self> {
544 map(le_u16, Self::PciDid)(buf)
545 }
546
547 pub fn parse_pcisubvid(buf: &[u8]) -> VResult<&[u8], Self> {
548 map(le_u16, Self::PciSubVid)(buf)
549 }
550
551 pub fn parse_pcisubdid(buf: &[u8]) -> VResult<&[u8], Self> {
552 map(le_u16, Self::PciSubDid)(buf)
553 }
554
555 #[cfg(feature = "alloc")]
556 fn new_vendor(t: Option<DescriptorString>, d: &[u8]) -> Option<Self> {
557 Some(Self::Vendor {
558 title: t,
559 data: d.to_vec(),
560 })
561 }
562
563 #[cfg(not(feature = "alloc"))]
564 fn new_vendor(t: Option<DescriptorString>, d: &[u8]) -> Option<Self> {
565 let data = d.try_into().ok()?;
566 Some(Self::Vendor { title: t, data })
567 }
568
569 pub fn parse_vendor(buf: &[u8]) -> VResult<&[u8], Self> {
570 let f1 = |(t, d): (_, &[u8])| Self::new_vendor(Some(t), d);
573 let f2 = |d: &[u8]| Self::new_vendor(None, d);
574 alt((
575 map_opt(tuple((parse_string_adjacent, rest)), f1),
576 map_opt(rest, f2),
577 ))(buf)
578 }
579
580 fn parse_fail(buf: &[u8]) -> VResult<&[u8], Self> {
581 nom::combinator::fail(buf)
582 }
583
584 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
585 let f = |(typ, len)| {
586 let g = match typ {
587 0x0000 => Self::parse_pcivid,
588 0x0001 => Self::parse_iana,
589 0x0002 => Self::parse_uuid,
590 0x0100 => Self::parse_pcidid,
591 0x0101 => Self::parse_pcisubvid,
592 0x0102 => Self::parse_pcisubdid,
593 0xffff => Self::parse_vendor,
594 _ => {
595 debug!("Unknown descriptor type 0x{typ:04x}");
596 Self::parse_fail
597 }
598 };
599 map_parser(take(len), all_consuming(g))
600 };
601 flat_map(tuple((le_u16, le_u16)), f)(buf)
602 }
603
604 pub fn desc_type(&self) -> u16 {
605 match self {
606 Self::PciVid(_) => 0x0000,
607 Self::Iana(_) => 0x0001,
608 Self::Uuid(_) => 0x0002,
609 Self::PciDid(_) => 0x0100,
610 Self::PciSubVid(_) => 0x0101,
611 Self::PciSubDid(_) => 0x0102,
612 Self::Vendor { .. } => 0xffff,
613 }
614 }
615
616 pub fn write_buf(&self, buf: &mut [u8]) -> Option<usize> {
617 let mut b = SliceWriter::new(buf);
618 match self {
619 Self::PciVid(v) => b.push_le16(*v),
620 Self::Iana(v) => b.push_le32(*v),
621 Self::Uuid(v) => b.push(v.as_bytes()),
622 Self::PciDid(v) => b.push_le16(*v),
623 Self::PciSubVid(v) => b.push_le16(*v),
624 Self::PciSubDid(v) => b.push_le16(*v),
625 Self::Vendor { .. } => {
626 debug!("Vendor descriptor write not implemented");
628 None
629 }
630 }
631 }
632}
633
634impl fmt::Display for Descriptor {
635 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
636 match self {
637 Self::PciVid(id) => write!(f, "pci-vendor:{:04x}", id),
638 Self::Iana(id) => write!(f, "iana:{:08x}", id),
639 Self::Uuid(id) => write!(f, "uuid:{}", id),
640 Self::PciDid(id) => write!(f, "pci-device:{:04x}", id),
641 Self::PciSubVid(id) => write!(f, "pci-subsys-vendor:{:04x}", id),
642 Self::PciSubDid(id) => write!(f, "pci-subsys-device:{:04x}", id),
643 Self::Vendor { title, data } => {
644 match title {
645 Some(t) => write!(f, "vendor:{}", t)?,
646 None => write!(f, "vendor:")?,
647 }
648 write!(f, "[")?;
649 for b in data {
650 write!(f, "{:02x}", b)?;
651 }
652 write!(f, "]")?;
653 Ok(())
654 }
655 }
656 }
657}
658
659impl PartialEq for Descriptor {
660 fn eq(&self, other: &Self) -> bool {
661 match (self, other) {
662 (Self::Vendor { data: s, .. }, Self::Vendor { data: o, .. }) => {
663 s == o
664 }
665 (Self::Iana(s), Self::Iana(o)) => s == o,
666 (Self::Uuid(s), Self::Uuid(o)) => s == o,
667 (Self::PciVid(s), Self::PciVid(o)) => s == o,
668 (Self::PciDid(s), Self::PciDid(o)) => s == o,
669 (Self::PciSubVid(s), Self::PciSubVid(o)) => s == o,
670 (Self::PciSubDid(s), Self::PciSubDid(o)) => s == o,
671 _ => false,
672 }
673 }
674}
675
676#[derive(Debug)]
677pub struct DeviceIdentifiers {
678 #[cfg(feature = "alloc")]
679 pub ids: Vec<Descriptor>,
680 #[cfg(not(feature = "alloc"))]
681 pub ids: &'static [Descriptor],
682}
683
684impl PartialEq for DeviceIdentifiers {
685 fn eq(&self, other: &Self) -> bool {
686 self.ids == other.ids
687 }
688}
689
690#[cfg(feature = "alloc")]
691impl DeviceIdentifiers {
692 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
693 length_count(le_u8, Descriptor::parse)(buf)
694 .map(|(rest, ids)| (rest, Self { ids }))
695 }
696}
697
698impl DeviceIdentifiers {
699 pub fn write_buf(&self, buf: &mut [u8]) -> Option<usize> {
701 let mut b = SliceWriter::new(buf);
702
703 if self.ids.is_empty() {
704 return None;
705 }
706
707 b.push_le32(0)?;
709 b.push_le8(self.ids.len() as u8)?;
710
711 for v in self.ids.iter() {
712 b.push_le16(v.desc_type())?;
713 b.push_prefix_le::<u16, _>(|m| v.write_buf(m))?;
714 }
715
716 let written = b.written();
717
718 let mut b = SliceWriter::new(buf);
721 b.push_le32((written - 5) as u32)?;
722
723 Some(written)
724 }
725}
726
727impl fmt::Display for DeviceIdentifiers {
728 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
729 let mut first = true;
730 for id in self.ids.iter() {
731 write!(f, "{}{}", if first { "" } else { "," }, id)?;
732 first = false;
733 }
734 Ok(())
735 }
736}
737
738pub type PldmDate = chrono::naive::NaiveDate;
739
740#[derive(Debug)]
741#[allow(dead_code)]
742pub struct ComponentVersion {
743 pub stamp: u32,
744 pub version: DescriptorString,
745 pub date: Option<PldmDate>,
746}
747
748impl ComponentVersion {
749 pub fn new_str(s: &str) -> Option<Self> {
753 Some(Self {
754 stamp: 0,
755 version: DescriptorString::new_str(s)?,
756 date: None,
757 })
758 }
759
760 pub fn write_initial(&self, b: &mut [u8]) -> Option<usize> {
764 let mut b = SliceWriter::new(b);
765 b.push_le32(self.stamp)?;
766 b.push_le8(self.version.string_type())?;
767 b.push_le8(self.version.bytes_len())?;
768 b.push_with(|m| pldm_date_write_buf(&self.date, m))?;
769 Some(b.written())
770 }
771}
772
773impl fmt::Display for ComponentVersion {
774 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
775 write!(f, "{}", self.version)?;
776 if let Some(d) = self.date {
777 write!(f, " ({:?})", d)?;
778 }
779 if self.stamp != 0 {
780 write!(f, " [{:08x}]", self.stamp)?;
781 }
782 Ok(())
783 }
784}
785
786pub fn pldm_date_parse(buf: &[u8]) -> VResult<&[u8], Option<PldmDate>> {
787 let (r, o) = alt((
789 value(None, tag([0u8; 8])),
790 map(
791 tuple((
792 map_parser(take(4u8), c_u32),
793 map_parser(take(2u8), c_u32),
794 map_parser(take(2u8), c_u32),
795 )),
796 Some,
797 ),
798 ))(buf)?;
799
800 let d = o.and_then(|(y, m, d)| PldmDate::from_ymd_opt(y as i32, m, d));
801
802 Ok((r, d))
803}
804
805pub fn pldm_date_write_buf(
806 date: &Option<PldmDate>,
807 b: &mut [u8],
808) -> Option<usize> {
809 let mut b = SliceWriter::new(b);
810 if let Some(date) = date {
811 let mut y = date.year();
812 if y < 0 {
813 return None;
814 }
815 let m = date.month();
816 let d = date.day();
817
818 let mut w = [0u8; 8];
820 for i in 0..4 {
821 w[3 - i] = (y % 10) as u8;
822 y /= 10;
823 }
824 w[4] = (m / 10) as u8;
825 w[5] = (m % 10) as u8;
826 w[6] = (d / 10) as u8;
827 w[7] = (d % 10) as u8;
828 let w = w.map(|c| b'0' + c);
829 b.push(&w)?;
830
831 } else {
834 b.push(&[0u8; 8])?;
835 }
836
837 Some(b.written())
838}
839
840#[allow(missing_docs)]
842#[derive(Debug, Copy, Clone, PartialEq)]
843pub enum ComponentClassification {
844 Unknown,
845 Other,
846 Firmware,
847 Value(u16),
849}
850
851impl From<u16> for ComponentClassification {
852 fn from(x: u16) -> Self {
853 match x {
854 0x0000 => Self::Unknown,
855 0x0001 => Self::Other,
856 0x000a => Self::Firmware,
857 v => Self::Value(v),
858 }
859 }
860}
861
862impl From<&ComponentClassification> for u16 {
863 fn from(c: &ComponentClassification) -> u16 {
864 match c {
865 ComponentClassification::Unknown => 0x0000,
866 ComponentClassification::Other => 0x0001,
867 ComponentClassification::Firmware => 0x000a,
868 ComponentClassification::Value(v) => *v,
869 }
870 }
871}
872
873#[derive(EnumSetType, Debug)]
874pub enum ActivationMethod {
875 PendingComponentImageSet = 7,
876 PendingImage = 6,
877 ACPowerCycle = 5,
878 DCPowerCycle = 4,
879 SystemReboot = 3,
880 MediumSpecificReset = 2,
881 SelfContained = 1,
882 Automatic = 0,
883}
884
885pub type ActivationMethods = EnumSet<ActivationMethod>;
886
887#[derive(EnumSetType, Debug)]
888pub enum DeviceCapability {
889 ComponentUpdateFailureRecovery = 0,
890 ComponentUpdateFailureRetry = 1,
891 FDHostFunctionalityDuringUpdate = 2,
892 FDPartialUpdates = 3,
893 FDUpdateModeRestrictionOSActive = 4,
894 FDDowngradeRestrictions = 8,
895 SecurityRevisionUpdateRequest = 9,
896}
897
898impl DeviceCapability {
899 #[cfg(feature = "alloc")]
900 pub fn to_desc(&self, is_set: bool) -> String {
901 match self {
902 Self::ComponentUpdateFailureRecovery => format!(
903 "Device will{} revert to previous component on failure",
904 if is_set { " not" } else { "" }
905 ),
906 Self::ComponentUpdateFailureRetry => format!(
907 "{} restarting update on failure",
908 if is_set {
909 "Requires"
910 } else {
911 "Does not require"
912 }
913 ),
914 Self::FDHostFunctionalityDuringUpdate => format!(
915 "Host functionality is{} reduced during update",
916 if is_set { "" } else { " not" }
917 ),
918 Self::FDPartialUpdates => format!(
919 "Device can{} accept a partial update",
920 if is_set { "" } else { "not" }
921 ),
922 Self::FDUpdateModeRestrictionOSActive => String::from(if is_set {
923 "No host OS restrictions during update"
924 } else {
925 "Device unable to update while host OS active"
926 }),
927 Self::FDDowngradeRestrictions => String::from(if is_set {
928 "No downgrade restrictions"
929 } else {
930 "Downgrades may be restricted"
931 }),
932 Self::SecurityRevisionUpdateRequest => format!(
933 "Device components {} have security revision numbers",
934 if is_set { "may" } else { "do not" }
935 ),
936 }
937 }
938}
939
940#[derive(Debug, Default)]
941pub struct DeviceCapabilities(EnumSet<DeviceCapability>);
942
943impl DeviceCapabilities {
944 pub fn from_u32(x: u32) -> Self {
945 let x = x & EnumSet::<DeviceCapability>::all().as_u32();
946 Self(EnumSet::<DeviceCapability>::from_u32(x))
947 }
948
949 pub fn as_u32(&self) -> u32 {
950 self.0.as_u32()
951 }
952
953 pub fn is_empty(&self) -> bool {
954 self.0.is_empty()
955 }
956
957 #[cfg(feature = "alloc")]
958 pub fn values(&self) -> Vec<(DeviceCapability, bool)> {
959 EnumSet::<DeviceCapability>::all()
960 .iter()
961 .map(|cap| (cap, self.0.contains(cap)))
962 .collect()
963 }
964}
965
966#[derive(EnumSetType, Debug)]
967pub enum ComponentCapability {
968 FDApplyState = 0,
969 ComponentDowngrade = 2,
970 SecurityRevisionUpdateRequest = 3,
971 SecurityRevisionNotLatest = 4,
972}
973
974pub type ComponentCapabilities = EnumSet<ComponentCapability>;
975
976#[derive(Debug)]
978#[allow(dead_code)]
979pub struct Component {
980 pub classification: ComponentClassification,
981 pub identifier: u16,
982 pub classificationindex: u8,
983 pub active: ComponentVersion,
984 pub pending: ComponentVersion,
985 pub activation_methods: ActivationMethods,
986 pub caps_during_update: ComponentCapabilities,
987}
988
989impl Component {
990 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
991 let (
992 r,
993 (
994 classification,
995 identifier,
996 classificationindex,
997 c1,
998 c2,
999 activation_methods,
1000 caps_during_update,
1001 ),
1002 ) = tuple((
1003 le_u16,
1004 le_u16,
1005 le_u8,
1006 tuple((le_u32, le_u8, le_u8, pldm_date_parse)),
1007 tuple((le_u32, le_u8, le_u8, pldm_date_parse)),
1008 le_u16,
1009 le_u32,
1010 ))(buf)?;
1011
1012 let (r, c1_str) = parse_string(c1.1, c1.2)(r)?;
1013 let (r, c2_str) = parse_string(c2.1, c2.2)(r)?;
1014
1015 let c = Component {
1016 classification: classification.into(),
1017 identifier,
1018 classificationindex,
1019 active: ComponentVersion {
1020 stamp: c1.0,
1021 version: c1_str,
1022 date: c1.3,
1023 },
1024 pending: ComponentVersion {
1025 stamp: c2.0,
1026 version: c2_str,
1027 date: c2.3,
1028 },
1029 activation_methods: ActivationMethods::from_u16(activation_methods),
1030 caps_during_update: ComponentCapabilities::from_u32(
1031 caps_during_update,
1032 ),
1033 };
1034
1035 Ok((r, c))
1036 }
1037
1038 pub fn write_buf(&self, b: &mut [u8]) -> Option<usize> {
1039 let mut b = SliceWriter::new(b);
1040 b.push_le16(u16::from(&self.classification))?;
1041 b.push_le16(self.identifier)?;
1042 b.push_le8(self.classificationindex)?;
1043 b.push_with(|m| self.active.write_initial(m))?;
1044 b.push_with(|m| self.pending.write_initial(m))?;
1045 b.push_le16(self.activation_methods.as_u16())?;
1046 b.push_le32(self.caps_during_update.as_u32())?;
1047 b.push(self.active.version.as_bytes())?;
1048 b.push(self.pending.version.as_bytes())?;
1049
1050 Some(b.written())
1051 }
1052}
1053
1054#[allow(missing_docs)]
1059pub struct UpdateComponent {
1060 pub classification: ComponentClassification,
1061 pub identifier: u16,
1062 pub classificationindex: u8,
1063 pub comparisonstamp: u32,
1064 pub version: DescriptorString,
1065 pub size: Option<u32>,
1067 pub flags: Option<u32>,
1069}
1070
1071impl UpdateComponent {
1072 pub fn parse_pass_component(buf: &[u8]) -> VResult<&[u8], Self> {
1073 let (
1074 r,
1075 (
1076 classification,
1077 identifier,
1078 classificationindex,
1079 comparisonstamp,
1080 version,
1081 ),
1082 ) = tuple((le_u16, le_u16, le_u8, le_u32, parse_string_adjacent))(
1083 &buf,
1084 )?;
1085
1086 let s = Self {
1087 classification: classification.into(),
1088 identifier,
1089 classificationindex,
1090 comparisonstamp,
1091 version,
1092 size: None,
1093 flags: None,
1094 };
1095 Ok((r, s))
1096 }
1097 pub fn parse_update(buf: &[u8]) -> VResult<&[u8], Self> {
1098 let (
1099 r,
1100 (
1101 classification,
1102 identifier,
1103 classificationindex,
1104 comparisonstamp,
1105 size,
1106 flags,
1107 version,
1108 ),
1109 ) = tuple((
1110 le_u16,
1111 le_u16,
1112 le_u8,
1113 le_u32,
1114 le_u32,
1115 le_u32,
1116 parse_string_adjacent,
1117 ))(&buf)?;
1118
1119 let s = Self {
1120 classification: classification.into(),
1121 identifier,
1122 classificationindex,
1123 comparisonstamp,
1124 version,
1125 size: Some(size),
1126 flags: Some(flags),
1127 };
1128 Ok((r, s))
1129 }
1130}
1131
1132#[derive(Debug)]
1133pub struct UpdateComponentResponse {
1134 pub response_code: u8,
1136 pub update_flags: u32,
1137 pub estimate_time: u16,
1138}
1139
1140#[allow(missing_docs)]
1144#[repr(u8)]
1145#[derive(Debug, PartialEq)]
1146#[non_exhaustive]
1147pub enum ComponentResponseCode {
1148 Success = 0x00,
1149 IdenticalVersion = 0x01,
1150 DowngradeVersion = 0x02,
1151 InvalidVersion = 0x03,
1152 Conflict = 0x04,
1153 MissingPrerequisite = 0x05,
1154 NotSupported = 0x06,
1155 SecurityPreventDowngrade = 0x07,
1156}
1157
1158impl UpdateComponentResponse {
1159 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
1160 let (r, (_response, response_code, update_flags, estimate_time)) =
1161 tuple((le_u8, le_u8, le_u32, le_u16))(buf)?;
1162
1163 let s = Self {
1164 response_code,
1165 update_flags,
1166 estimate_time,
1167 };
1168 Ok((r, s))
1169 }
1170}
1171
1172#[derive(Debug)]
1173#[allow(dead_code)]
1174pub struct FirmwareParameters<'a> {
1175 pub caps: DeviceCapabilities,
1176 pub components: VecOrSlice<'a, Component>,
1177 pub active: DescriptorString,
1178 pub pending: DescriptorString,
1179}
1180
1181#[cfg(feature = "alloc")]
1182impl FirmwareParameters<'_> {
1183 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
1184 let (r, p) = tuple((le_u32, le_u16, le_u8, le_u8, le_u8, le_u8))(buf)?;
1185
1186 let (
1187 caps,
1188 ccount,
1189 active_str_type,
1190 active_str_len,
1191 pending_str_type,
1192 pending_str_len,
1193 ) = p;
1194
1195 let (r, active) = parse_string(active_str_type, active_str_len)(r)?;
1196 let (r, pending) = parse_string(pending_str_type, pending_str_len)(r)?;
1197
1198 let (r, components) = count(Component::parse, ccount as usize)(r)?;
1199
1200 let fp = FirmwareParameters {
1201 caps: DeviceCapabilities::from_u32(caps),
1202 components: components.into(),
1203 active,
1204 pending,
1205 };
1206
1207 Ok((r, fp))
1208 }
1209}
1210
1211impl FirmwareParameters<'_> {
1212 pub fn write_buf(&self, buf: &mut [u8]) -> Option<usize> {
1213 let mut w = SliceWriter::new(buf);
1214
1215 w.push_le32(self.caps.as_u32())?;
1216 w.push_le16(self.components.len() as u16)?;
1217 w.push_le8(self.active.string_type())?;
1218 w.push_le8(self.active.bytes_len())?;
1219 w.push_le8(self.pending.string_type())?;
1220 w.push_le8(self.pending.bytes_len())?;
1221 w.push(self.active.as_bytes())?;
1222 w.push(self.pending.as_bytes())?;
1223
1224 for c in self.components.as_ref() {
1225 w.push_with(|b| c.write_buf(b))?;
1226 }
1227
1228 Some(w.written())
1229 }
1230}
1231
1232#[derive(Debug)]
1233pub struct RequestUpdateResponse {
1234 pub fd_metadata_len: u16,
1235 pub fd_will_sent_gpd: u8,
1236}
1237
1238impl RequestUpdateResponse {
1239 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
1240 let (r, t) = tuple((le_u16, le_u8))(buf)?;
1241 Ok((
1242 r,
1243 RequestUpdateResponse {
1244 fd_metadata_len: t.0,
1245 fd_will_sent_gpd: t.1,
1246 },
1247 ))
1248 }
1249
1250 pub fn write_buf(&self, b: &mut [u8]) -> Option<usize> {
1251 let mut b = SliceWriter::new(b);
1252 b.push_le16(self.fd_metadata_len)?;
1253 b.push_le8(self.fd_will_sent_gpd)?;
1254 Some(b.written())
1255 }
1256}
1257
1258#[derive(Debug)]
1259pub struct RequestUpdateRequest {
1260 pub max_transfer: u32,
1261 pub num_components: u16,
1262 pub max_outstanding: u8,
1263 pub package_data_length: u16,
1264 pub component_image_set_version: DescriptorString,
1265}
1266
1267impl RequestUpdateRequest {
1268 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
1269 let (r, t) =
1270 tuple((le_u32, le_u16, le_u8, le_u16, parse_string_adjacent))(buf)?;
1271 Ok((
1272 r,
1273 RequestUpdateRequest {
1274 max_transfer: t.0,
1275 num_components: t.1,
1276 max_outstanding: t.2,
1277 package_data_length: t.3,
1278 component_image_set_version: t.4,
1279 },
1280 ))
1281 }
1282}
1283
1284#[derive(Debug)]
1285pub struct GetStatusResponse {
1286 pub current_state: PldmFDState,
1287 pub previous_state: PldmFDState,
1288 pub aux_state: u8,
1289 pub aux_state_status: u8,
1290 pub progress_percent: u8,
1291 pub reason_code: u8,
1292 pub update_option_flags_enabled: u32,
1293}
1294
1295impl GetStatusResponse {
1296 pub fn parse(buf: &[u8]) -> VResult<&[u8], Self> {
1297 let (r, t) = tuple((
1298 PldmFDState::parse,
1299 PldmFDState::parse,
1300 le_u8,
1301 le_u8,
1302 le_u8,
1303 le_u8,
1304 le_u32,
1305 ))(buf)?;
1306 Ok((
1307 r,
1308 Self {
1309 current_state: t.0,
1310 previous_state: t.1,
1311 aux_state: t.2,
1312 aux_state_status: t.3,
1313 progress_percent: t.4,
1314 reason_code: t.5,
1315 update_option_flags_enabled: t.6,
1316 },
1317 ))
1318 }
1319
1320 pub fn write_buf(&self, buf: &mut [u8]) -> Option<usize> {
1321 let mut b = SliceWriter::new(buf);
1322 b.push_le8(self.current_state as u8)?;
1323 b.push_le8(self.previous_state as u8)?;
1324 b.push_le8(self.aux_state)?;
1325 b.push_le8(self.aux_state_status)?;
1326 b.push_le8(self.progress_percent)?;
1327 b.push_le8(self.reason_code)?;
1328 b.push_le32(self.update_option_flags_enabled)?;
1329 Some(b.written())
1330 }
1331}
1332
1333impl fmt::Display for GetStatusResponse {
1334 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1335 write!(formatter, "{:?}", self.current_state)
1336 }
1337}
1338
1339pub struct UpdateTransferProgress {
1340 pub cur_xfer: Option<(u32, u32)>,
1341 pub percent: u8,
1342 pub bps: f32,
1343 pub duration: chrono::Duration,
1344 pub remaining: chrono::Duration,
1345 pub complete: bool,
1346}
1347
1348#[cfg(test)]
1349mod tests {
1350
1351 use crate::*;
1352
1353 #[test]
1354 fn date_parse() {
1355 let x = b"20240704x";
1356 let d = pldm_date_parse(x).unwrap();
1357 let expect = PldmDate::parse_from_str("20240704", "%Y%m%d").unwrap();
1358 assert_eq!(d, ("x".as_bytes(), Some(expect)));
1359
1360 let x = b"-0240704x";
1362 pldm_date_parse(x).unwrap_err();
1363
1364 let x = b"2024070";
1366 pldm_date_parse(x).unwrap_err();
1367
1368 let x = b" 0240704x";
1370 pldm_date_parse(x).unwrap_err();
1371
1372 let x = b"20240732";
1374 let (_, d) = pldm_date_parse(x).unwrap();
1375 assert_eq!(d, None);
1376 }
1377
1378 #[test]
1379 fn date_write() {
1380 let d = PldmDate::parse_from_str("20240704", "%Y%m%d").unwrap();
1381
1382 let mut b = [99u8; 9];
1383 let l = pldm_date_write_buf(&Some(d), &mut b).unwrap();
1384 assert_eq!(b[8], 99);
1385 assert_eq!(l, 8);
1386 let b = &b[..l];
1387 assert_eq!(b"20240704", b);
1388
1389 let mut b = [99u8; 7];
1391 assert!(pldm_date_write_buf(&Some(d), &mut b).is_none());
1392
1393 let mut b = [99u8; 8];
1395 let l = pldm_date_write_buf(&None, &mut b).unwrap();
1396 assert_eq!(l, 8);
1397 assert_eq!(b, [0u8; 8]);
1398 }
1399
1400 #[test]
1401 #[rustfmt::skip]
1402 fn write_device_identifier() {
1403 let ids = vec![Descriptor::PciVid(0xccde), Descriptor::Iana(1234)];
1404 let di = DeviceIdentifiers { ids };
1405
1406 let mut sendbuf = [0u8; 50];
1407 let l = di.write_buf(&mut sendbuf).unwrap();
1408 let sendbuf = &sendbuf[..l];
1409 let expect = [
1410 0x0e, 0x00, 0x00, 0x00,
1412 0x02,
1414 0x00, 0x00,
1416 0x02, 0x00,
1418 0xde, 0xcc,
1420 0x01, 0x00,
1422 0x04, 0x00,
1424 0xd2, 0x04, 0x00, 0x00,
1426 ];
1427 assert_eq!(sendbuf, expect);
1428 }
1429}