blob: 1f1100881fcc341f6e08438fc7d61b2fdeacce49 [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;
70 uint8_t cpu_serial;
71 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;
77 uint16_t cpu_family_2;
78} __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;
207
208 if (header->type == 17)
209 mem_devs[mem_devs_count++] = (struct mem_dev *)dmi;
210
211 // 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 }
226
227 dmi+=header->length;
228
229 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;
254 int sl1, sl2, sl3;
255
256 if(!dmi_initialized) { init_dmi(); }
257
258 string1 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->manufacturer);
259 sl1 = strlen(string1);
260 string2 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->productname);
261 sl2 = strlen(string2);
262 string3 = get_tstruct_string(&dmi_cpu_info->header,dmi_cpu_info->cpu_socket);
263 sl3 = strlen(string3);
264
265 slenght = sl1 + sl2;
266 if(sl3 > 2) { slenght += sl3 + 4; } else { slenght++; }
267
268 if(sl1 && sl2)
269 {
270 //dmicol -= slenght; // right align
271 dmicol = 39 - slenght/2; // center align
272 cprint(LINE_DMI, dmicol, string1);
273 dmicol += sl1 + 1;
274 cprint(LINE_DMI, dmicol, string2);
275 dmicol += sl2 + 1;
276
277 if(sl3 > 2){
278 cprint(LINE_DMI, dmicol, "(");
279 dmicol++;
280 cprint(LINE_DMI, dmicol, string3);
281 dmicol += sl3;
282 cprint(LINE_DMI, dmicol, ")");
283 }
284 }
285}
286
287void print_dmi_info(void){
288 int i,j,page;
289 char * string=0;
290
291 if(!dmi_initialized)
292 init_dmi();
293
294 if (mem_devs_count == 0){
295 cprint(POP2_Y+1, POP2_X+2, "No valid DMI Memory Devices info found");
296 while (get_key() == 0);
297 return;
298 }
299
300 for(page=1; page <= 1 + (mem_devs_count-1)/8; page++){
301 pop2clear();
302 cprint(POP2_Y+1, POP2_X+2, "DMI Memory Device Info (page ");
303 itoa(string,page);
304 cprint(POP2_Y+1, POP2_X+32, string);
305 cprint(POP2_Y+1, POP2_X+33, "/");
306 itoa(string,1 + (mem_devs_count-1)/8);
307 cprint(POP2_Y+1, POP2_X+34, string);
308 cprint(POP2_Y+1, POP2_X+35, ")");
309
310 cprint(POP2_Y+3, POP2_X+4, "Location Size(MB) Speed(MHz) Type Form");
311 cprint(POP2_Y+4, POP2_X+4, "--------------------------------------------------------------");
312
313 for(i=8*(page-1); i<mem_devs_count && i<8*page; i++){
314 int size_in_mb;
315 int yof;
316
317 yof=POP2_Y+5+2*(i-8*(page-1));
318 cprint(yof, POP2_X+4, get_tstruct_string(&(mem_devs[i]->header), mem_devs[i]->dev_locator));
319
320 if (mem_devs[i]->size == 0){
321 cprint(yof, POP2_X+4+18, "Empty");
322 }else if (mem_devs[i]->size == 0xFFFF){
323 cprint(yof, POP2_X+4+18, "Unknown");
324 }else{
325 size_in_mb = 0xEFFF & mem_devs[i]->size;
326 if (mem_devs[i]->size & 0x8000)
327 size_in_mb = size_in_mb<<10;
328 itoa(string, size_in_mb);
329 cprint(yof, POP2_X+4+18, string);
330 }
331
332 //this is the only field that needs to be SMBIOS 2.3+
333 if ( mem_devs[i]->speed &&
334 mem_devs[i]->header.length > 21){
335 itoa(string, mem_devs[i]->speed);
336 cprint(yof, POP2_X+4+27, string);
337 }else{
338 cprint(yof, POP2_X+4+27, "Unknown");
339 }
340 cprint(yof, POP2_X+4+37, memory_types[mem_devs[i]->type]);
341 cprint(yof, POP2_X+4+44, form_factors[mem_devs[i]->form]);
342
343 //print mappings
344 int mapped=0,of=0;
345 cprint(yof+1, POP2_X+6,"mapped to: ");
346 for(j=0; j<md_maps_count; j++)
347 {
348 if (mem_devs[i]->header.handle != md_maps[j]->md_handle)
349 continue;
350 if (mapped++){
351 cprint(yof+1, POP2_X+17+of, ",");
352 of++;
353 }
354 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start>>22, 4);
355 of += 4;
356 hprint3(yof+1, POP2_X+17+of, md_maps[j]->start<<10, 8);
357 of += 8;
358 cprint(yof+1, POP2_X+17+of, "-");
359 of++;
360 hprint3(yof+1, POP2_X+17+of, md_maps[j]->end>>22, 4);
361 of += 4;
362 hprint3(yof+1, POP2_X+17+of, ((md_maps[j]->end+1)<<10) - 1, 8);
363 of += 8;
364 if(md_maps[j]->end == 0) { hprint3(yof+1, POP2_X+17+of-8,0,8); }
365 }
366 if (!mapped)
367 {
368 cprint(yof+1, POP2_X+17, "No mapping (Interleaved Device)");
369 }
370
371 }
372
373 wait_keyup();
374 while (get_key() == 0);
375 }
376}
377
378//return 1 if the list of bad memory devices changes, 0 otherwise, -1 if no mapped
379int add_dmi_err(ulong adr){
380 int i,j,found=-1;
381
382 if(!dmi_initialized)
383 init_dmi();
384
385 for(i=0; i < md_maps_count; i++){
386 if ( adr < (md_maps[i]->start<<10) ||
387 adr > (md_maps[i]->end<<10) )
388 continue;
389
390 //matching map found, now check find corresponding dev
391 for(j=0; j < mem_devs_count; j++){
392 if (mem_devs[j]->header.handle != md_maps[i]->md_handle)
393 continue;
394 if (dmi_err_cnts[j]){
395 found=0;
396 }else{
397 found = dmi_err_cnts[j] = 1;
398 }
399 }
400 }
401
402 return found;
403}
404
405void print_dmi_err(void){
406 int i,count,of;
407 char *string;
408
409 scroll();
410
411 cprint(v->msg_line, 0,"Bad Memory Devices: ");
412 of=20;
413 for ( i=count=0; i < MAX_DMI_MEMDEVS; i++){
414 if (!dmi_err_cnts[i])
415 continue;
416 struct mem_dev *md = mem_devs[i];
417 if(count++){
418 cprint(v->msg_line, of, ", ");
419 of+=2;
420 }
421 string=get_tstruct_string((struct tstruct_header *)md,md->dev_locator);
422 if (strlen(string) + of > 80){
423 scroll();
424 of=7;
425 }
426 cprint(v->msg_line, of, string);
427 of += strlen(string);
428 }
429}