diff mbox series

[4/8] hw/ipmi: Refactor IPMI interface

Message ID 20210909230620.511815-5-wuhaotsh@google.com (mailing list archive)
State New, archived
Headers show
Series Handing IPMI for emulating BMC | expand

Commit Message

Hao Wu Sept. 9, 2021, 11:06 p.m. UTC
This patch refactors the IPMI interface so that it can be used by both
the BMC side and core-side simulation.

Detail changes:
(1) rename handle_rsp -> handle_msg so the name fits both BMC side and
    Core side.
(2) Add a new class IPMICore. This class represents a simulator/external
    connection for both BMC and Core side emulation. The old IPMIBmc is
    a sub-class of IPMICore.
(3) Change all ibe->parent.intf in hw/ipmi/ipmi_bmc_*.c to use type
    cast to IPMICore. Directly accessing parent QOM is against QEMU
    guide and by using type casting the code can fit both core side and
    BMC side emulation.

Signed-off-by: Hao Wu <wuhaotsh@google.com>
---
 hw/ipmi/ipmi.c            | 15 +++++++++++---
 hw/ipmi/ipmi_bmc_extern.c | 37 +++++++++++++++++++++--------------
 hw/ipmi/ipmi_bmc_sim.c    | 41 ++++++++++++++++++++++++++-------------
 hw/ipmi/ipmi_bt.c         |  2 +-
 hw/ipmi/ipmi_kcs.c        |  2 +-
 hw/ipmi/isa_ipmi_bt.c     |  4 +++-
 hw/ipmi/isa_ipmi_kcs.c    |  4 +++-
 hw/ipmi/pci_ipmi_bt.c     |  4 +++-
 hw/ipmi/pci_ipmi_kcs.c    |  4 +++-
 hw/ipmi/smbus_ipmi.c      |  6 ++++--
 include/hw/ipmi/ipmi.h    | 40 ++++++++++++++++++++++++++++++--------
 11 files changed, 111 insertions(+), 48 deletions(-)

Comments

Corey Minyard Sept. 10, 2021, 12:26 a.m. UTC | #1
On Thu, Sep 09, 2021 at 04:06:16PM -0700, Hao Wu wrote:
> This patch refactors the IPMI interface so that it can be used by both
> the BMC side and core-side simulation.
> 
> Detail changes:
> (1) rename handle_rsp -> handle_msg so the name fits both BMC side and
>     Core side.
> (2) Add a new class IPMICore. This class represents a simulator/external
>     connection for both BMC and Core side emulation. The old IPMIBmc is
>     a sub-class of IPMICore.
> (3) Change all ibe->parent.intf in hw/ipmi/ipmi_bmc_*.c to use type
>     cast to IPMICore. Directly accessing parent QOM is against QEMU
>     guide and by using type casting the code can fit both core side and
>     BMC side emulation.

I think I'm ok with this.  It fixes some fundamental issues (maybe that
should be separate patches, but I think it's ok here).

I was kind of against this at first, I was thinking a completely
separate code for the BMC-side hardware emulation.  But I can see that
so much code would be duplicated that it would be silly.

It would be better if there was an ipmi_bmc.[ch] that had the
BMC-specific things, split out from the ipmi.[ch] code.  I'm not 100%
sure how important that is, but it would be less confusing.  Do you
agree?

A couple of comments inline...

-corey

