diff mbox

[v4,02/17] Add a base IPMI interface

Message ID 1447354953-18893-3-git-send-email-minyard@acm.org
State Superseded
Headers show

Commit Message

Corey Minyard Nov. 12, 2015, 7:02 p.m. UTC
From: Corey Minyard <cminyard@mvista.com>


Add the basic IPMI types and infrastructure to QEMU.  Low-level
interfaces and simulation interfaces will register with this; it's
kind of the go-between to tie them together.

Signed-off-by: Corey Minyard <cminyard@mvista.com>

---
 default-configs/i386-softmmu.mak   |   1 +
 default-configs/x86_64-softmmu.mak |   1 +
 hw/Makefile.objs                   |   1 +
 hw/ipmi/Makefile.objs              |   1 +
 hw/ipmi/ipmi.c                     | 125 ++++++++++++++++++++++++++
 include/hw/ipmi/ipmi.h             | 178 +++++++++++++++++++++++++++++++++++++
 qemu-doc.texi                      |   2 +
 7 files changed, 309 insertions(+)
 create mode 100644 hw/ipmi/Makefile.objs
 create mode 100644 hw/ipmi/ipmi.c
 create mode 100644 include/hw/ipmi/ipmi.h

-- 
1.8.3.1

Comments

Corey Minyard Nov. 18, 2015, 6:41 p.m. UTC | #1
I haven't heard any more comments on this series, should I resubmit with
the one shutdown change?

-corey
On Nov 12, 2015 1:02 PM, <minyard@acm.org> wrote:

> From: Corey Minyard <cminyard@mvista.com>

>

> Add the basic IPMI types and infrastructure to QEMU.  Low-level

> interfaces and simulation interfaces will register with this; it's

> kind of the go-between to tie them together.

>

> Signed-off-by: Corey Minyard <cminyard@mvista.com>

> ---

>  default-configs/i386-softmmu.mak   |   1 +

>  default-configs/x86_64-softmmu.mak |   1 +

>  hw/Makefile.objs                   |   1 +

>  hw/ipmi/Makefile.objs              |   1 +

>  hw/ipmi/ipmi.c                     | 125 ++++++++++++++++++++++++++

>  include/hw/ipmi/ipmi.h             | 178

> +++++++++++++++++++++++++++++++++++++

>  qemu-doc.texi                      |   2 +

>  7 files changed, 309 insertions(+)

>  create mode 100644 hw/ipmi/Makefile.objs

>  create mode 100644 hw/ipmi/ipmi.c

>  create mode 100644 include/hw/ipmi/ipmi.h

>

> diff --git a/default-configs/i386-softmmu.mak

> b/default-configs/i386-softmmu.mak

> index 43c96d1..8fa751a 100644

> --- a/default-configs/i386-softmmu.mak

> +++ b/default-configs/i386-softmmu.mak

> @@ -9,6 +9,7 @@ CONFIG_VGA_CIRRUS=y

>  CONFIG_VMWARE_VGA=y

>  CONFIG_VIRTIO_VGA=y

>  CONFIG_VMMOUSE=y

> +CONFIG_IPMI=y

>  CONFIG_SERIAL=y

>  CONFIG_PARALLEL=y

>  CONFIG_I8254=y

> diff --git a/default-configs/x86_64-softmmu.mak

> b/default-configs/x86_64-softmmu.mak

> index dfb8095..6767f4f 100644

> --- a/default-configs/x86_64-softmmu.mak

> +++ b/default-configs/x86_64-softmmu.mak

> @@ -9,6 +9,7 @@ CONFIG_VGA_CIRRUS=y

>  CONFIG_VMWARE_VGA=y

>  CONFIG_VIRTIO_VGA=y

>  CONFIG_VMMOUSE=y

> +CONFIG_IPMI=y

>  CONFIG_SERIAL=y

>  CONFIG_PARALLEL=y

>  CONFIG_I8254=y

> diff --git a/hw/Makefile.objs b/hw/Makefile.objs

> index 7e7c241..4a07ed4 100644

> --- a/hw/Makefile.objs

