Skip to content

Commit e8bd358

Browse files
authored
feat(slot-ctrl): unify device behavior (#1156)
Motivation: - forwarding the backing of SR_RF from efvars into Orin - backporting the handling of SR_RF in xavier from the tegra-pmc driver `slot-ctrl` infrastructure needs to updated to reflect the two above changes. Additionally a couple of bugs are fixed
1 parent 3ba8068 commit e8bd358

5 files changed

Lines changed: 231 additions & 290 deletions

File tree

slot-ctrl/src/domain.rs

Lines changed: 77 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use std::{fmt::Display, str::FromStr};
1+
use std::{fmt::Display, fs, path::Path, str::FromStr};
22

33
use derive_more::Display;
44
use efivar::EfiVarData;
5-
use orb_info::orb_os_release::OrbOsPlatform;
65

76
pub type Result<T> = std::result::Result<T, Error>;
87

@@ -14,16 +13,16 @@ pub enum Error {
1413
InvalidEfiVarLen { expected: usize, actual: usize },
1514
#[error("invalid slot configuration")]
1615
InvalidSlotData,
16+
#[error("invalid bootchain-firmware status")]
17+
InvalidBootChainFwStatusData,
1718
#[error("invalid rootfs status")]
1819
InvalidRootFsStatusData,
19-
#[error("failed reading scratch register: {0}")]
20-
CouldNotReadScratchReg(String),
20+
#[error("failed opening scratch register: {0}")]
21+
CouldNotOpenScratchReg(String),
2122
#[error("invalid retry counter({counter}), exceeding the maximum ({max})")]
2223
ExceedingRetryCount { counter: u8, max: u8 },
2324
#[error("{0}")]
2425
EfiVar(#[from] color_eyre::Report),
25-
#[error("unsupported orb type: {0}")]
26-
UnsupportedOrbType(OrbOsPlatform),
2726
}
2827

2928
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
@@ -95,13 +94,14 @@ impl TryFrom<u8> for BootChainFwStatus {
9594
16 => Ok(Self::ErrorSettingScratch),
9695
17 => Ok(Self::ErrorUpdateBrBctFlagSet),
9796
18 => Ok(Self::ErrorSettingPrevious),
98-
_ => Err(Error::InvalidRootFsStatusData),
97+
_ => Err(Error::InvalidBootChainFwStatusData),
9998
}
10099
}
101100
}
102101