> 
> Signed-off-by: Hao Wu <wuhaotsh@google.com>
> ---
>  hw/ipmi/ipmi.c            | 15 +++++++++++---
>  hw/ipmi/ipmi_bmc_extern.c | 37 +++++++++++++++++++++--------------
>  hw/ipmi/ipmi_bmc_sim.c    | 41 ++++++++++++++++++++++++++-------------
>  hw/ipmi/ipmi_bt.c         |  2 +-
>  hw/ipmi/ipmi_kcs.c        |  2 +-
>  hw/ipmi/isa_ipmi_bt.c     |  4 +++-
>  hw/ipmi/isa_ipmi_kcs.c    |  4 +++-
>  hw/ipmi/pci_ipmi_bt.c     |  4 +++-
>  hw/ipmi/pci_ipmi_kcs.c    |  4 +++-
>  hw/ipmi/smbus_ipmi.c      |  6 ++++--
>  include/hw/ipmi/ipmi.h    | 40 ++++++++++++++++++++++++++++++--------
>  11 files changed, 111 insertions(+), 48 deletions(-)
> 
> diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
> index 8d35c9fdd6..7da1b36fab 100644
> --- a/hw/ipmi/ipmi.c
> +++ b/hw/ipmi/ipmi.c
> @@ -92,13 +92,21 @@ static TypeInfo ipmi_interface_type_info = {
>      .class_init = ipmi_interface_class_init,
>  };
>  
> +static TypeInfo ipmi_core_type_info = {
> +    .name = TYPE_IPMI_CORE,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(IPMICore),
> +    .abstract = true,
> +};
> +
>  static void isa_ipmi_bmc_check(const Object *obj, const char *name,
>                                 Object *val, Error **errp)
>  {
> -    IPMIBmc *bmc = IPMI_BMC(val);
> +    IPMICore *ic = IPMI_CORE(val);
>  
> -    if (bmc->intf)
> +    if (ic->intf) {
>          error_setg(errp, "BMC object is already in use");
> +    }
>  }
>  
>  void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
> @@ -122,7 +130,7 @@ static void bmc_class_init(ObjectClass *oc, void *data)
>  
>  static TypeInfo ipmi_bmc_type_info = {
>      .name = TYPE_IPMI_BMC,
> -    .parent = TYPE_DEVICE,
> +    .parent = TYPE_IPMI_CORE,
>      .instance_size = sizeof(IPMIBmc),
>      .abstract = true,
>      .class_size = sizeof(IPMIBmcClass),
> @@ -132,6 +140,7 @@ static TypeInfo ipmi_bmc_type_info = {
>  static void ipmi_register_types(void)
>  {
>      type_register_static(&ipmi_interface_type_info);
> +    type_register_static(&ipmi_core_type_info);
>      type_register_static(&ipmi_bmc_type_info);
>  }
>  
> diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
> index acf2bab35f..a0c3a40e7c 100644
> --- a/hw/ipmi/ipmi_bmc_extern.c
> +++ b/hw/ipmi/ipmi_bmc_extern.c
> @@ -147,8 +147,9 @@ static void continue_send(IPMIBmcExtern *ibe)
>  
>  static void extern_timeout(void *opaque)
>  {
> +    IPMICore *ic = opaque;
>      IPMIBmcExtern *ibe = opaque;

Shouldn't the above be a cast from ic?

> -    IPMIInterface *s = ibe->parent.intf;
> +    IPMIInterface *s = ic->intf;
>  
>      if (ibe->connected) {
>          if (ibe->waiting_rsp && (ibe->outlen == 0)) {
> @@ -158,7 +159,7 @@ static void extern_timeout(void *opaque)
>              ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
>              ibe->inbuf[2] = ibe->outbuf[2];
>              ibe->inbuf[3] = IPMI_CC_TIMEOUT;
> -            k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
> +            k->handle_msg(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
>          } else {
>              continue_send(ibe);
>          }
> @@ -186,8 +187,9 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
>                                         unsigned int max_cmd_len,
>                                         uint8_t msg_id)
>  {
> +    IPMICore *ic = IPMI_CORE(b);
>      IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(b);
> -    IPMIInterface *s = ibe->parent.intf;
> +    IPMIInterface *s = ic->intf;
>      uint8_t err = 0, csum;
>      unsigned int i;
>  
> @@ -213,7 +215,7 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
>          rsp[1] = cmd[1];
>          rsp[2] = err;
>          ibe->waiting_rsp = false;
> -        k->handle_rsp(s, msg_id, rsp, 3);
> +        k->handle_msg(s, msg_id, rsp, 3);
>          goto out;
>      }
>  
> @@ -236,7 +238,8 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
>  
>  static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
>  {
> -    IPMIInterface *s = ibe->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibe);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      switch (hw_op) {
> @@ -284,7 +287,9 @@ static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
>  
>  static void handle_msg(IPMIBmcExtern *ibe)
>  {
> -    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(ibe->parent.intf);
> +    IPMICore *ic = IPMI_CORE(ibe);
> +    IPMIInterface *s = ic->intf;
> +    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      if (ibe->in_escape) {
>          ipmi_debug("msg escape not ended\n");
> @@ -306,7 +311,7 @@ static void handle_msg(IPMIBmcExtern *ibe)
>  
>      timer_del(ibe->extern_timer);
>      ibe->waiting_rsp = false;
> -    k->handle_rsp(ibe->parent.intf, ibe->inbuf[0], ibe->inbuf + 1, ibe->inpos - 1);
> +    k->handle_msg(s, ibe->inbuf[0], ibe->inbuf + 1, ibe->inpos - 1);
>  }
>  
>  static int can_receive(void *opaque)
> @@ -382,8 +387,9 @@ static void receive(void *opaque, const uint8_t *buf, int size)
>  
>  static void chr_event(void *opaque, QEMUChrEvent event)
>  {
> +    IPMICore *ic = opaque;
>      IPMIBmcExtern *ibe = opaque;

Shouldn't the above be a cast from ic?

> -    IPMIInterface *s = ibe->parent.intf;
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      unsigned char v;
>  
> @@ -398,17 +404,17 @@ static void chr_event(void *opaque, QEMUChrEvent event)
>          ibe->outlen++;
>          addchar(ibe, VM_CMD_CAPABILITIES);
>          v = VM_CAPABILITIES_IRQ | VM_CAPABILITIES_ATTN;
> -        if (k->do_hw_op(ibe->parent.intf, IPMI_POWEROFF_CHASSIS, 1) == 0) {
> +        if (k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1) == 0) {
>              v |= VM_CAPABILITIES_POWER;
>          }
> -        if (k->do_hw_op(ibe->parent.intf, IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 1)
> +        if (k->do_hw_op(s, IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 1)
>              == 0) {
>              v |= VM_CAPABILITIES_GRACEFUL_SHUTDOWN;
>          }
> -        if (k->do_hw_op(ibe->parent.intf, IPMI_RESET_CHASSIS, 1) == 0) {
> +        if (k->do_hw_op(s, IPMI_RESET_CHASSIS, 1) == 0) {
>              v |= VM_CAPABILITIES_RESET;
>          }
> -        if (k->do_hw_op(ibe->parent.intf, IPMI_SEND_NMI, 1) == 0) {
> +        if (k->do_hw_op(s, IPMI_SEND_NMI, 1) == 0) {
>              v |= VM_CAPABILITIES_NMI;
>          }
>          addchar(ibe, v);
> @@ -433,7 +439,7 @@ static void chr_event(void *opaque, QEMUChrEvent event)
>              ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
>              ibe->inbuf[2] = ibe->outbuf[2];
>              ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
> -            k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
> +            k->handle_msg(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
>          }
>          break;
>  
> @@ -475,14 +481,15 @@ static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
>       * error on the interface if a response was being waited for.
>       */
>      if (ibe->waiting_rsp) {
> -        IPMIInterface *ii = ibe->parent.intf;
> +        IPMICore *ic = opaque;
> +        IPMIInterface *ii = ic->intf;
>          IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
>  
>          ibe->waiting_rsp = false;
>          ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
>          ibe->inbuf[2] = ibe->outbuf[2];
>          ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
> -        iic->handle_rsp(ii, ibe->outbuf[0], ibe->inbuf + 1, 3);
> +        iic->handle_msg(ii, ibe->outbuf[0], ibe->inbuf + 1, 3);
>      }
>      return 0;
>  }
> diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
> index 905e091094..7cc4a22456 100644
> --- a/hw/ipmi/ipmi_bmc_sim.c
> +++ b/hw/ipmi/ipmi_bmc_sim.c
> @@ -451,7 +451,8 @@ static int attn_irq_enabled(IPMIBmcSim *ibs)
>  void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
>  {
>      IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
> @@ -475,7 +476,8 @@ void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
>  static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
>                        uint8_t evd1, uint8_t evd2, uint8_t evd3)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      uint8_t evt[16];
>      IPMISensor *sens = ibs->sensors + sens_num;
> @@ -644,7 +646,8 @@ static void ipmi_sim_handle_command(IPMIBmc *b,
>                                      uint8_t msg_id)
>  {
>      IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      const IPMICmdHandler *hdl;
>      RspBuffer rsp = RSP_BUFFER_INITIALIZER;
> @@ -690,14 +693,15 @@ static void ipmi_sim_handle_command(IPMIBmc *b,
>      hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
>  
>   out:
> -    k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
> +    k->handle_msg(s, msg_id, rsp.buffer, rsp.len);
>  
>      next_timeout(ibs);
>  }
>  
>  static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      if (!ibs->watchdog_running) {
> @@ -788,7 +792,8 @@ static void chassis_control(IPMIBmcSim *ibs,
>                              uint8_t *cmd, unsigned int cmd_len,
>                              RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      switch (cmd[2] & 0xf) {
> @@ -845,7 +850,8 @@ static void get_device_id(IPMIBmcSim *ibs,
>  
>  static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      bool irqs_on;
>  
> @@ -861,7 +867,8 @@ static void cold_reset(IPMIBmcSim *ibs,
>                         uint8_t *cmd, unsigned int cmd_len,
>                         RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      /* Disable all interrupts */
> @@ -876,7 +883,8 @@ static void warm_reset(IPMIBmcSim *ibs,
>                         uint8_t *cmd, unsigned int cmd_len,
>                         RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      if (k->reset) {
> @@ -939,7 +947,8 @@ static void clr_msg_flags(IPMIBmcSim *ibs,
>                            uint8_t *cmd, unsigned int cmd_len,
>                            RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>      ibs->msg_flags &= ~cmd[2];
> @@ -957,7 +966,8 @@ static void read_evt_msg_buf(IPMIBmcSim *ibs,
>                               uint8_t *cmd, unsigned int cmd_len,
>                               RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      unsigned int i;
>  
> @@ -989,7 +999,8 @@ static void get_msg(IPMIBmcSim *ibs,
>      g_free(msg);
>  
>      if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
> -        IPMIInterface *s = ibs->parent.intf;
> +        IPMICore *ic = IPMI_CORE(ibs);
> +        IPMIInterface *s = ic->intf;
>          IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>  
>          ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
> @@ -1014,7 +1025,8 @@ static void send_msg(IPMIBmcSim *ibs,
>                       uint8_t *cmd, unsigned int cmd_len,
>                       RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      IPMIRcvBufEntry *msg;
>      uint8_t *buf;
> @@ -1130,7 +1142,8 @@ static void set_watchdog_timer(IPMIBmcSim *ibs,
>                                 uint8_t *cmd, unsigned int cmd_len,
>                                 RspBuffer *rsp)
>  {
> -    IPMIInterface *s = ibs->parent.intf;
> +    IPMICore *ic = IPMI_CORE(ibs);
> +    IPMIInterface *s = ic->intf;
>      IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
>      unsigned int val;
>  
> diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c
> index 22f94fb98d..f76c369e4a 100644
> --- a/hw/ipmi/ipmi_bt.c
> +++ b/hw/ipmi/ipmi_bt.c
> @@ -430,7 +430,7 @@ void ipmi_bt_class_init(IPMIInterfaceClass *iic)
>  {
>      iic->init = ipmi_bt_init;
>      iic->set_atn = ipmi_bt_set_atn;
> -    iic->handle_rsp = ipmi_bt_handle_rsp;
> +    iic->handle_msg = ipmi_bt_handle_rsp;
>      iic->handle_if_event = ipmi_bt_handle_event;
>      iic->set_irq_enable = ipmi_bt_set_irq_enable;
>      iic->reset = ipmi_bt_handle_reset;
> diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c
> index a77612946a..e0f870e13a 100644
> --- a/hw/ipmi/ipmi_kcs.c
> +++ b/hw/ipmi/ipmi_kcs.c
> @@ -417,7 +417,7 @@ void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
>  {
>      iic->init = ipmi_kcs_init;
>      iic->set_atn = ipmi_kcs_set_atn;
> -    iic->handle_rsp = ipmi_kcs_handle_rsp;
> +    iic->handle_msg = ipmi_kcs_handle_rsp;
>      iic->handle_if_event = ipmi_kcs_handle_event;
>      iic->set_irq_enable = ipmi_kcs_set_irq_enable;
>  }
> diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
> index 02625eb94e..0f52fc4262 100644
> --- a/hw/ipmi/isa_ipmi_bt.c
> +++ b/hw/ipmi/isa_ipmi_bt.c
> @@ -74,6 +74,7 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
>      ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
>      IPMIInterface *ii = IPMI_INTERFACE(dev);
>      IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
> +    IPMICore *ic;
>  
>      if (!iib->bt.bmc) {
>          error_setg(errp, "IPMI device requires a bmc attribute to be set");
> @@ -82,7 +83,8 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
>  
>      iib->uuid = ipmi_next_uuid();
>  
> -    iib->bt.bmc->intf = ii;
> +    ic = IPMI_CORE(iib->bt.bmc);
> +    ic->intf = ii;
>      iib->bt.opaque = iib;
>  
>      iic->init(ii, 0, &err);
> diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
> index 3b23ad08b3..60cab90a21 100644
> --- a/hw/ipmi/isa_ipmi_kcs.c
> +++ b/hw/ipmi/isa_ipmi_kcs.c
> @@ -73,6 +73,7 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
>      ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev);
>      IPMIInterface *ii = IPMI_INTERFACE(dev);
>      IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
> +    IPMICore *ic;
>  
>      if (!iik->kcs.bmc) {
>          error_setg(errp, "IPMI device requires a bmc attribute to be set");
> @@ -81,7 +82,8 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
>  
>      iik->uuid = ipmi_next_uuid();
>  
> -    iik->kcs.bmc->intf = ii;
> +    ic = IPMI_CORE(iik->kcs.bmc);
> +    ic->intf = ii;
>      iik->kcs.opaque = iik;
>  
>      iic->init(ii, 0, &err);
> diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c
> index b6e52730d3..751c15a31f 100644
> --- a/hw/ipmi/pci_ipmi_bt.c
> +++ b/hw/ipmi/pci_ipmi_bt.c
> @@ -58,6 +58,7 @@ static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
>      PCIIPMIBTDevice *pik = PCI_IPMI_BT(pd);
>      IPMIInterface *ii = IPMI_INTERFACE(pd);
>      IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
> +    IPMICore *ic;
>  
>      if (!pik->bt.bmc) {
>          error_setg(errp, "IPMI device requires a bmc attribute to be set");
> @@ -66,7 +67,8 @@ static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
>  
>      pik->uuid = ipmi_next_uuid();
>  
> -    pik->bt.bmc->intf = ii;
> +    ic = IPMI_CORE(pik->bt.bmc);
> +    ic->intf = ii;
>      pik->bt.opaque = pik;
>  
>      pci_config_set_prog_interface(pd->config, 0x02); /* BT */
> diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c
> index de13418862..44a645723c 100644
> --- a/hw/ipmi/pci_ipmi_kcs.c
> +++ b/hw/ipmi/pci_ipmi_kcs.c
> @@ -58,6 +58,7 @@ static void pci_ipmi_kcs_realize(PCIDevice *pd, Error **errp)
>      PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(pd);
>      IPMIInterface *ii = IPMI_INTERFACE(pd);
>      IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
> +    IPMICore *ic;
>  
>      if (!pik->kcs.bmc) {
>          error_setg(errp, "IPMI device requires a bmc attribute to be set");
> @@ -66,7 +67,8 @@ static void pci_ipmi_kcs_realize(PCIDevice *pd, Error **errp)
>  
>      pik->uuid = ipmi_next_uuid();
>  
> -    pik->kcs.bmc->intf = ii;
> +    ic = IPMI_CORE(pik->kcs.bmc);
> +    ic->intf = ii;
>      pik->kcs.opaque = pik;
>  
>      pci_config_set_prog_interface(pd->config, 0x01); /* KCS */
> diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c
> index 1fdf0a66b6..a2383f1212 100644
> --- a/hw/ipmi/smbus_ipmi.c
> +++ b/hw/ipmi/smbus_ipmi.c
> @@ -315,6 +315,7 @@ static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
>  {
>      SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
>      IPMIInterface *ii = IPMI_INTERFACE(dev);
> +    IPMICore *ic;
>  
>      if (!sid->bmc) {
>          error_setg(errp, "IPMI device requires a bmc attribute to be set");
> @@ -323,7 +324,8 @@ static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
>  
>      sid->uuid = ipmi_next_uuid();
>  
> -    sid->bmc->intf = ii;
> +    ic = IPMI_CORE(sid->bmc);
> +    ic->intf = ii;
>  }
>  
>  static void smbus_ipmi_init(Object *obj)
> @@ -359,7 +361,7 @@ static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
>      dc->vmsd = &vmstate_smbus_ipmi;
>      dc->realize = smbus_ipmi_realize;
>      iic->set_atn = smbus_ipmi_set_atn;
> -    iic->handle_rsp = smbus_ipmi_handle_rsp;
> +    iic->handle_msg = smbus_ipmi_handle_rsp;
>      iic->handle_if_event = smbus_ipmi_handle_event;
>      iic->set_irq_enable = smbus_ipmi_set_irq_enable;
>      iic->get_fwinfo = smbus_ipmi_get_fwinfo;
> diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h
> index 77a7213ed9..1fa8cd12e5 100644
> --- a/include/hw/ipmi/ipmi.h
> +++ b/include/hw/ipmi/ipmi.h
> @@ -111,11 +111,11 @@ uint32_t ipmi_next_uuid(void);
>  #define TYPE_IPMI_INTERFACE "ipmi-interface"
>  #define IPMI_INTERFACE(obj) \
>       INTERFACE_CHECK(IPMIInterface, (obj), TYPE_IPMI_INTERFACE)
> +typedef struct IPMIInterface IPMIInterface;
>  typedef struct IPMIInterfaceClass IPMIInterfaceClass;
>  DECLARE_CLASS_CHECKERS(IPMIInterfaceClass, IPMI_INTERFACE,
>                         TYPE_IPMI_INTERFACE)
> -
> -typedef struct IPMIInterface IPMIInterface;
> +struct IPMICore;
>  
>  struct IPMIInterfaceClass {
>      InterfaceClass parent;
> @@ -156,9 +156,9 @@ struct IPMIInterfaceClass {
>      void (*reset)(struct IPMIInterface *s, bool is_cold);
>  
>      /*
> -     * Handle a response from the bmc.
> +     * Handle an IPMI message.

Could you add a little more explaination here.  Like:

Handle an IPMI message from the remote side.  This is either a message
from the BMC being handled by an IPMI interface on the host side, or a
message from the host side being handled by a BMC emulator running in
this VM.

>       */
> -    void (*handle_rsp)(struct IPMIInterface *s, uint8_t msg_id,
> +    void (*handle_msg)(struct IPMIInterface *s, uint8_t msg_id,
>                         unsigned char *rsp, unsigned int rsp_len);
>  
>      /*
> @@ -166,12 +166,38 @@ struct IPMIInterfaceClass {
>       */
>      void *(*get_backend_data)(struct IPMIInterface *s);
>  
> +    /*
> +     * Set the IPMI core.
> +     */
> +    void (*set_ipmi_handler)(struct IPMIInterface *s, struct IPMICore *ic);
> +
>      /*
>       * Return the firmware info for a device.
>       */
>      void (*get_fwinfo)(struct IPMIInterface *s, IPMIFwInfo *info);
>  };
>  
> +/*
> + * Define an IPMI core (Either BMC or Host simulator.)
> + */
> +#define TYPE_IPMI_CORE "ipmi-core"
> +OBJECT_DECLARE_TYPE(IPMICore, IPMICoreClass, IPMI_CORE)
> +
> +struct IPMICore {
> +    DeviceState parent;
> +
> +    IPMIInterface *intf;
> +};
> +
> +struct IPMICoreClass {
> +    DeviceClass parent;
> +
> +    /*
> +     * Handle a hardware command.
> +     */
> +    void (*handle_hw_op)(struct IPMICore *s, uint8_t hw_op, uint8_t operand);
> +};
> +
>  /*
>   * Define a BMC simulator (or perhaps a connection to a real BMC)
>   */
> @@ -180,15 +206,13 @@ OBJECT_DECLARE_TYPE(IPMIBmc, IPMIBmcClass,
>                      IPMI_BMC)
>  
>  struct IPMIBmc {
> -    DeviceState parent;
> +    IPMICore parent;
>  
>      uint8_t slave_addr;
> -
> -    IPMIInterface *intf;
>  };
>  
>  struct IPMIBmcClass {
> -    DeviceClass parent;
> +    IPMICoreClass parent;
>  
>      /* Called when the system resets to report to the bmc. */
>      void (*handle_reset)(struct IPMIBmc *s);
> -- 
> 2.33.0.309.g3052b89438-goog
>
diff mbox series

Patch

diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
index 8d35c9fdd6..7da1b36fab 100644
--- a/hw/ipmi/ipmi.c
+++ b/hw/ipmi/ipmi.c
@@ -92,13 +92,21 @@  static TypeInfo ipmi_interface_type_info = {
     .class_init = ipmi_interface_class_init,
 };
 
+static TypeInfo ipmi_core_type_info = {
+    .name = TYPE_IPMI_CORE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(IPMICore),
+    .abstract = true,
+};
+
 static void isa_ipmi_bmc_check(const Object *obj, const char *name,
                                Object *val, Error **errp)
 {
-    IPMIBmc *bmc = IPMI_BMC(val);
+    IPMICore *ic = IPMI_CORE(val);
 
-    if (bmc->intf)
+    if (ic->intf) {
         error_setg(errp, "BMC object is already in use");
+    }
 }
 
 void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
@@ -122,7 +130,7 @@  static void bmc_class_init(ObjectClass *oc, void *data)
 
 static TypeInfo ipmi_bmc_type_info = {
     .name = TYPE_IPMI_BMC,
-    .parent = TYPE_DEVICE,
+    .parent = TYPE_IPMI_CORE,
     .instance_size = sizeof(IPMIBmc),
     .abstract = true,
     .class_size = sizeof(IPMIBmcClass),
@@ -132,6 +140,7 @@  static TypeInfo ipmi_bmc_type_info = {
 static void ipmi_register_types(void)
 {
     type_register_static(&ipmi_interface_type_info);
+    type_register_static(&ipmi_core_type_info);
     type_register_static(&ipmi_bmc_type_info);
 }
 
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index acf2bab35f..a0c3a40e7c 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -147,8 +147,9 @@  static void continue_send(IPMIBmcExtern *ibe)
 
 static void extern_timeout(void *opaque)
 {
+    IPMICore *ic = opaque;
     IPMIBmcExtern *ibe = opaque;
-    IPMIInterface *s = ibe->parent.intf;
+    IPMIInterface *s = ic->intf;
 
     if (ibe->connected) {
         if (ibe->waiting_rsp && (ibe->outlen == 0)) {
@@ -158,7 +159,7 @@  static void extern_timeout(void *opaque)
             ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
             ibe->inbuf[2] = ibe->outbuf[2];
             ibe->inbuf[3] = IPMI_CC_TIMEOUT;
-            k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
+            k->handle_msg(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
         } else {
             continue_send(ibe);
         }
@@ -186,8 +187,9 @@  static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
                                        unsigned int max_cmd_len,
                                        uint8_t msg_id)
 {
+    IPMICore *ic = IPMI_CORE(b);
     IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(b);
-    IPMIInterface *s = ibe->parent.intf;
+    IPMIInterface *s = ic->intf;
     uint8_t err = 0, csum;
     unsigned int i;
 
@@ -213,7 +215,7 @@  static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
         rsp[1] = cmd[1];
         rsp[2] = err;
         ibe->waiting_rsp = false;
-        k->handle_rsp(s, msg_id, rsp, 3);
+        k->handle_msg(s, msg_id, rsp, 3);
         goto out;
     }
 
@@ -236,7 +238,8 @@  static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
 
 static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
 {
-    IPMIInterface *s = ibe->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibe);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     switch (hw_op) {
@@ -284,7 +287,9 @@  static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
 
 static void handle_msg(IPMIBmcExtern *ibe)
 {
-    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(ibe->parent.intf);
+    IPMICore *ic = IPMI_CORE(ibe);
+    IPMIInterface *s = ic->intf;
+    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     if (ibe->in_escape) {
         ipmi_debug("msg escape not ended\n");
@@ -306,7 +311,7 @@  static void handle_msg(IPMIBmcExtern *ibe)
 
     timer_del(ibe->extern_timer);
     ibe->waiting_rsp = false;
-    k->handle_rsp(ibe->parent.intf, ibe->inbuf[0], ibe->inbuf + 1, ibe->inpos - 1);
+    k->handle_msg(s, ibe->inbuf[0], ibe->inbuf + 1, ibe->inpos - 1);
 }
 
 static int can_receive(void *opaque)
@@ -382,8 +387,9 @@  static void receive(void *opaque, const uint8_t *buf, int size)
 
 static void chr_event(void *opaque, QEMUChrEvent event)
 {
+    IPMICore *ic = opaque;
     IPMIBmcExtern *ibe = opaque;
-    IPMIInterface *s = ibe->parent.intf;
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     unsigned char v;
 
@@ -398,17 +404,17 @@  static void chr_event(void *opaque, QEMUChrEvent event)
         ibe->outlen++;
         addchar(ibe, VM_CMD_CAPABILITIES);
         v = VM_CAPABILITIES_IRQ | VM_CAPABILITIES_ATTN;
-        if (k->do_hw_op(ibe->parent.intf, IPMI_POWEROFF_CHASSIS, 1) == 0) {
+        if (k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1) == 0) {
             v |= VM_CAPABILITIES_POWER;
         }
-        if (k->do_hw_op(ibe->parent.intf, IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 1)
+        if (k->do_hw_op(s, IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 1)
             == 0) {
             v |= VM_CAPABILITIES_GRACEFUL_SHUTDOWN;
         }
-        if (k->do_hw_op(ibe->parent.intf, IPMI_RESET_CHASSIS, 1) == 0) {
+        if (k->do_hw_op(s, IPMI_RESET_CHASSIS, 1) == 0) {
             v |= VM_CAPABILITIES_RESET;
         }
-        if (k->do_hw_op(ibe->parent.intf, IPMI_SEND_NMI, 1) == 0) {
+        if (k->do_hw_op(s, IPMI_SEND_NMI, 1) == 0) {
             v |= VM_CAPABILITIES_NMI;
         }
         addchar(ibe, v);
@@ -433,7 +439,7 @@  static void chr_event(void *opaque, QEMUChrEvent event)
             ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
             ibe->inbuf[2] = ibe->outbuf[2];
             ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
-            k->handle_rsp(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
+            k->handle_msg(s, ibe->outbuf[0], ibe->inbuf + 1, 3);
         }
         break;
 
@@ -475,14 +481,15 @@  static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
      * error on the interface if a response was being waited for.
      */
     if (ibe->waiting_rsp) {
-        IPMIInterface *ii = ibe->parent.intf;
+        IPMICore *ic = opaque;
+        IPMIInterface *ii = ic->intf;
         IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 
         ibe->waiting_rsp = false;
         ibe->inbuf[1] = ibe->outbuf[1] | 0x04;
         ibe->inbuf[2] = ibe->outbuf[2];
         ibe->inbuf[3] = IPMI_CC_BMC_INIT_IN_PROGRESS;
-        iic->handle_rsp(ii, ibe->outbuf[0], ibe->inbuf + 1, 3);
+        iic->handle_msg(ii, ibe->outbuf[0], ibe->inbuf + 1, 3);
     }
     return 0;
 }
diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 905e091094..7cc4a22456 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -451,7 +451,8 @@  static int attn_irq_enabled(IPMIBmcSim *ibs)
 void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
 {
     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
@@ -475,7 +476,8 @@  void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
 static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     uint8_t evt[16];
     IPMISensor *sens = ibs->sensors + sens_num;
@@ -644,7 +646,8 @@  static void ipmi_sim_handle_command(IPMIBmc *b,
                                     uint8_t msg_id)
 {
     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     const IPMICmdHandler *hdl;
     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
@@ -690,14 +693,15 @@  static void ipmi_sim_handle_command(IPMIBmc *b,
     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
 
  out:
-    k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
+    k->handle_msg(s, msg_id, rsp.buffer, rsp.len);
 
     next_timeout(ibs);
 }
 
 static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     if (!ibs->watchdog_running) {
@@ -788,7 +792,8 @@  static void chassis_control(IPMIBmcSim *ibs,
                             uint8_t *cmd, unsigned int cmd_len,
                             RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     switch (cmd[2] & 0xf) {
@@ -845,7 +850,8 @@  static void get_device_id(IPMIBmcSim *ibs,
 
 static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     bool irqs_on;
 
@@ -861,7 +867,8 @@  static void cold_reset(IPMIBmcSim *ibs,
                        uint8_t *cmd, unsigned int cmd_len,
                        RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     /* Disable all interrupts */
@@ -876,7 +883,8 @@  static void warm_reset(IPMIBmcSim *ibs,
                        uint8_t *cmd, unsigned int cmd_len,
                        RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     if (k->reset) {
@@ -939,7 +947,8 @@  static void clr_msg_flags(IPMIBmcSim *ibs,
                           uint8_t *cmd, unsigned int cmd_len,
                           RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
     ibs->msg_flags &= ~cmd[2];
@@ -957,7 +966,8 @@  static void read_evt_msg_buf(IPMIBmcSim *ibs,
                              uint8_t *cmd, unsigned int cmd_len,
                              RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     unsigned int i;
 
@@ -989,7 +999,8 @@  static void get_msg(IPMIBmcSim *ibs,
     g_free(msg);
 
     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
-        IPMIInterface *s = ibs->parent.intf;
+        IPMICore *ic = IPMI_CORE(ibs);
+        IPMIInterface *s = ic->intf;
         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 
         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
@@ -1014,7 +1025,8 @@  static void send_msg(IPMIBmcSim *ibs,
                      uint8_t *cmd, unsigned int cmd_len,
                      RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     IPMIRcvBufEntry *msg;
     uint8_t *buf;
@@ -1130,7 +1142,8 @@  static void set_watchdog_timer(IPMIBmcSim *ibs,
                                uint8_t *cmd, unsigned int cmd_len,
                                RspBuffer *rsp)
 {
-    IPMIInterface *s = ibs->parent.intf;
+    IPMICore *ic = IPMI_CORE(ibs);
+    IPMIInterface *s = ic->intf;
     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
     unsigned int val;
 
diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c
index 22f94fb98d..f76c369e4a 100644
--- a/hw/ipmi/ipmi_bt.c
+++ b/hw/ipmi/ipmi_bt.c
@@ -430,7 +430,7 @@  void ipmi_bt_class_init(IPMIInterfaceClass *iic)
 {
     iic->init = ipmi_bt_init;
     iic->set_atn = ipmi_bt_set_atn;
-    iic->handle_rsp = ipmi_bt_handle_rsp;
+    iic->handle_msg = ipmi_bt_handle_rsp;
     iic->handle_if_event = ipmi_bt_handle_event;
     iic->set_irq_enable = ipmi_bt_set_irq_enable;
     iic->reset = ipmi_bt_handle_reset;
diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c
index a77612946a..e0f870e13a 100644
--- a/hw/ipmi/ipmi_kcs.c
+++ b/hw/ipmi/ipmi_kcs.c
@@ -417,7 +417,7 @@  void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
 {
     iic->init = ipmi_kcs_init;
     iic->set_atn = ipmi_kcs_set_atn;
-    iic->handle_rsp = ipmi_kcs_handle_rsp;
+    iic->handle_msg = ipmi_kcs_handle_rsp;
     iic->handle_if_event = ipmi_kcs_handle_event;
     iic->set_irq_enable = ipmi_kcs_set_irq_enable;
 }
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index 02625eb94e..0f52fc4262 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -74,6 +74,7 @@  static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
     ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
     IPMIInterface *ii = IPMI_INTERFACE(dev);
     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
+    IPMICore *ic;
 
     if (!iib->bt.bmc) {
         error_setg(errp, "IPMI device requires a bmc attribute to be set");
@@ -82,7 +83,8 @@  static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
 
     iib->uuid = ipmi_next_uuid();
 
-    iib->bt.bmc->intf = ii;
+    ic = IPMI_CORE(iib->bt.bmc);
+    ic->intf = ii;
     iib->bt.opaque = iib;
 
     iic->init(ii, 0, &err);
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index 3b23ad08b3..60cab90a21 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -73,6 +73,7 @@  static void ipmi_isa_realize(DeviceState *dev, Error **errp)
     ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(dev);
     IPMIInterface *ii = IPMI_INTERFACE(dev);
     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
+    IPMICore *ic;
 
     if (!iik->kcs.bmc) {
         error_setg(errp, "IPMI device requires a bmc attribute to be set");
@@ -81,7 +82,8 @@  static void ipmi_isa_realize(DeviceState *dev, Error **errp)
 
     iik->uuid = ipmi_next_uuid();
 
-    iik->kcs.bmc->intf = ii;
+    ic = IPMI_CORE(iik->kcs.bmc);
+    ic->intf = ii;
     iik->kcs.opaque = iik;
 
     iic->init(ii, 0, &err);
diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c
index b6e52730d3..751c15a31f 100644
--- a/hw/ipmi/pci_ipmi_bt.c
+++ b/hw/ipmi/pci_ipmi_bt.c
@@ -58,6 +58,7 @@  static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
     PCIIPMIBTDevice *pik = PCI_IPMI_BT(pd);
     IPMIInterface *ii = IPMI_INTERFACE(pd);
     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
+    IPMICore *ic;
 
     if (!pik->bt.bmc) {
         error_setg(errp, "IPMI device requires a bmc attribute to be set");
@@ -66,7 +67,8 @@  static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
 
     pik->uuid = ipmi_next_uuid();
 
-    pik->bt.bmc->intf = ii;
+    ic = IPMI_CORE(pik->bt.bmc);
+    ic->intf = ii;
     pik->bt.opaque = pik;
 
     pci_config_set_prog_interface(pd->config, 0x02); /* BT */
diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c
index de13418862..44a645723c 100644
--- a/hw/ipmi/pci_ipmi_kcs.c
+++ b/hw/ipmi/pci_ipmi_kcs.c
@@ -58,6 +58,7 @@  static void pci_ipmi_kcs_realize(PCIDevice *pd, Error **errp)
     PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(pd);
     IPMIInterface *ii = IPMI_INTERFACE(pd);
     IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
+    IPMICore *ic;
 
     if (!pik->kcs.bmc) {
         error_setg(errp, "IPMI device requires a bmc attribute to be set");
@@ -66,7 +67,8 @@  static void pci_ipmi_kcs_realize(PCIDevice *pd, Error **errp)
 
     pik->uuid = ipmi_next_uuid();
 
-    pik->kcs.bmc->intf = ii;
+    ic = IPMI_CORE(pik->kcs.bmc);
+    ic->intf = ii;
     pik->kcs.opaque = pik;
 
     pci_config_set_prog_interface(pd->config, 0x01); /* KCS */
diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c
index 1fdf0a66b6..a2383f1212 100644
--- a/hw/ipmi/smbus_ipmi.c
+++ b/hw/ipmi/smbus_ipmi.c
@@ -315,6 +315,7 @@  static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
 {
     SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
     IPMIInterface *ii = IPMI_INTERFACE(dev);
+    IPMICore *ic;
 
     if (!sid->bmc) {
         error_setg(errp, "IPMI device requires a bmc attribute to be set");
@@ -323,7 +324,8 @@  static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
 
     sid->uuid = ipmi_next_uuid();
 
-    sid->bmc->intf = ii;
+    ic = IPMI_CORE(sid->bmc);
+    ic->intf = ii;
 }
 
 static void smbus_ipmi_init(Object *obj)
@@ -359,7 +361,7 @@  static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
     dc->vmsd = &vmstate_smbus_ipmi;
     dc->realize = smbus_ipmi_realize;
     iic->set_atn = smbus_ipmi_set_atn;
-    iic->handle_rsp = smbus_ipmi_handle_rsp;
+    iic->handle_msg = smbus_ipmi_handle_rsp;
     iic->handle_if_event = smbus_ipmi_handle_event;
     iic->set_irq_enable = smbus_ipmi_set_irq_enable;
     iic->get_fwinfo = smbus_ipmi_get_fwinfo;
diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h
index 77a7213ed9..1fa8cd12e5 100644
--- a/include/hw/ipmi/ipmi.h
+++ b/include/hw/ipmi/ipmi.h
@@ -111,11 +111,11 @@  uint32_t ipmi_next_uuid(void);
 #define TYPE_IPMI_INTERFACE "ipmi-interface"
 #define IPMI_INTERFACE(obj) \
      INTERFACE_CHECK(IPMIInterface, (obj), TYPE_IPMI_INTERFACE)
+typedef struct IPMIInterface IPMIInterface;
 typedef struct IPMIInterfaceClass IPMIInterfaceClass;
 DECLARE_CLASS_CHECKERS(IPMIInterfaceClass, IPMI_INTERFACE,
                        TYPE_IPMI_INTERFACE)
-
-typedef struct IPMIInterface IPMIInterface;
+struct IPMICore;
 
 struct IPMIInterfaceClass {
     InterfaceClass parent;
@@ -156,9 +156,9 @@  struct IPMIInterfaceClass {
     void (*reset)(struct IPMIInterface *s, bool is_cold);
 
     /*
-     * Handle a response from the bmc.
+     * Handle an IPMI message.
      */
-    void (*handle_rsp)(struct IPMIInterface *s, uint8_t msg_id,
+    void (*handle_msg)(struct IPMIInterface *s, uint8_t msg_id,
                        unsigned char *rsp, unsigned int rsp_len);
 
     /*
@@ -166,12 +166,38 @@  struct IPMIInterfaceClass {
      */
     void *(*get_backend_data)(struct IPMIInterface *s);
 
+    /*
+     * Set the IPMI core.
+     */
+    void (*set_ipmi_handler)(struct IPMIInterface *s, struct IPMICore *ic);
+
     /*
      * Return the firmware info for a device.
      */
     void (*get_fwinfo)(struct IPMIInterface *s, IPMIFwInfo *info);
 };
 
+/*
+ * Define an IPMI core (Either BMC or Host simulator.)
+ */
+#define TYPE_IPMI_CORE "ipmi-core"
+OBJECT_DECLARE_TYPE(IPMICore, IPMICoreClass, IPMI_CORE)
+
+struct IPMICore {
+    DeviceState parent;
+
+    IPMIInterface *intf;
+};
+
+struct IPMICoreClass {
+    DeviceClass parent;
+
+    /*
+     * Handle a hardware command.
+     */
+    void (*handle_hw_op)(struct IPMICore *s, uint8_t hw_op, uint8_t operand);
+};
+
 /*
  * Define a BMC simulator (or perhaps a connection to a real BMC)
  */
@@ -180,15 +206,13 @@  OBJECT_DECLARE_TYPE(IPMIBmc, IPMIBmcClass,
                     IPMI_BMC)
 
 struct IPMIBmc {
-    DeviceState parent;
+    IPMICore parent;
 
     uint8_t slave_addr;
-
-    IPMIInterface *intf;
 };
 
 struct IPMIBmcClass {
-    DeviceClass parent;
+    IPMICoreClass parent;
 
     /* Called when the system resets to report to the bmc. */
     void (*handle_reset)(struct IPMIBmc *s);