> +++ b/hw/Makefile.objs

> @@ -13,6 +13,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += ide/

>  devices-dirs-$(CONFIG_SOFTMMU) += input/

>  devices-dirs-$(CONFIG_SOFTMMU) += intc/

>  devices-dirs-$(CONFIG_IPACK) += ipack/

> +devices-dirs-$(CONFIG_IPMI) += ipmi/

>  devices-dirs-$(CONFIG_SOFTMMU) += isa/

>  devices-dirs-$(CONFIG_SOFTMMU) += misc/

>  devices-dirs-$(CONFIG_SOFTMMU) += net/

> diff --git a/hw/ipmi/Makefile.objs b/hw/ipmi/Makefile.objs

> new file mode 100644

> index 0000000..65bde11

> --- /dev/null

> +++ b/hw/ipmi/Makefile.objs

> @@ -0,0 +1 @@

> +common-obj-$(CONFIG_IPMI) += ipmi.o

> diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c

> new file mode 100644

> index 0000000..7d17469

> --- /dev/null

> +++ b/hw/ipmi/ipmi.c

> @@ -0,0 +1,125 @@

> +/*

> + * QEMU IPMI emulation

> + *

> + * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC

> + *

> + * Permission is hereby granted, free of charge, to any person obtaining

> a copy

> + * of this software and associated documentation files (the "Software"),

> to deal

> + * in the Software without restriction, including without limitation the

> rights

> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or

> sell

> + * copies of the Software, and to permit persons to whom the Software is

> + * furnished to do so, subject to the following conditions:

> + *

> + * The above copyright notice and this permission notice shall be

> included in

> + * all copies or substantial portions of the Software.

> + *

> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

> EXPRESS OR

> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

> MERCHANTABILITY,

> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR

> OTHER

> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

> ARISING FROM,

> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

> IN

> + * THE SOFTWARE.

> + */

> +

> +#include "hw/hw.h"

> +#include "hw/ipmi/ipmi.h"

> +#include "sysemu/sysemu.h"

> +#include "qmp-commands.h"

> +#include "qom/object_interfaces.h"

> +#include "qapi/visitor.h"

> +

> +static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly)

> +{

> +    switch (op) {

> +    case IPMI_RESET_CHASSIS:

> +        if (checkonly) {

> +            return 0;

> +        }

> +        qemu_system_reset_request();

> +        return 0;

> +

> +    case IPMI_POWEROFF_CHASSIS:

> +        if (checkonly) {

> +            return 0;

> +        }

> +        qemu_system_powerdown_request();

> +        return 0;

> +

> +    case IPMI_SEND_NMI:

> +        if (checkonly) {

> +            return 0;

> +        }

> +        qemu_mutex_lock_iothread();

> +        qmp_inject_nmi(NULL);

> +        qemu_mutex_unlock_iothread();

> +        return 0;

> +

> +    case IPMI_POWERCYCLE_CHASSIS:

> +    case IPMI_PULSE_DIAG_IRQ:

> +    case IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP:

> +    case IPMI_POWERON_CHASSIS:

> +    default:

> +        return IPMI_CC_COMMAND_NOT_SUPPORTED;

> +    }

> +}

> +

> +static void ipmi_interface_class_init(ObjectClass *class, void *data)

> +{

> +    IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class);

> +

> +    ik->do_hw_op = ipmi_do_hw_op;

> +}

> +

> +static TypeInfo ipmi_interface_type_info = {

> +    .name = TYPE_IPMI_INTERFACE,

> +    .parent = TYPE_INTERFACE,

> +    .class_size = sizeof(IPMIInterfaceClass),

> +    .class_init = ipmi_interface_class_init,

> +};

> +

> +static void isa_ipmi_bmc_check(Object *obj, const char *name,

> +                               Object *val, Error **errp)

> +{

> +    IPMIBmc *bmc = IPMI_BMC(val);

> +

> +    if (bmc->intf)

> +        error_setg(errp, "BMC object is already in use");

> +}

> +

> +void ipmi_bmc_find_and_link(Object *obj, Object **bmc)