103102
/// Representation of the slot.
104103
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
104+
#[repr(u8)]
105105
pub enum Slot {
106106
#[display("a")]
107107
A = 0,
@@ -111,38 +111,28 @@ pub enum Slot {
111111

112112
/// Representation of the rootfs status.
113113
#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
114+
#[repr(u8)]
114115
pub enum RootFsStatus {
115116
/// Default status of the rootfs.
116-
Normal,
117-
/// Status of the rootfs where the partitions during an update are written.
118-
UpdateInProcess,
119-
/// Status of the rootfs where the boot slot was just switched to it.
120-
UpdateDone,
121-
/// Status of the rootfs is considered unbootable.
122-
Unbootable,
117+
Normal = 0x0,
118+
/// Rootfs status signifying that an update consumption has initiated
119+
UpdateInProcess = 0x1,
120+
/// Rootfs status signifying that an update was done & active slot switched
121+
UpdateDone = 0x2,
122+
/// Rootfs status signifying that the target slot is considered unbootable.
123+
Unbootable = 0x3,
123124
}
124125

125126
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126127
pub struct RetryCounts {
127-
pub efi_var: Option<EfiRetryCount>,
128-
pub scratch_reg: Option<ScratchRegRetryCount>,
128+
pub efi_var: EfiRetryCount,
129+
pub sr_rf: ScratchRegRetryCount,
129130
}
130131

131132
impl Display for RetryCounts {
132133
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133-
const NA: &str = "unavailable in this platform";
134-
135-
write!(f, "efi var: ")?;
136-
match self.efi_var {
137-
Some(v) => write!(f, "{v}")?,
138-
None => write!(f, "{NA}")?,
139-
};
140-
141-
write!(f, "\nscratch register: ")?;
142-
match self.scratch_reg {
143-
Some(v) => write!(f, "{v}")?,
144-
None => write!(f, "{NA}")?,
145-
};
134+
writeln!(f, "efi var: {}", &self.efi_var)?;
135+
writeln!(f, "SR_RF: {}", &self.sr_rf)?;
146136

147137
Ok(())
148138
}
@@ -152,10 +142,32 @@ impl Display for RetryCounts {
152142
pub struct ScratchRegRetryCount(pub u8);
153143

154144
impl ScratchRegRetryCount {
155-
pub(crate) const DIAMOND_COUNT_A_PATH: &str =
145+
pub(crate) const DIAMOND_REG_PATH_A: &str =
156146
"sys/devices/platform/bus@0/c360000.pmc/rootfs_retry_count_a";
157-
pub(crate) const DIAMOND_COUNT_B_PATH: &str =
147+
pub(crate) const DIAMOND_REG_PATH_B: &str =
158148
"sys/devices/platform/bus@0/c360000.pmc/rootfs_retry_count_b";
149+
pub(crate) const PEARL_REG_PATH_A: &str =
150+
"sys/devices/platform/c360000.pmc/rootfs_retry_count_a";
151+
pub(crate) const PEARL_REG_PATH_B: &str =
152+
"sys/devices/platform/c360000.pmc/rootfs_retry_count_b";
153+
pub(crate) const SR_RF_COUNT_MAX: u8 = 0x3;
154+
155+
pub(crate) fn new(sr_rf_path: impl AsRef<Path>) -> Result<Self> {
156+
let raw = fs::read_to_string(sr_rf_path)
157+
.map_err(|e| Error::CouldNotOpenScratchReg(e.to_string()))?;
158+
159+
let hex = raw.trim().strip_prefix("0x").ok_or_else(|| {
160+
Error::CouldNotOpenScratchReg(format!(
161+
"scratch register retry count in unexpected format: {raw}"
162+
))
163+
})?;
164+
165+
let count = hex
166+
.parse::<u8>()
167+
.map_err(|e| Error::CouldNotOpenScratchReg(format!("{e}: '{hex}'")))?;
168+
169+
Ok(ScratchRegRetryCount(count))
170+
}
159171
}
160172

161173
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
@@ -201,8 +213,8 @@ impl FromStr for Slot {
201213
}
202214

203215
impl Slot {
204-
pub(crate) const SLOT_A_BYTES: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
205-
pub(crate) const SLOT_B_BYTES: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
216+
const SLOT_A_BYTES: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
217+
const SLOT_B_BYTES: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
206218

207219
pub(crate) const CURRENT_SLOT_PATH: &str =
208220
"BootChainFwCurrent-781e084c-a330-417c-b678-38e696380cb9";
@@ -215,12 +227,17 @@ impl Slot {
215227
}
216228

217229
pub fn from_efivar_data(data: &EfiVarData) -> Result<Slot> {
218-
if Slot::SLOT_A_BYTES == data.value() {
219-
Ok(Slot::A)
220-
} else if Slot::SLOT_B_BYTES == data.value() {
221-
Ok(Slot::B)
222-
} else {
223-
Err(Error::InvalidSlotData)
230+
if data.len() != 8 {
231+
return Err(Error::InvalidEfiVarLen {
232+
expected: 8,
233+
actual: data.len(),
234+
});
235+
}
236+
237+
match data.value() {
238+
val if val == Self::SLOT_A_BYTES => Ok(Slot::A),
239+
val if val == Self::SLOT_B_BYTES => Ok(Slot::B),
240+
_ => Err(Error::InvalidSlotData),
224241
}
225242
}
226243
}
@@ -231,83 +248,43 @@ impl FromStr for RootFsStatus {
231248
fn from_str(s: &str) -> Result<Self> {
232249
match s.to_lowercase().as_str() {
233250
"normal" | "0" => Ok(RootFsStatus::Normal),
234-
"updateinprocess" | "updinprocess" | "1" => {
235-
Ok(RootFsStatus::UpdateInProcess)
236-
}
237-
"updatedone" | "upddone" | "2" => Ok(RootFsStatus::UpdateDone),
251+
"updateinprocess" | "1" => Ok(RootFsStatus::UpdateInProcess),
252+
"updatedone" | "2" => Ok(RootFsStatus::UpdateDone),
238253
"unbootable" | "3" => Ok(RootFsStatus::Unbootable),
239-
_ => Err(Error::InvalidSlotData),
254+
_ => Err(Error::InvalidRootFsStatusData),
240255
}
241256
}
242257
}
243258

244259
impl RootFsStatus {
245-
// Right now Pearl has extra states in the update status, some thing
246-
// we will probably get rid of in the future. Values were also altered and are
247-
// different than the default NVIDIA ones (used by Diamond)
248-
// https://github.com/worldcoin/edk2-nvidia/blob/ede09eb66b00d5d185ba93b7992390f2a483b46f/Silicon/NVIDIA/Include/NVIDIAConfiguration.h#L23
249-
pub(crate) const PEARL_NORMAL: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
250-
pub(crate) const PEARL_UPDATE_IN_PROGRESS: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
251-
pub(crate) const PEARL_UPDATE_DONE: [u8; 4] = [0x02, 0x00, 0x00, 0x00];
252-
pub(crate) const PEARL_UNBOOTABLE: [u8; 4] = [0x03, 0x00, 0x00, 0x00];
253-
254-
// https://github.com/worldcoin/edk2-nvidia/blob/86a32d95373d6aaf87278093a855ccf193b9c61f/Silicon/NVIDIA/Include/NVIDIAConfiguration.h#L23
255-
pub(crate) const DIAMOND_NORMAL: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
256-
pub(crate) const DIAMOND_UNBOOTABLE: [u8; 4] = [0xFF, 0x00, 0x00, 0x00];
260+
const NORMAL: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
261+
const UPDATE_IN_PROGRESS: [u8; 4] = [0x01, 0x00, 0x00, 0x00];
262+
const UPDATE_DONE: [u8; 4] = [0x02, 0x00, 0x00, 0x00];
263+
const UNBOOTABLE: [u8; 4] = [0x03, 0x00, 0x00, 0x00];
257264

258265
pub(crate) const STATUS_A_PATH: &str =
259266
"RootfsStatusSlotA-781e084c-a330-417c-b678-38e696380cb9";
260267
pub(crate) const STATUS_B_PATH: &str =
261268
"RootfsStatusSlotB-781e084c-a330-417c-b678-38e696380cb9";
262269

263-
pub fn to_efivar_data(&self, orb: OrbOsPlatform) -> Result<EfiVarData> {
264-
let value = match (self, orb) {
265-
(Self::Normal, OrbOsPlatform::Pearl) => &Self::PEARL_NORMAL,
266-
(Self::UpdateInProcess, OrbOsPlatform::Pearl) => {
267-
&Self::PEARL_UPDATE_IN_PROGRESS
268-
}
269-
(Self::UpdateDone, OrbOsPlatform::Pearl) => &Self::PEARL_UPDATE_DONE,
270-
(Self::Unbootable, OrbOsPlatform::Pearl) => &Self::PEARL_UNBOOTABLE,
271-
(Self::Normal, OrbOsPlatform::Diamond) => &Self::DIAMOND_NORMAL,
272-
(Self::Unbootable, OrbOsPlatform::Diamond) => &Self::DIAMOND_UNBOOTABLE,
273-
_ => return Err(Error::InvalidRootFsStatusData),
274-
};
275-
276-
Ok(EfiVarData::new(0x7, value))
270+
pub fn to_efivar_data(&self) -> EfiVarData {
271+
EfiVarData::new(0x7, [*self as u8, 0x0, 0x0, 0x0])
277272
}
278273

279274
/// RootFsStatus from EfiVar raw bytes
280-
pub fn from_efivar_data(
281-
data: &EfiVarData,
282-
orb: OrbOsPlatform,
283-
) -> Result<RootFsStatus> {
284-
let bytes = data.value();
285-
286-
match orb {
287-
OrbOsPlatform::Pearl if bytes == Self::PEARL_NORMAL => {
288-
Ok(RootFsStatus::Normal)
289-
}
290-
291-
OrbOsPlatform::Pearl if bytes == Self::PEARL_UPDATE_IN_PROGRESS => {
292-
Ok(RootFsStatus::UpdateInProcess)
293-
}
294-
295-
OrbOsPlatform::Pearl if bytes == Self::PEARL_UPDATE_DONE => {
296-
Ok(RootFsStatus::UpdateDone)
297-
}
298-
299-
OrbOsPlatform::Pearl if bytes == Self::PEARL_UNBOOTABLE => {
300-
Ok(RootFsStatus::Unbootable)
301-
}
302-
303-
OrbOsPlatform::Diamond if bytes == Self::DIAMOND_NORMAL => {
304-
Ok(RootFsStatus::Normal)
305-
}
306-
307-
OrbOsPlatform::Diamond if bytes == Self::DIAMOND_UNBOOTABLE => {
308-
Ok(RootFsStatus::Unbootable)
309-
}
275+
pub fn from_efivar_data(data: &EfiVarData) -> Result<RootFsStatus> {
276+
if data.len() != 8 {
277+
return Err(Error::InvalidEfiVarLen {
278+
expected: 8,
279+
actual: data.len(),
280+
});
281+
}
310282

283+
match data.value() {
284+
val if val == Self::NORMAL => Ok(Self::Normal),
285+
val if val == Self::UPDATE_IN_PROGRESS => Ok(Self::UpdateInProcess),
286+
val if val == Self::UPDATE_DONE => Ok(Self::UpdateDone),
287+
val if val == Self::UNBOOTABLE => Ok(Self::Unbootable),
311288
_ => Err(Error::InvalidRootFsStatusData),
312289
}
313290
}

0 commit comments

Comments
 (0)