qemu/hw/ipmi/ipmi_bmc_sim.c
<<
>>
Prefs
   1/*
   2 * IPMI BMC emulation
   3 *
   4 * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "sysemu/sysemu.h"
  27#include "qemu/timer.h"
  28#include "hw/ipmi/ipmi.h"
  29#include "qemu/error-report.h"
  30
  31#define IPMI_NETFN_CHASSIS            0x00
  32
  33#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
  34#define IPMI_CMD_GET_CHASSIS_STATUS       0x01
  35#define IPMI_CMD_CHASSIS_CONTROL          0x02
  36#define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
  37
  38#define IPMI_NETFN_SENSOR_EVENT       0x04
  39
  40#define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
  41#define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
  42#define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
  43#define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
  44#define IPMI_CMD_GET_SENSOR_READING       0x2d
  45#define IPMI_CMD_SET_SENSOR_TYPE          0x2e
  46#define IPMI_CMD_GET_SENSOR_TYPE          0x2f
  47
  48/* #define IPMI_NETFN_APP             0x06 In ipmi.h */
  49
  50#define IPMI_CMD_GET_DEVICE_ID            0x01
  51#define IPMI_CMD_COLD_RESET               0x02
  52#define IPMI_CMD_WARM_RESET               0x03
  53#define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
  54#define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
  55#define IPMI_CMD_GET_DEVICE_GUID          0x08
  56#define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
  57#define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
  58#define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
  59#define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
  60#define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
  61#define IPMI_CMD_CLR_MSG_FLAGS            0x30
  62#define IPMI_CMD_GET_MSG_FLAGS            0x31
  63#define IPMI_CMD_GET_MSG                  0x33
  64#define IPMI_CMD_SEND_MSG                 0x34
  65#define IPMI_CMD_READ_EVT_MSG_BUF         0x35
  66
  67#define IPMI_NETFN_STORAGE            0x0a
  68
  69#define IPMI_CMD_GET_SDR_REP_INFO         0x20
  70#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
  71#define IPMI_CMD_RESERVE_SDR_REP          0x22
  72#define IPMI_CMD_GET_SDR                  0x23
  73#define IPMI_CMD_ADD_SDR                  0x24
  74#define IPMI_CMD_PARTIAL_ADD_SDR          0x25
  75#define IPMI_CMD_DELETE_SDR               0x26
  76#define IPMI_CMD_CLEAR_SDR_REP            0x27
  77#define IPMI_CMD_GET_SDR_REP_TIME         0x28
  78#define IPMI_CMD_SET_SDR_REP_TIME         0x29
  79#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
  80#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
  81#define IPMI_CMD_RUN_INIT_AGENT           0x2C
  82#define IPMI_CMD_GET_SEL_INFO             0x40
  83#define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
  84#define IPMI_CMD_RESERVE_SEL              0x42
  85#define IPMI_CMD_GET_SEL_ENTRY            0x43
  86#define IPMI_CMD_ADD_SEL_ENTRY            0x44
  87#define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
  88#define IPMI_CMD_DELETE_SEL_ENTRY         0x46
  89#define IPMI_CMD_CLEAR_SEL                0x47
  90#define IPMI_CMD_GET_SEL_TIME             0x48
  91#define IPMI_CMD_SET_SEL_TIME             0x49
  92
  93
  94/* Same as a timespec struct. */
  95struct ipmi_time {
  96    long tv_sec;
  97    long tv_nsec;
  98};
  99
 100#define MAX_SEL_SIZE 128
 101
 102typedef struct IPMISel {
 103    uint8_t sel[MAX_SEL_SIZE][16];
 104    unsigned int next_free;
 105    long time_offset;
 106    uint16_t reservation;
 107    uint8_t last_addition[4];
 108    uint8_t last_clear[4];
 109    uint8_t overflow;
 110} IPMISel;
 111
 112#define MAX_SDR_SIZE 16384
 113
 114typedef struct IPMISdr {
 115    uint8_t sdr[MAX_SDR_SIZE];
 116    unsigned int next_free;
 117    uint16_t next_rec_id;
 118    uint16_t reservation;
 119    uint8_t last_addition[4];
 120    uint8_t last_clear[4];
 121    uint8_t overflow;
 122} IPMISdr;
 123
 124typedef struct IPMISensor {
 125    uint8_t status;
 126    uint8_t reading;
 127    uint16_t states_suppt;
 128    uint16_t assert_suppt;
 129    uint16_t deassert_suppt;
 130    uint16_t states;
 131    uint16_t assert_states;
 132    uint16_t deassert_states;
 133    uint16_t assert_enable;
 134    uint16_t deassert_enable;
 135    uint8_t  sensor_type;
 136    uint8_t  evt_reading_type_code;
 137} IPMISensor;
 138#define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
 139#define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
 140                                             !!(v))
 141#define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
 142#define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
 143                                             ((!!(v)) << 6))
 144#define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
 145#define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
 146                                             ((!!(v)) << 7))
 147#define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
 148#define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
 149                                             (v & 0xc0))
 150#define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
 151
 152#define MAX_SENSORS 20
 153#define IPMI_WATCHDOG_SENSOR 0
 154
 155typedef struct IPMIBmcSim IPMIBmcSim;
 156typedef struct RspBuffer RspBuffer;
 157
 158#define MAX_NETFNS 64
 159
 160typedef struct IPMICmdHandler {
 161    void (*cmd_handler)(IPMIBmcSim *s,
 162                        uint8_t *cmd, unsigned int cmd_len,
 163                        RspBuffer *rsp);
 164    unsigned int cmd_len_min;
 165} IPMICmdHandler;
 166
 167typedef struct IPMINetfn {
 168    unsigned int cmd_nums;
 169    const IPMICmdHandler *cmd_handlers;
 170} IPMINetfn;
 171
 172typedef struct IPMIRcvBufEntry {
 173    QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
 174    uint8_t len;
 175    uint8_t buf[MAX_IPMI_MSG_SIZE];
 176} IPMIRcvBufEntry;
 177
 178#define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
 179#define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
 180                                        TYPE_IPMI_BMC_SIMULATOR)
 181struct IPMIBmcSim {
 182    IPMIBmc parent;
 183
 184    QEMUTimer *timer;
 185
 186    uint8_t bmc_global_enables;
 187    uint8_t msg_flags;
 188
 189    bool     watchdog_initialized;
 190    uint8_t  watchdog_use;
 191    uint8_t  watchdog_action;
 192    uint8_t  watchdog_pretimeout; /* In seconds */
 193    bool     watchdog_expired;
 194    uint16_t watchdog_timeout; /* in 100's of milliseconds */
 195
 196    bool     watchdog_running;
 197    bool     watchdog_preaction_ran;
 198    int64_t  watchdog_expiry;
 199
 200    uint8_t device_id;
 201    uint8_t ipmi_version;
 202    uint8_t device_rev;
 203    uint8_t fwrev1;
 204    uint8_t fwrev2;
 205    uint8_t mfg_id[3];
 206    uint8_t product_id[2];
 207
 208    uint8_t restart_cause;
 209
 210    uint8_t acpi_power_state[2];
 211    uint8_t uuid[16];
 212
 213    IPMISel sel;
 214    IPMISdr sdr;
 215    IPMISensor sensors[MAX_SENSORS];
 216
 217    /* Odd netfns are for responses, so we only need the even ones. */
 218    const IPMINetfn *netfns[MAX_NETFNS / 2];
 219
 220    /* We allow one event in the buffer */
 221    uint8_t evtbuf[16];
 222
 223    QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
 224};
 225
 226#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
 227#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
 228#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
 229#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
 230    (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
 231#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
 232    (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
 233#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
 234    (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
 235
 236#define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
 237#define IPMI_BMC_EVBUF_FULL_INT_BIT       1
 238#define IPMI_BMC_EVENT_MSG_BUF_BIT        2
 239#define IPMI_BMC_EVENT_LOG_BIT            3
 240#define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
 241                                 (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
 242#define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
 243                                        (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
 244#define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
 245                                       (1 << IPMI_BMC_EVENT_LOG_BIT))
 246#define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
 247                                           (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
 248
 249#define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
 250#define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
 251#define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
 252#define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
 253#define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
 254#define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
 255#define IPMI_BMC_WATCHDOG_PRE_NONE               0
 256#define IPMI_BMC_WATCHDOG_PRE_SMI                1
 257#define IPMI_BMC_WATCHDOG_PRE_NMI                2
 258#define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
 259#define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
 260#define IPMI_BMC_WATCHDOG_ACTION_NONE            0
 261#define IPMI_BMC_WATCHDOG_ACTION_RESET           1
 262#define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
 263#define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
 264
 265struct RspBuffer {
 266    uint8_t buffer[MAX_IPMI_MSG_SIZE];
 267    unsigned int len;
 268};
 269
 270#define RSP_BUFFER_INITIALIZER { }
 271
 272static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
 273{
 274    rsp->buffer[2] = byte;
 275}
 276
 277/* Add a byte to the response. */
 278static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
 279{
 280    if (rsp->len >= sizeof(rsp->buffer)) {
 281        rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
 282        return;
 283    }
 284    rsp->buffer[rsp->len++] = byte;
 285}
 286
 287static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
 288                                       unsigned int n)
 289{
 290    if (rsp->len + n >= sizeof(rsp->buffer)) {
 291        rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
 292        return;
 293    }
 294
 295    memcpy(&rsp->buffer[rsp->len], bytes, n);
 296    rsp->len += n;
 297}
 298
 299static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
 300
 301static void ipmi_gettime(struct ipmi_time *time)
 302{
 303    int64_t stime;
 304
 305    stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
 306    time->tv_sec = stime / 1000000000LL;
 307    time->tv_nsec = stime % 1000000000LL;
 308}
 309
 310static int64_t ipmi_getmonotime(void)
 311{
 312    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 313}
 314
 315static void ipmi_timeout(void *opaque)
 316{
 317    IPMIBmcSim *ibs = opaque;
 318
 319    ipmi_sim_handle_timeout(ibs);
 320}
 321
 322static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
 323{
 324    unsigned int val;
 325    struct ipmi_time now;
 326
 327    ipmi_gettime(&now);
 328    val = now.tv_sec + ibs->sel.time_offset;
 329    ts[0] = val & 0xff;
 330    ts[1] = (val >> 8) & 0xff;
 331    ts[2] = (val >> 16) & 0xff;
 332    ts[3] = (val >> 24) & 0xff;
 333}
 334
 335static void sdr_inc_reservation(IPMISdr *sdr)
 336{
 337    sdr->reservation++;
 338    if (sdr->reservation == 0) {
 339        sdr->reservation = 1;
 340    }
 341}
 342
 343static int sdr_add_entry(IPMIBmcSim *ibs,
 344                         const struct ipmi_sdr_header *sdrh_entry,
 345                         unsigned int len, uint16_t *recid)
 346{
 347    struct ipmi_sdr_header *sdrh =
 348        (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
 349
 350    if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
 351        return 1;
 352    }
 353
 354    if (ipmi_sdr_length(sdrh_entry) != len) {
 355        return 1;
 356    }
 357
 358    if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
 359        ibs->sdr.overflow = 1;
 360        return 1;
 361    }
 362
 363    memcpy(sdrh, sdrh_entry, len);
 364    sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
 365    sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
 366    sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
 367
 368    if (recid) {
 369        *recid = ibs->sdr.next_rec_id;
 370    }
 371    ibs->sdr.next_rec_id++;
 372    set_timestamp(ibs, ibs->sdr.last_addition);
 373    ibs->sdr.next_free += len;
 374    sdr_inc_reservation(&ibs->sdr);
 375    return 0;
 376}
 377
 378static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
 379                          unsigned int *retpos, uint16_t *nextrec)
 380{
 381    unsigned int pos = *retpos;
 382
 383    while (pos < sdr->next_free) {
 384        struct ipmi_sdr_header *sdrh =
 385            (struct ipmi_sdr_header *) &sdr->sdr[pos];
 386        uint16_t trec = ipmi_sdr_recid(sdrh);
 387        unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
 388
 389        if (trec == recid) {
 390            if (nextrec) {
 391                if (nextpos >= sdr->next_free) {
 392                    *nextrec = 0xffff;
 393                } else {
 394                    *nextrec = (sdr->sdr[nextpos] |
 395                                (sdr->sdr[nextpos + 1] << 8));
 396                }
 397            }
 398            *retpos = pos;
 399            return 0;
 400        }
 401        pos = nextpos;
 402    }
 403    return 1;
 404}
 405
 406static void sel_inc_reservation(IPMISel *sel)
 407{
 408    sel->reservation++;
 409    if (sel->reservation == 0) {
 410        sel->reservation = 1;
 411    }
 412}
 413
 414/* Returns 1 if the SEL is full and can't hold the event. */
 415static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
 416{
 417    event[0] = 0xff;
 418    event[1] = 0xff;
 419    set_timestamp(ibs, event + 3);
 420    if (ibs->sel.next_free == MAX_SEL_SIZE) {
 421        ibs->sel.overflow = 1;
 422        return 1;
 423    }
 424    event[0] = ibs->sel.next_free & 0xff;
 425    event[1] = (ibs->sel.next_free >> 8) & 0xff;
 426    memcpy(ibs->sel.last_addition, event + 3, 4);
 427    memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
 428    ibs->sel.next_free++;
 429    sel_inc_reservation(&ibs->sel);
 430    return 0;
 431}
 432
 433static int attn_set(IPMIBmcSim *ibs)
 434{
 435    return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
 436        || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
 437        || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
 438}
 439
 440static int attn_irq_enabled(IPMIBmcSim *ibs)
 441{
 442    return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
 443        || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
 444            IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
 445}
 446
 447static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
 448                      uint8_t evd1, uint8_t evd2, uint8_t evd3)
 449{
 450    IPMIInterface *s = ibs->parent.intf;
 451    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 452    uint8_t evt[16];
 453    IPMISensor *sens = ibs->sensors + sens_num;
 454
 455    if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
 456        return;
 457    }
 458    if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
 459        return;
 460    }
 461
 462    evt[2] = 0x2; /* System event record */
 463    evt[7] = ibs->parent.slave_addr;
 464    evt[8] = 0;
 465    evt[9] = 0x04; /* Format version */
 466    evt[10] = sens->sensor_type;
 467    evt[11] = sens_num;
 468    evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
 469    evt[13] = evd1;
 470    evt[14] = evd2;
 471    evt[15] = evd3;
 472
 473    if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
 474        sel_add_event(ibs, evt);
 475    }
 476
 477    if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
 478        return;
 479    }
 480
 481    memcpy(ibs->evtbuf, evt, 16);
 482    ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
 483    k->set_atn(s, 1, attn_irq_enabled(ibs));
 484}
 485
 486static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
 487                                    unsigned int bit, unsigned int val,
 488                                    uint8_t evd1, uint8_t evd2, uint8_t evd3)
 489{
 490    IPMISensor *sens;
 491    uint16_t mask;
 492
 493    if (sensor >= MAX_SENSORS) {
 494        return;
 495    }
 496    if (bit >= 16) {
 497        return;
 498    }
 499
 500    mask = (1 << bit);
 501    sens = ibs->sensors + sensor;
 502    if (val) {
 503        sens->states |= mask & sens->states_suppt;
 504        if (sens->assert_states & mask) {
 505            return; /* Already asserted */
 506        }
 507        sens->assert_states |= mask & sens->assert_suppt;
 508        if (sens->assert_enable & mask & sens->assert_states) {
 509            /* Send an event on assert */
 510            gen_event(ibs, sensor, 0, evd1, evd2, evd3);
 511        }
 512    } else {
 513        sens->states &= ~(mask & sens->states_suppt);
 514        if (sens->deassert_states & mask) {
 515            return; /* Already deasserted */
 516        }
 517        sens->deassert_states |= mask & sens->deassert_suppt;
 518        if (sens->deassert_enable & mask & sens->deassert_states) {
 519            /* Send an event on deassert */
 520            gen_event(ibs, sensor, 1, evd1, evd2, evd3);
 521        }
 522    }
 523}
 524
 525static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
 526{
 527    unsigned int i, pos;
 528    IPMISensor *sens;
 529
 530    for (i = 0; i < MAX_SENSORS; i++) {
 531        memset(s->sensors + i, 0, sizeof(*sens));
 532    }
 533
 534    pos = 0;
 535    for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
 536        struct ipmi_sdr_compact *sdr =
 537            (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
 538        unsigned int len = sdr->header.rec_length;
 539
 540        if (len < 20) {
 541            continue;
 542        }
 543        if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
 544            continue; /* Not a sensor SDR we set from */
 545        }
 546
 547        if (sdr->sensor_owner_number >= MAX_SENSORS) {
 548            continue;
 549        }
 550        sens = s->sensors + sdr->sensor_owner_number;
 551
 552        IPMI_SENSOR_SET_PRESENT(sens, 1);
 553        IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
 554        IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
 555        sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
 556        sens->deassert_suppt =
 557            sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
 558        sens->states_suppt =
 559            sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
 560        sens->sensor_type = sdr->sensor_type;
 561        sens->evt_reading_type_code = sdr->reading_type & 0x7f;
 562
 563        /* Enable all the events that are supported. */
 564        sens->assert_enable = sens->assert_suppt;
 565        sens->deassert_enable = sens->deassert_suppt;
 566    }
 567}
 568
 569static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
 570                               const IPMINetfn *netfnd)
 571{
 572    if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
 573        return -1;
 574    }
 575    s->netfns[netfn / 2] = netfnd;
 576    return 0;
 577}
 578
 579static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
 580                                              unsigned int netfn,
 581                                              unsigned int cmd)
 582{
 583    const IPMICmdHandler *hdl;
 584
 585    if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
 586        return NULL;
 587    }
 588
 589    if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
 590        return NULL;
 591    }
 592
 593    hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
 594    if (!hdl->cmd_handler) {
 595        return NULL;
 596    }
 597
 598    return hdl;
 599}
 600
 601static void next_timeout(IPMIBmcSim *ibs)
 602{
 603    int64_t next;
 604    if (ibs->watchdog_running) {
 605        next = ibs->watchdog_expiry;
 606    } else {
 607        /* Wait a minute */
 608        next = ipmi_getmonotime() + 60 * 1000000000LL;
 609    }
 610    timer_mod_ns(ibs->timer, next);
 611}
 612
 613static void ipmi_sim_handle_command(IPMIBmc *b,
 614                                    uint8_t *cmd, unsigned int cmd_len,
 615                                    unsigned int max_cmd_len,
 616                                    uint8_t msg_id)
 617{
 618    IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
 619    IPMIInterface *s = ibs->parent.intf;
 620    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 621    const IPMICmdHandler *hdl;
 622    RspBuffer rsp = RSP_BUFFER_INITIALIZER;
 623
 624    /* Set up the response, set the low bit of NETFN. */
 625    /* Note that max_rsp_len must be at least 3 */
 626    if (sizeof(rsp.buffer) < 3) {
 627        rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
 628        goto out;
 629    }
 630
 631    rsp_buffer_push(&rsp, cmd[0] | 0x04);
 632    rsp_buffer_push(&rsp, cmd[1]);
 633    rsp_buffer_push(&rsp, 0); /* Assume success */
 634
 635    /* If it's too short or it was truncated, return an error. */
 636    if (cmd_len < 2) {
 637        rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
 638        goto out;
 639    }
 640    if (cmd_len > max_cmd_len) {
 641        rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
 642        goto out;
 643    }
 644
 645    if ((cmd[0] & 0x03) != 0) {
 646        /* Only have stuff on LUN 0 */
 647        rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
 648        goto out;
 649    }
 650
 651    hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
 652    if (!hdl) {
 653        rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
 654        goto out;
 655    }
 656
 657    if (cmd_len < hdl->cmd_len_min) {
 658        rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
 659        goto out;
 660    }
 661
 662    hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
 663
 664 out:
 665    k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
 666
 667    next_timeout(ibs);
 668}
 669
 670static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
 671{
 672    IPMIInterface *s = ibs->parent.intf;
 673    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 674
 675    if (!ibs->watchdog_running) {
 676        goto out;
 677    }
 678
 679    if (!ibs->watchdog_preaction_ran) {
 680        switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
 681        case IPMI_BMC_WATCHDOG_PRE_NMI:
 682            ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
 683            k->do_hw_op(s, IPMI_SEND_NMI, 0);
 684            sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
 685                                    0xc8, (2 << 4) | 0xf, 0xff);
 686            break;
 687
 688        case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
 689            ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
 690            k->set_atn(s, 1, attn_irq_enabled(ibs));
 691            sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
 692                                    0xc8, (3 << 4) | 0xf, 0xff);
 693            break;
 694
 695        default:
 696            goto do_full_expiry;
 697        }
 698
 699        ibs->watchdog_preaction_ran = 1;
 700        /* Issued the pretimeout, do the rest of the timeout now. */
 701        ibs->watchdog_expiry = ipmi_getmonotime();
 702        ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
 703        goto out;
 704    }
 705
 706 do_full_expiry:
 707    ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
 708    ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
 709    switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
 710    case IPMI_BMC_WATCHDOG_ACTION_NONE:
 711        sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
 712                                0xc0, ibs->watchdog_use & 0xf, 0xff);
 713        break;
 714
 715    case IPMI_BMC_WATCHDOG_ACTION_RESET:
 716        sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
 717                                0xc1, ibs->watchdog_use & 0xf, 0xff);
 718        k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
 719        break;
 720
 721    case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
 722        sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
 723                                0xc2, ibs->watchdog_use & 0xf, 0xff);
 724        k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
 725        break;
 726
 727    case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
 728        sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
 729                                0xc3, ibs->watchdog_use & 0xf, 0xff);
 730        k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
 731        break;
 732    }
 733
 734 out:
 735    next_timeout(ibs);
 736}
 737
 738static void chassis_capabilities(IPMIBmcSim *ibs,
 739                                 uint8_t *cmd, unsigned int cmd_len,
 740                                 RspBuffer *rsp)
 741{
 742    rsp_buffer_push(rsp, 0);
 743    rsp_buffer_push(rsp, ibs->parent.slave_addr);
 744    rsp_buffer_push(rsp, ibs->parent.slave_addr);
 745    rsp_buffer_push(rsp, ibs->parent.slave_addr);
 746    rsp_buffer_push(rsp, ibs->parent.slave_addr);
 747}
 748
 749static void chassis_status(IPMIBmcSim *ibs,
 750                           uint8_t *cmd, unsigned int cmd_len,
 751                           RspBuffer *rsp)
 752{
 753    rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
 754    rsp_buffer_push(rsp, 0);
 755    rsp_buffer_push(rsp, 0);
 756    rsp_buffer_push(rsp, 0);
 757}
 758
 759static void chassis_control(IPMIBmcSim *ibs,
 760                            uint8_t *cmd, unsigned int cmd_len,
 761                            RspBuffer *rsp)
 762{
 763    IPMIInterface *s = ibs->parent.intf;
 764    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 765
 766    switch (cmd[2] & 0xf) {
 767    case 0: /* power down */
 768        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
 769        break;
 770    case 1: /* power up */
 771        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
 772        break;
 773    case 2: /* power cycle */
 774        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
 775        break;
 776    case 3: /* hard reset */
 777        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
 778        break;
 779    case 4: /* pulse diagnostic interrupt */
 780        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
 781        break;
 782    case 5: /* soft shutdown via ACPI by overtemp emulation */
 783        rsp_buffer_set_error(rsp, k->do_hw_op(s,
 784                                          IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
 785        break;
 786    default:
 787        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
 788        return;
 789    }
 790}
 791
 792static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
 793                           uint8_t *cmd, unsigned int cmd_len,
 794                           RspBuffer *rsp)
 795
 796{
 797    rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
 798    rsp_buffer_push(rsp, 0);  /* Channel 0 */
 799}
 800
 801static void get_device_id(IPMIBmcSim *ibs,
 802                          uint8_t *cmd, unsigned int cmd_len,
 803                          RspBuffer *rsp)
 804{
 805    rsp_buffer_push(rsp, ibs->device_id);
 806    rsp_buffer_push(rsp, ibs->device_rev & 0xf);
 807    rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
 808    rsp_buffer_push(rsp, ibs->fwrev2);
 809    rsp_buffer_push(rsp, ibs->ipmi_version);
 810    rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
 811    rsp_buffer_push(rsp, ibs->mfg_id[0]);
 812    rsp_buffer_push(rsp, ibs->mfg_id[1]);
 813    rsp_buffer_push(rsp, ibs->mfg_id[2]);
 814    rsp_buffer_push(rsp, ibs->product_id[0]);
 815    rsp_buffer_push(rsp, ibs->product_id[1]);
 816}
 817
 818static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
 819{
 820    IPMIInterface *s = ibs->parent.intf;
 821    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 822    bool irqs_on;
 823
 824    ibs->bmc_global_enables = val;
 825
 826    irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
 827                     IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
 828
 829    k->set_irq_enable(s, irqs_on);
 830}
 831
 832static void cold_reset(IPMIBmcSim *ibs,
 833                       uint8_t *cmd, unsigned int cmd_len,
 834                       RspBuffer *rsp)
 835{
 836    IPMIInterface *s = ibs->parent.intf;
 837    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 838
 839    /* Disable all interrupts */
 840    set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
 841
 842    if (k->reset) {
 843        k->reset(s, true);
 844    }
 845}
 846
 847static void warm_reset(IPMIBmcSim *ibs,
 848                       uint8_t *cmd, unsigned int cmd_len,
 849                       RspBuffer *rsp)
 850{
 851    IPMIInterface *s = ibs->parent.intf;
 852    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 853
 854    if (k->reset) {
 855        k->reset(s, false);
 856    }
 857}
 858static void set_acpi_power_state(IPMIBmcSim *ibs,
 859                                 uint8_t *cmd, unsigned int cmd_len,
 860                                 RspBuffer *rsp)
 861{
 862    ibs->acpi_power_state[0] = cmd[2];
 863    ibs->acpi_power_state[1] = cmd[3];
 864}
 865
 866static void get_acpi_power_state(IPMIBmcSim *ibs,
 867                                 uint8_t *cmd, unsigned int cmd_len,
 868                                 RspBuffer *rsp)
 869{
 870    rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
 871    rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
 872}
 873
 874static void get_device_guid(IPMIBmcSim *ibs,
 875                            uint8_t *cmd, unsigned int cmd_len,
 876                            RspBuffer *rsp)
 877{
 878    unsigned int i;
 879
 880    for (i = 0; i < 16; i++) {
 881        rsp_buffer_push(rsp, ibs->uuid[i]);
 882    }
 883}
 884
 885static void set_bmc_global_enables(IPMIBmcSim *ibs,
 886                                   uint8_t *cmd, unsigned int cmd_len,
 887                                   RspBuffer *rsp)
 888{
 889    set_global_enables(ibs, cmd[2]);
 890}
 891
 892static void get_bmc_global_enables(IPMIBmcSim *ibs,
 893                                   uint8_t *cmd, unsigned int cmd_len,
 894                                   RspBuffer *rsp)
 895{
 896    rsp_buffer_push(rsp, ibs->bmc_global_enables);
 897}
 898
 899static void clr_msg_flags(IPMIBmcSim *ibs,
 900                          uint8_t *cmd, unsigned int cmd_len,
 901                          RspBuffer *rsp)
 902{
 903    IPMIInterface *s = ibs->parent.intf;
 904    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 905
 906    ibs->msg_flags &= ~cmd[2];
 907    k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
 908}
 909
 910static void get_msg_flags(IPMIBmcSim *ibs,
 911                          uint8_t *cmd, unsigned int cmd_len,
 912                          RspBuffer *rsp)
 913{
 914    rsp_buffer_push(rsp, ibs->msg_flags);
 915}
 916
 917static void read_evt_msg_buf(IPMIBmcSim *ibs,
 918                             uint8_t *cmd, unsigned int cmd_len,
 919                             RspBuffer *rsp)
 920{
 921    IPMIInterface *s = ibs->parent.intf;
 922    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 923    unsigned int i;
 924
 925    if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
 926        rsp_buffer_set_error(rsp, 0x80);
 927        return;
 928    }
 929    for (i = 0; i < 16; i++) {
 930        rsp_buffer_push(rsp, ibs->evtbuf[i]);
 931    }
 932    ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
 933    k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
 934}
 935
 936static void get_msg(IPMIBmcSim *ibs,
 937                    uint8_t *cmd, unsigned int cmd_len,
 938                    RspBuffer *rsp)
 939{
 940    IPMIRcvBufEntry *msg;
 941
 942    if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
 943        rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
 944        goto out;
 945    }
 946    rsp_buffer_push(rsp, 0); /* Channel 0 */
 947    msg = QTAILQ_FIRST(&ibs->rcvbufs);
 948    rsp_buffer_pushmore(rsp, msg->buf, msg->len);
 949    QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
 950    g_free(msg);
 951
 952    if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
 953        IPMIInterface *s = ibs->parent.intf;
 954        IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 955
 956        ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
 957        k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
 958    }
 959
 960out:
 961    return;
 962}
 963
 964static unsigned char
 965ipmb_checksum(unsigned char *data, int size, unsigned char csum)
 966{
 967    for (; size > 0; size--, data++) {
 968            csum += *data;
 969    }
 970
 971    return -csum;
 972}
 973
 974static void send_msg(IPMIBmcSim *ibs,
 975                     uint8_t *cmd, unsigned int cmd_len,
 976                     RspBuffer *rsp)
 977{
 978    IPMIInterface *s = ibs->parent.intf;
 979    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
 980    IPMIRcvBufEntry *msg;
 981    uint8_t *buf;
 982    uint8_t netfn, rqLun, rsLun, rqSeq;
 983
 984    if (cmd[2] != 0) {
 985        /* We only handle channel 0 with no options */
 986        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
 987        return;
 988    }
 989
 990    if (cmd_len < 10) {
 991        rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
 992        return;
 993    }
 994
 995    if (cmd[3] != 0x40) {
 996        /* We only emulate a MC at address 0x40. */
 997        rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
 998        return;
 999    }
1000
1001    cmd += 3; /* Skip the header. */
1002    cmd_len -= 3;
1003
1004    /*
1005     * At this point we "send" the message successfully.  Any error will
1006     * be returned in the response.
1007     */
1008    if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
1009        cmd[3] != 0x20) { /* Improper response address */
1010        return; /* No response */
1011    }
1012
1013    netfn = cmd[1] >> 2;
1014    rqLun = cmd[4] & 0x3;
1015    rsLun = cmd[1] & 0x3;
1016    rqSeq = cmd[4] >> 2;
1017
1018    if (rqLun != 2) {
1019        /* We only support LUN 2 coming back to us. */
1020        return;
1021    }
1022
1023    msg = g_malloc(sizeof(*msg));
1024    msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
1025    msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
1026    msg->buf[2] = cmd[0]; /* rsSA */
1027    msg->buf[3] = (rqSeq << 2) | rsLun;
1028    msg->buf[4] = cmd[5]; /* Cmd */
1029    msg->buf[5] = 0; /* Completion Code */
1030    msg->len = 6;
1031
1032    if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
1033        /* Not a command we handle. */
1034        msg->buf[5] = IPMI_CC_INVALID_CMD;
1035        goto end_msg;
1036    }
1037
1038    buf = msg->buf + msg->len; /* After the CC */
1039    buf[0] = 0;
1040    buf[1] = 0;
1041    buf[2] = 0;
1042    buf[3] = 0;
1043    buf[4] = 0x51;
1044    buf[5] = 0;
1045    buf[6] = 0;
1046    buf[7] = 0;
1047    buf[8] = 0;
1048    buf[9] = 0;
1049    buf[10] = 0;
1050    msg->len += 11;
1051
1052 end_msg:
1053    msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1054    msg->len++;
1055    QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1056    ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1057    k->set_atn(s, 1, attn_irq_enabled(ibs));
1058}
1059
1060static void do_watchdog_reset(IPMIBmcSim *ibs)
1061{
1062    if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1063        IPMI_BMC_WATCHDOG_ACTION_NONE) {
1064        ibs->watchdog_running = 0;
1065        return;
1066    }
1067    ibs->watchdog_preaction_ran = 0;
1068
1069
1070    /* Timeout is in tenths of a second, offset is in seconds */
1071    ibs->watchdog_expiry = ipmi_getmonotime();
1072    ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1073    if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1074        ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1075    }
1076    ibs->watchdog_running = 1;
1077}
1078
1079static void reset_watchdog_timer(IPMIBmcSim *ibs,
1080                                 uint8_t *cmd, unsigned int cmd_len,
1081                                 RspBuffer *rsp)
1082{
1083    if (!ibs->watchdog_initialized) {
1084        rsp_buffer_set_error(rsp, 0x80);
1085        return;
1086    }
1087    do_watchdog_reset(ibs);
1088}
1089
1090static void set_watchdog_timer(IPMIBmcSim *ibs,
1091                               uint8_t *cmd, unsigned int cmd_len,
1092                               RspBuffer *rsp)
1093{
1094    IPMIInterface *s = ibs->parent.intf;
1095    IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1096    unsigned int val;
1097
1098    val = cmd[2] & 0x7; /* Validate use */
1099    if (val == 0 || val > 5) {
1100        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1101        return;
1102    }
1103    val = cmd[3] & 0x7; /* Validate action */
1104    switch (val) {
1105    case IPMI_BMC_WATCHDOG_ACTION_NONE:
1106        break;
1107
1108    case IPMI_BMC_WATCHDOG_ACTION_RESET:
1109        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
1110        break;
1111
1112    case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
1113        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
1114        break;
1115
1116    case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
1117        rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
1118        break;
1119
1120    default:
1121        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1122    }
1123    if (rsp->buffer[2]) {
1124        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1125        return;
1126    }
1127
1128    val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1129    switch (val) {
1130    case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1131    case IPMI_BMC_WATCHDOG_PRE_NONE:
1132        break;
1133
1134    case IPMI_BMC_WATCHDOG_PRE_NMI:
1135        if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
1136            /* NMI not supported. */
1137            rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1138            return;
1139        }
1140        break;
1141
1142    default:
1143        /* We don't support PRE_SMI */
1144        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1145        return;
1146    }
1147
1148    ibs->watchdog_initialized = 1;
1149    ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1150    ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1151    ibs->watchdog_pretimeout = cmd[4];
1152    ibs->watchdog_expired &= ~cmd[5];
1153    ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1154    if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1155        do_watchdog_reset(ibs);
1156    } else {
1157        ibs->watchdog_running = 0;
1158    }
1159}
1160
1161static void get_watchdog_timer(IPMIBmcSim *ibs,
1162                               uint8_t *cmd, unsigned int cmd_len,
1163                               RspBuffer *rsp)
1164{
1165    rsp_buffer_push(rsp, ibs->watchdog_use);
1166    rsp_buffer_push(rsp, ibs->watchdog_action);
1167    rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1168    rsp_buffer_push(rsp, ibs->watchdog_expired);
1169    if (ibs->watchdog_running) {
1170        long timeout;
1171        timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1172                   / 100000000);
1173        rsp_buffer_push(rsp, timeout & 0xff);
1174        rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
1175    } else {
1176        rsp_buffer_push(rsp, 0);
1177        rsp_buffer_push(rsp, 0);
1178    }
1179}
1180
1181static void get_sdr_rep_info(IPMIBmcSim *ibs,
1182                             uint8_t *cmd, unsigned int cmd_len,
1183                             RspBuffer *rsp)
1184{
1185    unsigned int i;
1186
1187    rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1188    rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1189    rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1190    rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1191    rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
1192    for (i = 0; i < 4; i++) {
1193        rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
1194    }
1195    for (i = 0; i < 4; i++) {
1196        rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
1197    }
1198    /* Only modal support, reserve supported */
1199    rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
1200}
1201
1202static void reserve_sdr_rep(IPMIBmcSim *ibs,
1203                            uint8_t *cmd, unsigned int cmd_len,
1204                            RspBuffer *rsp)
1205{
1206    rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1207    rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
1208}
1209
1210static void get_sdr(IPMIBmcSim *ibs,
1211                    uint8_t *cmd, unsigned int cmd_len,
1212                    RspBuffer *rsp)
1213{
1214    unsigned int pos;
1215    uint16_t nextrec;
1216    struct ipmi_sdr_header *sdrh;
1217
1218    if (cmd[6]) {
1219        if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1220            rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1221            return;
1222        }
1223    }
1224
1225    pos = 0;
1226    if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1227                       &pos, &nextrec)) {
1228        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1229        return;
1230    }
1231
1232    sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1233
1234    if (cmd[6] > ipmi_sdr_length(sdrh)) {
1235        rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1236        return;
1237    }
1238
1239    rsp_buffer_push(rsp, nextrec & 0xff);
1240    rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
1241
1242    if (cmd[7] == 0xff) {
1243        cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
1244    }
1245
1246    if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
1247        rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1248        return;
1249    }
1250
1251    rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
1252}
1253
1254static void add_sdr(IPMIBmcSim *ibs,
1255                    uint8_t *cmd, unsigned int cmd_len,
1256                    RspBuffer *rsp)
1257{
1258    uint16_t recid;
1259    struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
1260
1261    if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
1262        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1263        return;
1264    }
1265    rsp_buffer_push(rsp, recid & 0xff);
1266    rsp_buffer_push(rsp, (recid >> 8) & 0xff);
1267}
1268
1269static void clear_sdr_rep(IPMIBmcSim *ibs,
1270                          uint8_t *cmd, unsigned int cmd_len,
1271                          RspBuffer *rsp)
1272{
1273    if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1274        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1275        return;
1276    }
1277
1278    if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1279        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1280        return;
1281    }
1282    if (cmd[7] == 0xaa) {
1283        ibs->sdr.next_free = 0;
1284        ibs->sdr.overflow = 0;
1285        set_timestamp(ibs, ibs->sdr.last_clear);
1286        rsp_buffer_push(rsp, 1); /* Erasure complete */
1287        sdr_inc_reservation(&ibs->sdr);
1288    } else if (cmd[7] == 0) {
1289        rsp_buffer_push(rsp, 1); /* Erasure complete */
1290    } else {
1291        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1292        return;
1293    }
1294}
1295
1296static void get_sel_info(IPMIBmcSim *ibs,
1297                         uint8_t *cmd, unsigned int cmd_len,
1298                         RspBuffer *rsp)
1299{
1300    unsigned int i, val;
1301
1302    rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1303    rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1304    rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
1305    val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1306    rsp_buffer_push(rsp, val & 0xff);
1307    rsp_buffer_push(rsp, (val >> 8) & 0xff);
1308    for (i = 0; i < 4; i++) {
1309        rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
1310    }
1311    for (i = 0; i < 4; i++) {
1312        rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
1313    }
1314    /* Only support Reserve SEL */
1315    rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
1316}
1317
1318static void reserve_sel(IPMIBmcSim *ibs,
1319                        uint8_t *cmd, unsigned int cmd_len,
1320                        RspBuffer *rsp)
1321{
1322    rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1323    rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
1324}
1325
1326static void get_sel_entry(IPMIBmcSim *ibs,
1327                          uint8_t *cmd, unsigned int cmd_len,
1328                          RspBuffer *rsp)
1329{
1330    unsigned int val;
1331
1332    if (cmd[6]) {
1333        if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1334            rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1335            return;
1336        }
1337    }
1338    if (ibs->sel.next_free == 0) {
1339        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1340        return;
1341    }
1342    if (cmd[6] > 15) {
1343        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1344        return;
1345    }
1346    if (cmd[7] == 0xff) {
1347        cmd[7] = 16;
1348    } else if ((cmd[7] + cmd[6]) > 16) {
1349        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1350        return;
1351    } else {
1352        cmd[7] += cmd[6];
1353    }
1354
1355    val = cmd[4] | (cmd[5] << 8);
1356    if (val == 0xffff) {
1357        val = ibs->sel.next_free - 1;
1358    } else if (val >= ibs->sel.next_free) {
1359        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1360        return;
1361    }
1362    if ((val + 1) == ibs->sel.next_free) {
1363        rsp_buffer_push(rsp, 0xff);
1364        rsp_buffer_push(rsp, 0xff);
1365    } else {
1366        rsp_buffer_push(rsp, (val + 1) & 0xff);
1367        rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
1368    }
1369    for (; cmd[6] < cmd[7]; cmd[6]++) {
1370        rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
1371    }
1372}
1373
1374static void add_sel_entry(IPMIBmcSim *ibs,
1375                          uint8_t *cmd, unsigned int cmd_len,
1376                          RspBuffer *rsp)
1377{
1378    if (sel_add_event(ibs, cmd + 2)) {
1379        rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1380        return;
1381    }
1382    /* sel_add_event fills in the record number. */
1383    rsp_buffer_push(rsp, cmd[2]);
1384    rsp_buffer_push(rsp, cmd[3]);
1385}
1386
1387static void clear_sel(IPMIBmcSim *ibs,
1388                      uint8_t *cmd, unsigned int cmd_len,
1389                      RspBuffer *rsp)
1390{
1391    if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1392        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1393        return;
1394    }
1395
1396    if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1397        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1398        return;
1399    }
1400    if (cmd[7] == 0xaa) {
1401        ibs->sel.next_free = 0;
1402        ibs->sel.overflow = 0;
1403        set_timestamp(ibs, ibs->sdr.last_clear);
1404        rsp_buffer_push(rsp, 1); /* Erasure complete */
1405        sel_inc_reservation(&ibs->sel);
1406    } else if (cmd[7] == 0) {
1407        rsp_buffer_push(rsp, 1); /* Erasure complete */
1408    } else {
1409        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1410        return;
1411    }
1412}
1413
1414static void get_sel_time(IPMIBmcSim *ibs,
1415                         uint8_t *cmd, unsigned int cmd_len,
1416                         RspBuffer *rsp)
1417{
1418    uint32_t val;
1419    struct ipmi_time now;
1420
1421    ipmi_gettime(&now);
1422    val = now.tv_sec + ibs->sel.time_offset;
1423    rsp_buffer_push(rsp, val & 0xff);
1424    rsp_buffer_push(rsp, (val >> 8) & 0xff);
1425    rsp_buffer_push(rsp, (val >> 16) & 0xff);
1426    rsp_buffer_push(rsp, (val >> 24) & 0xff);
1427}
1428
1429static void set_sel_time(IPMIBmcSim *ibs,
1430                         uint8_t *cmd, unsigned int cmd_len,
1431                         RspBuffer *rsp)
1432{
1433    uint32_t val;
1434    struct ipmi_time now;
1435
1436    val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1437    ipmi_gettime(&now);
1438    ibs->sel.time_offset = now.tv_sec - ((long) val);
1439}
1440
1441static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1442                                  uint8_t *cmd, unsigned int cmd_len,
1443                                  RspBuffer *rsp)
1444{
1445    IPMISensor *sens;
1446
1447    if ((cmd[2] >= MAX_SENSORS) ||
1448            !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1449        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1450        return;
1451    }
1452    sens = ibs->sensors + cmd[2];
1453    switch ((cmd[3] >> 4) & 0x3) {
1454    case 0: /* Do not change */
1455        break;
1456    case 1: /* Enable bits */
1457        if (cmd_len > 4) {
1458            sens->assert_enable |= cmd[4];
1459        }
1460        if (cmd_len > 5) {
1461            sens->assert_enable |= cmd[5] << 8;
1462        }
1463        if (cmd_len > 6) {
1464            sens->deassert_enable |= cmd[6];
1465        }
1466        if (cmd_len > 7) {
1467            sens->deassert_enable |= cmd[7] << 8;
1468        }
1469        break;
1470    case 2: /* Disable bits */
1471        if (cmd_len > 4) {
1472            sens->assert_enable &= ~cmd[4];
1473        }
1474        if (cmd_len > 5) {
1475            sens->assert_enable &= ~(cmd[5] << 8);
1476        }
1477        if (cmd_len > 6) {
1478            sens->deassert_enable &= ~cmd[6];
1479        }
1480        if (cmd_len > 7) {
1481            sens->deassert_enable &= ~(cmd[7] << 8);
1482        }
1483        break;
1484    case 3:
1485        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1486        return;
1487    }
1488    IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
1489}
1490
1491static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1492                                  uint8_t *cmd, unsigned int cmd_len,
1493                                  RspBuffer *rsp)
1494{
1495    IPMISensor *sens;
1496
1497    if ((cmd[2] >= MAX_SENSORS) ||
1498        !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1499        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1500        return;
1501    }
1502    sens = ibs->sensors + cmd[2];
1503    rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1504    rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1505    rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1506    rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1507    rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
1508}
1509
1510static void rearm_sensor_evts(IPMIBmcSim *ibs,
1511                              uint8_t *cmd, unsigned int cmd_len,
1512                              RspBuffer *rsp)
1513{
1514    IPMISensor *sens;
1515
1516    if ((cmd[2] >= MAX_SENSORS) ||
1517        !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1518        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1519        return;
1520    }
1521    sens = ibs->sensors + cmd[2];
1522
1523    if ((cmd[3] & 0x80) == 0) {
1524        /* Just clear everything */
1525        sens->states = 0;
1526        return;
1527    }
1528}
1529
1530static void get_sensor_evt_status(IPMIBmcSim *ibs,
1531                                  uint8_t *cmd, unsigned int cmd_len,
1532                                  RspBuffer *rsp)
1533{
1534    IPMISensor *sens;
1535
1536    if ((cmd[2] >= MAX_SENSORS) ||
1537        !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1538        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1539        return;
1540    }
1541    sens = ibs->sensors + cmd[2];
1542    rsp_buffer_push(rsp, sens->reading);
1543    rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1544    rsp_buffer_push(rsp, sens->assert_states & 0xff);
1545    rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1546    rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1547    rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
1548}
1549
1550static void get_sensor_reading(IPMIBmcSim *ibs,
1551                               uint8_t *cmd, unsigned int cmd_len,
1552                               RspBuffer *rsp)
1553{
1554    IPMISensor *sens;
1555
1556    if ((cmd[2] >= MAX_SENSORS) ||
1557            !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1558        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1559        return;
1560    }
1561    sens = ibs->sensors + cmd[2];
1562    rsp_buffer_push(rsp, sens->reading);
1563    rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1564    rsp_buffer_push(rsp, sens->states & 0xff);
1565    if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1566        rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
1567    }
1568}
1569
1570static void set_sensor_type(IPMIBmcSim *ibs,
1571                            uint8_t *cmd, unsigned int cmd_len,
1572                            RspBuffer *rsp)
1573{
1574    IPMISensor *sens;
1575
1576
1577    if ((cmd[2] >= MAX_SENSORS) ||
1578            !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1579        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1580        return;
1581    }
1582    sens = ibs->sensors + cmd[2];
1583    sens->sensor_type = cmd[3];
1584    sens->evt_reading_type_code = cmd[4] & 0x7f;
1585}
1586
1587static void get_sensor_type(IPMIBmcSim *ibs,
1588                            uint8_t *cmd, unsigned int cmd_len,
1589                            RspBuffer *rsp)
1590{
1591    IPMISensor *sens;
1592
1593
1594    if ((cmd[2] >= MAX_SENSORS) ||
1595            !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1596        rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1597        return;
1598    }
1599    sens = ibs->sensors + cmd[2];
1600    rsp_buffer_push(rsp, sens->sensor_type);
1601    rsp_buffer_push(rsp, sens->evt_reading_type_code);
1602}
1603
1604
1605static const IPMICmdHandler chassis_cmds[] = {
1606    [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
1607    [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
1608    [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
1609    [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
1610};
1611static const IPMINetfn chassis_netfn = {
1612    .cmd_nums = ARRAY_SIZE(chassis_cmds),
1613    .cmd_handlers = chassis_cmds
1614};
1615
1616static const IPMICmdHandler sensor_event_cmds[] = {
1617    [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
1618    [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
1619    [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
1620    [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
1621    [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
1622    [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
1623    [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
1624};
1625static const IPMINetfn sensor_event_netfn = {
1626    .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
1627    .cmd_handlers = sensor_event_cmds
1628};
1629
1630static const IPMICmdHandler app_cmds[] = {
1631    [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
1632    [IPMI_CMD_COLD_RESET] = { cold_reset },
1633    [IPMI_CMD_WARM_RESET] = { warm_reset },
1634    [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
1635    [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
1636    [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
1637    [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
1638    [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
1639    [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
1640    [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
1641    [IPMI_CMD_GET_MSG] = { get_msg },
1642    [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
1643    [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
1644    [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
1645    [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
1646    [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
1647};
1648static const IPMINetfn app_netfn = {
1649    .cmd_nums = ARRAY_SIZE(app_cmds),
1650    .cmd_handlers = app_cmds
1651};
1652
1653static const IPMICmdHandler storage_cmds[] = {
1654    [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
1655    [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
1656    [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
1657    [IPMI_CMD_ADD_SDR] = { add_sdr },
1658    [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
1659    [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
1660    [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
1661    [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
1662    [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
1663    [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
1664    [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
1665    [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
1666};
1667
1668static const IPMINetfn storage_netfn = {
1669    .cmd_nums = ARRAY_SIZE(storage_cmds),
1670    .cmd_handlers = storage_cmds
1671};
1672
1673static void register_cmds(IPMIBmcSim *s)
1674{
1675    ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
1676    ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
1677    ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
1678    ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
1679}
1680
1681static uint8_t init_sdrs[] = {
1682    /* Watchdog device */
1683    0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
1684    0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
1685    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1686    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
1687    'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
1688};
1689
1690static void ipmi_sdr_init(IPMIBmcSim *ibs)
1691{
1692    unsigned int i;
1693    int len;
1694    size_t sdrs_size;
1695    uint8_t *sdrs;
1696
1697    sdrs_size = sizeof(init_sdrs);
1698    sdrs = init_sdrs;
1699
1700    for (i = 0; i < sdrs_size; i += len) {
1701        struct ipmi_sdr_header *sdrh;
1702
1703        if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
1704            error_report("Problem with recid 0x%4.4x", i);
1705            return;
1706        }
1707        sdrh = (struct ipmi_sdr_header *) &sdrs[i];
1708        len = ipmi_sdr_length(sdrh);
1709        if (i + len > sdrs_size) {
1710            error_report("Problem with recid 0x%4.4x", i);
1711            return;
1712        }
1713        sdr_add_entry(ibs, sdrh, len, NULL);
1714    }
1715}
1716
1717static const VMStateDescription vmstate_ipmi_sim = {
1718    .name = TYPE_IPMI_BMC_SIMULATOR,
1719    .version_id = 1,
1720    .minimum_version_id = 1,
1721    .fields      = (VMStateField[]) {
1722        VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1723        VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1724        VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1725        VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1726        VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1727        VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1728        VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1729        VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1730        VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1731        VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1732        VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1733        VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1734        VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1735        VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1736        VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1737        VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1738        VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1739                       IPMIBmcSim),
1740        VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1741        VMSTATE_END_OF_LIST()
1742    }
1743};
1744
1745static void ipmi_sim_realize(DeviceState *dev, Error **errp)
1746{
1747    IPMIBmc *b = IPMI_BMC(dev);
1748    unsigned int i;
1749    IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
1750
1751    QTAILQ_INIT(&ibs->rcvbufs);
1752
1753    ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
1754    ibs->device_id = 0x20;
1755    ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1756    ibs->restart_cause = 0;
1757    for (i = 0; i < 4; i++) {
1758        ibs->sel.last_addition[i] = 0xff;
1759        ibs->sel.last_clear[i] = 0xff;
1760        ibs->sdr.last_addition[i] = 0xff;
1761        ibs->sdr.last_clear[i] = 0xff;
1762    }
1763
1764    ipmi_sdr_init(ibs);
1765
1766    ibs->acpi_power_state[0] = 0;
1767    ibs->acpi_power_state[1] = 0;
1768
1769    if (qemu_uuid_set) {
1770        memcpy(&ibs->uuid, &qemu_uuid, 16);
1771    } else {
1772        memset(&ibs->uuid, 0, 16);
1773    }
1774
1775    ipmi_init_sensors_from_sdrs(ibs);
1776    register_cmds(ibs);
1777
1778    ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1779
1780    vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
1781}
1782
1783static void ipmi_sim_class_init(ObjectClass *oc, void *data)
1784{
1785    DeviceClass *dc = DEVICE_CLASS(oc);
1786    IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
1787
1788    dc->hotpluggable = false;
1789    dc->realize = ipmi_sim_realize;
1790    bk->handle_command = ipmi_sim_handle_command;
1791}
1792
1793static const TypeInfo ipmi_sim_type = {
1794    .name          = TYPE_IPMI_BMC_SIMULATOR,
1795    .parent        = TYPE_IPMI_BMC,
1796    .instance_size = sizeof(IPMIBmcSim),
1797    .class_init    = ipmi_sim_class_init,
1798};
1799
1800static void ipmi_sim_register_types(void)
1801{
1802    type_register_static(&ipmi_sim_type);
1803}
1804
1805type_init(ipmi_sim_register_types)
1806