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