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