blob: d56c354040eb27727777626901ea6d1c72078e99 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* dmi.c using the DMI from SMBIOS to read information about the hardware's
2 * memory devices capabilities and where they are mapped into the address space
3 *
4 * Copyright (c) Joachim Deguara, AMD 2006
5 *
6 * Release under the GPL version 2
7 * ----------------------------------------------------
8 * Memtest86+ V4.00 - Added compliance with SMBIOS Spec V2.6.1
9 */
10
11
12#include "test.h"
13#include <stdint.h>
14
15
16#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
17#define round_down(x,y) ((x) & ~((y)-1))
18
19
20struct dmi_eps {
21 uint8_t anchor[4];
22 int8_t checksum;
23 uint8_t length;
24 uint8_t majorversion;
25 uint8_t minorversion;
26 uint16_t maxstructsize;
27 uint8_t revision;
28 uint8_t pad[5];
29 uint8_t intanchor[5];
30 int8_t intchecksum;
31 uint16_t tablelength;
32 uint32_t tableaddress;
33 uint16_t numstructs;
34 uint8_t SMBIOSrev;
35} __attribute__((packed));
36
37struct tstruct_header{
38 uint8_t type;
39 uint8_t length;
40 uint16_t handle;
41} __attribute__((packed));
42
43struct system_map {
44 struct tstruct_header header;
45 uint8_t manufacturer;
46 uint8_t productname;
47 uint8_t version;
48 uint8_t serialnumber;
49 uint8_t uuidbytes[16];
50 uint8_t wut;
51} __attribute__((packed));
52
53struct cpu_map {
54 struct tstruct_header header;
55 uint8_t cpu_socket;
56 uint8_t cpu_type;
57 uint8_t cpu_family;
58 uint8_t cpu_manufacturer;
59 uint32_t cpu_id;
60 uint8_t cpu_version;
61 uint8_t cpu_voltage;
62 uint16_t ext_clock;
63 uint16_t max_speed;
64 uint16_t cur_speed;
65 uint8_t cpu_status;
66 uint8_t cpu_upgrade;
67 uint16_t l1_handle;
68 uint16_t l2_handle;
69 uint16_t l3_handle;
Martin Roth4dcd13d2016-02-24 13:53:07 -080070 uint8_t cpu_serial;
Martin Roth9b1b3352016-02-24 12:27:06 -080071 uint8_t cpu_asset_tag;
72 uint8_t cpu_part_number;
73 uint8_t core_count;
74 uint8_t core_enabled;
75 uint8_t thread_count;
76 uint16_t cpu_specs;
Martin Roth4dcd13d2016-02-24 13:53:07 -080077 uint16_t cpu_family_2;
Martin Roth9b1b3352016-02-24 12:27:06 -080078} __attribute__((packed));
79
80struct mem_dev {
81 struct tstruct_header header;
82 uint16_t pma_handle;
83 uint16_t err_handle;
84 uint16_t tot_width;
85 uint16_t dat_width;
86 uint16_t size;
87 uint8_t form;
88 uint8_t set;
89 uint8_t dev_locator;
90 uint8_t bank_locator;
91 uint8_t type;
92 uint16_t typedetail;
93 uint16_t speed;
94 uint8_t manufacturer;
95 uint8_t serialnum;
96 uint8_t asset;
97 uint8_t partnum;
98} __attribute__((packed));
99
100struct md_map{
101 struct tstruct_header header;
102 uint32_t start;
103 uint32_t end;
104 uint16_t md_handle;
105 uint16_t mama_handle;
106 uint8_t row_pos;
107 uint8_t interl_pos;
108 uint8_t interl_depth;
109} __attribute__((packed));
110
111struct pma{
112 struct tstruct_header header;
113 uint8_t location;
114 uint8_t use;
115 uint8_t ecc;
116 uint32_t capacity;
117 uint16_t errhandle;
118 uint16_t numdevs;
119} __attribute__((packed));
120
121static char *form_factors[] = {
122 "?",
123 "Other", "Unknown", "SIMM", "SIP", "Chip", "DIP", "ZIP",
124 "Proprietary Card", "DIMM", "TSOP", "Row of chips", "RIMM",
125 "SODIMM", "SRIMM", "FB-DIMM"
126};
127
128
129static char *memory_types[] = {
130 "?",
131 "Other", "????", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM",
132 "ROM", "FLASH", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM",
133 "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR2", "DDR2 FB", "RSVD",
134 "RSVD","RSVD","DDR3","FBD2"
135};
136
137
138struct mem_dev * mem_devs[MAX_DMI_MEMDEVS];
139int mem_devs_count=0;
140struct md_map * md_maps[MAX_DMI_MEMDEVS];
141struct system_map * dmi_system_info;
142struct cpu_map * dmi_cpu_info;
143int md_maps_count=0;
144int dmi_err_cnts[MAX_DMI_MEMDEVS];
145short dmi_initialized=0;
146
147char * get_tstruct_string(struct tstruct_header *header, int n){
148 if(n<1)
149 return 0;
150 char * a = (char *)header + header->length;
151 n--;
152 do{
153 if (!*a)
154 n--;
155 if (!n && *a)
156 return a;
157 a++;
158 }while (!(*a==0 && *(a-1)==0));
159 return 0;
160}
161
162
163int open_dmi(void){
164 char *dmi, *dmi_search_start, *dmi_start;
165 int found=0;
166 struct dmi_eps *eps;
167 char *table_start;
168 int tstruct_count=0;
169 dmi_search_start = (char *)DMI_SEARCH_START;
170
171 //find anchor
172 for(dmi = dmi_search_start; dmi < dmi_search_start + 0xf0000; dmi +=16){
173 if( *dmi == '_' &&
174 *(dmi+1) == 'S' &&
175 *(dmi+2) == 'M' &&
176 *(dmi+3) == '_'){
177 found =1;
178 break;
179 }
180 }
181 if (!found) {
182 return -1;
183 }
184 dmi_start=dmi;
185 eps=(struct dmi_eps *)dmi;
186
187 //check checksum
188 int8_t checksum=0;
189 for (; dmi < dmi_start + eps->length; dmi++)
190 checksum += *dmi;
191 if (checksum){
192 return -1;
193 }
194
195 //we need at least revision 2.1 of SMBIOS
Elyes HAOUASa5c8cea2019-06-09 20:25:43 +0200196 if (eps->majorversion < 2 && eps->minorversion < 1) {
197 return -1;
Martin Roth9b1b3352016-02-24 12:27:06 -0800198 }
199
200
201 table_start=(char *)eps->tableaddress;
202 dmi=table_start;
203//look at all structs
204 while(dmi < table_start + eps->tablelength){
205 struct tstruct_header *header = (struct tstruct_header *)dmi;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800206
Martin Roth9b1b3352016-02-24 12:27:06 -0800207 if (header->type == 17)
208 mem_devs[mem_devs_count++] = (struct mem_dev *)dmi;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800209
Martin Roth9b1b3352016-02-24 12:27:06 -0800210 // Need fix (SMBIOS/DDR3)
211 if (header->type == 20 || header->type == 1)
212 md_maps[md_maps_count++] = (struct md_map *)dmi;
213
214 // MB_SPEC
215 if (header->type == 2)
216 {
217 dmi_system_info = (struct system_map *)dmi;
218 }
219
220 // CPU_SPEC
221 if (header->type == 4)
222 {
223 dmi_cpu_info = (struct cpu_map *)dmi;
224 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800225
Martin Roth9b1b3352016-02-24 12:27:06 -0800226 dmi+=header->length;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800227
Martin Roth9b1b3352016-02-24 12:27:06 -0800228 while( ! (*dmi == 0 && *(dmi+1) == 0 ) )
229 dmi++;
230 dmi+=2;
231
232 if (++tstruct_count > eps->numstructs)
233 return -1;
234 }
235 return 0;
236}
237
238void init_dmi(void){
239 int i;
240 for(i=0; i < MAX_DMI_MEMDEVS; i++)
241 dmi_err_cnts[i]=0;
242 open_dmi();
243 dmi_initialized=1;
244}
245
246void print_dmi_startup_info(void)
247{
248 char *string1;
249 char *string2;
250 char *string3;
251 int dmicol = 78;
252 int slenght;
Tristan Corrickf0b21172018-07-31 00:36:14 +1200253 int sl1 = 0, sl2 = 0, sl3 = 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800254
Martin Roth9b1b3352016-02-24 12:27:06 -0800255 if(!dmi_initialized) { init_dmi(); }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800256
Martin Roth9b1b3352016-02-24 12:27:06 -0800257 string1 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->manufacturer);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200258 if (string1)
259 sl1 = strlen(string1);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800260 string2 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->productname);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200261 if (string2)
262 sl2 = strlen(string2);
Martin Roth9b1b3352016-02-24 12:27:06 -0800263 string3 = get_tstruct_string(&dmi_cpu_info->header,dmi_cpu_info->cpu_socket);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200264 if (string3)
265 sl3 = strlen(string3);
Martin Roth9b1b3352016-02-24 12:27:06 -0800266
267 slenght = sl1 + sl2;
268 if(sl3 > 2) { slenght += sl3 + 4; } else { slenght++; }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800269
Elyes HAOUASa5c8cea2019-06-09 20:25:43 +0200270 if (sl1 && sl2) {
271 //dmicol -= slenght; // right align
272 dmicol = 39 - slenght / 2; // center align
273 cprint(LINE_DMI, dmicol, string1);
274 dmicol += sl1 + 1;
275 cprint(LINE_DMI, dmicol, string2);
276 dmicol += sl2 + 1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800277
Elyes HAOUASa5c8cea2019-06-09 20:25:43 +0200278 if (sl3 > 2) {
279 cprint(LINE_DMI, dmicol, "(");
280 dmicol++;
281 cprint(LINE_DMI, dmicol, string3);
282 dmicol += sl3;
283 cprint(LINE_DMI, dmicol, ")");
Martin Roth9b1b3352016-02-24 12:27:06 -0800284 }
Elyes HAOUASa5c8cea2019-06-09 20:25:43 +0200285 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800286}
287
288void print_dmi_info(void){
289 int i,j,page;
290 char * string=0;
291
292 if(!dmi_initialized)
293 init_dmi();
294
295 if (mem_devs_count == 0){
296 cprint(POP2_Y+1, POP2_X+2, "No valid DMI Memory Devices info found");
297 while (get_key() == 0);
298 return;
299 }
300
301 for(page=1; page <= 1 + (mem_devs_count-1)/8; page++){
Martin Roth5bb29b22016-03-27 20:51:17 -0600302 popclear(POP_SAVE_BUFFER_2);
Martin Roth9b1b3352016-02-24 12:27:06 -0800303 cprint(POP2_Y+1, POP2_X+2, "DMI Memory Device Info (page ");
304 itoa(string,page);
305 cprint(POP2_Y+1, POP2_X+32, string);
306 cprint(POP2_Y+1, POP2_X+33, "/");
307 itoa(string,1 + (mem_devs_count-1)/8);
308 cprint(POP2_Y+1, POP2_X+34, string);
309 cprint(POP2_Y+1, POP2_X+35, ")");
310
311 cprint(POP2_Y+3, POP2_X+4, "Location Size(MB) Speed(MHz) Type Form");
312 cprint(POP2_Y+4, POP2_X+4, "--------------------------------------------------------------");
313
314 for(i=8*(page-1); i<mem_devs_count && i<8*page; i++){
315 int size_in_mb;
316 int yof;
317
318 yof=POP2_Y+5+2*(i-8*(page-1));
319 cprint(yof, POP2_X+4, get_tstruct_string(&(mem_devs[i]->header), mem_devs[i]->dev_locator));
320
321 if (mem_devs[i]->size == 0){
322 cprint(yof, POP2_X+4+18, "Empty");
323 }else if (mem_devs[i]->size == 0xFFFF){
324 cprint(yof, POP2_X+4+18, "Unknown");
325 }else{
326 size_in_mb = 0xEFFF & mem_devs[i]->size;
327 if (mem_devs[i]->size & 0x8000)
328 size_in_mb = size_in_mb<<10;
329 itoa(string, size_in_mb);
330 cprint(yof, POP2_X+4+18, string);
331 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800332
333 //this is the only field that needs to be SMBIOS 2.3+
334 if ( mem_devs[i]->speed &&
Martin Roth9b1b3352016-02-24 12:27:06 -0800335 mem_devs[i]->header.length > 21){
336 itoa(string, mem_devs[i]->speed);
337 cprint(yof, POP2_X+4+27, string);
338 }else{
339 cprint(yof, POP2_X+4+27, "Unknown");
340 }
341 cprint(yof, POP2_X+4+37, memory_types[mem_devs[i]->type]);
342 cprint(yof, POP2_X+4+44, form_factors[mem_devs[i]->form]);
343
344 //print mappings
345 int mapped=0,of=0;
346 cprint(yof+1, POP2_X+6,"mapped to: ");
347 for(j=0; j<md_maps_count; j++)
348 {
349 if (mem_devs[i]->header.handle != md_maps[j]->md_handle)
350 continue;
351 if (mapped++){
352 cprint(yof+1, POP2_X+17+of, ",");
353 of++;
354 }
355 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start>>22, 4);
356 of += 4;
357 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start<<10, 8);
358 of += 8;
359 cprint(yof+1, POP2_X+17+of, "-");
360 of++;
361 hprint3(yof+1, POP2_X+17+of, md_maps[j]->end>>22, 4);
362 of += 4;
363 hprint3(yof+1, POP2_X+17+of, ((md_maps[j]->end+1)<<10) - 1, 8);
364 of += 8;
365 if(md_maps[j]->end == 0) { hprint3(yof+1, POP2_X+17+of-8,0,8); }
366 }
367 if (!mapped)
368 {
369 cprint(yof+1, POP2_X+17, "No mapping (Interleaved Device)");
370 }
371
372 }
373
374 wait_keyup();
375 while (get_key() == 0);
376 }
377}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800378
Martin Roth9b1b3352016-02-24 12:27:06 -0800379//return 1 if the list of bad memory devices changes, 0 otherwise, -1 if no mapped
380int add_dmi_err(ulong adr){
381 int i,j,found=-1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800382
Martin Roth9b1b3352016-02-24 12:27:06 -0800383 if(!dmi_initialized)
384 init_dmi();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800385
Martin Roth9b1b3352016-02-24 12:27:06 -0800386 for(i=0; i < md_maps_count; i++){
387 if ( adr < (md_maps[i]->start<<10) ||
388 adr > (md_maps[i]->end<<10) )
389 continue;
390
391 //matching map found, now check find corresponding dev
392 for(j=0; j < mem_devs_count; j++){
393 if (mem_devs[j]->header.handle != md_maps[i]->md_handle)
394 continue;
395 if (dmi_err_cnts[j]){
396 found=0;
397 }else{
398 found = dmi_err_cnts[j] = 1;
399 }
400 }
401 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800402
Martin Roth9b1b3352016-02-24 12:27:06 -0800403 return found;
404}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800405
Martin Roth9b1b3352016-02-24 12:27:06 -0800406void print_dmi_err(void){
407 int i,count,of;
408 char *string;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800409
Martin Roth9b1b3352016-02-24 12:27:06 -0800410 scroll();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800411
Martin Roth9b1b3352016-02-24 12:27:06 -0800412 cprint(v->msg_line, 0,"Bad Memory Devices: ");
413 of=20;
414 for ( i=count=0; i < MAX_DMI_MEMDEVS; i++){
415 if (!dmi_err_cnts[i])
416 continue;
417 struct mem_dev *md = mem_devs[i];
418 if(count++){
419 cprint(v->msg_line, of, ", ");
420 of+=2;
421 }
422 string=get_tstruct_string((struct tstruct_header *)md,md->dev_locator);
423 if (strlen(string) + of > 80){
424 scroll();
425 of=7;
426 }
427 cprint(v->msg_line, of, string);
428 of += strlen(string);
429 }
430}