Annotation of qemu/roms/seabios/src/smbios.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.