Add Post Memory Manager (PMM) support.
[seabios.git] / 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
11
12 /****************************************************************
13  * UUID probe
14  ****************************************************************/
15
16 #define QEMU_CFG_SIGNATURE  0x00
17 #define QEMU_CFG_ID         0x01
18 #define QEMU_CFG_UUID       0x02
19
20 static void
21 qemu_cfg_read(u8 *buf, u16 f, int len)
22 {
23     outw(f, PORT_QEMU_CFG_CTL);
24     while (len--)
25         *(buf++) = inb(PORT_QEMU_CFG_DATA);
26 }
27
28 static int
29 qemu_cfg_port_probe()
30 {
31     u8 sig[4] = "QEMU";
32     u8 buf[4];
33     qemu_cfg_read(buf, QEMU_CFG_SIGNATURE, 4);
34     return *(u32*)buf == *(u32*)sig;
35 }
36
37 static void
38 uuid_probe(u8 *bios_uuid)
39 {
40     // Default to UUID not set
41     memset(bios_uuid, 0, 16);
42
43     if (! CONFIG_UUID_BACKDOOR)
44         return;
45     if (CONFIG_COREBOOT)
46         return;
47     if (! qemu_cfg_port_probe())
48         // Feature not available
49         return;
50
51     qemu_cfg_read(bios_uuid, QEMU_CFG_UUID, 16);
52 }
53
54
55 /****************************************************************
56  * smbios tables
57  ****************************************************************/
58
59 /* SMBIOS entry point -- must be written to a 16-bit aligned address
60    between 0xf0000 and 0xfffff.
61  */
62 struct smbios_entry_point {
63         char anchor_string[4];
64         u8 checksum;
65         u8 length;
66         u8 smbios_major_version;
67         u8 smbios_minor_version;
68         u16 max_structure_size;
69         u8 entry_point_revision;
70         u8 formatted_area[5];
71         char intermediate_anchor_string[5];
72         u8 intermediate_checksum;
73         u16 structure_table_length;
74         u32 structure_table_address;
75         u16 number_of_structures;
76         u8 smbios_bcd_revision;
77 } PACKED;
78
79 /* This goes at the beginning of every SMBIOS structure. */
80 struct smbios_structure_header {
81         u8 type;
82         u8 length;
83         u16 handle;
84 } PACKED;
85
86 /* SMBIOS type 0 - BIOS Information */
87 struct smbios_type_0 {
88         struct smbios_structure_header header;
89         u8 vendor_str;
90         u8 bios_version_str;
91         u16 bios_starting_address_segment;
92         u8 bios_release_date_str;
93         u8 bios_rom_size;
94         u8 bios_characteristics[8];
95         u8 bios_characteristics_extension_bytes[2];
96         u8 system_bios_major_release;
97         u8 system_bios_minor_release;
98         u8 embedded_controller_major_release;
99         u8 embedded_controller_minor_release;
100 } PACKED;
101
102 /* SMBIOS type 1 - System Information */
103 struct smbios_type_1 {
104         struct smbios_structure_header header;
105         u8 manufacturer_str;
106         u8 product_name_str;
107         u8 version_str;
108         u8 serial_number_str;
109         u8 uuid[16];
110         u8 wake_up_type;
111         u8 sku_number_str;
112         u8 family_str;
113 } PACKED;
114
115 /* SMBIOS type 3 - System Enclosure (v2.3) */
116 struct smbios_type_3 {
117         struct smbios_structure_header header;
118         u8 manufacturer_str;
119         u8 type;
120         u8 version_str;
121         u8 serial_number_str;
122         u8 asset_tag_number_str;
123         u8 boot_up_state;
124         u8 power_supply_state;
125         u8 thermal_state;
126         u8 security_status;
127     u32 oem_defined;
128     u8 height;
129     u8 number_of_power_cords;
130     u8 contained_element_count;
131     // contained elements follow
132 } PACKED;
133
134 /* SMBIOS type 4 - Processor Information (v2.0) */
135 struct smbios_type_4 {
136         struct smbios_structure_header header;
137         u8 socket_designation_str;
138         u8 processor_type;
139         u8 processor_family;
140         u8 processor_manufacturer_str;
141         u32 processor_id[2];
142         u8 processor_version_str;
143         u8 voltage;
144         u16 external_clock;
145         u16 max_speed;
146         u16 current_speed;
147         u8 status;
148         u8 processor_upgrade;
149         u16 l1_cache_handle;
150         u16 l2_cache_handle;
151         u16 l3_cache_handle;
152 } PACKED;
153
154 /* SMBIOS type 16 - Physical Memory Array
155  *   Associated with one type 17 (Memory Device).
156  */
157 struct smbios_type_16 {
158         struct smbios_structure_header header;
159         u8 location;
160         u8 use;
161         u8 error_correction;
162         u32 maximum_capacity;
163         u16 memory_error_information_handle;
164         u16 number_of_memory_devices;
165 } PACKED;
166
167 /* SMBIOS type 17 - Memory Device
168  *   Associated with one type 19
169  */
170 struct smbios_type_17 {
171         struct smbios_structure_header header;
172         u16 physical_memory_array_handle;
173         u16 memory_error_information_handle;
174         u16 total_width;
175         u16 data_width;
176         u16 size;
177         u8 form_factor;
178         u8 device_set;
179         u8 device_locator_str;
180         u8 bank_locator_str;
181         u8 memory_type;
182         u16 type_detail;
183 } PACKED;
184
185 /* SMBIOS type 19 - Memory Array Mapped Address */
186 struct smbios_type_19 {
187         struct smbios_structure_header header;
188         u32 starting_address;
189         u32 ending_address;
190         u16 memory_array_handle;
191         u8 partition_width;
192 } PACKED;
193
194 /* SMBIOS type 20 - Memory Device Mapped Address */
195 struct smbios_type_20 {
196         struct smbios_structure_header header;
197         u32 starting_address;
198         u32 ending_address;
199         u16 memory_device_handle;
200         u16 memory_array_mapped_address_handle;
201         u8 partition_row_position;
202         u8 interleave_position;
203         u8 interleaved_data_depth;
204 } PACKED;
205
206 /* SMBIOS type 32 - System Boot Information */
207 struct smbios_type_32 {
208         struct smbios_structure_header header;
209         u8 reserved[6];
210         u8 boot_status;
211 } PACKED;
212
213 /* SMBIOS type 127 -- End-of-table */
214 struct smbios_type_127 {
215         struct smbios_structure_header header;
216 } PACKED;
217
218
219 /****************************************************************
220  * smbios init
221  ****************************************************************/
222
223 static void
224 smbios_entry_point_init(u16 max_structure_size,
225                         u16 structure_table_length,
226                         void *structure_table_address,
227                         u16 number_of_structures)
228 {
229     struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
230     if (! ep) {
231         dprintf(1, "No space for smbios entry table!\n");
232         return;
233     }
234
235     memcpy(ep->anchor_string, "_SM_", 4);
236     ep->length = 0x1f;
237     ep->smbios_major_version = 2;
238     ep->smbios_minor_version = 4;
239     ep->max_structure_size = max_structure_size;
240     ep->entry_point_revision = 0;
241     memset(ep->formatted_area, 0, 5);
242     memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
243
244     ep->structure_table_length = structure_table_length;
245     ep->structure_table_address = (u32)structure_table_address;
246     ep->number_of_structures = number_of_structures;
247     ep->smbios_bcd_revision = 0x24;
248
249     ep->checksum -= checksum(ep, 0x10);
250
251     ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10);
252
253     dprintf(1, "SMBIOS ptr=%p table=%p\n", ep, structure_table_address);
254 }
255
256 /* Type 0 -- BIOS Information */
257 #define RELEASE_DATE_STR "01/01/2007"
258 static void *
259 smbios_type_0_init(void *start)
260 {
261     struct smbios_type_0 *p = (struct smbios_type_0 *)start;
262
263     p->header.type = 0;
264     p->header.length = sizeof(struct smbios_type_0);
265     p->header.handle = 0;
266
267     p->vendor_str = 1;
268     p->bios_version_str = 1;
269     p->bios_starting_address_segment = 0xe800;
270     p->bios_release_date_str = 2;
271     p->bios_rom_size = 0; /* FIXME */
272
273     memset(p->bios_characteristics, 0, sizeof(p->bios_characteristics));
274     p->bios_characteristics[0] = 0x08; /* BIOS characteristics not supported */
275     p->bios_characteristics_extension_bytes[0] = 0;
276     p->bios_characteristics_extension_bytes[1] = 0;
277
278     p->system_bios_major_release = 1;
279     p->system_bios_minor_release = 0;
280     p->embedded_controller_major_release = 0xff;
281     p->embedded_controller_minor_release = 0xff;
282
283     start += sizeof(struct smbios_type_0);
284     memcpy((char *)start, CONFIG_APPNAME, sizeof(CONFIG_APPNAME));
285     start += sizeof(CONFIG_APPNAME);
286     memcpy((char *)start, RELEASE_DATE_STR, sizeof(RELEASE_DATE_STR));
287     start += sizeof(RELEASE_DATE_STR);
288     *((u8 *)start) = 0;
289
290     return start+1;
291 }
292
293 /* Type 1 -- System Information */
294 static void *
295 smbios_type_1_init(void *start)
296 {
297     struct smbios_type_1 *p = (struct smbios_type_1 *)start;
298     p->header.type = 1;
299     p->header.length = sizeof(struct smbios_type_1);
300     p->header.handle = 0x100;
301
302     p->manufacturer_str = 0;
303     p->product_name_str = 0;
304     p->version_str = 0;
305     p->serial_number_str = 0;
306
307     uuid_probe(p->uuid);
308
309     p->wake_up_type = 0x06; /* power switch */
310     p->sku_number_str = 0;
311     p->family_str = 0;
312
313     start += sizeof(struct smbios_type_1);
314     *((u16 *)start) = 0;
315
316     return start+2;
317 }
318
319 /* Type 3 -- System Enclosure */
320 static void *
321 smbios_type_3_init(void *start)
322 {
323     struct smbios_type_3 *p = (struct smbios_type_3 *)start;
324
325     p->header.type = 3;
326     p->header.length = sizeof(struct smbios_type_3);
327     p->header.handle = 0x300;
328
329     p->manufacturer_str = 0;
330     p->type = 0x01; /* other */
331     p->version_str = 0;
332     p->serial_number_str = 0;
333     p->asset_tag_number_str = 0;
334     p->boot_up_state = 0x03; /* safe */
335     p->power_supply_state = 0x03; /* safe */
336     p->thermal_state = 0x03; /* safe */
337     p->security_status = 0x02; /* unknown */
338     p->oem_defined = 0;
339     p->height = 0;
340     p->number_of_power_cords = 0;
341     p->contained_element_count = 0;
342
343     start += sizeof(struct smbios_type_3);
344     *((u16 *)start) = 0;
345
346     return start+2;
347 }
348
349 /* Type 4 -- Processor Information */
350 static void *
351 smbios_type_4_init(void *start, unsigned int cpu_number)
352 {
353     struct smbios_type_4 *p = (struct smbios_type_4 *)start;
354
355     p->header.type = 4;
356     p->header.length = sizeof(struct smbios_type_4);
357     p->header.handle = 0x400 + cpu_number;
358
359     p->socket_designation_str = 1;
360     p->processor_type = 0x03; /* CPU */
361     p->processor_family = 0x01; /* other */
362     p->processor_manufacturer_str = 0;
363
364     u32 cpuid_signature, ebx, ecx, cpuid_features;
365     cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
366     p->processor_id[0] = cpuid_signature;
367     p->processor_id[1] = cpuid_features;
368
369     p->processor_version_str = 0;
370     p->voltage = 0;
371     p->external_clock = 0;
372
373     p->max_speed = 0; /* unknown */
374     p->current_speed = 0; /* unknown */
375
376     p->status = 0x41; /* socket populated, CPU enabled */
377     p->processor_upgrade = 0x01; /* other */
378
379     p->l1_cache_handle = 0xffff; /* cache information structure not provided */
380     p->l2_cache_handle = 0xffff;
381     p->l3_cache_handle = 0xffff;
382
383     start += sizeof(struct smbios_type_4);
384
385     memcpy((char *)start, "CPU  " "\0" "" "\0" "", 7);
386         ((char *)start)[4] = cpu_number + '0';
387
388     return start+7;
389 }
390
391 /* Type 16 -- Physical Memory Array */
392 static void *
393 smbios_type_16_init(void *start)
394 {
395     struct smbios_type_16 *p = (struct smbios_type_16*)start;
396
397     p->header.type = 16;
398     p->header.length = sizeof(struct smbios_type_16);
399     p->header.handle = 0x1000;
400
401     p->location = 0x01; /* other */
402     p->use = 0x03; /* system memory */
403     p->error_correction = 0x01; /* other */
404     u64 memsize = RamSize + RamSizeOver4G;
405     p->maximum_capacity = memsize / 1024;
406     p->memory_error_information_handle = 0xfffe; /* none provided */
407     p->number_of_memory_devices = 1;
408
409     start += sizeof(struct smbios_type_16);
410     *((u16 *)start) = 0;
411
412     return start + 2;
413 }
414
415 /* Type 17 -- Memory Device */
416 static void *
417 smbios_type_17_init(void *start)
418 {
419     struct smbios_type_17 *p = (struct smbios_type_17 *)start;
420
421     p->header.type = 17;
422     p->header.length = sizeof(struct smbios_type_17);
423     p->header.handle = 0x1100;
424
425     p->physical_memory_array_handle = 0x1000;
426     p->total_width = 64;
427     p->data_width = 64;
428     /* truncate memory_size_mb to 16 bits and clear most significant
429        bit [indicates size in MB] */
430     u64 memsize = RamSize + RamSizeOver4G;
431     p->size = (u16) (memsize / (1024*1024)) & 0x7fff;
432     p->form_factor = 0x09; /* DIMM */
433     p->device_set = 0;
434     p->device_locator_str = 1;
435     p->bank_locator_str = 0;
436     p->memory_type = 0x07; /* RAM */
437     p->type_detail = 0;
438
439     start += sizeof(struct smbios_type_17);
440     memcpy((char *)start, "DIMM 1", 7);
441     start += 7;
442     *((u8 *)start) = 0;
443
444     return start+1;
445 }
446
447 /* Type 19 -- Memory Array Mapped Address */
448 static void *
449 smbios_type_19_init(void *start)
450 {
451     struct smbios_type_19 *p = (struct smbios_type_19 *)start;
452
453     p->header.type = 19;
454     p->header.length = sizeof(struct smbios_type_19);
455     p->header.handle = 0x1300;
456
457     p->starting_address = 0;
458     u64 memsize = RamSizeOver4G;
459     if (memsize)
460         memsize += 0x100000000ull;
461     else
462         memsize = RamSize;
463     p->ending_address = memsize / 1024 - 1;
464     p->memory_array_handle = 0x1000;
465     p->partition_width = 1;
466
467     start += sizeof(struct smbios_type_19);
468     *((u16 *)start) = 0;
469
470     return start + 2;
471 }
472
473 /* Type 20 -- Memory Device Mapped Address */
474 static void *
475 smbios_type_20_init(void *start)
476 {
477     struct smbios_type_20 *p = (struct smbios_type_20 *)start;
478
479     p->header.type = 20;
480     p->header.length = sizeof(struct smbios_type_20);
481     p->header.handle = 0x1400;
482
483     p->starting_address = 0;
484     u64 memsize = RamSizeOver4G;
485     if (memsize)
486         memsize += 0x100000000ull;
487     else
488         memsize = RamSize;
489     p->ending_address = memsize / 1024 - 1;
490     p->memory_device_handle = 0x1100;
491     p->memory_array_mapped_address_handle = 0x1300;
492     p->partition_row_position = 1;
493     p->interleave_position = 0;
494     p->interleaved_data_depth = 0;
495
496     start += sizeof(struct smbios_type_20);
497
498     *((u16 *)start) = 0;
499     return start+2;
500 }
501
502 /* Type 32 -- System Boot Information */
503 static void *
504 smbios_type_32_init(void *start)
505 {
506     struct smbios_type_32 *p = (struct smbios_type_32 *)start;
507
508     p->header.type = 32;
509     p->header.length = sizeof(struct smbios_type_32);
510     p->header.handle = 0x2000;
511     memset(p->reserved, 0, 6);
512     p->boot_status = 0; /* no errors detected */
513
514     start += sizeof(struct smbios_type_32);
515     *((u16 *)start) = 0;
516
517     return start+2;
518 }
519
520 /* Type 127 -- End of Table */
521 static void *
522 smbios_type_127_init(void *start)
523 {
524     struct smbios_type_127 *p = (struct smbios_type_127 *)start;
525
526     p->header.type = 127;
527     p->header.length = sizeof(struct smbios_type_127);
528     p->header.handle = 0x7f00;
529
530     start += sizeof(struct smbios_type_127);
531     *((u16 *)start) = 0;
532
533     return start + 2;
534 }
535
536 void
537 smbios_init(void)
538 {
539     if (! CONFIG_SMBIOS)
540         return;
541
542     dprintf(3, "init SMBIOS tables\n");
543
544     char *start = malloc_high(2048); // XXX - determine real size
545     if (! start) {
546         dprintf(1, "No memory for smbios tables\n");
547         return;
548     }
549
550     u32 nr_structs = 0, max_struct_size = 0;
551     char *q, *p = start;
552
553 #define add_struct(fn) { \
554     q = (fn); \
555     nr_structs++; \
556     if ((q - p) > max_struct_size) \
557         max_struct_size = q - p; \
558     p = q; \
559 }
560
561     add_struct(smbios_type_0_init(p));
562     add_struct(smbios_type_1_init(p));
563     add_struct(smbios_type_3_init(p));
564     int cpu_num, smp_cpus = CountCPUs;
565     for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
566         add_struct(smbios_type_4_init(p, cpu_num));
567     add_struct(smbios_type_16_init(p));
568     add_struct(smbios_type_17_init(p));
569     add_struct(smbios_type_19_init(p));
570     add_struct(smbios_type_20_init(p));
571     add_struct(smbios_type_32_init(p));
572     add_struct(smbios_type_127_init(p));
573
574 #undef add_struct
575
576     smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
577 }