Skip to content

Commit a80b6dd

Browse files
committed
freebsd: Parse full SMBIOS from /dev/mem
Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 0bbdc7e commit a80b6dd

2 files changed

Lines changed: 112 additions & 3 deletions

File tree

framework_lib/src/commandline/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,14 @@ fn selftest(ec: &CrosEc) -> Option<()> {
907907
}
908908

909909
fn smbios_info() {
910+
println!("Summary");
911+
println!(" Is Framework: {}", is_framework());
912+
if let Some(platform) = smbios::get_platform() {
913+
println!(" Platform: {:?}", platform);
914+
} else {
915+
println!(" Platform: Unknown",);
916+
}
917+
910918
let smbios = get_smbios();
911919
if smbios.is_none() {
912920
error!("Failed to find SMBIOS");

framework_lib/src/smbios.rs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::prelude::v1::*;
44

5-
#[cfg(not(feature = "uefi"))]
5+
#[cfg(all(not(feature = "uefi"), not(target_os = "freebsd")))]
66
use std::io::ErrorKind;
77

88
use crate::util::{Config, Platform};
@@ -13,6 +13,9 @@ use spin::Mutex;
1313
#[cfg(not(feature = "uefi"))]
1414
use std::sync::Mutex;
1515

16+
#[cfg(target_os = "freebsd")]
17+
use std::io::{Read, Seek, SeekFrom};
18+
1619
/// Current platform. Won't ever change during the program's runtime
1720
static CACHED_PLATFORM: Mutex<Option<Option<Platform>>> = Mutex::new(None);
1821

@@ -82,6 +85,103 @@ pub fn dmidecode_string_val(s: &SMBiosString) -> Option<String> {
8285
}
8386
}
8487

88+
#[cfg(target_os = "freebsd")]
89+
#[repr(C)]
90+
pub struct Smbios3 {
91+
pub anchor: [u8; 5],
92+
pub checksum: u8,
93+
pub length: u8,
94+
pub major_version: u8,
95+
pub minor_version: u8,
96+
pub docrev: u8,
97+
pub revision: u8,
98+
_reserved: u8,
99+
pub table_length: u32,
100+
pub table_address: u64,
101+
}
102+
103+
#[cfg(target_os = "freebsd")]
104+
#[repr(packed)]
105+
pub struct Smbios {
106+
pub anchor: [u8; 4],
107+
pub checksum: u8,
108+
pub length: u8,
109+
pub major_version: u8,
110+
pub minor_version: u8,
111+
pub max_structure_size: u16,
112+
pub revision: u8,
113+
pub formatted: [u8; 5],
114+
pub inter_anchor: [u8; 5],
115+
pub inter_checksum: u8,
116+
pub table_length: u16,
117+
pub table_address: u32,
118+
pub structure_count: u16,
119+
pub bcd_revision: u8,
120+
}
121+
122+
#[cfg(target_os = "freebsd")]
123+
pub fn get_smbios() -> Option<SMBiosData> {
124+
// Get the SMBIOS entrypoint address from the kernel environment
125+
let addr_hex = kenv_get("hint.smbios.0.mem").ok()?;
126+
let addr_hex = addr_hex.trim_start_matches("0x");
127+
let addr = u64::from_str_radix(&addr_hex, 16).unwrap();
128+
trace!("SMBIOS Entrypoint Addr: {} 0x{:x}", addr_hex, addr);
129+
130+
let mut dev_mem = std::fs::File::open("/dev/mem").ok()?;
131+
// Smbios struct is larger than Smbios3 struct
132+
let mut header_buf = [0; std::mem::size_of::<Smbios>()];
133+
dev_mem.seek(SeekFrom::Start(addr)).ok()?;
134+
dev_mem.read_exact(&mut header_buf).ok()?;
135+
136+
let entrypoint = unsafe { &*(header_buf.as_ptr() as *const Smbios3) };
137+
138+
trace!("SMBIOS Anchor {:?} = ", entrypoint.anchor);
139+
let (addr, len, version) = match entrypoint.anchor {
140+
[b'_', b'S', b'M', b'3', b'_'] => {
141+
trace!("_SM3_");
142+
let entrypoint = unsafe { &*(header_buf.as_ptr() as *const Smbios3) };
143+
let ver = Some(SMBiosVersion {
144+
major: entrypoint.major_version,
145+
minor: entrypoint.minor_version,
146+
revision: 0,
147+
});
148+
149+
(entrypoint.table_address, entrypoint.table_length, ver)
150+
}
151+
[b'_', b'S', b'M', b'_', _] => {
152+
trace!("_SM_");
153+
let entrypoint = unsafe { &*(header_buf.as_ptr() as *const Smbios) };
154+
let ver = Some(SMBiosVersion {
155+
major: entrypoint.major_version,
156+
minor: entrypoint.minor_version,
157+
revision: 0,
158+
});
159+
160+
(
161+
entrypoint.table_address as u64,
162+
entrypoint.table_length as u32,
163+
ver,
164+
)
165+
}
166+
[b'_', b'D', b'M', b'I', b'_'] => {
167+
error!("_DMI_ - UNSUPPORTED");
168+
return None;
169+
}
170+
_ => {
171+
error!(" Unknown - UNSUPPORTED");
172+
return None;
173+
}
174+
};
175+
176+
// Get actual SMBIOS table data
177+
let mut smbios_buf = vec![0; len as usize];
178+
dev_mem.seek(SeekFrom::Start(addr)).ok()?;
179+
dev_mem.read_exact(&mut smbios_buf).ok()?;
180+
181+
let smbios = SMBiosData::from_vec_and_version(smbios_buf, version);
182+
Some(smbios)
183+
}
184+
85185
#[cfg(feature = "uefi")]
86186
pub fn get_smbios() -> Option<SMBiosData> {
87187
let data = crate::uefi::smbios_data().unwrap();
@@ -90,9 +190,8 @@ pub fn get_smbios() -> Option<SMBiosData> {
90190
Some(smbios)
91191
}
92192
// On Linux this reads either from /dev/mem or sysfs
93-
// On FreeBSD from /dev/mem
94193
// On Windows from the kernel API
95-
#[cfg(not(feature = "uefi"))]
194+
#[cfg(all(not(feature = "uefi"), not(target_os = "freebsd")))]
96195
pub fn get_smbios() -> Option<SMBiosData> {
97196
match smbioslib::table_load_from_device() {
98197
Ok(data) => Some(data),
@@ -104,6 +203,8 @@ pub fn get_smbios() -> Option<SMBiosData> {
104203
println!("Failed to get SMBIOS: {:?}", err);
105204
None
106205
}
206+
}
207+
}
107208

108209
fn get_product_name() -> Option<String> {
109210
// On FreeBSD we can short-circuit and avoid parsing SMBIOS

0 commit comments

Comments
 (0)