|
|
1.1 ! root 1: qemu:bios: Load SMBIOS entries and files from qemu (Alex Williamson) ! 2: ! 3: Allow SMBIOS fields to be overridden and entries replaced by those ! 4: read from qemu. ! 5: ! 6: Signed-off-by: Alex Williamson <[email protected]> ! 7: Signed-off-by: Anthony Liguori <[email protected]> ! 8: ! 9: diff --git a/bios/rombios32.c b/bios/rombios32.c ! 10: index 7be4216..1a1ed64 100644 ! 11: --- a/bios/rombios32.c ! 12: +++ b/bios/rombios32.c ! 13: @@ -441,7 +441,6 @@ uint32_t cpuid_features; ! 14: uint32_t cpuid_ext_features; ! 15: unsigned long ram_size; ! 16: uint64_t ram_end; ! 17: -uint8_t bios_uuid[16]; ! 18: #ifdef BX_USE_EBDA_TABLES ! 19: unsigned long ebda_cur_addr; ! 20: #endif ! 21: @@ -471,6 +470,7 @@ void wrmsr_smp(uint32_t index, uint64_t val) ! 22: #define QEMU_CFG_UUID 0x02 ! 23: #define QEMU_CFG_ARCH_LOCAL 0x8000 ! 24: #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) ! 25: +#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) ! 26: ! 27: int qemu_cfg_port; ! 28: ! 29: @@ -519,19 +519,17 @@ static int acpi_load_table(int i, uint32_t addr, uint16_t *len) ! 30: qemu_cfg_read((uint8_t*)addr, *len); ! 31: return 0; ! 32: } ! 33: -#endif ! 34: ! 35: -void uuid_probe(void) ! 36: +static uint16_t smbios_entries(void) ! 37: { ! 38: -#ifdef BX_QEMU ! 39: - if(qemu_cfg_port) { ! 40: - qemu_cfg_select(QEMU_CFG_UUID); ! 41: - qemu_cfg_read(bios_uuid, 16); ! 42: - return; ! 43: - } ! 44: -#endif ! 45: - memset(bios_uuid, 0, 16); ! 46: + uint16_t cnt; ! 47: + ! 48: + qemu_cfg_select(QEMU_CFG_SMBIOS_ENTRIES); ! 49: + qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt)); ! 50: + ! 51: + return cnt; ! 52: } ! 53: +#endif ! 54: ! 55: void cpu_probe(void) ! 56: { ! 57: @@ -1963,21 +1961,105 @@ smbios_entry_point_init(void *start, ! 58: ep->intermediate_checksum = -sum; ! 59: } ! 60: ! 61: +struct smbios_header { ! 62: + uint16_t length; ! 63: + uint8_t type; ! 64: +} __attribute__((__packed__)); ! 65: + ! 66: +struct smbios_field { ! 67: + struct smbios_header header; ! 68: + uint8_t type; ! 69: + uint16_t offset; ! 70: + uint8_t data[]; ! 71: +} __attribute__((__packed__)); ! 72: + ! 73: +struct smbios_table { ! 74: + struct smbios_header header; ! 75: + uint8_t data[]; ! 76: +} __attribute__((__packed__)); ! 77: + ! 78: +#define SMBIOS_FIELD_ENTRY 0 ! 79: +#define SMBIOS_TABLE_ENTRY 1 ! 80: + ! 81: +static size_t ! 82: +smbios_load_field(int type, size_t offset, void *addr) ! 83: +{ ! 84: +#ifdef BX_QEMU ! 85: + int i; ! 86: + ! 87: + for (i = smbios_entries(); i > 0; i--) { ! 88: + struct smbios_field field; ! 89: + ! 90: + qemu_cfg_read((uint8_t *)&field, sizeof(struct smbios_header)); ! 91: + field.header.length -= sizeof(struct smbios_header); ! 92: + ! 93: + if (field.header.type != SMBIOS_FIELD_ENTRY) { ! 94: + while (field.header.length--) ! 95: + inb(QEMU_CFG_DATA_PORT); ! 96: + continue; ! 97: + } ! 98: + ! 99: + qemu_cfg_read((uint8_t *)&field.type, ! 100: + sizeof(field) - sizeof(struct smbios_header)); ! 101: + field.header.length -= sizeof(field) - sizeof(struct smbios_header); ! 102: + ! 103: + if (field.type != type || field.offset != offset) { ! 104: + while (field.header.length--) ! 105: + inb(QEMU_CFG_DATA_PORT); ! 106: + continue; ! 107: + } ! 108: + ! 109: + qemu_cfg_read(addr, field.header.length); ! 110: + return (size_t)field.header.length; ! 111: + } ! 112: +#endif ! 113: + return 0; ! 114: +} ! 115: + ! 116: +#define load_str_field_with_default(type, field, def) do { \ ! 117: + size = smbios_load_field(type, offsetof(struct smbios_type_##type, \ ! 118: + field), end); \ ! 119: + if (size > 0) { \ ! 120: + end += size; \ ! 121: + } else { \ ! 122: + memcpy(end, def, sizeof(def)); \ ! 123: + end += sizeof(def); \ ! 124: + } \ ! 125: + p->field = ++str_index; \ ! 126: +} while (0) ! 127: + ! 128: +#define load_str_field_or_skip(type, field) do { \ ! 129: + size = smbios_load_field(type, offsetof(struct smbios_type_##type, \ ! 130: + field), end); \ ! 131: + if (size > 0) { \ ! 132: + end += size; \ ! 133: + p->field = ++str_index; \ ! 134: + } else { \ ! 135: + p->field = 0; \ ! 136: + } \ ! 137: +} while (0) ! 138: + ! 139: /* Type 0 -- BIOS Information */ ! 140: #define RELEASE_DATE_STR "01/01/2007" ! 141: static void * ! 142: -smbios_type_0_init(void *start) ! 143: +smbios_init_type_0(void *start) ! 144: { ! 145: struct smbios_type_0 *p = (struct smbios_type_0 *)start; ! 146: + char *end = (char *)start + sizeof(struct smbios_type_0); ! 147: + size_t size; ! 148: + int str_index = 0; ! 149: ! 150: p->header.type = 0; ! 151: p->header.length = sizeof(struct smbios_type_0); ! 152: p->header.handle = 0; ! 153: ! 154: - p->vendor_str = 1; ! 155: - p->bios_version_str = 1; ! 156: + load_str_field_with_default(0, vendor_str, BX_APPNAME); ! 157: + load_str_field_with_default(0, bios_version_str, BX_APPNAME); ! 158: + ! 159: p->bios_starting_address_segment = 0xe800; ! 160: - p->bios_release_date_str = 2; ! 161: + ! 162: + load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR); ! 163: + ! 164: p->bios_rom_size = 0; /* FIXME */ ! 165: ! 166: memset(p->bios_characteristics, 0, 8); ! 167: @@ -1985,50 +2067,66 @@ smbios_type_0_init(void *start) ! 168: p->bios_characteristics_extension_bytes[0] = 0; ! 169: p->bios_characteristics_extension_bytes[1] = 0; ! 170: ! 171: - p->system_bios_major_release = 1; ! 172: - p->system_bios_minor_release = 0; ! 173: + if (!smbios_load_field(0, offsetof(struct smbios_type_0, ! 174: + system_bios_major_release), ! 175: + &p->system_bios_major_release)) ! 176: + p->system_bios_major_release = 1; ! 177: + ! 178: + if (!smbios_load_field(0, offsetof(struct smbios_type_0, ! 179: + system_bios_minor_release), ! 180: + &p->system_bios_minor_release)) ! 181: + p->system_bios_minor_release = 0; ! 182: + ! 183: p->embedded_controller_major_release = 0xff; ! 184: p->embedded_controller_minor_release = 0xff; ! 185: ! 186: - start += sizeof(struct smbios_type_0); ! 187: - memcpy((char *)start, BX_APPNAME, sizeof(BX_APPNAME)); ! 188: - start += sizeof(BX_APPNAME); ! 189: - memcpy((char *)start, RELEASE_DATE_STR, sizeof(RELEASE_DATE_STR)); ! 190: - start += sizeof(RELEASE_DATE_STR); ! 191: - *((uint8_t *)start) = 0; ! 192: + *end = 0; ! 193: + end++; ! 194: ! 195: - return start+1; ! 196: + return end; ! 197: } ! 198: ! 199: /* Type 1 -- System Information */ ! 200: static void * ! 201: -smbios_type_1_init(void *start) ! 202: +smbios_init_type_1(void *start) ! 203: { ! 204: struct smbios_type_1 *p = (struct smbios_type_1 *)start; ! 205: + char *end = (char *)start + sizeof(struct smbios_type_1); ! 206: + size_t size; ! 207: + int str_index = 0; ! 208: + ! 209: p->header.type = 1; ! 210: p->header.length = sizeof(struct smbios_type_1); ! 211: p->header.handle = 0x100; ! 212: ! 213: - p->manufacturer_str = 0; ! 214: - p->product_name_str = 0; ! 215: - p->version_str = 0; ! 216: - p->serial_number_str = 0; ! 217: + load_str_field_or_skip(1, manufacturer_str); ! 218: + load_str_field_or_skip(1, product_name_str); ! 219: + load_str_field_or_skip(1, version_str); ! 220: + load_str_field_or_skip(1, serial_number_str); ! 221: ! 222: - memcpy(p->uuid, bios_uuid, 16); ! 223: + size = smbios_load_field(1, offsetof(struct smbios_type_1, ! 224: + uuid), &p->uuid); ! 225: + if (size == 0) ! 226: + memset(p->uuid, 0, 16); ! 227: ! 228: p->wake_up_type = 0x06; /* power switch */ ! 229: - p->sku_number_str = 0; ! 230: - p->family_str = 0; ! 231: ! 232: - start += sizeof(struct smbios_type_1); ! 233: - *((uint16_t *)start) = 0; ! 234: + load_str_field_or_skip(1, sku_number_str); ! 235: + load_str_field_or_skip(1, family_str); ! 236: ! 237: - return start+2; ! 238: + *end = 0; ! 239: + end++; ! 240: + if (!str_index) { ! 241: + *end = 0; ! 242: + end++; ! 243: + } ! 244: + ! 245: + return end; ! 246: } ! 247: ! 248: /* Type 3 -- System Enclosure */ ! 249: static void * ! 250: -smbios_type_3_init(void *start) ! 251: +smbios_init_type_3(void *start) ! 252: { ! 253: struct smbios_type_3 *p = (struct smbios_type_3 *)start; ! 254: ! 255: @@ -2058,7 +2156,7 @@ smbios_type_3_init(void *start) ! 256: ! 257: /* Type 4 -- Processor Information */ ! 258: static void * ! 259: -smbios_type_4_init(void *start, unsigned int cpu_number) ! 260: +smbios_init_type_4(void *start, unsigned int cpu_number) ! 261: { ! 262: struct smbios_type_4 *p = (struct smbios_type_4 *)start; ! 263: ! 264: @@ -2098,7 +2196,7 @@ smbios_type_4_init(void *start, unsigned int cpu_number) ! 265: ! 266: /* Type 16 -- Physical Memory Array */ ! 267: static void * ! 268: -smbios_type_16_init(void *start, uint32_t memsize, int nr_mem_devs) ! 269: +smbios_init_type_16(void *start, uint32_t memsize, int nr_mem_devs) ! 270: { ! 271: struct smbios_type_16 *p = (struct smbios_type_16*)start; ! 272: ! 273: @@ -2121,7 +2219,7 @@ smbios_type_16_init(void *start, uint32_t memsize, int nr_mem_devs) ! 274: ! 275: /* Type 17 -- Memory Device */ ! 276: static void * ! 277: -smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance) ! 278: +smbios_init_type_17(void *start, uint32_t memory_size_mb, int instance) ! 279: { ! 280: struct smbios_type_17 *p = (struct smbios_type_17 *)start; ! 281: ! 282: @@ -2151,7 +2249,7 @@ smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance) ! 283: ! 284: /* Type 19 -- Memory Array Mapped Address */ ! 285: static void * ! 286: -smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance) ! 287: +smbios_init_type_19(void *start, uint32_t memory_size_mb, int instance) ! 288: { ! 289: struct smbios_type_19 *p = (struct smbios_type_19 *)start; ! 290: ! 291: @@ -2172,7 +2270,7 @@ smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance) ! 292: ! 293: /* Type 20 -- Memory Device Mapped Address */ ! 294: static void * ! 295: -smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance) ! 296: +smbios_init_type_20(void *start, uint32_t memory_size_mb, int instance) ! 297: { ! 298: struct smbios_type_20 *p = (struct smbios_type_20 *)start; ! 299: ! 300: @@ -2196,7 +2294,7 @@ smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance) ! 301: ! 302: /* Type 32 -- System Boot Information */ ! 303: static void * ! 304: -smbios_type_32_init(void *start) ! 305: +smbios_init_type_32(void *start) ! 306: { ! 307: struct smbios_type_32 *p = (struct smbios_type_32 *)start; ! 308: ! 309: @@ -2214,7 +2312,7 @@ smbios_type_32_init(void *start) ! 310: ! 311: /* Type 127 -- End of Table */ ! 312: static void * ! 313: -smbios_type_127_init(void *start) ! 314: +smbios_init_type_127(void *start) ! 315: { ! 316: struct smbios_type_127 *p = (struct smbios_type_127 *)start; ! 317: ! 318: @@ -2228,6 +2326,78 @@ smbios_type_127_init(void *start) ! 319: return start + 2; ! 320: } ! 321: ! 322: +static int ! 323: +smbios_load_external(int type, char **p, unsigned *nr_structs, ! 324: + unsigned *max_struct_size) ! 325: +{ ! 326: +#ifdef BX_QEMU ! 327: + static uint64_t used_bitmap[4] = { 0 }; ! 328: + char *start = *p; ! 329: + int i; ! 330: + ! 331: + /* Check if we've already reported these tables */ ! 332: + if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f))) ! 333: + return 1; ! 334: + ! 335: + /* Don't introduce spurious end markers */ ! 336: + if (type == 127) ! 337: + return 0; ! 338: + ! 339: + for (i = smbios_entries(); i > 0; i--) { ! 340: + struct smbios_table table; ! 341: + struct smbios_structure_header *header = (void *)*p; ! 342: + int string; ! 343: + ! 344: + qemu_cfg_read((uint8_t *)&table, sizeof(struct smbios_header)); ! 345: + table.header.length -= sizeof(struct smbios_header); ! 346: + ! 347: + if (table.header.type != SMBIOS_TABLE_ENTRY) { ! 348: + while (table.header.length--) ! 349: + inb(QEMU_CFG_DATA_PORT); ! 350: + continue; ! 351: + } ! 352: + ! 353: + qemu_cfg_read((uint8_t *)*p, sizeof(struct smbios_structure_header)); ! 354: + table.header.length -= sizeof(struct smbios_structure_header); ! 355: + ! 356: + if (header->type != type) { ! 357: + while (table.header.length--) ! 358: + inb(QEMU_CFG_DATA_PORT); ! 359: + continue; ! 360: + } ! 361: + ! 362: + *p += sizeof(struct smbios_structure_header); ! 363: + ! 364: + /* Entries end with a double NULL char, if there's a string at ! 365: + * the end (length is greater than formatted length), the string ! 366: + * terminator provides the first NULL. */ ! 367: + string = header->length < table.header.length + ! 368: + sizeof(struct smbios_structure_header); ! 369: + ! 370: + /* Read the rest and terminate the entry */ ! 371: + qemu_cfg_read((uint8_t *)*p, table.header.length); ! 372: + *p += table.header.length; ! 373: + *((uint8_t*)*p) = 0; ! 374: + (*p)++; ! 375: + if (!string) { ! 376: + *((uint8_t*)*p) = 0; ! 377: + (*p)++; ! 378: + } ! 379: + ! 380: + (*nr_structs)++; ! 381: + if (*p - (char *)header > *max_struct_size) ! 382: + *max_struct_size = *p - (char *)header; ! 383: + } ! 384: + ! 385: + /* Mark that we've reported on this type */ ! 386: + used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f)); ! 387: + ! 388: + return (start != *p); ! 389: +#else /* !BX_QEMU */ ! 390: + return 0; ! 391: +#endif ! 392: +} ! 393: + ! 394: void smbios_init(void) ! 395: { ! 396: unsigned cpu_num, nr_structs = 0, max_struct_size = 0; ! 397: @@ -2246,34 +2416,39 @@ void smbios_init(void) ! 398: ! 399: p = (char *)start + sizeof(struct smbios_entry_point); ! 400: ! 401: -#define add_struct(fn) do{ \ ! 402: - q = (fn); \ ! 403: - nr_structs++; \ ! 404: - if ((q - p) > max_struct_size) \ ! 405: - max_struct_size = q - p; \ ! 406: - p = q; \ ! 407: -}while (0) ! 408: - ! 409: - add_struct(smbios_type_0_init(p)); ! 410: - add_struct(smbios_type_1_init(p)); ! 411: - add_struct(smbios_type_3_init(p)); ! 412: +#define add_struct(type, args...) do { \ ! 413: + if (!smbios_load_external(type, &p, &nr_structs, &max_struct_size)) { \ ! 414: + q = smbios_init_type_##type(args); \ ! 415: + nr_structs++; \ ! 416: + if ((q - p) > max_struct_size) \ ! 417: + max_struct_size = q - p; \ ! 418: + p = q; \ ! 419: + } \ ! 420: +} while (0) ! 421: + ! 422: + add_struct(0, p); ! 423: + add_struct(1, p); ! 424: + add_struct(3, p); ! 425: for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++) ! 426: - add_struct(smbios_type_4_init(p, cpu_num)); ! 427: + add_struct(4, p, cpu_num); ! 428: ! 429: /* Each 'memory device' covers up to 16GB of address space. */ ! 430: nr_mem_devs = (memsize + 0x3fff) >> 14; ! 431: - add_struct(smbios_type_16_init(p, memsize, nr_mem_devs)); ! 432: + add_struct(16, p, memsize, nr_mem_devs); ! 433: for ( i = 0; i < nr_mem_devs; i++ ) ! 434: { ! 435: uint32_t dev_memsize = ((i == (nr_mem_devs - 1)) ! 436: ? (((memsize-1) & 0x3fff)+1) : 0x4000); ! 437: - add_struct(smbios_type_17_init(p, dev_memsize, i)); ! 438: - add_struct(smbios_type_19_init(p, dev_memsize, i)); ! 439: - add_struct(smbios_type_20_init(p, dev_memsize, i)); ! 440: + add_struct(17, p, dev_memsize, i); ! 441: + add_struct(19, p, dev_memsize, i); ! 442: + add_struct(20, p, dev_memsize, i); ! 443: } ! 444: ! 445: - add_struct(smbios_type_32_init(p)); ! 446: - add_struct(smbios_type_127_init(p)); ! 447: + add_struct(32, p); ! 448: + /* Add any remaining provided entries before the end marker */ ! 449: + for (i = 0; i < 256; i++) ! 450: + smbios_load_external(i, &p, &nr_structs, &max_struct_size); ! 451: + add_struct(127, p); ! 452: ! 453: #undef add_struct ! 454: ! 455: @@ -2380,8 +2555,6 @@ void rombios32_init(uint32_t *s3_resume_vector, uint8_t *shutdown_flag) ! 456: ! 457: mptable_init(); ! 458: ! 459: - uuid_probe(); ! 460: - ! 461: smbios_init(); ! 462: ! 463: if (acpi_enabled) ! 464: ! 465: ! 466: -- ! 467: To unsubscribe from this list: send the line "unsubscribe kvm" in ! 468: the body of a message to [email protected] ! 469: More majordomo info at http://vger.kernel.org/majordomo-info.html ! 470:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.