1use crate::update::{FlashError, FlashRuntime, FlashTransport, PrepareError, Verified};
5use crate::{
6 drive::{self, Transport},
7 image, layout, receiver, Chip, DriveClass,
8};
9
10#[derive(Debug, Clone)]
12pub struct Receiver {
13 receiver: receiver::Receiver,
14 chip: Chip,
15 banner: [u8; layout::BANNER.len],
16}
17#[derive(Debug)]
19pub enum Error<E> {
20 Receiver(receiver::Error<E>),
22 Reference(receiver::reference::Error<E>),
24 Read(drive::Error<E>),
26 Image(PrepareError),
28 Flash(FlashError<E>),
30 Changed,
32 Startup,
34}
35impl<E: core::fmt::Debug> core::fmt::Display for Error<E> {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 match self {
38 Self::Receiver(e)=>write!(f,"{e}"), Self::Reference(e)=>write!(f,"{e}"), Self::Read(e)=>write!(f,"{e}"),
39 Self::Image(e)=>write!(f,"{e}"), Self::Flash(e)=>write!(f,"{e}"),
40 Self::Changed=>f.write_str("MediaTek boot banner changed; re-plan recovery"),
41 Self::Startup=>f.write_str("recovery did not confirm startup of the selected firmware; drive may still be in BOOT"),
42 }
43 }
44}
45impl<E: core::fmt::Debug + 'static> std::error::Error for Error<E> {
46 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47 match self {
48 Self::Receiver(source) => Some(source),
49 Self::Reference(source) => Some(source),
50 Self::Read(source) => Some(source),
51 Self::Image(source) => Some(source),
52 Self::Flash(source) => Some(source),
53 _ => None,
54 }
55 }
56}
57
58impl Receiver {
59 pub fn identify<T: Transport>(t: &mut T) -> Result<Option<Self>, Error<T::Error>> {
62 let mode = match receiver::detect_mode(t) {
63 Ok(mode) => mode,
64 Err(receiver::Error::InvalidIdentity) => return Ok(None),
65 Err(e) => return Err(Error::Receiver(e)),
66 };
67 if [&b"PIONEER "[..], &b"RENESAS "[..]].contains(&&mode.inquiry()[8..16]) {
68 return Ok(None);
69 }
70 let mut banner = [0; layout::BANNER.len];
71 if drive::read_memory(t, layout::BANNER.start as u32, &mut banner).is_err() {
72 return Ok(None);
73 }
74 let Some(chip) = Chip::from_banner(&banner) else {
75 return Ok(None);
76 };
77 let receiver = receiver::detect(t, &mode).map_err(Error::Receiver)?;
78 Ok(Some(Self {
79 receiver,
80 chip,
81 banner,
82 }))
83 }
84 pub fn identify_reference<T: Transport>(
87 t: &mut T,
88 envelope: &crate::envelope::Envelope,
89 ) -> Result<Self, Error<T::Error>> {
90 let receiver = receiver::reference::detect(t, envelope).map_err(Error::Reference)?;
91 let mut banner = [0; layout::BANNER.len];
92 drive::read_memory(t, layout::BANNER.start as u32, &mut banner).map_err(Error::Read)?;
93 let chip = Chip::from_banner(&banner).ok_or(Error::Changed)?;
94 Ok(Self {
95 receiver,
96 chip,
97 banner,
98 })
99 }
100 pub fn mode(&self) -> receiver::Mode {
102 self.receiver.mode()
103 }
104 pub fn encoding(&self) -> receiver::Encoding {
106 self.receiver.encoding()
107 }
108 pub fn chip(&self) -> Chip {
110 self.chip
111 }
112 pub fn revalidate<T: Transport>(&self, t: &mut T) -> Result<(), Error<T::Error>> {
114 self.receiver.revalidate(t).map_err(Error::Receiver)?;
115 let mut banner = [0; layout::BANNER.len];
116 drive::read_memory(t, layout::BANNER.start as u32, &mut banner).map_err(Error::Read)?;
117 if banner != self.banner {
118 return Err(Error::Changed);
119 }
120 Ok(())
121 }
122 pub fn prepare(&self, image: &[u8]) -> Result<PreparedRecovery, PrepareError> {
125 if image.len() != layout::IMAGE_SIZE {
126 return Err(PrepareError::Size(image.len()));
127 }
128 if !image::cmac::verify(image) {
129 return Err(PrepareError::Integrity);
130 }
131 if image::is_drive_read(image) {
132 return Err(PrepareError::DriveRead);
133 }
134 let chip = image::detect_chip(image)
135 .map_err(|_| PrepareError::UnknownChip)?
136 .family;
137 if chip != self.chip {
138 return Err(PrepareError::ChipMismatch {
139 image: chip,
140 drive: self.chip,
141 });
142 }
143 Ok(PreparedRecovery {
144 receiver: self.clone(),
145 plan: receiver::TransferPlan::new(
146 &self.receiver,
147 image,
148 DriveClass::of(self.chip),
149 crate::update::flash::ExecutionMode::Recovery,
150 )?,
151 })
152 }
153}
154
155#[derive(Debug, Clone)]
157pub struct PreparedRecovery {
158 receiver: Receiver,
159 plan: receiver::TransferPlan,
160}
161impl PreparedRecovery {
162 pub fn encoding(&self) -> receiver::Encoding {
164 self.receiver.encoding()
165 }
166 pub fn mode(&self) -> receiver::Mode {
168 self.receiver.mode()
169 }
170 pub fn transfer(&self) -> &[u8] {
172 self.plan.transfer()
173 }
174 pub fn plan(&self) -> &receiver::TransferPlan {
176 &self.plan
177 }
178 pub fn flash<R, W, H>(
183 &self,
184 io: FlashTransport<'_, R, W>,
185 runtime: &mut H,
186 ) -> Result<Verified, Error<W::Error>>
187 where
188 W: Transport,
189 R: Transport<Error = W::Error>,
190 H: FlashRuntime<W::Error>,
191 {
192 self.flash_completed(io, runtime)?
193 .into_verified()
194 .map_err(Error::Flash)
195 }
196
197 pub fn flash_completed<R, W, H>(
200 &self,
201 io: FlashTransport<'_, R, W>,
202 runtime: &mut H,
203 ) -> Result<crate::update::Completion, Error<W::Error>>
204 where
205 W: Transport,
206 R: Transport<Error = W::Error>,
207 H: FlashRuntime<W::Error>,
208 {
209 let mut banner = [0; layout::BANNER.len];
210 drive::read_memory(io.reads, layout::BANNER.start as u32, &mut banner)
211 .map_err(Error::Read)?;
212 if banner != self.receiver.banner {
213 return Err(Error::Changed);
214 }
215 self.plan
216 .execute_completed(io, runtime)
217 .map_err(|e| match e {
218 receiver::ExecuteError::Receiver(e) => Error::Receiver(e),
219 receiver::ExecuteError::Flash(e) => Error::Flash(e),
220 })
221 }
222}