1 /*
2 * smbios.c - Generate SMBIOS tables for Xen HVM domU's.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) IBM Corporation, 2006
18 *
19 * Authors: Andrew D. Ball <aball@us.ibm.com>
20 */
21
22 #include <stdint.h>
23 #include <xen/xen.h>
24 #include <xen/version.h>
25 #include "smbios_types.h"
26 #include "util.h"
27 #include "hypercall.h"
28 #include <xen/hvm/hvm_xs_strings.h>
29
30 /* SBMIOS handle base values */
31 #define SMBIOS_HANDLE_TYPE0 0x0000
32 #define SMBIOS_HANDLE_TYPE1 0x0100
33 #define SMBIOS_HANDLE_TYPE2 0x0200
34 #define SMBIOS_HANDLE_TYPE3 0x0300
35 #define SMBIOS_HANDLE_TYPE4 0x0400
36 #define SMBIOS_HANDLE_TYPE11 0x0B00
37 #define SMBIOS_HANDLE_TYPE16 0x1000
38 #define SMBIOS_HANDLE_TYPE17 0x1100
39 #define SMBIOS_HANDLE_TYPE19 0x1300
40 #define SMBIOS_HANDLE_TYPE20 0x1400
41 #define SMBIOS_HANDLE_TYPE22 0x1600
42 #define SMBIOS_HANDLE_TYPE32 0x2000
43 #define SMBIOS_HANDLE_TYPE39 0x2700
44 #define SMBIOS_HANDLE_TYPE127 0x7f00
45
46 static void
47 smbios_pt_init(void);
48 static void*
49 get_smbios_pt_struct(uint8_t type, uint32_t *length_out);
50 static void
51 get_cpu_manufacturer(char *buf, int len);
52 static int
53 write_smbios_tables(void *ep, void *start,
54 uint32_t vcpus, uint64_t memsize,
55 uint8_t uuid[16], char *xen_version,
56 uint32_t xen_major_version, uint32_t xen_minor_version,
57 unsigned *nr_structs, unsigned *max_struct_size);
58 static uint64_t
59 get_memsize(void);
60 static void
61 smbios_entry_point_init(void *start,
62 uint16_t max_structure_size,
63 uint16_t structure_table_length,
64 uint32_t structure_table_address,
65 uint16_t number_of_structures);
66 static void *
67 smbios_type_0_init(void *start, const char *xen_version,
68 uint32_t xen_major_version, uint32_t xen_minor_version);
69 static void *
70 smbios_type_1_init(void *start, const char *xen_version,
71 uint8_t uuid[16]);
72 static void *
73 smbios_type_2_init(void *start);
74 static void *
75 smbios_type_3_init(void *start);
76 static void *
77 smbios_type_4_init(void *start, unsigned int cpu_number,
78 char *cpu_manufacturer);
79 static void *
80 smbios_type_11_init(void *start);
81 static void *
82 smbios_type_16_init(void *start, uint32_t memory_size_mb, int nr_mem_devs);
83 static void *
84 smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance);
85 static void *
86 smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance);
87 static void *
88 smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance);
89 static void *
90 smbios_type_22_init(void *start);
91 static void *
92 smbios_type_32_init(void *start);
93 static void *
94 smbios_type_39_init(void *start);
95 static void *
96 smbios_type_vendor_oem_init(void *start);
97 static void *
98 smbios_type_127_init(void *start);
99
100 static uint32_t *smbios_pt_addr = NULL;
101 static uint32_t smbios_pt_length = 0;
102
103 static void
smbios_pt_init(void)104 smbios_pt_init(void)
105 {
106 const char *s;
107
108 s = xenstore_read(HVM_XS_SMBIOS_PT_ADDRESS, NULL);
109 if ( s == NULL )
110 goto reset;
111
112 smbios_pt_addr = (uint32_t*)(uint32_t)strtoll(s, NULL, 0);
113 if ( smbios_pt_addr == NULL )
114 goto reset;
115
116 s = xenstore_read(HVM_XS_SMBIOS_PT_LENGTH, NULL);
117 if ( s == NULL )
118 goto reset;
119
120 smbios_pt_length = (uint32_t)strtoll(s, NULL, 0);
121 if ( smbios_pt_length == 0 )
122 goto reset;
123
124 return;
125
126 reset:
127 smbios_pt_addr = NULL;
128 smbios_pt_length = 0;
129 }
130
131 static void*
get_smbios_pt_struct(uint8_t type,uint32_t * length_out)132 get_smbios_pt_struct(uint8_t type, uint32_t *length_out)
133 {
134 uint32_t *sep = smbios_pt_addr;
135 uint32_t total = 0;
136 uint8_t *ptr;
137
138 if ( sep == NULL )
139 return NULL;
140
141 while ( total < smbios_pt_length )
142 {
143 ptr = (uint8_t*)(sep + 1);
144 if ( ptr[0] == type )
145 {
146 *length_out = *sep;
147 return ptr;
148 }
149
150 total += (*sep + sizeof(uint32_t));
151 sep = (uint32_t*)(ptr + *sep);
152 }
153
154 return NULL;
155 }
156
157 static void
get_cpu_manufacturer(char * buf,int len)158 get_cpu_manufacturer(char *buf, int len)
159 {
160 char id[12];
161 uint32_t eax = 0;
162
163 cpuid(0, &eax, (uint32_t *)&id[0], (uint32_t *)&id[8],
164 (uint32_t *)&id[4]);
165
166 if ( memcmp(id, "GenuineIntel", 12) == 0 )
167 strncpy(buf, "Intel", len);
168 else if ( memcmp(id, "AuthenticAMD", 12) == 0 )
169 strncpy(buf, "AMD", len);
170 else
171 strncpy(buf, "unknown", len);
172 }
173
174 static int
write_smbios_tables(void * ep,void * start,uint32_t vcpus,uint64_t memsize,uint8_t uuid[16],char * xen_version,uint32_t xen_major_version,uint32_t xen_minor_version,unsigned * nr_structs,unsigned * max_struct_size)175 write_smbios_tables(void *ep, void *start,
176 uint32_t vcpus, uint64_t memsize,
177 uint8_t uuid[16], char *xen_version,
178 uint32_t xen_major_version, uint32_t xen_minor_version,
179 unsigned *nr_structs, unsigned *max_struct_size)
180 {
181 unsigned cpu_num;
182 char *p, *q;
183 char cpu_manufacturer[15];
184 int i, nr_mem_devs;
185
186 smbios_pt_init();
187
188 get_cpu_manufacturer(cpu_manufacturer, 15);
189
190 p = (char *)start;
191
192 #define do_struct(fn) do { \
193 q = (fn); \
194 if ( q != p ) \
195 (*nr_structs)++; \
196 if ( (q - p) > *max_struct_size ) \
197 *max_struct_size = q - p; \
198 p = q; \
199 } while (0)
200
201 do_struct(smbios_type_0_init(p, xen_version, xen_major_version,
202 xen_minor_version));
203 do_struct(smbios_type_1_init(p, xen_version, uuid));
204 do_struct(smbios_type_2_init(p));
205 do_struct(smbios_type_3_init(p));
206 for ( cpu_num = 1; cpu_num <= vcpus; cpu_num++ )
207 do_struct(smbios_type_4_init(p, cpu_num, cpu_manufacturer));
208 do_struct(smbios_type_11_init(p));
209
210 /* Each 'memory device' covers up to 16GB of address space. */
211 nr_mem_devs = (memsize + 0x3fff) >> 14;
212 do_struct(smbios_type_16_init(p, memsize, nr_mem_devs));
213 for ( i = 0; i < nr_mem_devs; i++ )
214 {
215 uint32_t dev_memsize = 0x4000; /* all but last covers 16GB */
216 if ( (i == (nr_mem_devs - 1)) && ((memsize & 0x3fff) != 0) )
217 dev_memsize = memsize & 0x3fff; /* last dev is <16GB */
218 do_struct(smbios_type_17_init(p, dev_memsize, i));
219 do_struct(smbios_type_19_init(p, dev_memsize, i));
220 do_struct(smbios_type_20_init(p, dev_memsize, i));
221 }
222
223 do_struct(smbios_type_22_init(p));
224 do_struct(smbios_type_32_init(p));
225 do_struct(smbios_type_39_init(p));
226 do_struct(smbios_type_vendor_oem_init(p));
227 do_struct(smbios_type_127_init(p));
228
229 #undef do_struct
230
231 return ((char *)p - (char *)start);
232 }
233
234 /* Calculate how much pseudo-physical memory (in MB) is allocated to us. */
235 static uint64_t
get_memsize(void)236 get_memsize(void)
237 {
238 uint64_t sz;
239
240 sz = (uint64_t)hvm_info->low_mem_pgend << PAGE_SHIFT;
241 if ( hvm_info->high_mem_pgend )
242 sz += (((uint64_t)hvm_info->high_mem_pgend << PAGE_SHIFT) - GB(4));
243
244 /*
245 * Round up to the nearest MB. The user specifies domU pseudo-physical
246 * memory in megabytes, so not doing this could easily lead to reporting
247 * one less MB than the user specified.
248 */
249 return (sz + MB(1) - 1) >> 20;
250 }
251
252 void
hvm_write_smbios_tables(unsigned long ep,unsigned long smbios_start,unsigned long smbios_end)253 hvm_write_smbios_tables(
254 unsigned long ep, unsigned long smbios_start, unsigned long smbios_end)
255 {
256 xen_domain_handle_t uuid;
257 uint16_t xen_major_version, xen_minor_version;
258 uint32_t xen_version;
259 char xen_extra_version[XEN_EXTRAVERSION_LEN];
260 /* guess conservatively on buffer length for Xen version string */
261 char xen_version_str[80];
262 /* temporary variables used to build up Xen version string */
263 char *p = NULL; /* points to next point of insertion */
264 unsigned len = 0; /* length of string already composed */
265 char tmp[16]; /* holds result of itoa() */
266 unsigned tmp_len; /* length of next string to add */
267 unsigned nr_structs = 0, max_struct_size = 0;
268
269 hypercall_xen_version(XENVER_guest_handle, uuid);
270 BUILD_BUG_ON(sizeof(xen_domain_handle_t) != 16);
271
272 /* xen_version major and minor */
273 xen_version = hypercall_xen_version(XENVER_version, NULL);
274 xen_major_version = (uint16_t) (xen_version >> 16);
275 xen_minor_version = (uint16_t) xen_version;
276
277 hypercall_xen_version(XENVER_extraversion, xen_extra_version);
278
279 /* build up human-readable Xen version string */
280 p = xen_version_str;
281 len = 0;
282
283 itoa(tmp, xen_major_version);
284 tmp_len = strlen(tmp);
285 len += tmp_len;
286 if ( len >= sizeof(xen_version_str) )
287 goto error_out;
288 strcpy(p, tmp);
289 p += tmp_len;
290
291 len++;
292 if ( len >= sizeof(xen_version_str) )
293 goto error_out;
294 *p = '.';
295 p++;
296
297 itoa(tmp, xen_minor_version);
298 tmp_len = strlen(tmp);
299 len += tmp_len;
300 if ( len >= sizeof(xen_version_str) )
301 goto error_out;
302 strcpy(p, tmp);
303 p += tmp_len;
304
305 tmp_len = strlen(xen_extra_version);
306 len += tmp_len;
307 if ( len >= sizeof(xen_version_str) )
308 goto error_out;
309 strcpy(p, xen_extra_version);
310 p += tmp_len;
311
312 xen_version_str[sizeof(xen_version_str)-1] = '\0';
313
314 /* scratch_start is a safe large memory area for scratch. */
315 len = write_smbios_tables((void *)ep, (void *)scratch_start,
316 hvm_info->nr_vcpus, get_memsize(),
317 uuid, xen_version_str,
318 xen_major_version, xen_minor_version,
319 &nr_structs, &max_struct_size);
320 if ( smbios_start && smbios_start + len > smbios_end )
321 goto error_out;
322
323 if ( !smbios_start )
324 smbios_start = (unsigned long)mem_alloc(len, 0);
325
326 memcpy((void *)smbios_start, (void *)scratch_start, len);
327
328 smbios_entry_point_init(
329 (void *)ep, max_struct_size, len, smbios_start, nr_structs);
330
331 return;
332
333 error_out:
334 printf("Could not write SMBIOS tables, error in hvmloader.c:"
335 "hvm_write_smbios_tables()\n");
336 }
337
338
339 static void
smbios_entry_point_init(void * start,uint16_t max_structure_size,uint16_t structure_table_length,uint32_t structure_table_address,uint16_t number_of_structures)340 smbios_entry_point_init(void *start,
341 uint16_t max_structure_size,
342 uint16_t structure_table_length,
343 uint32_t structure_table_address,
344 uint16_t number_of_structures)
345 {
346 uint8_t sum;
347 int i;
348 struct smbios_entry_point *ep = start;
349
350 memset(ep, 0, sizeof(*ep));
351
352 memcpy(ep->anchor_string, "_SM_", 4);
353 ep->length = 0x1f;
354 ep->smbios_major_version = 2;
355 ep->smbios_minor_version = 4;
356 ep->max_structure_size = max_structure_size;
357 ep->entry_point_revision = 0;
358 memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
359
360 ep->structure_table_length = structure_table_length;
361 ep->structure_table_address = structure_table_address;
362 ep->number_of_structures = number_of_structures;
363 ep->smbios_bcd_revision = 0x24;
364
365 sum = 0;
366 for ( i = 0; i < 0x10; i++ )
367 sum += ((int8_t *)start)[i];
368 ep->checksum = -sum;
369
370 sum = 0;
371 for ( i = 0x10; i < ep->length; i++ )
372 sum += ((int8_t *)start)[i];
373 ep->intermediate_checksum = -sum;
374 }
375
376 /* Type 0 -- BIOS Information */
377 static void *
smbios_type_0_init(void * start,const char * xen_version,uint32_t xen_major_version,uint32_t xen_minor_version)378 smbios_type_0_init(void *start, const char *xen_version,
379 uint32_t xen_major_version, uint32_t xen_minor_version)
380 {
381 struct smbios_type_0 *p = (struct smbios_type_0 *)start;
382 static const char *smbios_release_date = __SMBIOS_DATE__;
383 const char *s;
384 void *pts;
385 uint32_t length;
386
387 pts = get_smbios_pt_struct(0, &length);
388 if ( (pts != NULL)&&(length > 0) )
389 {
390 memcpy(start, pts, length);
391 p->header.handle = SMBIOS_HANDLE_TYPE0;
392 return (start + length);
393 }
394
395 memset(p, 0, sizeof(*p));
396
397 p->header.type = 0;
398 p->header.length = sizeof(struct smbios_type_0);
399 p->header.handle = SMBIOS_HANDLE_TYPE0;
400
401 p->vendor_str = 1;
402 p->version_str = 2;
403 p->starting_address_segment = 0xe800;
404 p->release_date_str = 3;
405 p->rom_size = 0;
406
407 /* BIOS Characteristics. */
408 p->characteristics[0] = 0x80; /* PCI is supported */
409 p->characteristics[2] = 0x08; /* EDD is supported */
410
411 /* Extended Characteristics: Enable Targeted Content Distribution. */
412 p->characteristics_extension_bytes[1] = 0x04;
413
414 p->major_release = (uint8_t) xen_major_version;
415 p->minor_release = (uint8_t) xen_minor_version;
416 p->embedded_controller_major = 0xff;
417 p->embedded_controller_minor = 0xff;
418
419 start += sizeof(struct smbios_type_0);
420 s = xenstore_read(HVM_XS_BIOS_VENDOR, "Xen");
421 strcpy((char *)start, s);
422 start += strlen(s) + 1;
423
424 s = xenstore_read(HVM_XS_BIOS_VERSION, xen_version);
425 strcpy((char *)start, s);
426 start += strlen(s) + 1;
427
428 strcpy((char *)start, smbios_release_date);
429 start += strlen(smbios_release_date) + 1;
430
431 *((uint8_t *)start) = 0;
432 return start + 1;
433 }
434
435 /* Type 1 -- System Information */
436 static void *
smbios_type_1_init(void * start,const char * xen_version,uint8_t uuid[16])437 smbios_type_1_init(void *start, const char *xen_version,
438 uint8_t uuid[16])
439 {
440 char uuid_str[37];
441 struct smbios_type_1 *p = (struct smbios_type_1 *)start;
442 const char *s;
443 void *pts;
444 uint32_t length;
445
446 pts = get_smbios_pt_struct(1, &length);
447 if ( (pts != NULL)&&(length > 0) )
448 {
449 memcpy(start, pts, length);
450 p->header.handle = SMBIOS_HANDLE_TYPE1;
451 return (start + length);
452 }
453
454 memset(p, 0, sizeof(*p));
455
456 p->header.type = 1;
457 p->header.length = sizeof(struct smbios_type_1);
458 p->header.handle = SMBIOS_HANDLE_TYPE1;
459
460 p->manufacturer_str = 1;
461 p->product_name_str = 2;
462 p->version_str = 3;
463 p->serial_number_str = 4;
464
465 memcpy(p->uuid, uuid, 16);
466
467 p->wake_up_type = 0x06; /* power switch */
468 p->sku_str = 0;
469 p->family_str = 0;
470
471 start += sizeof(struct smbios_type_1);
472
473 s = xenstore_read(HVM_XS_SYSTEM_MANUFACTURER, "Xen");
474 strcpy((char *)start, s);
475 start += strlen(s) + 1;
476
477 s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU");
478 strcpy((char *)start, s);
479 start += strlen(s) + 1;
480
481 s = xenstore_read(HVM_XS_SYSTEM_VERSION, xen_version);
482 strcpy((char *)start, s);
483 start += strlen(s) + 1;
484
485 uuid_to_string(uuid_str, uuid);
486 s = xenstore_read(HVM_XS_SYSTEM_SERIAL_NUMBER, uuid_str);
487 strcpy((char *)start, s);
488 start += strlen(s) + 1;
489
490 *((uint8_t *)start) = 0;
491
492 return start+1;
493 }
494
495 /* Type 2 -- System Board */
496 static void *
smbios_type_2_init(void * start)497 smbios_type_2_init(void *start)
498 {
499 struct smbios_type_2 *p = (struct smbios_type_2 *)start;
500 const char *s;
501 uint8_t *ptr;
502 void *pts;
503 uint32_t length;
504 unsigned int counter = 0;
505
506 pts = get_smbios_pt_struct(2, &length);
507 if ( (pts != NULL)&&(length > 0) )
508 {
509 memcpy(start, pts, length);
510 p->header.handle = SMBIOS_HANDLE_TYPE2;
511
512 /* Set current chassis handle if present */
513 if ( p->header.length > 13 )
514 {
515 ptr = ((uint8_t*)start) + 11;
516 if ( *((uint16_t*)ptr) != 0 )
517 *((uint16_t*)ptr) = SMBIOS_HANDLE_TYPE3;
518 }
519
520 return (start + length);
521 }
522
523 memset(p, 0, sizeof(*p));
524 p->header.type = 2;
525 p->header.length = sizeof(struct smbios_type_2);
526 p->header.handle = SMBIOS_HANDLE_TYPE2;
527 p->feature_flags = 0x09; /* Board is a hosting board and replaceable */
528 p->chassis_handle = SMBIOS_HANDLE_TYPE3;
529 p->board_type = 0x0a; /* Motherboard */
530 start += sizeof(*p);
531
532 s = xenstore_read(HVM_XS_BASEBOARD_MANUFACTURER, NULL);
533 if ( (s != NULL) && (*s != '\0') )
534 {
535 strcpy(start, s);
536 start += strlen(s) + 1;
537 p->manufacturer_str = ++counter;
538 }
539
540 s = xenstore_read(HVM_XS_BASEBOARD_PRODUCT_NAME, NULL);
541 if ( (s != NULL) && (*s != '\0') )
542 {
543 strcpy(start, s);
544 start += strlen(s) + 1;
545 p->product_name_str = ++counter;
546 }
547
548 s = xenstore_read(HVM_XS_BASEBOARD_VERSION, NULL);
549 if ( (s != NULL) && (*s != '\0') )
550 {
551 strcpy(start, s);
552 start += strlen(s) + 1;
553 p->version_str = ++counter;
554 }
555
556 s = xenstore_read(HVM_XS_BASEBOARD_SERIAL_NUMBER, NULL);
557 if ( (s != NULL) && (*s != '\0') )
558 {
559 strcpy(start, s);
560 start += strlen(s) + 1;
561 p->serial_number_str = ++counter;
562 }
563
564 s = xenstore_read(HVM_XS_BASEBOARD_ASSET_TAG, NULL);
565 if ( (s != NULL) && (*s != '\0') )
566 {
567 strcpy(start, s);
568 start += strlen(s) + 1;
569 p->asset_tag_str = ++counter;
570 }
571
572 s = xenstore_read(HVM_XS_BASEBOARD_LOCATION_IN_CHASSIS, NULL);
573 if ( (s != NULL) && (*s != '\0') )
574 {
575 strcpy(start, s);
576 start += strlen(s) + 1;
577 p->location_in_chassis_str = ++counter;
578 }
579
580 if ( counter )
581 {
582 *(uint8_t *)start = 0;
583 return start + 1;
584 }
585
586 /* Only present when passed in or with customized string */
587 return start - sizeof(*p);
588 }
589
590 /* Type 3 -- System Enclosure */
591 static void *
smbios_type_3_init(void * start)592 smbios_type_3_init(void *start)
593 {
594 struct smbios_type_3 *p = (struct smbios_type_3 *)start;
595 const char *s;
596 void *pts;
597 uint32_t length;
598 uint32_t counter = 0;
599
600 pts = get_smbios_pt_struct(3, &length);
601 if ( (pts != NULL)&&(length > 0) )
602 {
603 memcpy(start, pts, length);
604 p->header.handle = SMBIOS_HANDLE_TYPE3;
605 return (start + length);
606 }
607
608 memset(p, 0, sizeof(*p));
609
610 p->header.type = 3;
611 p->header.length = sizeof(struct smbios_type_3);
612 p->header.handle = SMBIOS_HANDLE_TYPE3;
613
614 p->manufacturer_str = ++counter;
615 p->type = 0x01; /* other */
616 p->version_str = 0;
617 p->serial_number_str = 0;
618 p->asset_tag_str = 0;
619 p->boot_up_state = 0x03; /* safe */
620 p->power_supply_state = 0x03; /* safe */
621 p->thermal_state = 0x03; /* safe */
622 p->security_status = 0x02; /* unknown */
623
624 start += sizeof(struct smbios_type_3);
625
626 s = xenstore_read(HVM_XS_ENCLOSURE_MANUFACTURER, "Xen");
627 strcpy((char *)start, s);
628 start += strlen(s) + 1;
629
630 /* No internal defaults for following ones if the value is not set */
631 s = xenstore_read(HVM_XS_ENCLOSURE_SERIAL_NUMBER, NULL);
632 if ( (s != NULL)&&(*s != '\0') )
633 {
634 strcpy((char *)start, s);
635 start += strlen(s) + 1;
636 p->serial_number_str = ++counter;
637 }
638 s = xenstore_read(HVM_XS_ENCLOSURE_ASSET_TAG, NULL);
639 if ( (s != NULL) && (*s != '\0') )
640 {
641 strcpy(start, s);
642 start += strlen(s) + 1;
643 p->asset_tag_str = ++counter;
644 }
645
646 *((uint8_t *)start) = 0;
647 return start+1;
648 }
649
650 /* Type 4 -- Processor Information */
651 static void *
smbios_type_4_init(void * start,unsigned int cpu_number,char * cpu_manufacturer)652 smbios_type_4_init(
653 void *start, unsigned int cpu_number, char *cpu_manufacturer)
654 {
655 char buf[80];
656 struct smbios_type_4 *p = (struct smbios_type_4 *)start;
657 uint32_t eax, ebx, ecx, edx;
658
659 memset(p, 0, sizeof(*p));
660
661 p->header.type = 4;
662 p->header.length = sizeof(struct smbios_type_4);
663 p->header.handle = SMBIOS_HANDLE_TYPE4 + cpu_number;
664
665 p->socket_designation_str = 1;
666 p->processor_type = 0x03; /* CPU */
667 p->processor_family = 0x01; /* other */
668 p->manufacturer_str = 2;
669
670 cpuid(1, &eax, &ebx, &ecx, &edx);
671
672 p->cpuid[0] = eax;
673 p->cpuid[1] = edx;
674
675 p->version_str = 0;
676 p->voltage = 0;
677 p->external_clock = 0;
678
679 p->max_speed = p->current_speed = get_cpu_mhz();
680
681 p->status = 0x41; /* socket populated, CPU enabled */
682 p->upgrade = 0x01; /* other */
683 p->l1_cache_handle = 0xffff; /* No cache information structure provided. */
684 p->l2_cache_handle = 0xffff; /* No cache information structure provided. */
685 p->l3_cache_handle = 0xffff; /* No cache information structure provided. */
686
687 start += sizeof(struct smbios_type_4);
688
689 strncpy(buf, "CPU ", sizeof(buf));
690 if ( (sizeof(buf) - strlen("CPU ")) >= 3 )
691 itoa(buf + strlen("CPU "), cpu_number);
692
693 strcpy((char *)start, buf);
694 start += strlen(buf) + 1;
695
696 strcpy((char *)start, cpu_manufacturer);
697 start += strlen(cpu_manufacturer) + 1;
698
699 *((uint8_t *)start) = 0;
700 return start+1;
701 }
702
703 /* Type 11 -- OEM Strings */
704 static void *
smbios_type_11_init(void * start)705 smbios_type_11_init(void *start)
706 {
707 struct smbios_type_11 *p = (struct smbios_type_11 *)start;
708 char path[20];
709 const char *s;
710 int i;
711 void *pts;
712 uint32_t length;
713
714 pts = get_smbios_pt_struct(11, &length);
715 if ( (pts != NULL)&&(length > 0) )
716 {
717 memcpy(start, pts, length);
718 p->header.handle = SMBIOS_HANDLE_TYPE11;
719 return (start + length);
720 }
721
722 p->header.type = 11;
723 p->header.length = sizeof(struct smbios_type_11);
724 p->header.handle = SMBIOS_HANDLE_TYPE11;
725
726 p->count = 0;
727
728 start += sizeof(struct smbios_type_11);
729
730 /* Pull out as many oem-* strings we find in xenstore */
731 for ( i = 1; i < 100; i++ )
732 {
733 snprintf(path, sizeof(path), HVM_XS_OEM_STRINGS, i);
734 if ( ((s = xenstore_read(path, NULL)) == NULL) || (*s == '\0') )
735 break;
736 strcpy((char *)start, s);
737 start += strlen(s) + 1;
738 p->count++;
739 }
740
741 /* Make sure there's at least one type-11 string */
742 if ( p->count == 0 )
743 {
744 strcpy((char *)start, "Xen");
745 start += strlen("Xen") + 1;
746 p->count++;
747 }
748 *((uint8_t *)start) = 0;
749
750 return start+1;
751 }
752
753 /* Type 16 -- Physical Memory Array */
754 static void *
smbios_type_16_init(void * start,uint32_t memsize,int nr_mem_devs)755 smbios_type_16_init(void *start, uint32_t memsize, int nr_mem_devs)
756 {
757 struct smbios_type_16 *p = (struct smbios_type_16*)start;
758
759 memset(p, 0, sizeof(*p));
760
761 p->header.type = 16;
762 p->header.handle = SMBIOS_HANDLE_TYPE16;
763 p->header.length = sizeof(struct smbios_type_16);
764
765 p->location = 0x01; /* other */
766 p->use = 0x03; /* system memory */
767 p->error_correction = 0x06; /* Multi-bit ECC to make Microsoft happy */
768 p->maximum_capacity = memsize * 1024;
769 p->memory_error_information_handle = 0xfffe; /* none provided */
770 p->number_of_memory_devices = nr_mem_devs;
771
772 start += sizeof(struct smbios_type_16);
773 *((uint16_t *)start) = 0;
774 return start + 2;
775 }
776
777 /* Type 17 -- Memory Device */
778 static void *
smbios_type_17_init(void * start,uint32_t memory_size_mb,int instance)779 smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance)
780 {
781 char buf[16];
782 struct smbios_type_17 *p = (struct smbios_type_17 *)start;
783
784 memset(p, 0, sizeof(*p));
785
786 p->header.type = 17;
787 p->header.length = sizeof(struct smbios_type_17);
788 p->header.handle = SMBIOS_HANDLE_TYPE17 + instance;
789
790 p->physical_memory_array_handle = 0x1000;
791 p->total_width = 64;
792 p->data_width = 64;
793 ASSERT((memory_size_mb & ~0x7fff) == 0);
794 p->size = memory_size_mb;
795 p->form_factor = 0x09; /* DIMM */
796 p->device_set = 0;
797 p->device_locator_str = 1;
798 p->bank_locator_str = 0;
799 p->memory_type = 0x07; /* RAM */
800 p->type_detail = 0;
801
802 start += sizeof(struct smbios_type_17);
803 strcpy(start, "DIMM ");
804 start += strlen("DIMM ");
805 itoa(buf, instance);
806 strcpy(start, buf);
807 start += strlen(buf) + 1;
808 *((uint8_t *)start) = 0;
809
810 return start+1;
811 }
812
813 /* Type 19 -- Memory Array Mapped Address */
814 static void *
smbios_type_19_init(void * start,uint32_t memory_size_mb,int instance)815 smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance)
816 {
817 struct smbios_type_19 *p = (struct smbios_type_19 *)start;
818
819 memset(p, 0, sizeof(*p));
820
821 p->header.type = 19;
822 p->header.length = sizeof(struct smbios_type_19);
823 p->header.handle = SMBIOS_HANDLE_TYPE19 + instance;
824
825 p->starting_address = instance << 24;
826 p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
827 p->memory_array_handle = 0x1000;
828 p->partition_width = 1;
829
830 start += sizeof(struct smbios_type_19);
831 *((uint16_t *)start) = 0;
832 return start + 2;
833 }
834
835 /* Type 20 -- Memory Device Mapped Address */
836 static void *
smbios_type_20_init(void * start,uint32_t memory_size_mb,int instance)837 smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance)
838 {
839 struct smbios_type_20 *p = (struct smbios_type_20 *)start;
840
841 memset(p, 0, sizeof(*p));
842
843 p->header.type = 20;
844 p->header.length = sizeof(struct smbios_type_20);
845 p->header.handle = SMBIOS_HANDLE_TYPE20 + instance;
846
847 p->starting_address = instance << 24;
848 p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
849 p->memory_device_handle = 0x1100 + instance;
850 p->memory_array_mapped_address_handle = 0x1300 + instance;
851 p->partition_row_position = 1;
852 p->interleave_position = 0;
853 p->interleaved_data_depth = 0;
854
855 start += sizeof(struct smbios_type_20);
856
857 *((uint16_t *)start) = 0;
858 return start+2;
859 }
860
861 /* Type 22 -- Portable Battery */
862 static void *
smbios_type_22_init(void * start)863 smbios_type_22_init(void *start)
864 {
865 struct smbios_type_22 *p = (struct smbios_type_22 *)start;
866 static const char *smbios_release_date = __SMBIOS_DATE__;
867 const char *s;
868 void *pts;
869 uint32_t length;
870
871 pts = get_smbios_pt_struct(22, &length);
872 if ( (pts != NULL)&&(length > 0) )
873 {
874 memcpy(start, pts, length);
875 p->header.handle = SMBIOS_HANDLE_TYPE22;
876 return (start + length);
877 }
878
879 s = xenstore_read(HVM_XS_SMBIOS_DEFAULT_BATTERY, "0");
880 if ( strncmp(s, "1", 1) != 0 )
881 return start;
882
883 memset(p, 0, sizeof(*p));
884
885 p->header.type = 22;
886 p->header.length = sizeof(struct smbios_type_22);
887 p->header.handle = SMBIOS_HANDLE_TYPE22;
888
889 p->location_str = 1;
890 p->manufacturer_str = 2;
891 p->manufacturer_date_str = 3;
892 p->serial_number_str = 0;
893 p->device_name_str = 4;
894 p->device_chemistry = 0x2; /* unknown */
895 p->device_capacity = 0; /* unknown */
896 p->device_voltage = 0; /* unknown */
897 p->sbds_version_number = 0;
898 p->max_error = 0xff; /* unknown */
899 p->sbds_serial_number = 0;
900 p->sbds_manufacturer_date = 0;
901 p->sbds_device_chemistry = 0;
902 p->design_capacity_multiplier = 0;
903 p->oem_specific = 0;
904
905 start += sizeof(struct smbios_type_22);
906
907 strcpy((char *)start, "Primary");
908 start += strlen("Primary") + 1;
909
910 s = xenstore_read(HVM_XS_BATTERY_MANUFACTURER, "Xen");
911 strcpy((char *)start, s);
912 start += strlen(s) + 1;
913
914 strcpy((char *)start, smbios_release_date);
915 start += strlen(smbios_release_date) + 1;
916
917 s = xenstore_read(HVM_XS_BATTERY_DEVICE_NAME, "XEN-VBAT");
918 strcpy((char *)start, s);
919 start += strlen(s) + 1;
920
921 *((uint8_t *)start) = 0;
922
923 return start+1;
924 }
925
926 /* Type 32 -- System Boot Information */
927 static void *
smbios_type_32_init(void * start)928 smbios_type_32_init(void *start)
929 {
930 struct smbios_type_32 *p = (struct smbios_type_32 *)start;
931
932 memset(p, 0, sizeof(*p));
933
934 p->header.type = 32;
935 p->header.length = sizeof(struct smbios_type_32);
936 p->header.handle = SMBIOS_HANDLE_TYPE32;
937 memset(p->reserved, 0, 6);
938 p->boot_status = 0; /* no errors detected */
939
940 start += sizeof(struct smbios_type_32);
941 *((uint16_t *)start) = 0;
942 return start+2;
943 }
944
945 /* Type 39 -- Power Supply */
946 static void *
smbios_type_39_init(void * start)947 smbios_type_39_init(void *start)
948 {
949 struct smbios_type_39 *p = (struct smbios_type_39 *)start;
950 void *pts;
951 uint32_t length;
952
953 pts = get_smbios_pt_struct(39, &length);
954 if ( (pts != NULL)&&(length > 0) )
955 {
956 memcpy(start, pts, length);
957 p->header.handle = SMBIOS_HANDLE_TYPE39;
958 return (start + length);
959 }
960
961 /* Only present when passed in */
962 return start;
963 }
964
965 static void *
smbios_type_vendor_oem_init(void * start)966 smbios_type_vendor_oem_init(void *start)
967 {
968 uint32_t *sep = smbios_pt_addr;
969 uint32_t total = 0;
970 uint8_t *ptr;
971
972 if ( sep == NULL )
973 return start;
974
975 while ( total < smbios_pt_length )
976 {
977 ptr = (uint8_t*)(sep + 1);
978 if ( ptr[0] >= 128 )
979 {
980 /* Vendor/OEM table, copy it in. Note the handle values cannot
981 * be changed since it is unknown what is in each of these tables
982 * but they could contain handle references to other tables. This
983 * means a slight risk of collision with the tables above but that
984 * would have to be dealt with on a case by case basis.
985 */
986 memcpy(start, ptr, *sep);
987 start += *sep;
988 }
989
990 total += (*sep + sizeof(uint32_t));
991 sep = (uint32_t*)(ptr + *sep);
992 }
993
994 return start;
995 }
996
997 /* Type 127 -- End of Table */
998 static void *
smbios_type_127_init(void * start)999 smbios_type_127_init(void *start)
1000 {
1001 struct smbios_type_127 *p = (struct smbios_type_127 *)start;
1002
1003 memset(p, 0, sizeof(*p));
1004
1005 p->header.type = 127;
1006 p->header.length = sizeof(struct smbios_type_127);
1007 p->header.handle = SMBIOS_HANDLE_TYPE127;
1008
1009 start += sizeof(struct smbios_type_127);
1010 *((uint16_t *)start) = 0;
1011 return start + 2;
1012 }
1013
1014 /*
1015 * Local variables:
1016 * mode: C
1017 * c-file-style: "BSD"
1018 * c-basic-offset: 4
1019 * tab-width: 4
1020 * indent-tabs-mode: nil
1021 * End:
1022 */
1023