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