Skip to content

Commit bf934a7

Browse files
committed
add physical memory array type
1 parent ec9412a commit bf934a7

File tree

3 files changed

+263
-2
lines changed

3 files changed

+263
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ sudo dmitui
5050
- [x] Baseboard (type 2)
5151
- [x] Chassis (type 3) (Partially)
5252
- [x] Firmware Language Information (type 13)
53+
- [x] Physical Memory Array (type 16)
5354

5455
## ⚖️ License
5556

src/dmi.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod baseboard;
22
mod chassis;
33
mod firmware;
4+
mod memory;
45
mod system;
56

67
use std::{
@@ -14,6 +15,7 @@ use anyhow::{Result, bail};
1415
use crate::dmi::baseboard::Baseboard;
1516
use crate::dmi::chassis::Chassis;
1617
use crate::dmi::firmware::Firmware;
18+
use crate::dmi::memory::{Memory, PhysicalMemoryArray};
1719
use crate::dmi::system::System;
1820

1921
use crossterm::event::{KeyCode, KeyEvent};
@@ -31,6 +33,7 @@ pub struct DMI {
3133
system: System,
3234
baseboard: Baseboard,
3335
chassis: Chassis,
36+
memory: Memory,
3437
pub focused_section: FocusedSection,
3538
}
3639

@@ -41,6 +44,7 @@ pub enum FocusedSection {
4144
System,
4245
Baseboard,
4346
Chassis,
47+
Memory,
4448
}
4549

4650
#[derive(Debug)]
@@ -58,6 +62,7 @@ impl From<[u8; 4]> for Header {
5862
2 => StructureType::Baseboard,
5963
3 => StructureType::Chassis,
6064
13 => StructureType::FirmwareLanguage,
65+
16 => StructureType::PhysicalMemoryArray,
6166
127 => StructureType::End,
6267
_ => StructureType::Other,
6368
};
@@ -78,6 +83,7 @@ pub enum StructureType {
7883
Baseboard = 2,
7984
Chassis = 3,
8085
FirmwareLanguage = 13,
86+
PhysicalMemoryArray = 16,
8187
End = 127,
8288
Other = 255,
8389
}
@@ -90,6 +96,7 @@ impl DMI {
9096
let mut system: Option<System> = None;
9197
let mut baseboard: Option<Baseboard> = None;
9298
let mut chassis: Option<Chassis> = None;
99+
let mut memory: Option<Memory> = None;
93100

94101
let dmi_file_path = Path::new("/sys/firmware/dmi/tables/DMI");
95102

@@ -167,6 +174,11 @@ impl DMI {
167174
firmware.language_infos = Some(language_infos);
168175
}
169176
}
177+
StructureType::PhysicalMemoryArray => {
178+
memory = Some(Memory {
179+
physical_memory_array: PhysicalMemoryArray::from(data.as_slice()),
180+
});
181+
}
170182
_ => {}
171183
}
172184
}
@@ -176,6 +188,7 @@ impl DMI {
176188
system: system.unwrap(),
177189
baseboard: baseboard.unwrap(),
178190
chassis: chassis.unwrap(),
191+
memory: memory.unwrap(),
179192
focused_section: FocusedSection::Firmware,
180193
})
181194
}
@@ -188,13 +201,15 @@ impl DMI {
188201
FocusedSection::Firmware => self.focused_section = FocusedSection::System,
189202
FocusedSection::System => self.focused_section = FocusedSection::Baseboard,
190203
FocusedSection::Baseboard => self.focused_section = FocusedSection::Chassis,
191-
FocusedSection::Chassis => self.focused_section = FocusedSection::Firmware,
204+
FocusedSection::Chassis => self.focused_section = FocusedSection::Memory,
205+
FocusedSection::Memory => self.focused_section = FocusedSection::Firmware,
192206
},
193207
KeyCode::BackTab => match self.focused_section {
194-
FocusedSection::Firmware => self.focused_section = FocusedSection::Chassis,
208+
FocusedSection::Firmware => self.focused_section = FocusedSection::Memory,
195209
FocusedSection::System => self.focused_section = FocusedSection::Firmware,
196210
FocusedSection::Baseboard => self.focused_section = FocusedSection::System,
197211
FocusedSection::Chassis => self.focused_section = FocusedSection::Baseboard,
212+
FocusedSection::Memory => self.focused_section = FocusedSection::Chassis,
198213
},
199214
_ => {}
200215
}
@@ -243,6 +258,16 @@ impl DMI {
243258
Span::from(" Chassis ").fg(Color::DarkGray)
244259
}
245260
}
261+
FocusedSection::Memory => {
262+
if is_focused {
263+
Span::styled(
264+
" Memory ",
265+
Style::default().bg(Color::Yellow).fg(Color::Black).bold(),
266+
)
267+
} else {
268+
Span::from(" Memory ").fg(Color::DarkGray)
269+
}
270+
}
246271
}
247272
}
248273

