Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / smbios.c
1 // smbios table generation (on emulators)
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2006 Fabrice Bellard
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "util.h" // dprintf
9 #include "biosvar.h" // GET_EBDA
10 #include "paravirt.h" // qemu_cfg_smbios_load_field
11 #include "smbios.h" // struct smbios_entry_point
12
13 struct smbios_entry_point *SMBiosAddr;
14
15 static void
16 smbios_entry_point_init(u16 max_structure_size,
17                         u16 structure_table_length,
18                         void *structure_table_address,
19                         u16 number_of_structures)
20 {
21     struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
22     void *finaltable;
23     if (structure_table_length <= BUILD_MAX_SMBIOS_FSEG)
24         // Table is small enough for f-seg - allocate there.  This
25         // works around a bug in JunOS (at least for small SMBIOS tables).
26         finaltable = malloc_fseg(structure_table_length);
27     else
28         finaltable = malloc_high(structure_table_length);
29     if (!ep || !finaltable) {
30         warn_noalloc();
31         free(ep);
32         free(finaltable);
33         return;
34     }
35     memcpy(finaltable, structure_table_address, structure_table_length);
36
37     memcpy(ep->anchor_string, "_SM_", 4);
38     ep->length = 0x1f;
39     ep->smbios_major_version = 2;
40     ep->smbios_minor_version = 4;
41     ep->max_structure_size = max_structure_size;
42     ep->entry_point_revision = 0;
43     memset(ep->formatted_area, 0, 5);
44     memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
45
46     ep->structure_table_length = structure_table_length;
47     ep->structure_table_address = (u32)finaltable;
48     ep->number_of_structures = number_of_structures;
49     ep->smbios_bcd_revision = 0x24;
50
51     ep->checksum -= checksum(ep, 0x10);
52
53     ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10);
54
55     SMBiosAddr = ep;
56     dprintf(1, "SMBIOS ptr=%p table=%p size=%d\n"
57             , ep, finaltable, structure_table_length);
58 }
59
60 #define load_str_field_with_default(type, field, def)                   \
61     do {                                                                \
62         size = qemu_cfg_smbios_load_field(type,                         \
63                                  offsetof(struct smbios_type_##type,    \
64                                           field), end);                 \
65         if (size > 0) {                                                 \
66             end += size;                                                \
67         } else {                                                        \
68             memcpy(end, def, sizeof(def));                              \
69             end += sizeof(def);                                         \
70         }                                                               \
71         p->field = ++str_index;                                         \
72     } while (0)
73
74 #define load_str_field_or_skip(type, field)                             \
75     do {                                                                \
76         size = qemu_cfg_smbios_load_field(type,                         \
77                                  offsetof(struct smbios_type_##type,    \
78                                           field), end);                 \
79         if (size > 0) {                                                 \
80             end += size;                                                \
81             p->field = ++str_index;                                     \
82         } else {                                                        \
83             p->field = 0;                                               \
84         }                                                               \
85     } while (0)
86
87 #define set_field_with_default(type, field, def)                        \
88     do {                                                                \
89         if (!qemu_cfg_smbios_load_field(type,                           \
90                                  offsetof(struct smbios_type_##type,    \
91                                           field), &p->field)) {         \
92             p->field = def;                                             \
93         }                                                               \
94     } while (0)
95
96 /* Type 0 -- BIOS Information */
97 #define RELEASE_DATE_STR "01/01/2007"
98 static void *
99 smbios_init_type_0(void *start)
100 {
101     struct smbios_type_0 *p = (struct smbios_type_0 *)start;
102     char *end = (char *)start + sizeof(struct smbios_type_0);
103     size_t size;
104     int str_index = 0;
105
106     p->header.type = 0;
107     p->header.length = sizeof(struct smbios_type_0);
108     p->header.handle = 0;
109
110     load_str_field_with_default(0, vendor_str, CONFIG_APPNAME);
111     load_str_field_with_default(0, bios_version_str, CONFIG_APPNAME);
112
113     p->bios_starting_address_segment = 0xe800;
114
115     load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
116
117     p->bios_rom_size = 0; /* FIXME */
118
119     if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
120                                                 bios_characteristics),
121                                     &p->bios_characteristics)) {
122         memset(p->bios_characteristics, 0, 8);
123         /* BIOS characteristics not supported */
124         p->bios_characteristics[0] = 0x08;
125     }
126
127     if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
128                                     bios_characteristics_extension_bytes),
129                                     &p->bios_characteristics_extension_bytes)) {
130         p->bios_characteristics_extension_bytes[0] = 0;
131         /* Enable targeted content distribution. Needed for SVVP */
132         p->bios_characteristics_extension_bytes[1] = 4;
133     }
134
135     set_field_with_default(0, system_bios_major_release, 1);
136     set_field_with_default(0, system_bios_minor_release, 0);
137     set_field_with_default(0, embedded_controller_major_release, 0xff);
138     set_field_with_default(0, embedded_controller_minor_release, 0xff);
139
140     *end = 0;
141     end++;
142
143     return end;
144 }
145
146 /* Type 1 -- System Information */
147 static void *
148 smbios_init_type_1(void *start)
149 {
150     struct smbios_type_1 *p = (struct smbios_type_1 *)start;
151     char *end = (char *)start + sizeof(struct smbios_type_1);
152     size_t size;
153     int str_index = 0;
154
155     p->header.type = 1;
156     p->header.length = sizeof(struct smbios_type_1);
157     p->header.handle = 0x100;
158
159     load_str_field_with_default(1, manufacturer_str, CONFIG_APPNAME);
160     load_str_field_with_default(1, product_name_str, CONFIG_APPNAME);
161     load_str_field_or_skip(1, version_str);
162     load_str_field_or_skip(1, serial_number_str);
163
164     if (!qemu_cfg_smbios_load_field(1, offsetof(struct smbios_type_1,
165                                                   uuid), &p->uuid)) {
166         memset(p->uuid, 0, 16);
167     }
168
169     set_field_with_default(1, wake_up_type, 0x06); /* power switch */
170
171     load_str_field_or_skip(1, sku_number_str);
172     load_str_field_or_skip(1, family_str);
173
174     *end = 0;
175     end++;
176     if (!str_index) {
177         *end = 0;
178         end++;
179     }
180
181     return end;
182 }
183
184 /* Type 3 -- System Enclosure */
185 static void *
186 smbios_init_type_3(void *start)
187 {
188     struct smbios_type_3 *p = (struct smbios_type_3 *)start;
189     char *end = (char *)start + sizeof(struct smbios_type_3);
190     size_t size;
191     int str_index = 0;
192
193     p->header.type = 3;
194     p->header.length = sizeof(struct smbios_type_3);
195     p->header.handle = 0x300;
196
197     load_str_field_with_default(3, manufacturer_str, CONFIG_APPNAME);
198     set_field_with_default(3, type, 0x01); /* other */
199
200     load_str_field_or_skip(3, version_str);
201     load_str_field_or_skip(3, serial_number_str);
202     load_str_field_or_skip(3, asset_tag_number_str);
203
204     set_field_with_default(3, boot_up_state, 0x03); /* safe */
205     set_field_with_default(3, power_supply_state, 0x03); /* safe */
206     set_field_with_default(3, thermal_state, 0x03); /* safe */
207     set_field_with_default(3, security_status, 0x02); /* unknown */
208
209     set_field_with_default(3, oem_defined, 0);
210     set_field_with_default(3, height, 0);
211     set_field_with_default(3, number_of_power_cords, 0);
212     set_field_with_default(3, contained_element_count, 0);
213
214     *end = 0;
215     end++;
216     if (!str_index) {
217         *end = 0;
218         end++;
219     }
220
221     return end;
222 }
223
224 /* Type 4 -- Processor Information */
225 static void *
226 smbios_init_type_4(void *start, unsigned int cpu_number)
227 {
228     struct smbios_type_4 *p = (struct smbios_type_4 *)start;
229     char *end = (char *)start + sizeof(struct smbios_type_4);
230     size_t size;
231     int str_index = 0;
232     char name[1024];
233
234     p->header.type = 4;
235     p->header.length = sizeof(struct smbios_type_4);
236     p->header.handle = 0x400 + cpu_number;
237
238     size = qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
239                                                   socket_designation_str),
240                                                   name);
241     if (size)
242         snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
243     else
244         snprintf(name, sizeof(name), "CPU%2x", cpu_number);
245
246     memcpy(end, name, strlen(name) + 1);
247     end += strlen(name) + 1;
248     p->socket_designation_str = ++str_index;
249
250     set_field_with_default(4, processor_type, 0x03); /* CPU */
251     set_field_with_default(4, processor_family, 0x01); /* other */
252
253     load_str_field_with_default(4, processor_manufacturer_str, CONFIG_APPNAME);
254
255     if (!qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
256                                     processor_id), p->processor_id)) {
257         u32 cpuid_signature, ebx, ecx, cpuid_features;
258         cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
259         p->processor_id[0] = cpuid_signature;
260         p->processor_id[1] = cpuid_features;
261     }
262
263     load_str_field_or_skip(4, processor_version_str);
264     set_field_with_default(4, voltage, 0);
265     set_field_with_default(4, external_clock, 0);
266
267     set_field_with_default(4, max_speed, 2000);
268     set_field_with_default(4, current_speed, 2000);
269
270     set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */
271     set_field_with_default(4, processor_upgrade, 0x01); /* other */
272
273     /* cache information structure not provided */
274     p->l1_cache_handle =  0xffff;
275     p->l2_cache_handle =  0xffff;
276     p->l3_cache_handle =  0xffff;
277
278     *end = 0;
279     end++;
280     if (!str_index) {
281         *end = 0;
282         end++;
283     }
284
285     return end;
286 }
287
288 /* Type 16 -- Physical Memory Array */
289 static void *
290 smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs)
291 {
292     struct smbios_type_16 *p = (struct smbios_type_16*)start;
293
294     p->header.type = 16;
295     p->header.length = sizeof(struct smbios_type_16);
296     p->header.handle = 0x1000;
297
298     set_field_with_default(16, location, 0x01); /* other */
299     set_field_with_default(16, use, 0x03); /* system memory */
300     /* Multi-bit ECC to make Microsoft happy */
301     set_field_with_default(16, error_correction, 0x06);
302     /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */
303     p->maximum_capacity = memory_size_mb < 2 << 20 ?
304                           memory_size_mb << 10 : 0x80000000;
305     p->memory_error_information_handle = 0xfffe; /* none provided */
306     p->number_of_memory_devices = nr_mem_devs;
307
308     start += sizeof(struct smbios_type_16);
309     *((u16 *)start) = 0;
310
311     return start + 2;
312 }
313
314 /* Type 17 -- Memory Device */
315 static void *
316 smbios_init_type_17(void *start, u32 size_mb, int instance)
317 {
318     struct smbios_type_17 *p = (struct smbios_type_17 *)start;
319     char *end = (char *)start + sizeof(struct smbios_type_17);
320     size_t size;
321     int str_index = 0;
322     char name[1024];
323
324     p->header.type = 17;
325     p->header.length = sizeof(struct smbios_type_17);
326     p->header.handle = 0x1100 + instance;
327
328     p->physical_memory_array_handle = 0x1000;
329     set_field_with_default(17, total_width, 64);
330     set_field_with_default(17, data_width, 64);
331 /* TODO: should assert in case something is wrong   ASSERT((memory_size_mb & ~0x7fff) == 0); */
332     p->size = size_mb;
333     set_field_with_default(17, form_factor, 0x09); /* DIMM */
334     p->device_set = 0;
335
336     size = qemu_cfg_smbios_load_field(17, offsetof(struct smbios_type_17,
337                                                    device_locator_str),
338                                                    name);
339     if (size)
340         snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
341     else
342         snprintf(name, sizeof(name), "DIMM %d", instance);
343
344     memcpy(end, name, strlen(name) + 1);
345     end += strlen(name) + 1;
346     p->device_locator_str = ++str_index;
347
348     load_str_field_or_skip(17, bank_locator_str);
349     set_field_with_default(17, memory_type, 0x07); /* RAM */
350     set_field_with_default(17, type_detail, 0);
351
352     *end = 0;
353     end++;
354     if (!str_index) {
355         *end = 0;
356         end++;
357     }
358
359     return end;
360 }
361
362 /* Type 19 -- Memory Array Mapped Address */
363 static void *
364 smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance)
365 {
366     struct smbios_type_19 *p = (struct smbios_type_19 *)start;
367
368     p->header.type = 19;
369     p->header.length = sizeof(struct smbios_type_19);
370     p->header.handle = 0x1300 + instance;
371
372     p->starting_address = start_mb << 10;
373     p->ending_address = p->starting_address + (size_mb << 10) - 1;
374     p->memory_array_handle = 0x1000;
375     p->partition_width = 1;
376
377     start += sizeof(struct smbios_type_19);
378     *((u16 *)start) = 0;
379
380     return start + 2;
381 }
382
383 /* Type 20 -- Memory Device Mapped Address */
384 static void *
385 smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance,
386                     int dev_handle, int array_handle)
387 {
388     struct smbios_type_20 *p = (struct smbios_type_20 *)start;
389
390     p->header.type = 20;
391     p->header.length = sizeof(struct smbios_type_20);
392     p->header.handle = 0x1400 + instance;
393
394     p->starting_address = start_mb << 10;
395     p->ending_address = p->starting_address + (size_mb << 10) - 1;
396     p->memory_device_handle = 0x1100 + dev_handle;
397     p->memory_array_mapped_address_handle = 0x1300 + array_handle;
398     p->partition_row_position = 1;
399     p->interleave_position = 0;
400     p->interleaved_data_depth = 0;
401
402     start += sizeof(struct smbios_type_20);
403
404     *((u16 *)start) = 0;
405     return start+2;
406 }
407
408 /* Type 32 -- System Boot Information */
409 static void *
410 smbios_init_type_32(void *start)
411 {
412     struct smbios_type_32 *p = (struct smbios_type_32 *)start;
413
414     p->header.type = 32;
415     p->header.length = sizeof(struct smbios_type_32);
416     p->header.handle = 0x2000;
417     memset(p->reserved, 0, 6);
418     set_field_with_default(32, boot_status, 0); /* no errors detected */
419
420     start += sizeof(struct smbios_type_32);
421     *((u16 *)start) = 0;
422
423     return start+2;
424 }
425
426 /* Type 127 -- End of Table */
427 static void *
428 smbios_init_type_127(void *start)
429 {
430     struct smbios_type_127 *p = (struct smbios_type_127 *)start;
431
432     p->header.type = 127;
433     p->header.length = sizeof(struct smbios_type_127);
434     p->header.handle = 0x7f00;
435
436     start += sizeof(struct smbios_type_127);
437     *((u16 *)start) = 0;
438
439     return start + 2;
440 }
441
442 #define TEMPSMBIOSSIZE (32 * 1024)
443
444 void
445 smbios_init(void)
446 {
447     if (! CONFIG_SMBIOS)
448         return;
449
450     dprintf(3, "init SMBIOS tables\n");
451
452     char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
453     if (! start) {
454         warn_noalloc();
455         return;
456     }
457
458     u32 nr_structs = 0, max_struct_size = 0;
459     char *q, *p = start;
460     char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127);
461
462 #define add_struct(type, args...)                                       \
463     do {                                                                \
464         if (!qemu_cfg_smbios_load_external(type, &p, &nr_structs,       \
465                                            &max_struct_size, end)) {    \
466             q = smbios_init_type_##type(args);                          \
467             nr_structs++;                                               \
468             if ((q - p) > max_struct_size)                              \
469                 max_struct_size = q - p;                                \
470             p = q;                                                      \
471         }                                                               \
472     } while (0)
473
474     add_struct(0, p);
475     add_struct(1, p);
476     add_struct(3, p);
477
478     int cpu_num;
479     for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
480         add_struct(4, p, cpu_num);
481
482     int ram_mb = (RamSize + RamSizeOver4G) >> 20;
483     int nr_mem_devs = (ram_mb + 0x3fff) >> 14;
484     add_struct(16, p, ram_mb, nr_mem_devs);
485
486     int i, j;
487     for (i = 0; i < nr_mem_devs; i++) {
488         u32 dev_mb = ((i == (nr_mem_devs - 1))
489                       ? (((ram_mb - 1) & 0x3fff) + 1)
490                       : 16384);
491         add_struct(17, p, dev_mb, i);
492     }
493
494     add_struct(19, p, 0, RamSize >> 20, 0);
495     if (RamSizeOver4G)
496         add_struct(19, p, 4096, RamSizeOver4G >> 20, 1);
497
498     add_struct(20, p, 0, RamSize >> 20, 0, 0, 0);
499     if (RamSizeOver4G) {
500         u32 start_mb = 4096;
501         for (j = 1, i = 0; i < nr_mem_devs; i++, j++) {
502             u32 dev_mb = ((i == (nr_mem_devs - 1))
503                                ? (((ram_mb - 1) & 0x3fff) + 1)
504                                : 16384);
505             if (i == 0)
506                 dev_mb -= RamSize >> 20;
507
508             add_struct(20, p, start_mb, dev_mb, j, i, 1);
509             start_mb += dev_mb;
510         }
511     }
512
513     add_struct(32, p);
514     /* Add any remaining provided entries before the end marker */
515     for (i = 0; i < 256; i++)
516         qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,
517                                       end);
518     add_struct(127, p);
519
520 #undef add_struct
521
522     smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
523     free(start);
524 }