> +{

> +    object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc,

> +                             isa_ipmi_bmc_check,

> +                             OBJ_PROP_LINK_UNREF_ON_RELEASE,

> +                             &error_abort);

> +}

> +

> +static Property ipmi_bmc_properties[] = {

> +    DEFINE_PROP_UINT8("slave_addr",  IPMIBmc, slave_addr, 0x20),

> +    DEFINE_PROP_END_OF_LIST(),

> +};

> +

> +static void bmc_class_init(ObjectClass *oc, void *data)

> +{

> +    DeviceClass *dc = DEVICE_CLASS(oc);

> +

> +    dc->props = ipmi_bmc_properties;

> +}

> +

> +static TypeInfo ipmi_bmc_type_info = {

> +    .name = TYPE_IPMI_BMC,

> +    .parent = TYPE_DEVICE,

> +    .instance_size = sizeof(IPMIBmc),

> +    .abstract = true,

> +    .class_size = sizeof(IPMIBmcClass),

> +    .class_init = bmc_class_init,

> +};

> +

> +static void ipmi_register_types(void)

> +{

> +    type_register_static(&ipmi_interface_type_info);

> +    type_register_static(&ipmi_bmc_type_info);

> +}

> +

> +type_init(ipmi_register_types)

> diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h

> new file mode 100644

> index 0000000..e4f7738

> --- /dev/null

> +++ b/include/hw/ipmi/ipmi.h

> @@ -0,0 +1,178 @@

> +/*

> + * IPMI base class

> + *

> + * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC

> + *

> + * Permission is hereby granted, free of charge, to any person obtaining

> a copy

> + * of this software and associated documentation files (the "Software"),

> to deal

> + * in the Software without restriction, including without limitation the

> rights

> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or

> sell

> + * copies of the Software, and to permit persons to whom the Software is

> + * furnished to do so, subject to the following conditions:

> + *

> + * The above copyright notice and this permission notice shall be

> included in

> + * all copies or substantial portions of the Software.

> + *

> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

> EXPRESS OR

> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

> MERCHANTABILITY,

> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR

> OTHER

> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

> ARISING FROM,

> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

> IN

> + * THE SOFTWARE.

> + */

> +

> +#ifndef HW_IPMI_H

> +#define HW_IPMI_H

> +

> +#include "exec/memory.h"

> +#include "qemu-common.h"

> +#include "hw/qdev.h"

> +

> +#define MAX_IPMI_MSG_SIZE 300

> +

> +enum ipmi_op {

> +    IPMI_RESET_CHASSIS,

> +    IPMI_POWEROFF_CHASSIS,

> +    IPMI_POWERON_CHASSIS,

> +    IPMI_POWERCYCLE_CHASSIS,

> +    IPMI_PULSE_DIAG_IRQ,

> +    IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP,

> +    IPMI_SEND_NMI

> +};

> +

> +#define IPMI_CC_INVALID_CMD                              0xc1

> +#define IPMI_CC_COMMAND_INVALID_FOR_LUN                  0xc2

> +#define IPMI_CC_TIMEOUT                                  0xc3

> +#define IPMI_CC_OUT_OF_SPACE                             0xc4

> +#define IPMI_CC_INVALID_RESERVATION                      0xc5

> +#define IPMI_CC_REQUEST_DATA_TRUNCATED                   0xc6

> +#define IPMI_CC_REQUEST_DATA_LENGTH_INVALID              0xc7

> +#define IPMI_CC_PARM_OUT_OF_RANGE                        0xc9

> +#define IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES              0xca

> +#define IPMI_CC_REQ_ENTRY_NOT_PRESENT                    0xcb

> +#define IPMI_CC_INVALID_DATA_FIELD                       0xcc

> +#define IPMI_CC_BMC_INIT_IN_PROGRESS                     0xd2

> +#define IPMI_CC_COMMAND_NOT_SUPPORTED                    0xd5

> +

> +#define IPMI_NETFN_APP                0x06

> +

> +#define IPMI_DEBUG 1

> +

