|
|
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.