qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

smbios_type_38.c (3153B)


      1 /*
      2  * IPMI SMBIOS firmware handling
      3  *
      4  * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7  * See the COPYING file in the top-level directory.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "hw/ipmi/ipmi.h"
     12 #include "hw/firmware/smbios.h"
     13 #include "qemu/error-report.h"
     14 #include "smbios_build.h"
     15 
     16 /* SMBIOS type 38 - IPMI */
     17 struct smbios_type_38 {
     18     struct smbios_structure_header header;
     19     uint8_t interface_type;
     20     uint8_t ipmi_spec_revision;
     21     uint8_t i2c_slave_address;
     22     uint8_t nv_storage_device_address;
     23     uint64_t base_address;
     24     uint8_t base_address_modifier;
     25     uint8_t interrupt_number;
     26 } QEMU_PACKED;
     27 
     28 static void smbios_build_one_type_38(IPMIFwInfo *info)
     29 {
     30     uint64_t baseaddr = info->base_address;
     31     SMBIOS_BUILD_TABLE_PRE(38, 0x3000, true);
     32 
     33     t->interface_type = info->interface_type;
     34     t->ipmi_spec_revision = ((info->ipmi_spec_major_revision << 4)
     35                              | info->ipmi_spec_minor_revision);
     36     t->i2c_slave_address = info->i2c_slave_address;
     37     t->nv_storage_device_address = 0;
     38 
     39     assert(info->ipmi_spec_minor_revision <= 15);
     40     assert(info->ipmi_spec_major_revision <= 15);
     41 
     42     /* or 1 to set it to I/O space */
     43     switch (info->memspace) {
     44     case IPMI_MEMSPACE_IO:
     45         baseaddr |= 1;
     46         break;
     47     case IPMI_MEMSPACE_MEM32:
     48     case IPMI_MEMSPACE_MEM64:
     49         break;
     50     case IPMI_MEMSPACE_SMBUS:
     51         baseaddr <<= 1;
     52         break;
     53     }
     54 
     55     t->base_address = cpu_to_le64(baseaddr);
     56 
     57     t->base_address_modifier = 0;
     58     if (info->irq_type == IPMI_LEVEL_IRQ) {
     59         t->base_address_modifier |= 1;
     60     }
     61     switch (info->register_spacing) {
     62     case 1:
     63         break;
     64     case 4:
     65         t->base_address_modifier |= 1 << 6;
     66         break;
     67     case 16:
     68         t->base_address_modifier |= 2 << 6;
     69         break;
     70     default:
     71         error_report("IPMI register spacing %d is not compatible with"
     72                      " SMBIOS, ignoring this entry.", info->register_spacing);
     73         return;
     74     }
     75     t->interrupt_number = info->interrupt_number;
     76 
     77     SMBIOS_BUILD_TABLE_POST;
     78 }
     79 
     80 static void smbios_add_ipmi_devices(BusState *bus)
     81 {
     82     BusChild *kid;
     83 
     84     QTAILQ_FOREACH(kid, &bus->children,  sibling) {
     85         DeviceState *dev = kid->child;
     86         Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_IPMI_INTERFACE);
     87         BusState *childbus;
     88 
     89         if (obj) {
     90             IPMIInterface *ii;
     91             IPMIInterfaceClass *iic;
     92             IPMIFwInfo info;
     93 
     94             ii = IPMI_INTERFACE(obj);
     95             iic = IPMI_INTERFACE_GET_CLASS(obj);
     96             memset(&info, 0, sizeof(info));
     97             if (!iic->get_fwinfo) {
     98                 continue;
     99             }
    100             iic->get_fwinfo(ii, &info);
    101             smbios_build_one_type_38(&info);
    102             continue;
    103         }
    104 
    105         QLIST_FOREACH(childbus, &dev->child_bus, sibling) {
    106             smbios_add_ipmi_devices(childbus);
    107         }
    108     }
    109 }
    110 
    111 void smbios_build_type_38_table(void)
    112 {
    113     BusState *bus;
    114 
    115     bus = sysbus_get_default();
    116     if (bus) {
    117         smbios_add_ipmi_devices(bus);
    118     }
    119 }