Skip to main content

intel_crashlog/source/acpi/
sysfs.rs

1// Copyright (C) 2026 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4use crate::CrashLog;
5use crate::bert::Berr;
6use crate::error::Error;
7use std::path::{Path, PathBuf};
8
9pub(super) struct AcpiSysFs {
10    root: PathBuf,
11}
12
13impl Default for AcpiSysFs {
14    fn default() -> Self {
15        Self::new(Path::new("/"))
16    }
17}
18
19impl AcpiSysFs {
20    pub fn new(path: &Path) -> Self {
21        Self {
22            root: path.to_owned(),
23        }
24    }
25
26    fn tables_path(&self) -> PathBuf {
27        let mut path = self.root.clone();
28        path.push("sys");
29        path.push("firmware");
30        path.push("acpi");
31        path.push("tables");
32        path
33    }
34
35    fn berr_path(&self) -> PathBuf {
36        let mut path = self.tables_path();
37        path.push("data");
38        path.push("BERT");
39        path
40    }
41
42    pub fn extract(&self) -> Result<CrashLog, Error> {
43        let path = self.berr_path();
44        let berr = std::fs::read(&path)
45            .map_err(|err| {
46                log::warn!("Cannot read {}: {err}", path.display());
47                match err.kind() {
48                    std::io::ErrorKind::NotFound => Error::NoCrashLogFound,
49                    _ => Error::from(err),
50                }
51            })
52            .and_then(|berr| {
53                log::info!("Found ACPI boot error record in sysfs");
54                Berr::from_slice(&berr).ok_or(Error::InvalidBootErrorRecordRegion)
55            })?;
56
57        CrashLog::from_berr(berr)
58    }
59}
60
61impl CrashLog {
62    /// Reads the Crash Log reported through ACPI from the Linux sysfs
63    pub fn from_acpi_sysfs() -> Result<Self, Error> {
64        AcpiSysFs::default().extract()
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use tempfile;
72
73    #[test]
74    fn extract() {
75        let root = tempfile::tempdir().unwrap();
76
77        let acpi = AcpiSysFs::new(root.path());
78
79        let mut berr_path = root.path().to_owned();
80        berr_path.push("sys");
81        berr_path.push("firmware");
82        berr_path.push("acpi");
83        berr_path.push("tables");
84        berr_path.push("data");
85        std::fs::create_dir_all(&berr_path).unwrap();
86
87        berr_path.push("BERT");
88
89        let bert = std::fs::read("tests/samples/dummy.bert").unwrap();
90        let crashlog = CrashLog::from_slice(&bert).unwrap();
91
92        let berr = Berr::from_crashlog(&crashlog);
93        std::fs::write(berr_path, berr.to_bytes()).unwrap();
94
95        let extracted_crashlog = acpi.extract().unwrap();
96
97        assert_eq!(crashlog.to_bytes(), extracted_crashlog.to_bytes());
98    }
99}