> +/* Specified in the SMBIOS spec. */

> +#define IPMI_SMBIOS_KCS         0x01

> +#define IPMI_SMBIOS_SMIC        0x02

> +#define IPMI_SMBIOS_BT          0x03

> +#define IPMI_SMBIOS_SSIF        0x04

> +

> +/* IPMI Interface types (KCS, SMIC, BT) are prefixed with this */

> +#define TYPE_IPMI_INTERFACE_PREFIX "ipmi-interface-"

> +

> +/*

> + * An IPMI Interface, the interface for talking between the target

> + * and the BMC.

> + */

> +#define TYPE_IPMI_INTERFACE "ipmi-interface"

> +#define IPMI_INTERFACE(obj) \

> +     INTERFACE_CHECK(IPMIInterface, (obj), TYPE_IPMI_INTERFACE)

> +#define IPMI_INTERFACE_CLASS(class) \

> +     OBJECT_CLASS_CHECK(IPMIInterfaceClass, (class), TYPE_IPMI_INTERFACE)

> +#define IPMI_INTERFACE_GET_CLASS(class) \

> +     OBJECT_GET_CLASS(IPMIInterfaceClass, (class), TYPE_IPMI_INTERFACE)

> +

> +typedef struct IPMIInterface {

> +    Object parent;

> +} IPMIInterface;

> +

> +typedef struct IPMIInterfaceClass {

> +    InterfaceClass parent;

> +

> +    void (*init)(struct IPMIInterface *s, Error **errp);

> +

> +    /*

> +     * Perform various operations on the hardware.  If checkonly is

> +     * true, it will return if the operation can be performed, but it

> +     * will not do the operation.

> +     */

> +    int (*do_hw_op)(struct IPMIInterface *s, enum ipmi_op op, int

> checkonly);

> +

> +    /*

> +     * Enable/disable irqs on the interface when the BMC requests this.

> +     */

> +    void (*set_irq_enable)(struct IPMIInterface *s, int val);

> +

> +    /*

> +     * Handle an event that occurred on the interface, generally the.

> +     * target writing to a register.

> +     */

> +    void (*handle_if_event)(struct IPMIInterface *s);

> +

> +    /*

> +     * The interfaces use this to perform certain ops

> +     */

> +    void (*set_atn)(struct IPMIInterface *s, int val, int irq);

> +

> +    /*

> +     * Got an IPMI warm/cold reset.

> +     */

> +    void (*reset)(struct IPMIInterface *s, bool is_cold);

> +

> +    /*

> +     * Handle a response from the bmc.

> +     */

> +    void (*handle_rsp)(struct IPMIInterface *s, uint8_t msg_id,

> +                       unsigned char *rsp, unsigned int rsp_len);

> +

> +    /*

> +     * Set by the owner to hold the backend data for the interface.

> +     */

> +    void *(*get_backend_data)(struct IPMIInterface *s);

> +} IPMIInterfaceClass;

> +

> +/*

> + * Define a BMC simulator (or perhaps a connection to a real BMC)

> + */

> +#define TYPE_IPMI_BMC "ipmi-bmc"

> +#define IPMI_BMC(obj) \

> +     OBJECT_CHECK(IPMIBmc, (obj), TYPE_IPMI_BMC)

> +#define IPMI_BMC_CLASS(obj_class) \

> +     OBJECT_CLASS_CHECK(IPMIBmcClass, (obj_class), TYPE_IPMI_BMC)

> +#define IPMI_BMC_GET_CLASS(obj) \

> +     OBJECT_GET_CLASS(IPMIBmcClass, (obj), TYPE_IPMI_BMC)

> +

> +typedef struct IPMIBmc {

> +    DeviceState parent;

> +

> +    uint8_t slave_addr;

> +

> +    IPMIInterface *intf;

> +} IPMIBmc;

> +