@@ -264,6 +289,7 @@ impl DMI {
264289
self.title_span(FocusedSection::System),
265290
self.title_span(FocusedSection::Baseboard),
266291
self.title_span(FocusedSection::Chassis),
292+
self.title_span(FocusedSection::Memory),
267293
]))
268294
.title_alignment(Alignment::Left)
269295
.padding(Padding::top(1))
@@ -294,6 +320,9 @@ impl DMI {
294320
FocusedSection::Chassis => {
295321
self.chassis.render(frame, section_block);
296322
}
323+
FocusedSection::Memory => {
324+
self.memory.render(frame, section_block);
325+
}
297326
}
298327
}
299328
}

src/dmi/memory.rs

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
use ratatui::{
2+
Frame,
3+
layout::{Constraint, Margin, Rect},
4+
style::Stylize,
5+
widgets::{Block, Cell, Padding, Row, Table},
6+
};
7+
8+
#[derive(Debug)]
9+
pub struct Memory {
10+
pub physical_memory_array: PhysicalMemoryArray,
11+
}
12+
13+
impl Memory {
14+
pub fn render(&mut self, frame: &mut Frame, block: Rect) {
15+
self.physical_memory_array.render(frame, block);
16+
}
17+
}
18+
19+
#[derive(Debug)]
20+
pub struct PhysicalMemoryArray {
21+
location: Location,
22+
function: Function,
23+
error_correction: ErrorCorrection,
24+
max_capacity: String,
25+
error_information_handle: Option<u16>,
26+
number_memory_devices: u16,
27+
}
28+
29+
impl From<&[u8]> for PhysicalMemoryArray {
30+
fn from(data: &[u8]) -> Self {
31+
let max_capacity = {
32+
let value = u32::from_le_bytes(data[3..7].try_into().unwrap());
33+
34+
if value == 0x80008000 {
35+
format!("{}T", u64::from_le_bytes(data[11..19].try_into().unwrap()))
36+
} else {
37+
match value {
38+
value if value <= 1024 => {
39+
format!("{value}K")
40+
}
41+
value if value <= 1024 * 1024 => {
42+
format!("{}M", value / 1024)
43+
}
44+
_ => {
45+
format!("{}G", value / 1024 / 1024)
46+
}
47+
}
48+
}
49+
};
50+
let error_information_handle = {
51+
let value = u16::from_le_bytes(data[7..9].try_into().unwrap());
52+
53+
if value == 0xFFFE { None } else { Some(value) }
54+
};
55+
56+
let number_memory_devices = u16::from_le_bytes(data[9..11].try_into().unwrap());
57+
58+
Self {
59+
location: Location::from(data[0]),
60+
function: Function::from(data[1]),
61+
error_correction: ErrorCorrection::from(data[2]),
62+
max_capacity,
63+
error_information_handle,
64+
number_memory_devices,
65+
}
66+
}
67+
}
68+
69+
impl PhysicalMemoryArray {
70+
pub fn render(&self, frame: &mut Frame, block: Rect) {
71+
let rows = vec![
72+
Row::new(vec![
73+
Cell::from("Location").bold(),
74+
Cell::from(self.location.to_string()),
75+
]),
76+
Row::new(vec![
77+
Cell::from("Use").bold(),
78+
Cell::from(self.function.to_string()),
79+
]),
80+
Row::new(vec![
81+
Cell::from("Error Correction").bold(),
82+
Cell::from(self.error_correction.to_string()),
83+
]),
84+
Row::new(vec![
85+
Cell::from("Maximum Capacity").bold(),
86+
Cell::from(self.max_capacity.clone()),
87+
]),
88+
Row::new(vec![
89+
Cell::from("Error Information Handle ").bold(),
90+
Cell::from({
91+
if let Some(v) = self.error_information_handle {
92+
v.to_string()
93+
} else {
94+
"Not Provided".to_string()
95+
}
96+
}),
97+
]),
98+
Row::new(vec![
99+
Cell::from("Number Of Devices").bold(),
100+
Cell::from(self.number_memory_devices.to_string()),
101+
]),
102+
];
103+
104+
let widths = [Constraint::Length(30), Constraint::Fill(1)];
105+
let table = Table::new(rows, widths).block(Block::new().padding(Padding::uniform(2)));
106+
frame.render_widget(table, block.inner(Margin::new(2, 0)));
107+
}
108+
}
109+
110+
#[derive(Debug, strum::Display)]
111+
enum Location {
112+
#[strum(to_string = "Other")]
113+
Other,
114+
#[strum(to_string = "Unknown")]
115+
Unknown,
116+
#[strum(to_string = "System board or motherboard")]
117+
SystemBoard,
118+
#[strum(to_string = "ISA addon-on card")]
119+
Isa,
120+
#[strum(to_string = "EISA addon-on card")]
121+
Eisa,
122+
#[strum(to_string = "PCI addon-on card")]
123+
Pci,
124+
#[strum(to_string = "MCA addon-on card")]
125+
Mca,
126+
#[strum(to_string = "PCMCIA addon-on card")]
127+
Pcmcia,
128+
#[strum(to_string = "Proprietary addon-on card")]
129+
Proprietary,
130+
#[strum(to_string = "NuBus")]
131+
NuBus,
132+
#[strum(to_string = "PC-98/C20 add-on card")]
133+
Pc98C20,
134+
#[strum(to_string = "PC-98/C24 add-on card")]
135+
Pc98C24,
136+
#[strum(to_string = "PC-98/E add-on card")]
137+
Pc98E,
138+
#[strum(to_string = "PC-98/Local bus add-on card")]
139+
Pc98Local,
140+
#[strum(to_string = "CXL add-on card")]
141+
Cxl,
142+
}
143+
144+
impl From<u8> for Location {
145+
fn from(value: u8) -> Self {
146+
match value {
147+
1 => Self::Other,
148+
2 => Self::Unknown,
149+
3 => Self::SystemBoard,
150+
4 => Self::Isa,
151+
5 => Self::Eisa,
152+
6 => Self::Pci,
153+
7 => Self::Mca,
154+
8 => Self::Pcmcia,
155+
9 => Self::Proprietary,
156+
10 => Self::NuBus,
157+
11 => Self::Pc98C20,
158+
12 => Self::Pc98C24,
159+
13 => Self::Pc98E,
160+
14 => Self::Pc98Local,
161+
15 => Self::Cxl,
162+
_ => unreachable!(),
163+
}
164+
}
165+
}
166+
167+
#[derive(Debug, strum::Display)]
168+
enum Function {
169+
#[strum(to_string = "Other")]
170+
Other,
171+
#[strum(to_string = "Unknown")]
172+
Unknown,
173+
#[strum(to_string = "System Memory")]
174+
SystemMemory,
175+
#[strum(to_string = "Video Memory")]
176+
VideoMemory,
177+
#[strum(to_string = "Flash Memory")]
178+
FlashMemory,
179+
#[strum(to_string = "Non-volatile RAM")]
180+
NonVolatileRAM,
181+
#[strum(to_string = "Cache Memory")]
182+
CacheMemory,
183+
}
184+
185+
impl From<u8> for Function {
186+
fn from(value: u8) -> Self {
187+
match value {
188+
1 => Self::Other,
189+
2 => Self::Unknown,
190+
3 => Self::SystemMemory,
191+
4 => Self::VideoMemory,
192+
5 => Self::FlashMemory,
193+
6 => Self::NonVolatileRAM,
194+
7 => Self::CacheMemory,
195+
_ => unreachable!(),
196+
}
197+
}
198+
}
199+
200+
#[derive(Debug, strum::Display)]
201+
enum ErrorCorrection {
202+
#[strum(to_string = "Other")]
203+
Other,
204+
#[strum(to_string = "Unknown")]
205+
Unknown,
206+
#[strum(to_string = "None")]
207+
None,
208+
#[strum(to_string = "Parity")]
209+
Parity,
210+
#[strum(to_string = "Single-bit ECC")]
211+
SingleBitECC,
212+
#[strum(to_string = "Multi-bit ECC")]
213+
MultiBitECC,
214+
#[strum(to_string = "CRC")]
215+
Crc,
216+
}
217+
218+
impl From<u8> for ErrorCorrection {
219+
fn from(value: u8) -> Self {
220+
match value {
221+
1 => Self::Other,
222+
2 => Self::Unknown,
223+
3 => Self::None,
224+
4 => Self::Parity,
225+
5 => Self::SingleBitECC,
226+
6 => Self::MultiBitECC,
227+
7 => Self::Crc,
228+
_ => unreachable!(),
229+
}
230+
}
231+
}

0 commit comments

Comments
 (0)