1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
#include "physicalmemory.h"
#include "common/smbios.h"
// 7.18
typedef struct FFSmbiosMemoryDevice {
FFSmbiosHeader Header;
// 2.1+
uint16_t PhysicalMemoryArrayHandle; // varies
uint16_t MemoryErrorInformationHandle; // varies
uint16_t TotalWidth; // varies
uint16_t DataWidth; // varies
uint16_t Size; // varies
uint8_t FormFactor; // enum
uint8_t DeviceSet; // varies
uint8_t DeviceLocator; // string
uint8_t BankLocator; // string
uint8_t MemoryType; // enum
uint16_t TypeDetail; // bit field
// 2.3+
uint16_t Speed; // varies
uint8_t Manufacturer; // string
uint8_t SerialNumber; // string
uint8_t AssetTag; // string
uint8_t PartNumber; // string
// 2.6+
uint8_t Attributes; // varies
// 2.7+
uint32_t ExtendedSize; // varies
uint16_t ConfiguredMemorySpeed; // varies
// 2.8+
uint16_t MinimumVoltage; // varies
uint16_t MaximumVoltage; // varies
uint16_t ConfiguredVoltage; // varies
// 3.2+
uint8_t MemoryTechnology; // varies
uint16_t MemoryOperatingMode; // bit field
uint8_t FirmwareVersion; // string
uint16_t ModuleManufacturerID; // varies
uint16_t ModuleProductID; // varies
uint16_t MemorySubsystemControllerManufacturerID; // vaies
uint16_t MemorySubsystemControllerProductID; // varies
uint64_t NonVolatileSize; // varies
uint64_t VolatileSize; // varies
uint64_t CacheSize; // varies
uint64_t LogicalSize; // varies
// 3.3+
uint32_t ExtendedSpeed; // varies
uint32_t ExtendedConfiguredSpeed; // varies
// 3.7+
uint16_t Pmic0ManufacturerID; // varies
uint16_t Pmic0RevisionNumber; // varies
uint16_t RcdManufacturerID; // varies
uint16_t RcdRevisionNumber; // varies
} FF_A_PACKED FFSmbiosMemoryDevice;
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
"FFSmbiosMemoryDevice: Wrong struct alignment");
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
if (!smbiosTable) {
return "Failed to get SMBIOS data";
}
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
if (!data) {
return "Memory device is not found in SMBIOS data";
}
const FFSmbiosMemoryDevice* endOfTable = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
for (; data != endOfTable; data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) {
if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE) {
continue;
}
const char* strings = (const char*) data + data->Header.Length;
bool installed = data->Size != 0;
if (!installed && !options->showEmptySlots) {
continue;
}
FFPhysicalMemoryResult* device = FF_LIST_ADD(FFPhysicalMemoryResult, *result);
ffStrbufInit(&device->type);
ffStrbufInit(&device->formFactor);
ffStrbufInit(&device->locator);
ffStrbufInit(&device->vendor);
ffStrbufInit(&device->serial);
ffStrbufInit(&device->partNumber);
device->size = 0;
device->maxSpeed = 0;
device->runningSpeed = 0;
device->installed = installed;
device->ecc = false;
if (installed && data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF) {
device->ecc = data->TotalWidth > data->DataWidth;
}
if (installed && data->Size != 0xFFFF) {
if (data->Size == 0x7FFF) {
device->size = (data->ExtendedSize & ~(1ULL << 31)) * 1024ULL * 1024ULL;
} else if (data->Size & (1 << 15)) {
// in kB
device->size = (data->Size & ~(1ULL << 15)) * 1024ULL;
} else {
// in MB
device->size = data->Size * 1024ULL * 1024ULL;
}
}
// https://github.com/fastfetch-cli/fastfetch/issues/1051#issuecomment-2206687345
const char* lbank = ffSmbiosLocateString(strings, data->BankLocator);
const char* ldevice = ffSmbiosLocateString(strings, data->DeviceLocator);
if (lbank && ldevice) {
ffStrbufSetF(&device->locator, "%s/%s", lbank, ldevice);
} else if (lbank) {
ffStrbufSetS(&device->locator, lbank);
} else if (ldevice) {
ffStrbufSetS(&device->locator, ldevice);
}
const char* formFactorNames[] = {
NULL, // 0x00 (Placeholder for indexing)
"Other", // 0x01
"Unknown", // 0x02
"SIMM", // 0x03
"SIP", // 0x04
"Chip", // 0x05
"DIP", // 0x06
"ZIP", // 0x07
"Proprietary Card", // 0x08
"DIMM", // 0x09
"TSOP", // 0x0A
"Row of chips", // 0x0B
"RIMM", // 0x0C
"SODIMM", // 0x0D
"SRIMM", // 0x0E
"FBDIMM", // 0x0F
"Die", // 0x10
"CAMM", // 0x11
"CUDIMM", // 0x12
"CSODIMM", // 0x13
};
if (data->FormFactor > 0 && data->FormFactor < ARRAY_SIZE(formFactorNames)) {
ffStrbufSetS(&device->formFactor, formFactorNames[data->FormFactor]);
} else {
ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor);
}
const char* memoryTypeNames[] = {
NULL, // 0x00 (Placeholder for indexing)
"Other", // 0x01
"Unknown", // 0x02
"DRAM", // 0x03
"EDRAM", // 0x04
"VRAM", // 0x05
"SRAM", // 0x06
"RAM", // 0x07
"ROM", // 0x08
"FLASH", // 0x09
"EEPROM", // 0x0A
"FEPROM", // 0x0B
"EPROM", // 0x0C
"CDRAM", // 0x0D
"3DRAM", // 0x0E
"SDRAM", // 0x0F
"SGRAM", // 0x10
"RDRAM", // 0x11
"DDR", // 0x12
"DDR2", // 0x13
"DDR2 FB-DIMM", // 0x14
"Reserved", // 0x15
"Reserved", // 0x16
"Reserved", // 0x17
"DDR3", // 0x18
"FBD2", // 0x19
"DDR4", // 0x1A
"LPDDR", // 0x1B
"LPDDR2", // 0x1C
"LPDDR3", // 0x1D
"LPDDR4", // 0x1E
"Logical non-volatile device", // 0x1F
"HBM", // 0x20
"HBM2", // 0x21
"DDR5", // 0x22
"LPDDR5", // 0x23
"HBM3", // 0x24
"MRDIMM", // 0x25
};
if (!installed) {
ffStrbufSetStatic(&device->type, "Empty");
} else if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames)) {
ffStrbufSetStatic(&device->type, memoryTypeNames[data->MemoryType]);
} else {
ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType);
}
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+
{
if (data->Speed) {
device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed;
}
ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
ffCleanUpSmbiosValue(&device->vendor);
FFPhysicalMemoryUpdateVendorString(device);
ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber));
ffCleanUpSmbiosValue(&device->serial);
ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber));
ffCleanUpSmbiosValue(&device->partNumber);
}
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+
{
if (data->ConfiguredMemorySpeed) {
device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF
? data->ExtendedConfiguredSpeed
: data->ConfiguredMemorySpeed;
}
}
}
return NULL;
}
|