> +typedef struct IPMIBmcClass {

> +    DeviceClass parent;

> +

> +    /* Called when the system resets to report to the bmc. */

> +    void (*handle_reset)(struct IPMIBmc *s);

> +

> +    /*

> +     * Handle a command to the bmc.

> +     */

> +    void (*handle_command)(struct IPMIBmc *s,

> +                           uint8_t *cmd, unsigned int cmd_len,

> +                           unsigned int max_cmd_len,

> +                           uint8_t msg_id);

> +} IPMIBmcClass;

> +

> +/*

> + * Add a link property to obj that points to a BMC.

> + */

> +void ipmi_bmc_find_and_link(Object *obj, Object **bmc);

> +

> +#ifdef IPMI_DEBUG

> +#define ipmi_debug(fs, ...) \

> +    fprintf(stderr, "IPMI (%s): " fs, __func__, ##__VA_ARGS__)

> +#else

> +#define ipmi_debug(fs, ...)

> +#endif

> +

> +#endif

> diff --git a/qemu-doc.texi b/qemu-doc.texi

> index 460ab71..3c82d30 100644

> --- a/qemu-doc.texi

> +++ b/qemu-doc.texi

> @@ -195,6 +195,8 @@ PCI and ISA network adapters

>  @item

>  Serial ports

>  @item

> +IPMI BMC, either and internal or external one

> +@item

>  Creative SoundBlaster 16 sound card

>  @item

>  ENSONIQ AudioPCI ES1370 sound card

> --

> 1.8.3.1

>

>
diff mbox

Patch

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 43c96d1..8fa751a 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -9,6 +9,7 @@  CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VIRTIO_VGA=y
 CONFIG_VMMOUSE=y
+CONFIG_IPMI=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index dfb8095..6767f4f 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -9,6 +9,7 @@  CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VIRTIO_VGA=y
 CONFIG_VMMOUSE=y
+CONFIG_IPMI=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 7e7c241..4a07ed4 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -13,6 +13,7 @@  devices-dirs-$(CONFIG_SOFTMMU) += ide/
 devices-dirs-$(CONFIG_SOFTMMU) += input/
 devices-dirs-$(CONFIG_SOFTMMU) += intc/
 devices-dirs-$(CONFIG_IPACK) += ipack/
+devices-dirs-$(CONFIG_IPMI) += ipmi/
 devices-dirs-$(CONFIG_SOFTMMU) += isa/
 devices-dirs-$(CONFIG_SOFTMMU) += misc/
 devices-dirs-$(CONFIG_SOFTMMU) += net/
diff --git a/hw/ipmi/Makefile.objs b/hw/ipmi/Makefile.objs
new file mode 100644
index 0000000..65bde11
--- /dev/null
+++ b/hw/ipmi/Makefile.objs
@@ -0,0 +1 @@ 
+common-obj-$(CONFIG_IPMI) += ipmi.o
diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
new file mode 100644
index 0000000..7d17469
--- /dev/null
+++ b/hw/ipmi/ipmi.c
@@ -0,0 +1,125 @@ 
+/*
+ * QEMU IPMI emulation
+ *
+ * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/ipmi/ipmi.h"
+#include "sysemu/sysemu.h"
+#include "qmp-commands.h"
+#include "qom/object_interfaces.h"
+#include "qapi/visitor.h"
+
+static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly)
+{
+    switch (op) {
+    case IPMI_RESET_CHASSIS:
+        if (checkonly) {
+            return 0;
+        }
+        qemu_system_reset_request();
+        return 0;
+
+    case IPMI_POWEROFF_CHASSIS:
+        if (checkonly) {
+            return 0;
+        }
+        qemu_system_powerdown_request();
+        return 0;
+
+    case IPMI_SEND_NMI:
+        if (checkonly) {
+            return 0;
+        }
+        qemu_mutex_lock_iothread();
+        qmp_inject_nmi(NULL);
+        qemu_mutex_unlock_iothread();
+        return 0;
+
+    case IPMI_POWERCYCLE_CHASSIS:
+    case IPMI_PULSE_DIAG_IRQ:
+    case IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP:
+    case IPMI_POWERON_CHASSIS:
+    default:
+        return IPMI_CC_COMMAND_NOT_SUPPORTED;
+    }
+}
+
+static void ipmi_interface_class_init(ObjectClass *class, void *data)
+{
+    IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class);
+
+    ik->do_hw_op = ipmi_do_hw_op;
+}
+
+static TypeInfo ipmi_interface_type_info = {
+    .name = TYPE_IPMI_INTERFACE,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(IPMIInterfaceClass),
+    .class_init = ipmi_interface_class_init,
+};
+
+static void isa_ipmi_bmc_check(Object *obj, const char *name,
+                               Object *val, Error **errp)
+{
+    IPMIBmc *bmc = IPMI_BMC(val);
+
+    if (bmc->intf)
+        error_setg(errp, "BMC object is already in use");
+}
+
+void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
+{
+    object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc,
+                             isa_ipmi_bmc_check,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
+}
+
+static Property ipmi_bmc_properties[] = {
+    DEFINE_PROP_UINT8("slave_addr",  IPMIBmc, slave_addr, 0x20),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bmc_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->props = ipmi_bmc_properties;
+}
+
+static TypeInfo ipmi_bmc_type_info = {
+    .name = TYPE_IPMI_BMC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(IPMIBmc),
+    .abstract = true,
+    .class_size = sizeof(IPMIBmcClass),
+    .class_init = bmc_class_init,
+};
+
+static void ipmi_register_types(void)
+{
+    type_register_static(&ipmi_interface_type_info);
+    type_register_static(&ipmi_bmc_type_info);
+}
+
+type_init(ipmi_register_types)
diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h
new file mode 100644
index 0000000..e4f7738
--- /dev/null
+++ b/include/hw/ipmi/ipmi.h
@@ -0,0 +1,178 @@ 
+/*
+ * IPMI base class
+ *
+ * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_IPMI_H
+#define HW_IPMI_H
+
+#include "exec/memory.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+#define MAX_IPMI_MSG_SIZE 300
+
+enum ipmi_op {
+    IPMI_RESET_CHASSIS,
+    IPMI_POWEROFF_CHASSIS,
+    IPMI_POWERON_CHASSIS,
+    IPMI_POWERCYCLE_CHASSIS,
+    IPMI_PULSE_DIAG_IRQ,
+    IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP,
+    IPMI_SEND_NMI
+};
+
+#define IPMI_CC_INVALID_CMD                              0xc1
+#define IPMI_CC_COMMAND_INVALID_FOR_LUN                  0xc2
+#define IPMI_CC_TIMEOUT                                  0xc3
+#define IPMI_CC_OUT_OF_SPACE                             0xc4
+#define IPMI_CC_INVALID_RESERVATION                      0xc5
+#define IPMI_CC_REQUEST_DATA_TRUNCATED                   0xc6
+#define IPMI_CC_REQUEST_DATA_LENGTH_INVALID              0xc7
+#define IPMI_CC_PARM_OUT_OF_RANGE                        0xc9
+#define IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES              0xca
+#define IPMI_CC_REQ_ENTRY_NOT_PRESENT                    0xcb
+#define IPMI_CC_INVALID_DATA_FIELD                       0xcc
+#define IPMI_CC_BMC_INIT_IN_PROGRESS                     0xd2
+#define IPMI_CC_COMMAND_NOT_SUPPORTED                    0xd5
+
+#define IPMI_NETFN_APP                0x06
+
+#define IPMI_DEBUG 1
+
+/* Specified in the SMBIOS spec. */
+#define IPMI_SMBIOS_KCS         0x01
+#define IPMI_SMBIOS_SMIC        0x02
+#define IPMI_SMBIOS_BT          0x03
+#define IPMI_SMBIOS_SSIF        0x04
+
+/* IPMI Interface types (KCS, SMIC, BT) are prefixed with this */
+#define TYPE_IPMI_INTERFACE_PREFIX "ipmi-interface-"
+
+/*
+ * An IPMI Interface, the interface for talking between the target
+ * and the BMC.
+ */
+#define TYPE_IPMI_INTERFACE "ipmi-interface"
+#define IPMI_INTERFACE(obj) \
+     INTERFACE_CHECK(IPMIInterface, (obj), TYPE_IPMI_INTERFACE)
+#define IPMI_INTERFACE_CLASS(class) \
+     OBJECT_CLASS_CHECK(IPMIInterfaceClass, (class), TYPE_IPMI_INTERFACE)
+#define IPMI_INTERFACE_GET_CLASS(class) \
+     OBJECT_GET_CLASS(IPMIInterfaceClass, (class), TYPE_IPMI_INTERFACE)
+
+typedef struct IPMIInterface {
+    Object parent;
+} IPMIInterface;
+
+typedef struct IPMIInterfaceClass {
+    InterfaceClass parent;
+
+    void (*init)(struct IPMIInterface *s, Error **errp);
+
+    /*
+     * Perform various operations on the hardware.  If checkonly is
+     * true, it will return if the operation can be performed, but it
+     * will not do the operation.
+     */
+    int (*do_hw_op)(struct IPMIInterface *s, enum ipmi_op op, int checkonly);
+
+    /*
+     * Enable/disable irqs on the interface when the BMC requests this.
+     */
+    void (*set_irq_enable)(struct IPMIInterface *s, int val);
+
+    /*
+     * Handle an event that occurred on the interface, generally the.
+     * target writing to a register.
+     */
+    void (*handle_if_event)(struct IPMIInterface *s);
+
+    /*
+     * The interfaces use this to perform certain ops
+     */
+    void (*set_atn)(struct IPMIInterface *s, int val, int irq);
+
+    /*
+     * Got an IPMI warm/cold reset.
+     */
+    void (*reset)(struct IPMIInterface *s, bool is_cold);
+
+    /*
+     * Handle a response from the bmc.
+     */
+    void (*handle_rsp)(struct IPMIInterface *s, uint8_t msg_id,
+                       unsigned char *rsp, unsigned int rsp_len);
+
+    /*
+     * Set by the owner to hold the backend data for the interface.
+     */
+    void *(*get_backend_data)(struct IPMIInterface *s);
+} IPMIInterfaceClass;
+
+/*
+ * Define a BMC simulator (or perhaps a connection to a real BMC)
+ */
+#define TYPE_IPMI_BMC "ipmi-bmc"
+#define IPMI_BMC(obj) \
+     OBJECT_CHECK(IPMIBmc, (obj), TYPE_IPMI_BMC)
+#define IPMI_BMC_CLASS(obj_class) \
+     OBJECT_CLASS_CHECK(IPMIBmcClass, (obj_class), TYPE_IPMI_BMC)
+#define IPMI_BMC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(IPMIBmcClass, (obj), TYPE_IPMI_BMC)
+
+typedef struct IPMIBmc {
+    DeviceState parent;
+
+    uint8_t slave_addr;
+
+    IPMIInterface *intf;
+} IPMIBmc;
+
+typedef struct IPMIBmcClass {
+    DeviceClass parent;
+
+    /* Called when the system resets to report to the bmc. */
+    void (*handle_reset)(struct IPMIBmc *s);
+
+    /*
+     * Handle a command to the bmc.
+     */
+    void (*handle_command)(struct IPMIBmc *s,
+                           uint8_t *cmd, unsigned int cmd_len,
+                           unsigned int max_cmd_len,
+                           uint8_t msg_id);
+} IPMIBmcClass;
+
+/*
+ * Add a link property to obj that points to a BMC.
+ */
+void ipmi_bmc_find_and_link(Object *obj, Object **bmc);
+
+#ifdef IPMI_DEBUG
+#define ipmi_debug(fs, ...) \
+    fprintf(stderr, "IPMI (%s): " fs, __func__, ##__VA_ARGS__)
+#else
+#define ipmi_debug(fs, ...)
+#endif
+
+#endif
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 460ab71..3c82d30 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -195,6 +195,8 @@  PCI and ISA network adapters
 @item
 Serial ports
 @item
+IPMI BMC, either and internal or external one
+@item
 Creative SoundBlaster 16 sound card
 @item
 ENSONIQ AudioPCI ES1370 sound card