blob: f7915a1dfdac5bdf6b70a64a5da38eac53bec2b1 [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
196 if ( eps->majorversion < 2 &&
197 eps->minorversion < 1){
198 return -1;
199 }
200
201
202 table_start=(char *)eps->tableaddress;
203 dmi=table_start;
204//look at all structs
205 while(dmi < table_start + eps->tablelength){
206 struct tstruct_header *header = (struct tstruct_header *)dmi;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800207
Martin Roth9b1b3352016-02-24 12:27:06 -0800208 if (header->type == 17)
209 mem_devs[mem_devs_count++] = (struct mem_dev *)dmi;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800210
Martin Roth9b1b3352016-02-24 12:27:06 -0800211 // Need fix (SMBIOS/DDR3)
212 if (header->type == 20 || header->type == 1)
213 md_maps[md_maps_count++] = (struct md_map *)dmi;
214
215 // MB_SPEC
216 if (header->type == 2)
217 {
218 dmi_system_info = (struct system_map *)dmi;
219 }
220
221 // CPU_SPEC
222 if (header->type == 4)
223 {
224 dmi_cpu_info = (struct cpu_map *)dmi;
225 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800226
Martin Roth9b1b3352016-02-24 12:27:06 -0800227 dmi+=header->length;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800228
Martin Roth9b1b3352016-02-24 12:27:06 -0800229 while( ! (*dmi == 0 && *(dmi+1) == 0 ) )
230 dmi++;
231 dmi+=2;
232
233 if (++tstruct_count > eps->numstructs)
234 return -1;
235 }
236 return 0;
237}
238
239void init_dmi(void){
240 int i;
241 for(i=0; i < MAX_DMI_MEMDEVS; i++)
242 dmi_err_cnts[i]=0;
243 open_dmi();
244 dmi_initialized=1;
245}
246
247void print_dmi_startup_info(void)
248{
249 char *string1;
250 char *string2;
251 char *string3;
252 int dmicol = 78;
253 int slenght;
Tristan Corrickf0b21172018-07-31 00:36:14 +1200254 int sl1 = 0, sl2 = 0, sl3 = 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800255
Martin Roth9b1b3352016-02-24 12:27:06 -0800256 if(!dmi_initialized) { init_dmi(); }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800257
Martin Roth9b1b3352016-02-24 12:27:06 -0800258 string1 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->manufacturer);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200259 if (string1)
260 sl1 = strlen(string1);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800261 string2 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->productname);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200262 if (string2)
263 sl2 = strlen(string2);
Martin Roth9b1b3352016-02-24 12:27:06 -0800264 string3 = get_tstruct_string(&dmi_cpu_info->header,dmi_cpu_info->cpu_socket);
Tristan Corrickf0b21172018-07-31 00:36:14 +1200265 if (string3)
266 sl3 = strlen(string3);
Martin Roth9b1b3352016-02-24 12:27:06 -0800267
268 slenght = sl1 + sl2;
269 if(sl3 > 2) { slenght += sl3 + 4; } else { slenght++; }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800270
Martin Roth9b1b3352016-02-24 12:27:06 -0800271 if(sl1 && sl2)
272 {
273 //dmicol -= slenght; // right align
274 dmicol = 39 - slenght/2; // center align
275 cprint(LINE_DMI, dmicol, string1);
276 dmicol += sl1 + 1;
277 cprint(LINE_DMI, dmicol, string2);
278 dmicol += sl2 + 1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800279
Martin Roth9b1b3352016-02-24 12:27:06 -0800280 if(sl3 > 2){
281 cprint(LINE_DMI, dmicol, "(");
282 dmicol++;
283 cprint(LINE_DMI, dmicol, string3);
284 dmicol += sl3;
285 cprint(LINE_DMI, dmicol, ")");
286 }
287 }
288}
289
290void print_dmi_info(void){
291 int i,j,page;
292 char * string=0;
293
294 if(!dmi_initialized)
295 init_dmi();
296
297 if (mem_devs_count == 0){
298 cprint(POP2_Y+1, POP2_X+2, "No valid DMI Memory Devices info found");
299 while (get_key() == 0);
300 return;
301 }
302
303 for(page=1; page <= 1 + (mem_devs_count-1)/8; page++){
Martin Roth5bb29b22016-03-27 20:51:17 -0600304 popclear(POP_SAVE_BUFFER_2);
Martin Roth9b1b3352016-02-24 12:27:06 -0800305 cprint(POP2_Y+1, POP2_X+2, "DMI Memory Device Info (page ");
306 itoa(string,page);
307 cprint(POP2_Y+1, POP2_X+32, string);
308 cprint(POP2_Y+1, POP2_X+33, "/");
309 itoa(string,1 + (mem_devs_count-1)/8);
310 cprint(POP2_Y+1, POP2_X+34, string);
311 cprint(POP2_Y+1, POP2_X+35, ")");
312
313 cprint(POP2_Y+3, POP2_X+4, "Location Size(MB) Speed(MHz) Type Form");
314 cprint(POP2_Y+4, POP2_X+4, "--------------------------------------------------------------");
315
316 for(i=8*(page-1); i<mem_devs_count && i<8*page; i++){
317 int size_in_mb;
318 int yof;
319
320 yof=POP2_Y+5+2*(i-8*(page-1));
321 cprint(yof, POP2_X+4, get_tstruct_string(&(mem_devs[i]->header), mem_devs[i]->dev_locator));
322
323 if (mem_devs[i]->size == 0){
324 cprint(yof, POP2_X+4+18, "Empty");
325 }else if (mem_devs[i]->size == 0xFFFF){
326 cprint(yof, POP2_X+4+18, "Unknown");
327 }else{
328 size_in_mb = 0xEFFF & mem_devs[i]->size;
329 if (mem_devs[i]->size & 0x8000)
330 size_in_mb = size_in_mb<<10;
331 itoa(string, size_in_mb);
332 cprint(yof, POP2_X+4+18, string);
333 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800334
335 //this is the only field that needs to be SMBIOS 2.3+
336 if ( mem_devs[i]->speed &&
Martin Roth9b1b3352016-02-24 12:27:06 -0800337 mem_devs[i]->header.length > 21){
338 itoa(string, mem_devs[i]->speed);
339 cprint(yof, POP2_X+4+27, string);
340 }else{
341 cprint(yof, POP2_X+4+27, "Unknown");
342 }
343 cprint(yof, POP2_X+4+37, memory_types[mem_devs[i]->type]);
344 cprint(yof, POP2_X+4+44, form_factors[mem_devs[i]->form]);
345
346 //print mappings
347 int mapped=0,of=0;
348 cprint(yof+1, POP2_X+6,"mapped to: ");
349 for(j=0; j<md_maps_count; j++)
350 {
351 if (mem_devs[i]->header.handle != md_maps[j]->md_handle)
352 continue;
353 if (mapped++){
354 cprint(yof+1, POP2_X+17+of, ",");
355 of++;
356 }
357 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start>>22, 4);
358 of += 4;
359 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start<<10, 8);
360 of += 8;
361 cprint(yof+1, POP2_X+17+of, "-");
362 of++;
363 hprint3(yof+1, POP2_X+17+of, md_maps[j]->end>>22, 4);
364 of += 4;
365 hprint3(yof+1, POP2_X+17+of, ((md_maps[j]->end+1)<<10) - 1, 8);
366 of += 8;
367 if(md_maps[j]->end == 0) { hprint3(yof+1, POP2_X+17+of-8,0,8); }
368 }
369 if (!mapped)
370 {
371 cprint(yof+1, POP2_X+17, "No mapping (Interleaved Device)");
372 }
373
374 }
375
376 wait_keyup();
377 while (get_key() == 0);
378 }
379}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800380
Martin Roth9b1b3352016-02-24 12:27:06 -0800381//return 1 if the list of bad memory devices changes, 0 otherwise, -1 if no mapped
382int add_dmi_err(ulong adr){
383 int i,j,found=-1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800384
Martin Roth9b1b3352016-02-24 12:27:06 -0800385 if(!dmi_initialized)
386 init_dmi();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800387
Martin Roth9b1b3352016-02-24 12:27:06 -0800388 for(i=0; i < md_maps_count; i++){
389 if ( adr < (md_maps[i]->start<<10) ||
390 adr > (md_maps[i]->end<<10) )
391 continue;
392
393 //matching map found, now check find corresponding dev
394 for(j=0; j < mem_devs_count; j++){
395 if (mem_devs[j]->header.handle != md_maps[i]->md_handle)
396 continue;
397 if (dmi_err_cnts[j]){
398 found=0;
399 }else{
400 found = dmi_err_cnts[j] = 1;
401 }
402 }
403 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800404
Martin Roth9b1b3352016-02-24 12:27:06 -0800405 return found;
406}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800407
Martin Roth9b1b3352016-02-24 12:27:06 -0800408void print_dmi_err(void){
409 int i,count,of;
410 char *string;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800411
Martin Roth9b1b3352016-02-24 12:27:06 -0800412 scroll();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800413
Martin Roth9b1b3352016-02-24 12:27:06 -0800414 cprint(v->msg_line, 0,"Bad Memory Devices: ");
415 of=20;
416 for ( i=count=0; i < MAX_DMI_MEMDEVS; i++){
417 if (!dmi_err_cnts[i])
418 continue;
419 struct mem_dev *md = mem_devs[i];
420 if(count++){
421 cprint(v->msg_line, of, ", ");
422 of+=2;
423 }
424 string=get_tstruct_string((struct tstruct_header *)md,md->dev_locator);
425 if (strlen(string) + of > 80){
426 scroll();
427 of=7;
428 }
429 cprint(v->msg_line, of, string);
430 of += strlen(string);
431 }
432}