xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 7f11cb6585d97ecdb8a657c3d8732a494e409827)
18bfffbccSCorey Minyard /*
28bfffbccSCorey Minyard  * IPMI BMC emulation
38bfffbccSCorey Minyard  *
48bfffbccSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
58bfffbccSCorey Minyard  *
68bfffbccSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
78bfffbccSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
88bfffbccSCorey Minyard  * in the Software without restriction, including without limitation the rights
98bfffbccSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108bfffbccSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
118bfffbccSCorey Minyard  * furnished to do so, subject to the following conditions:
128bfffbccSCorey Minyard  *
138bfffbccSCorey Minyard  * The above copyright notice and this permission notice shall be included in
148bfffbccSCorey Minyard  * all copies or substantial portions of the Software.
158bfffbccSCorey Minyard  *
168bfffbccSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178bfffbccSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188bfffbccSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198bfffbccSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208bfffbccSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218bfffbccSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228bfffbccSCorey Minyard  * THE SOFTWARE.
238bfffbccSCorey Minyard  */
248bfffbccSCorey Minyard 
250430891cSPeter Maydell #include "qemu/osdep.h"
2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h"
278bfffbccSCorey Minyard #include "qemu/timer.h"
288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
298bfffbccSCorey Minyard #include "qemu/error-report.h"
308c6fd7f3SCédric Le Goater #include "hw/loader.h"
318bfffbccSCorey Minyard 
328bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
338bfffbccSCorey Minyard 
348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
358bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
368bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
37b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
388bfffbccSCorey Minyard 
398bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
408bfffbccSCorey Minyard 
418bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
438bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
458bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
46728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
47728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
488bfffbccSCorey Minyard 
498bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
508bfffbccSCorey Minyard 
518bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
528bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
538bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5452ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
5652ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
578bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
588bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
598bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
608bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
618bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
628bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
648bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
658bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
668bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
678bfffbccSCorey Minyard 
688bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
698bfffbccSCorey Minyard 
708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
718bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
728bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
748bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
758bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
768bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
778bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
798bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
808bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
818bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
828bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
83540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO        0x10
84540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA            0x11
85540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA           0x12
868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
878bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
888bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
898bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
908bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
918bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
928bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
938bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
948bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
958bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
968bfffbccSCorey Minyard 
978bfffbccSCorey Minyard 
988bfffbccSCorey Minyard /* Same as a timespec struct. */
998bfffbccSCorey Minyard struct ipmi_time {
1008bfffbccSCorey Minyard     long tv_sec;
1018bfffbccSCorey Minyard     long tv_nsec;
1028bfffbccSCorey Minyard };
1038bfffbccSCorey Minyard 
1048bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1058bfffbccSCorey Minyard 
1068bfffbccSCorey Minyard typedef struct IPMISel {
1078bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1088bfffbccSCorey Minyard     unsigned int next_free;
1098bfffbccSCorey Minyard     long time_offset;
1108bfffbccSCorey Minyard     uint16_t reservation;
1118bfffbccSCorey Minyard     uint8_t last_addition[4];
1128bfffbccSCorey Minyard     uint8_t last_clear[4];
1138bfffbccSCorey Minyard     uint8_t overflow;
1148bfffbccSCorey Minyard } IPMISel;
1158bfffbccSCorey Minyard 
1168bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1178bfffbccSCorey Minyard 
1188bfffbccSCorey Minyard typedef struct IPMISdr {
1198bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1208bfffbccSCorey Minyard     unsigned int next_free;
1218bfffbccSCorey Minyard     uint16_t next_rec_id;
1228bfffbccSCorey Minyard     uint16_t reservation;
1238bfffbccSCorey Minyard     uint8_t last_addition[4];
1248bfffbccSCorey Minyard     uint8_t last_clear[4];
1258bfffbccSCorey Minyard     uint8_t overflow;
1268bfffbccSCorey Minyard } IPMISdr;
1278bfffbccSCorey Minyard 
128540c07d3SCédric Le Goater typedef struct IPMIFru {
129540c07d3SCédric Le Goater     char *filename;
130540c07d3SCédric Le Goater     unsigned int nentries;
131540c07d3SCédric Le Goater     uint16_t areasize;
132540c07d3SCédric Le Goater     uint8_t *data;
133540c07d3SCédric Le Goater } IPMIFru;
134540c07d3SCédric Le Goater 
1358bfffbccSCorey Minyard typedef struct IPMISensor {
1368bfffbccSCorey Minyard     uint8_t status;
1378bfffbccSCorey Minyard     uint8_t reading;
1388bfffbccSCorey Minyard     uint16_t states_suppt;
1398bfffbccSCorey Minyard     uint16_t assert_suppt;
1408bfffbccSCorey Minyard     uint16_t deassert_suppt;
1418bfffbccSCorey Minyard     uint16_t states;
1428bfffbccSCorey Minyard     uint16_t assert_states;
1438bfffbccSCorey Minyard     uint16_t deassert_states;
1448bfffbccSCorey Minyard     uint16_t assert_enable;
1458bfffbccSCorey Minyard     uint16_t deassert_enable;
1468bfffbccSCorey Minyard     uint8_t  sensor_type;
1478bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1488bfffbccSCorey Minyard } IPMISensor;
1498bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1508bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1518bfffbccSCorey Minyard                                              !!(v))
1528bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1538bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1548bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1558bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1568bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1578bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1588bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1598bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1608bfffbccSCorey Minyard                                              (v & 0xc0))
1618bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1628bfffbccSCorey Minyard 
1638bfffbccSCorey Minyard #define MAX_SENSORS 20
1648bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1658bfffbccSCorey Minyard 
1668bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
167a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1688bfffbccSCorey Minyard 
1698bfffbccSCorey Minyard #define MAX_NETFNS 64
1704f298a4bSCédric Le Goater 
1714f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1724f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1738bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
174a580d820SCédric Le Goater                         RspBuffer *rsp);
1754f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1764f298a4bSCédric Le Goater } IPMICmdHandler;
1774f298a4bSCédric Le Goater 
1788bfffbccSCorey Minyard typedef struct IPMINetfn {
1798bfffbccSCorey Minyard     unsigned int cmd_nums;
1808bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1818bfffbccSCorey Minyard } IPMINetfn;
1828bfffbccSCorey Minyard 
1838bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1848bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1858bfffbccSCorey Minyard     uint8_t len;
1868bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1878bfffbccSCorey Minyard } IPMIRcvBufEntry;
1888bfffbccSCorey Minyard 
1898bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1908bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1918bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1928bfffbccSCorey Minyard struct IPMIBmcSim {
1938bfffbccSCorey Minyard     IPMIBmc parent;
1948bfffbccSCorey Minyard 
1958bfffbccSCorey Minyard     QEMUTimer *timer;
1968bfffbccSCorey Minyard 
1978bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1988bfffbccSCorey Minyard     uint8_t msg_flags;
1998bfffbccSCorey Minyard 
2008bfffbccSCorey Minyard     bool     watchdog_initialized;
2018bfffbccSCorey Minyard     uint8_t  watchdog_use;
2028bfffbccSCorey Minyard     uint8_t  watchdog_action;
2038bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
2048bfffbccSCorey Minyard     bool     watchdog_expired;
2058bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
2068bfffbccSCorey Minyard 
2078bfffbccSCorey Minyard     bool     watchdog_running;
2088bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
2098bfffbccSCorey Minyard     int64_t  watchdog_expiry;
2108bfffbccSCorey Minyard 
2118bfffbccSCorey Minyard     uint8_t device_id;
2128bfffbccSCorey Minyard     uint8_t ipmi_version;
2138bfffbccSCorey Minyard     uint8_t device_rev;
2148bfffbccSCorey Minyard     uint8_t fwrev1;
2158bfffbccSCorey Minyard     uint8_t fwrev2;
2168bfffbccSCorey Minyard     uint8_t mfg_id[3];
2178bfffbccSCorey Minyard     uint8_t product_id[2];
2188bfffbccSCorey Minyard 
219b7088392SCédric Le Goater     uint8_t restart_cause;
220b7088392SCédric Le Goater 
22152ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
22252ba4d50SCédric Le Goater     uint8_t uuid[16];
22352ba4d50SCédric Le Goater 
2248bfffbccSCorey Minyard     IPMISel sel;
2258bfffbccSCorey Minyard     IPMISdr sdr;
226540c07d3SCédric Le Goater     IPMIFru fru;
2278bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2288c6fd7f3SCédric Le Goater     char *sdr_filename;
2298bfffbccSCorey Minyard 
2308bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2318bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2328bfffbccSCorey Minyard 
2338bfffbccSCorey Minyard     /* We allow one event in the buffer */
2348bfffbccSCorey Minyard     uint8_t evtbuf[16];
2358bfffbccSCorey Minyard 
2368bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2378bfffbccSCorey Minyard };
2388bfffbccSCorey Minyard 
2398bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2408bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2438bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2448bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2458bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2468bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2478bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2488bfffbccSCorey Minyard 
2498bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2508bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2518bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2528bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2538bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2548bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2558bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2568bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2578bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2588bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2598bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2608bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2618bfffbccSCorey Minyard 
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2678bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2688bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2698bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2708bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2718bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2728bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2738bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2748bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2758bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2768bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2778bfffbccSCorey Minyard 
278a580d820SCédric Le Goater struct RspBuffer {
279a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
280a580d820SCédric Le Goater     unsigned int len;
281a580d820SCédric Le Goater };
282a580d820SCédric Le Goater 
283a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2848bfffbccSCorey Minyard 
2856acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
2866acb971aSCédric Le Goater {
2876acb971aSCédric Le Goater     rsp->buffer[2] = byte;
2886acb971aSCédric Le Goater }
2896acb971aSCédric Le Goater 
2908bfffbccSCorey Minyard /* Add a byte to the response. */
291a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
292a580d820SCédric Le Goater {
293a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
2946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
295a580d820SCédric Le Goater         return;
296a580d820SCédric Le Goater     }
297a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
298a580d820SCédric Le Goater }
299a580d820SCédric Le Goater 
300a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
301a580d820SCédric Le Goater                                        unsigned int n)
302a580d820SCédric Le Goater {
303a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
3046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
305a580d820SCédric Le Goater         return;
306a580d820SCédric Le Goater     }
307a580d820SCédric Le Goater 
308a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
309a580d820SCédric Le Goater     rsp->len += n;
310a580d820SCédric Le Goater }
3118bfffbccSCorey Minyard 
3128bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
3138bfffbccSCorey Minyard 
3148bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
3158bfffbccSCorey Minyard {
3168bfffbccSCorey Minyard     int64_t stime;
3178bfffbccSCorey Minyard 
3188bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3198bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3208bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3218bfffbccSCorey Minyard }
3228bfffbccSCorey Minyard 
3238bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3248bfffbccSCorey Minyard {
3258bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3268bfffbccSCorey Minyard }
3278bfffbccSCorey Minyard 
3288bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3298bfffbccSCorey Minyard {
3308bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3318bfffbccSCorey Minyard 
3328bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3338bfffbccSCorey Minyard }
3348bfffbccSCorey Minyard 
3358bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3368bfffbccSCorey Minyard {
3378bfffbccSCorey Minyard     unsigned int val;
3388bfffbccSCorey Minyard     struct ipmi_time now;
3398bfffbccSCorey Minyard 
3408bfffbccSCorey Minyard     ipmi_gettime(&now);
3418bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3428bfffbccSCorey Minyard     ts[0] = val & 0xff;
3438bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3448bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3458bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3468bfffbccSCorey Minyard }
3478bfffbccSCorey Minyard 
3488bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3498bfffbccSCorey Minyard {
3508bfffbccSCorey Minyard     sdr->reservation++;
3518bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3528bfffbccSCorey Minyard         sdr->reservation = 1;
3538bfffbccSCorey Minyard     }
3548bfffbccSCorey Minyard }
3558bfffbccSCorey Minyard 
356a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
357a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3588bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3598bfffbccSCorey Minyard {
360a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
361a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
362a2295f0aSCédric Le Goater 
363a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3648bfffbccSCorey Minyard         return 1;
3658bfffbccSCorey Minyard     }
3668bfffbccSCorey Minyard 
367a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3688bfffbccSCorey Minyard         return 1;
3698bfffbccSCorey Minyard     }
3708bfffbccSCorey Minyard 
3718bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3728bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3738bfffbccSCorey Minyard         return 1;
3748bfffbccSCorey Minyard     }
3758bfffbccSCorey Minyard 
376a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
377a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
378a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
379a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3808bfffbccSCorey Minyard 
3818bfffbccSCorey Minyard     if (recid) {
3828bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3838bfffbccSCorey Minyard     }
3848bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3858bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3868bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3878bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3888bfffbccSCorey Minyard     return 0;
3898bfffbccSCorey Minyard }
3908bfffbccSCorey Minyard 
3918bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3928bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3938bfffbccSCorey Minyard {
3948bfffbccSCorey Minyard     unsigned int pos = *retpos;
3958bfffbccSCorey Minyard 
3968bfffbccSCorey Minyard     while (pos < sdr->next_free) {
397a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
398a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
399a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
400a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
4018bfffbccSCorey Minyard 
4028bfffbccSCorey Minyard         if (trec == recid) {
4038bfffbccSCorey Minyard             if (nextrec) {
4048bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
4058bfffbccSCorey Minyard                     *nextrec = 0xffff;
4068bfffbccSCorey Minyard                 } else {
4078bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
4088bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
4098bfffbccSCorey Minyard                 }
4108bfffbccSCorey Minyard             }
4118bfffbccSCorey Minyard             *retpos = pos;
4128bfffbccSCorey Minyard             return 0;
4138bfffbccSCorey Minyard         }
4148bfffbccSCorey Minyard         pos = nextpos;
4158bfffbccSCorey Minyard     }
4168bfffbccSCorey Minyard     return 1;
4178bfffbccSCorey Minyard }
4188bfffbccSCorey Minyard 
4197fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
4207fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
4217fabcdb9SCédric Le Goater 
4227fabcdb9SCédric Le Goater {
4237fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
4247fabcdb9SCédric Le Goater     unsigned int pos;
4257fabcdb9SCédric Le Goater 
4267fabcdb9SCédric Le Goater     pos = 0;
4277fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
4287fabcdb9SCédric Le Goater         return -1;
4297fabcdb9SCédric Le Goater     }
4307fabcdb9SCédric Le Goater 
4317fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4327fabcdb9SCédric Le Goater     return 0;
4337fabcdb9SCédric Le Goater }
4347fabcdb9SCédric Le Goater 
4358bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4368bfffbccSCorey Minyard {
4378bfffbccSCorey Minyard     sel->reservation++;
4388bfffbccSCorey Minyard     if (sel->reservation == 0) {
4398bfffbccSCorey Minyard         sel->reservation = 1;
4408bfffbccSCorey Minyard     }
4418bfffbccSCorey Minyard }
4428bfffbccSCorey Minyard 
4438bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4448bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4458bfffbccSCorey Minyard {
4468bfffbccSCorey Minyard     event[0] = 0xff;
4478bfffbccSCorey Minyard     event[1] = 0xff;
4488bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4498bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4508bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4518bfffbccSCorey Minyard         return 1;
4528bfffbccSCorey Minyard     }
4538bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4548bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4558bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4568bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4578bfffbccSCorey Minyard     ibs->sel.next_free++;
4588bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4598bfffbccSCorey Minyard     return 0;
4608bfffbccSCorey Minyard }
4618bfffbccSCorey Minyard 
4628bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4638bfffbccSCorey Minyard {
4648bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4658bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4668bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4678bfffbccSCorey Minyard }
4688bfffbccSCorey Minyard 
4698bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4708bfffbccSCorey Minyard {
4718bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4728bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4738bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4748bfffbccSCorey Minyard }
4758bfffbccSCorey Minyard 
476cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
477cd60d85eSCédric Le Goater {
478cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
479cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
480cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
481cd60d85eSCédric Le Goater 
482cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
483cd60d85eSCédric Le Goater         return;
484cd60d85eSCédric Le Goater     }
485cd60d85eSCédric Le Goater 
486cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
487cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
488cd60d85eSCédric Le Goater     }
489cd60d85eSCédric Le Goater 
490cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
491cd60d85eSCédric Le Goater         goto out;
492cd60d85eSCédric Le Goater     }
493cd60d85eSCédric Le Goater 
494cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
495cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
496cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
497cd60d85eSCédric Le Goater  out:
498cd60d85eSCédric Le Goater     return;
499cd60d85eSCédric Le Goater }
5008bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
5018bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
5028bfffbccSCorey Minyard {
5038bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5048bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5058bfffbccSCorey Minyard     uint8_t evt[16];
5068bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
5078bfffbccSCorey Minyard 
5088bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
5098bfffbccSCorey Minyard         return;
5108bfffbccSCorey Minyard     }
5118bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
5128bfffbccSCorey Minyard         return;
5138bfffbccSCorey Minyard     }
5148bfffbccSCorey Minyard 
5158bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
5168bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
5178bfffbccSCorey Minyard     evt[8] = 0;
5188bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
5198bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
5208bfffbccSCorey Minyard     evt[11] = sens_num;
5218bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
5228bfffbccSCorey Minyard     evt[13] = evd1;
5238bfffbccSCorey Minyard     evt[14] = evd2;
5248bfffbccSCorey Minyard     evt[15] = evd3;
5258bfffbccSCorey Minyard 
5268bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5278bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5288bfffbccSCorey Minyard     }
5298bfffbccSCorey Minyard 
5308bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
531d13ada5dSCédric Le Goater         return;
5328bfffbccSCorey Minyard     }
5338bfffbccSCorey Minyard 
5348bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5358bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5368bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5378bfffbccSCorey Minyard }
5388bfffbccSCorey Minyard 
5398bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5408bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
5418bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
5428bfffbccSCorey Minyard {
5438bfffbccSCorey Minyard     IPMISensor *sens;
5448bfffbccSCorey Minyard     uint16_t mask;
5458bfffbccSCorey Minyard 
5468bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5478bfffbccSCorey Minyard         return;
5488bfffbccSCorey Minyard     }
5498bfffbccSCorey Minyard     if (bit >= 16) {
5508bfffbccSCorey Minyard         return;
5518bfffbccSCorey Minyard     }
5528bfffbccSCorey Minyard 
5538bfffbccSCorey Minyard     mask = (1 << bit);
5548bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5558bfffbccSCorey Minyard     if (val) {
5568bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5578bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5588bfffbccSCorey Minyard             return; /* Already asserted */
5598bfffbccSCorey Minyard         }
5608bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5618bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5628bfffbccSCorey Minyard             /* Send an event on assert */
5638bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5648bfffbccSCorey Minyard         }
5658bfffbccSCorey Minyard     } else {
5668bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5678bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5688bfffbccSCorey Minyard             return; /* Already deasserted */
5698bfffbccSCorey Minyard         }
5708bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5718bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5728bfffbccSCorey Minyard             /* Send an event on deassert */
5738bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5748bfffbccSCorey Minyard         }
5758bfffbccSCorey Minyard     }
5768bfffbccSCorey Minyard }
5778bfffbccSCorey Minyard 
5788bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5798bfffbccSCorey Minyard {
5808bfffbccSCorey Minyard     unsigned int i, pos;
5818bfffbccSCorey Minyard     IPMISensor *sens;
5828bfffbccSCorey Minyard 
5838bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5848bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5858bfffbccSCorey Minyard     }
5868bfffbccSCorey Minyard 
5878bfffbccSCorey Minyard     pos = 0;
5888bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
589a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
590a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
591a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5928bfffbccSCorey Minyard 
5938bfffbccSCorey Minyard         if (len < 20) {
5948bfffbccSCorey Minyard             continue;
5958bfffbccSCorey Minyard         }
596a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5978bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5988bfffbccSCorey Minyard         }
5998bfffbccSCorey Minyard 
60073d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
6018bfffbccSCorey Minyard             continue;
6028bfffbccSCorey Minyard         }
603a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
6048bfffbccSCorey Minyard 
6058bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
606a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
607a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
608a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
609a2295f0aSCédric Le Goater         sens->deassert_suppt =
610a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
611a2295f0aSCédric Le Goater         sens->states_suppt =
612a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
613a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
614a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
6158bfffbccSCorey Minyard 
6168bfffbccSCorey Minyard         /* Enable all the events that are supported. */
6178bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
6188bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
6198bfffbccSCorey Minyard     }
6208bfffbccSCorey Minyard }
6218bfffbccSCorey Minyard 
6228bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
6238bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
6248bfffbccSCorey Minyard {
62593a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6268bfffbccSCorey Minyard         return -1;
6278bfffbccSCorey Minyard     }
6288bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6298bfffbccSCorey Minyard     return 0;
6308bfffbccSCorey Minyard }
6318bfffbccSCorey Minyard 
6324f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6334f298a4bSCédric Le Goater                                               unsigned int netfn,
6344f298a4bSCédric Le Goater                                               unsigned int cmd)
6354f298a4bSCédric Le Goater {
6364f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6374f298a4bSCédric Le Goater 
6384f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6394f298a4bSCédric Le Goater         return NULL;
6404f298a4bSCédric Le Goater     }
6414f298a4bSCédric Le Goater 
6424f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6434f298a4bSCédric Le Goater         return NULL;
6444f298a4bSCédric Le Goater     }
6454f298a4bSCédric Le Goater 
6464f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6474f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6484f298a4bSCédric Le Goater         return NULL;
6494f298a4bSCédric Le Goater     }
6504f298a4bSCédric Le Goater 
6514f298a4bSCédric Le Goater     return hdl;
6524f298a4bSCédric Le Goater }
6534f298a4bSCédric Le Goater 
6548bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6558bfffbccSCorey Minyard {
6568bfffbccSCorey Minyard     int64_t next;
6578bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6588bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6598bfffbccSCorey Minyard     } else {
6608bfffbccSCorey Minyard         /* Wait a minute */
6618bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6628bfffbccSCorey Minyard     }
6638bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6648bfffbccSCorey Minyard }
6658bfffbccSCorey Minyard 
6668bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6678bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6688bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6698bfffbccSCorey Minyard                                     uint8_t msg_id)
6708bfffbccSCorey Minyard {
6718bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6728bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6738bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6744f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
675a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6768bfffbccSCorey Minyard 
6778bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6788bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
679a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6806acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
681d13ada5dSCédric Le Goater         goto out;
682d13ada5dSCédric Le Goater     }
683d13ada5dSCédric Le Goater 
684a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
685a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
686a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6878bfffbccSCorey Minyard 
6888bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6898bfffbccSCorey Minyard     if (cmd_len < 2) {
6906acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6918bfffbccSCorey Minyard         goto out;
6928bfffbccSCorey Minyard     }
6938bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6946acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6958bfffbccSCorey Minyard         goto out;
6968bfffbccSCorey Minyard     }
6978bfffbccSCorey Minyard 
6988bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6998bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
7006acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
7018bfffbccSCorey Minyard         goto out;
7028bfffbccSCorey Minyard     }
7038bfffbccSCorey Minyard 
7044f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
7054f298a4bSCédric Le Goater     if (!hdl) {
7066acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
7078bfffbccSCorey Minyard         goto out;
7088bfffbccSCorey Minyard     }
7098bfffbccSCorey Minyard 
7104f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
7116acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
7124f298a4bSCédric Le Goater         goto out;
7134f298a4bSCédric Le Goater     }
7144f298a4bSCédric Le Goater 
715a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
7168bfffbccSCorey Minyard 
7178bfffbccSCorey Minyard  out:
718a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
7198bfffbccSCorey Minyard 
7208bfffbccSCorey Minyard     next_timeout(ibs);
7218bfffbccSCorey Minyard }
7228bfffbccSCorey Minyard 
7238bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7248bfffbccSCorey Minyard {
7258bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7268bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7298bfffbccSCorey Minyard         goto out;
7308bfffbccSCorey Minyard     }
7318bfffbccSCorey Minyard 
7328bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7338bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7348bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7358bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7368bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7378bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7388bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
7398bfffbccSCorey Minyard             break;
7408bfffbccSCorey Minyard 
7418bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7428bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7438bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7448bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7458bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
7468bfffbccSCorey Minyard             break;
7478bfffbccSCorey Minyard 
7488bfffbccSCorey Minyard         default:
7498bfffbccSCorey Minyard             goto do_full_expiry;
7508bfffbccSCorey Minyard         }
7518bfffbccSCorey Minyard 
7528bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7538bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7548bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7558bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7568bfffbccSCorey Minyard         goto out;
7578bfffbccSCorey Minyard     }
7588bfffbccSCorey Minyard 
7598bfffbccSCorey Minyard  do_full_expiry:
7608bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7618bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7628bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7638bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7648bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7658bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7668bfffbccSCorey Minyard         break;
7678bfffbccSCorey Minyard 
7688bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7698bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7708bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7718bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7728bfffbccSCorey Minyard         break;
7738bfffbccSCorey Minyard 
7748bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7758bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7768bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7778bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7788bfffbccSCorey Minyard         break;
7798bfffbccSCorey Minyard 
7808bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7818bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7828bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7838bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7848bfffbccSCorey Minyard         break;
7858bfffbccSCorey Minyard     }
7868bfffbccSCorey Minyard 
7878bfffbccSCorey Minyard  out:
7888bfffbccSCorey Minyard     next_timeout(ibs);
7898bfffbccSCorey Minyard }
7908bfffbccSCorey Minyard 
7918bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7928bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
793a580d820SCédric Le Goater                                  RspBuffer *rsp)
7948bfffbccSCorey Minyard {
795a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
796a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
797a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
798a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
799a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
8008bfffbccSCorey Minyard }
8018bfffbccSCorey Minyard 
8028bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
8038bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
804a580d820SCédric Le Goater                            RspBuffer *rsp)
8058bfffbccSCorey Minyard {
806a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
807a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
808a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
809a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
8108bfffbccSCorey Minyard }
8118bfffbccSCorey Minyard 
8128bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
8138bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
814a580d820SCédric Le Goater                             RspBuffer *rsp)
8158bfffbccSCorey Minyard {
8168bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8178bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8188bfffbccSCorey Minyard 
8198bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
8208bfffbccSCorey Minyard     case 0: /* power down */
8216acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8228bfffbccSCorey Minyard         break;
8238bfffbccSCorey Minyard     case 1: /* power up */
8246acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8258bfffbccSCorey Minyard         break;
8268bfffbccSCorey Minyard     case 2: /* power cycle */
8276acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8288bfffbccSCorey Minyard         break;
8298bfffbccSCorey Minyard     case 3: /* hard reset */
8306acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8318bfffbccSCorey Minyard         break;
8328bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8336acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8348bfffbccSCorey Minyard         break;
8358bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8366acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8376acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8388bfffbccSCorey Minyard         break;
8398bfffbccSCorey Minyard     default:
8406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8418bfffbccSCorey Minyard         return;
8428bfffbccSCorey Minyard     }
843d13ada5dSCédric Le Goater }
8448bfffbccSCorey Minyard 
845b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
846b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
847a580d820SCédric Le Goater                            RspBuffer *rsp)
848a580d820SCédric Le Goater 
849b7088392SCédric Le Goater {
850a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
851a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
852b7088392SCédric Le Goater }
853b7088392SCédric Le Goater 
8548bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8558bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
856a580d820SCédric Le Goater                           RspBuffer *rsp)
8578bfffbccSCorey Minyard {
858a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
859a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
860a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
861a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
862a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
863a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
864a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[0]);
865a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[1]);
866a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[2]);
867a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[0]);
868a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[1]);
8698bfffbccSCorey Minyard }
8708bfffbccSCorey Minyard 
8718bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8728bfffbccSCorey Minyard {
8738bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8748bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8758bfffbccSCorey Minyard     bool irqs_on;
8768bfffbccSCorey Minyard 
8778bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8788bfffbccSCorey Minyard 
8798bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8808bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8818bfffbccSCorey Minyard 
8828bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8838bfffbccSCorey Minyard }
8848bfffbccSCorey Minyard 
8858bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8868bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
887a580d820SCédric Le Goater                        RspBuffer *rsp)
8888bfffbccSCorey Minyard {
8898bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8908bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8918bfffbccSCorey Minyard 
8928bfffbccSCorey Minyard     /* Disable all interrupts */
8938bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8948bfffbccSCorey Minyard 
8958bfffbccSCorey Minyard     if (k->reset) {
8968bfffbccSCorey Minyard         k->reset(s, true);
8978bfffbccSCorey Minyard     }
8988bfffbccSCorey Minyard }
8998bfffbccSCorey Minyard 
9008bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
9018bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
902a580d820SCédric Le Goater                        RspBuffer *rsp)
9038bfffbccSCorey Minyard {
9048bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9058bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9068bfffbccSCorey Minyard 
9078bfffbccSCorey Minyard     if (k->reset) {
9088bfffbccSCorey Minyard         k->reset(s, false);
9098bfffbccSCorey Minyard     }
9108bfffbccSCorey Minyard }
91152ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
91252ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
913a580d820SCédric Le Goater                                  RspBuffer *rsp)
91452ba4d50SCédric Le Goater {
91552ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
91652ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
91752ba4d50SCédric Le Goater }
91852ba4d50SCédric Le Goater 
91952ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
92052ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
921a580d820SCédric Le Goater                                  RspBuffer *rsp)
92252ba4d50SCédric Le Goater {
923a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
924a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
92552ba4d50SCédric Le Goater }
92652ba4d50SCédric Le Goater 
92752ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
92852ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
929a580d820SCédric Le Goater                             RspBuffer *rsp)
93052ba4d50SCédric Le Goater {
93152ba4d50SCédric Le Goater     unsigned int i;
93252ba4d50SCédric Le Goater 
93352ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
934a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->uuid[i]);
93552ba4d50SCédric Le Goater     }
93652ba4d50SCédric Le Goater }
9378bfffbccSCorey Minyard 
9388bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9398bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
940a580d820SCédric Le Goater                                    RspBuffer *rsp)
9418bfffbccSCorey Minyard {
9428bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9438bfffbccSCorey Minyard }
9448bfffbccSCorey Minyard 
9458bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9468bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
947a580d820SCédric Le Goater                                    RspBuffer *rsp)
9488bfffbccSCorey Minyard {
949a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9508bfffbccSCorey Minyard }
9518bfffbccSCorey Minyard 
9528bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9538bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
954a580d820SCédric Le Goater                           RspBuffer *rsp)
9558bfffbccSCorey Minyard {
9568bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9578bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9588bfffbccSCorey Minyard 
9598bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9608bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9618bfffbccSCorey Minyard }
9628bfffbccSCorey Minyard 
9638bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9648bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
965a580d820SCédric Le Goater                           RspBuffer *rsp)
9668bfffbccSCorey Minyard {
967a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9688bfffbccSCorey Minyard }
9698bfffbccSCorey Minyard 
9708bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9718bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
972a580d820SCédric Le Goater                              RspBuffer *rsp)
9738bfffbccSCorey Minyard {
9748bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9758bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9768bfffbccSCorey Minyard     unsigned int i;
9778bfffbccSCorey Minyard 
9788bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9796acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
980d13ada5dSCédric Le Goater         return;
9818bfffbccSCorey Minyard     }
9828bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
983a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9848bfffbccSCorey Minyard     }
9858bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9868bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9878bfffbccSCorey Minyard }
9888bfffbccSCorey Minyard 
9898bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9908bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
991a580d820SCédric Le Goater                     RspBuffer *rsp)
9928bfffbccSCorey Minyard {
9938bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9948bfffbccSCorey Minyard 
9958bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9978bfffbccSCorey Minyard         goto out;
9988bfffbccSCorey Minyard     }
999a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
10008bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
1001a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
10028bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
10038bfffbccSCorey Minyard     g_free(msg);
10048bfffbccSCorey Minyard 
10058bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10068bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
10078bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10088bfffbccSCorey Minyard 
10098bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10108bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10118bfffbccSCorey Minyard     }
10128bfffbccSCorey Minyard 
10138bfffbccSCorey Minyard out:
10148bfffbccSCorey Minyard     return;
10158bfffbccSCorey Minyard }
10168bfffbccSCorey Minyard 
10178bfffbccSCorey Minyard static unsigned char
10188bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10198bfffbccSCorey Minyard {
10208bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10218bfffbccSCorey Minyard             csum += *data;
10228bfffbccSCorey Minyard     }
10238bfffbccSCorey Minyard 
10248bfffbccSCorey Minyard     return -csum;
10258bfffbccSCorey Minyard }
10268bfffbccSCorey Minyard 
10278bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10288bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1029a580d820SCédric Le Goater                      RspBuffer *rsp)
10308bfffbccSCorey Minyard {
10318bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10328bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10338bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10348bfffbccSCorey Minyard     uint8_t *buf;
10358bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10368bfffbccSCorey Minyard 
10378bfffbccSCorey Minyard     if (cmd[2] != 0) {
10388bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
10396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1040d13ada5dSCédric Le Goater         return;
10418bfffbccSCorey Minyard     }
10428bfffbccSCorey Minyard 
10434f298a4bSCédric Le Goater     if (cmd_len < 10) {
10446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10454f298a4bSCédric Le Goater         return;
10464f298a4bSCédric Le Goater     }
10474f298a4bSCédric Le Goater 
10488bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10498bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10506acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1051d13ada5dSCédric Le Goater         return;
10528bfffbccSCorey Minyard     }
10538bfffbccSCorey Minyard 
10548bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10558bfffbccSCorey Minyard     cmd_len -= 3;
10568bfffbccSCorey Minyard 
10578bfffbccSCorey Minyard     /*
10588bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10598bfffbccSCorey Minyard      * be returned in the response.
10608bfffbccSCorey Minyard      */
10618bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10628bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1063d13ada5dSCédric Le Goater         return; /* No response */
10648bfffbccSCorey Minyard     }
10658bfffbccSCorey Minyard 
10668bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10678bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10688bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10698bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10708bfffbccSCorey Minyard 
10718bfffbccSCorey Minyard     if (rqLun != 2) {
10728bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1073d13ada5dSCédric Le Goater         return;
10748bfffbccSCorey Minyard     }
10758bfffbccSCorey Minyard 
10768bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10778bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10788bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10798bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10808bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10818bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10828bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10838bfffbccSCorey Minyard     msg->len = 6;
10848bfffbccSCorey Minyard 
10858bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10868bfffbccSCorey Minyard         /* Not a command we handle. */
10878bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10888bfffbccSCorey Minyard         goto end_msg;
10898bfffbccSCorey Minyard     }
10908bfffbccSCorey Minyard 
10918bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10928bfffbccSCorey Minyard     buf[0] = 0;
10938bfffbccSCorey Minyard     buf[1] = 0;
10948bfffbccSCorey Minyard     buf[2] = 0;
10958bfffbccSCorey Minyard     buf[3] = 0;
10968bfffbccSCorey Minyard     buf[4] = 0x51;
10978bfffbccSCorey Minyard     buf[5] = 0;
10988bfffbccSCorey Minyard     buf[6] = 0;
10998bfffbccSCorey Minyard     buf[7] = 0;
11008bfffbccSCorey Minyard     buf[8] = 0;
11018bfffbccSCorey Minyard     buf[9] = 0;
11028bfffbccSCorey Minyard     buf[10] = 0;
11038bfffbccSCorey Minyard     msg->len += 11;
11048bfffbccSCorey Minyard 
11058bfffbccSCorey Minyard  end_msg:
11068bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11078bfffbccSCorey Minyard     msg->len++;
11088bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11098bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11108bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
11118bfffbccSCorey Minyard }
11128bfffbccSCorey Minyard 
11138bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11148bfffbccSCorey Minyard {
11158bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11168bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11178bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11188bfffbccSCorey Minyard         return;
11198bfffbccSCorey Minyard     }
11208bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11218bfffbccSCorey Minyard 
11228bfffbccSCorey Minyard 
11238bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11248bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11258bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11268bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11278bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11288bfffbccSCorey Minyard     }
11298bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11308bfffbccSCorey Minyard }
11318bfffbccSCorey Minyard 
11328bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11338bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1134a580d820SCédric Le Goater                                  RspBuffer *rsp)
11358bfffbccSCorey Minyard {
11368bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1138d13ada5dSCédric Le Goater         return;
11398bfffbccSCorey Minyard     }
11408bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11418bfffbccSCorey Minyard }
11428bfffbccSCorey Minyard 
11438bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11448bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1145a580d820SCédric Le Goater                                RspBuffer *rsp)
11468bfffbccSCorey Minyard {
11478bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11488bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11498bfffbccSCorey Minyard     unsigned int val;
11508bfffbccSCorey Minyard 
11518bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11528bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11536acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1154d13ada5dSCédric Le Goater         return;
11558bfffbccSCorey Minyard     }
11568bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11578bfffbccSCorey Minyard     switch (val) {
11588bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11598bfffbccSCorey Minyard         break;
11608bfffbccSCorey Minyard 
11618bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11626acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11638bfffbccSCorey Minyard         break;
11648bfffbccSCorey Minyard 
11658bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11678bfffbccSCorey Minyard         break;
11688bfffbccSCorey Minyard 
11698bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11706acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11718bfffbccSCorey Minyard         break;
11728bfffbccSCorey Minyard 
11738bfffbccSCorey Minyard     default:
11746acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11758bfffbccSCorey Minyard     }
1176a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11776acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1178d13ada5dSCédric Le Goater         return;
11798bfffbccSCorey Minyard     }
11808bfffbccSCorey Minyard 
11818bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11828bfffbccSCorey Minyard     switch (val) {
11838bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11848bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11858bfffbccSCorey Minyard         break;
11868bfffbccSCorey Minyard 
11878bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11888bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11898bfffbccSCorey Minyard             /* NMI not supported. */
11906acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1191d13ada5dSCédric Le Goater             return;
11928bfffbccSCorey Minyard         }
119337eebb86SCorey Minyard         break;
119437eebb86SCorey Minyard 
11958bfffbccSCorey Minyard     default:
11968bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1198d13ada5dSCédric Le Goater         return;
11998bfffbccSCorey Minyard     }
12008bfffbccSCorey Minyard 
12018bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
12028bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
12038bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
12048bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
12058bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
12068bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12078bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12088bfffbccSCorey Minyard         do_watchdog_reset(ibs);
12098bfffbccSCorey Minyard     } else {
12108bfffbccSCorey Minyard         ibs->watchdog_running = 0;
12118bfffbccSCorey Minyard     }
12128bfffbccSCorey Minyard }
12138bfffbccSCorey Minyard 
12148bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12158bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1216a580d820SCédric Le Goater                                RspBuffer *rsp)
12178bfffbccSCorey Minyard {
1218a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1219a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1220a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1221a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
12228bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12238bfffbccSCorey Minyard         long timeout;
12248bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12258bfffbccSCorey Minyard                    / 100000000);
1226a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1227a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12288bfffbccSCorey Minyard     } else {
1229a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1230a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12318bfffbccSCorey Minyard     }
12328bfffbccSCorey Minyard }
12338bfffbccSCorey Minyard 
12348bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12358bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1236a580d820SCédric Le Goater                              RspBuffer *rsp)
12378bfffbccSCorey Minyard {
12388bfffbccSCorey Minyard     unsigned int i;
12398bfffbccSCorey Minyard 
1240a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1241a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1242a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1243a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1244a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12458bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1246a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12478bfffbccSCorey Minyard     }
12488bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1249a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12508bfffbccSCorey Minyard     }
12518bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1252a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12538bfffbccSCorey Minyard }
12548bfffbccSCorey Minyard 
12558bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12568bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1257a580d820SCédric Le Goater                             RspBuffer *rsp)
12588bfffbccSCorey Minyard {
1259a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1260a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12618bfffbccSCorey Minyard }
12628bfffbccSCorey Minyard 
12638bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12648bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1265a580d820SCédric Le Goater                     RspBuffer *rsp)
12668bfffbccSCorey Minyard {
12678bfffbccSCorey Minyard     unsigned int pos;
12688bfffbccSCorey Minyard     uint16_t nextrec;
1269a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12708bfffbccSCorey Minyard 
12718bfffbccSCorey Minyard     if (cmd[6]) {
12727f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12736acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12747f996411SCédric Le Goater             return;
12758bfffbccSCorey Minyard         }
12767f996411SCédric Le Goater     }
12777f996411SCédric Le Goater 
12788bfffbccSCorey Minyard     pos = 0;
12798bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12808bfffbccSCorey Minyard                        &pos, &nextrec)) {
12816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1282d13ada5dSCédric Le Goater         return;
12838bfffbccSCorey Minyard     }
1284a2295f0aSCédric Le Goater 
1285a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1286a2295f0aSCédric Le Goater 
1287a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1289d13ada5dSCédric Le Goater         return;
12908bfffbccSCorey Minyard     }
12918bfffbccSCorey Minyard 
1292a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1293a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12948bfffbccSCorey Minyard 
12958bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1296a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12978bfffbccSCorey Minyard     }
12988bfffbccSCorey Minyard 
1299a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13006acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1301d13ada5dSCédric Le Goater         return;
13028bfffbccSCorey Minyard     }
1303a580d820SCédric Le Goater 
1304a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13058bfffbccSCorey Minyard }
13068bfffbccSCorey Minyard 
13078bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13088bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1309a580d820SCédric Le Goater                     RspBuffer *rsp)
13108bfffbccSCorey Minyard {
13118bfffbccSCorey Minyard     uint16_t recid;
1312a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13138bfffbccSCorey Minyard 
1314a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13156acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1316d13ada5dSCédric Le Goater         return;
13178bfffbccSCorey Minyard     }
1318a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1319a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13208bfffbccSCorey Minyard }
13218bfffbccSCorey Minyard 
13228bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13238bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1324a580d820SCédric Le Goater                           RspBuffer *rsp)
13258bfffbccSCorey Minyard {
13267f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13276acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13287f996411SCédric Le Goater         return;
13297f996411SCédric Le Goater     }
13307f996411SCédric Le Goater 
13318bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1333d13ada5dSCédric Le Goater         return;
13348bfffbccSCorey Minyard     }
13358bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13368bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13378bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13388bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1339a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13408bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
13418bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1342a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13438bfffbccSCorey Minyard     } else {
13446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13458bfffbccSCorey Minyard         return;
13468bfffbccSCorey Minyard     }
1347d13ada5dSCédric Le Goater }
13488bfffbccSCorey Minyard 
13498bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13508bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1351a580d820SCédric Le Goater                          RspBuffer *rsp)
13528bfffbccSCorey Minyard {
13538bfffbccSCorey Minyard     unsigned int i, val;
13548bfffbccSCorey Minyard 
1355a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1356a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1357a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13588bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1359a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1360a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13618bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1362a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13638bfffbccSCorey Minyard     }
13648bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1365a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13668bfffbccSCorey Minyard     }
13678bfffbccSCorey Minyard     /* Only support Reserve SEL */
1368a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13698bfffbccSCorey Minyard }
13708bfffbccSCorey Minyard 
1371540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1372540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1373540c07d3SCédric Le Goater                          RspBuffer *rsp)
1374540c07d3SCédric Le Goater {
1375540c07d3SCédric Le Goater     uint8_t fruid;
1376540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1377540c07d3SCédric Le Goater 
1378540c07d3SCédric Le Goater     fruid = cmd[2];
1379540c07d3SCédric Le Goater 
1380540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1381540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1382540c07d3SCédric Le Goater         return;
1383540c07d3SCédric Le Goater     }
1384540c07d3SCédric Le Goater 
1385540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1386540c07d3SCédric Le Goater 
1387540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1388540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1389540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1390540c07d3SCédric Le Goater }
1391540c07d3SCédric Le Goater 
1392540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1393540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1394540c07d3SCédric Le Goater                          RspBuffer *rsp)
1395540c07d3SCédric Le Goater {
1396540c07d3SCédric Le Goater     uint8_t fruid;
1397540c07d3SCédric Le Goater     uint16_t offset;
1398540c07d3SCédric Le Goater     int i;
1399540c07d3SCédric Le Goater     uint8_t *fru_entry;
1400540c07d3SCédric Le Goater     unsigned int count;
1401540c07d3SCédric Le Goater 
1402540c07d3SCédric Le Goater     fruid = cmd[2];
1403540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1404540c07d3SCédric Le Goater 
1405540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1406540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1407540c07d3SCédric Le Goater         return;
1408540c07d3SCédric Le Goater     }
1409540c07d3SCédric Le Goater 
1410540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1411540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1412540c07d3SCédric Le Goater         return;
1413540c07d3SCédric Le Goater     }
1414540c07d3SCédric Le Goater 
1415540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1416540c07d3SCédric Le Goater 
1417540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1418540c07d3SCédric Le Goater 
1419540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1420540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1421540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1422540c07d3SCédric Le Goater     }
1423540c07d3SCédric Le Goater }
1424540c07d3SCédric Le Goater 
1425540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1426540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1427540c07d3SCédric Le Goater                          RspBuffer *rsp)
1428540c07d3SCédric Le Goater {
1429540c07d3SCédric Le Goater     uint8_t fruid;
1430540c07d3SCédric Le Goater     uint16_t offset;
1431540c07d3SCédric Le Goater     uint8_t *fru_entry;
1432540c07d3SCédric Le Goater     unsigned int count;
1433540c07d3SCédric Le Goater 
1434540c07d3SCédric Le Goater     fruid = cmd[2];
1435540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1436540c07d3SCédric Le Goater 
1437540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1438540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1439540c07d3SCédric Le Goater         return;
1440540c07d3SCédric Le Goater     }
1441540c07d3SCédric Le Goater 
1442540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1443540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1444540c07d3SCédric Le Goater         return;
1445540c07d3SCédric Le Goater     }
1446540c07d3SCédric Le Goater 
1447540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1448540c07d3SCédric Le Goater 
1449540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1450540c07d3SCédric Le Goater 
1451540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1452540c07d3SCédric Le Goater 
1453540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1454540c07d3SCédric Le Goater }
1455540c07d3SCédric Le Goater 
14568bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
14578bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1458a580d820SCédric Le Goater                         RspBuffer *rsp)
14598bfffbccSCorey Minyard {
1460a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1461a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
14628bfffbccSCorey Minyard }
14638bfffbccSCorey Minyard 
14648bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
14658bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1466a580d820SCédric Le Goater                           RspBuffer *rsp)
14678bfffbccSCorey Minyard {
14688bfffbccSCorey Minyard     unsigned int val;
14698bfffbccSCorey Minyard 
14708bfffbccSCorey Minyard     if (cmd[6]) {
14717f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
14726acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
14737f996411SCédric Le Goater             return;
14747f996411SCédric Le Goater         }
14758bfffbccSCorey Minyard     }
14768bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
14776acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1478d13ada5dSCédric Le Goater         return;
14798bfffbccSCorey Minyard     }
14808bfffbccSCorey Minyard     if (cmd[6] > 15) {
14816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1482d13ada5dSCédric Le Goater         return;
14838bfffbccSCorey Minyard     }
14848bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
14858bfffbccSCorey Minyard         cmd[7] = 16;
14868bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
14876acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1488d13ada5dSCédric Le Goater         return;
14898bfffbccSCorey Minyard     } else {
14908bfffbccSCorey Minyard         cmd[7] += cmd[6];
14918bfffbccSCorey Minyard     }
14928bfffbccSCorey Minyard 
14938bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
14948bfffbccSCorey Minyard     if (val == 0xffff) {
14958bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
14968bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
14976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1498d13ada5dSCédric Le Goater         return;
14998bfffbccSCorey Minyard     }
15008bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1501a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1502a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15038bfffbccSCorey Minyard     } else {
1504a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1505a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15068bfffbccSCorey Minyard     }
15078bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1508a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15098bfffbccSCorey Minyard     }
15108bfffbccSCorey Minyard }
15118bfffbccSCorey Minyard 
15128bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15138bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1514a580d820SCédric Le Goater                           RspBuffer *rsp)
15158bfffbccSCorey Minyard {
15168bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15176acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1518d13ada5dSCédric Le Goater         return;
15198bfffbccSCorey Minyard     }
15208bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1521a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1522a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15238bfffbccSCorey Minyard }
15248bfffbccSCorey Minyard 
15258bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15268bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1527a580d820SCédric Le Goater                       RspBuffer *rsp)
15288bfffbccSCorey Minyard {
15297f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15306acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15317f996411SCédric Le Goater         return;
15327f996411SCédric Le Goater     }
15337f996411SCédric Le Goater 
15348bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15356acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1536d13ada5dSCédric Le Goater         return;
15378bfffbccSCorey Minyard     }
15388bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15398bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15408bfffbccSCorey Minyard         ibs->sel.overflow = 0;
15418bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1542a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15438bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
15448bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1545a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15468bfffbccSCorey Minyard     } else {
15476acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15488bfffbccSCorey Minyard         return;
15498bfffbccSCorey Minyard     }
1550d13ada5dSCédric Le Goater }
15518bfffbccSCorey Minyard 
15528bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
15538bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1554a580d820SCédric Le Goater                          RspBuffer *rsp)
15558bfffbccSCorey Minyard {
15568bfffbccSCorey Minyard     uint32_t val;
15578bfffbccSCorey Minyard     struct ipmi_time now;
15588bfffbccSCorey Minyard 
15598bfffbccSCorey Minyard     ipmi_gettime(&now);
15608bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1561a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1562a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1563a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1564a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
15658bfffbccSCorey Minyard }
15668bfffbccSCorey Minyard 
15678bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
15688bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1569a580d820SCédric Le Goater                          RspBuffer *rsp)
15708bfffbccSCorey Minyard {
15718bfffbccSCorey Minyard     uint32_t val;
15728bfffbccSCorey Minyard     struct ipmi_time now;
15738bfffbccSCorey Minyard 
15748bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
15758bfffbccSCorey Minyard     ipmi_gettime(&now);
15768bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
15778bfffbccSCorey Minyard }
15788bfffbccSCorey Minyard 
15798bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
15808bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1581a580d820SCédric Le Goater                                   RspBuffer *rsp)
15828bfffbccSCorey Minyard {
15838bfffbccSCorey Minyard     IPMISensor *sens;
15848bfffbccSCorey Minyard 
158573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15868bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15876acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1588d13ada5dSCédric Le Goater         return;
15898bfffbccSCorey Minyard     }
15908bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15918bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
15928bfffbccSCorey Minyard     case 0: /* Do not change */
15938bfffbccSCorey Minyard         break;
15948bfffbccSCorey Minyard     case 1: /* Enable bits */
15958bfffbccSCorey Minyard         if (cmd_len > 4) {
15968bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
15978bfffbccSCorey Minyard         }
15988bfffbccSCorey Minyard         if (cmd_len > 5) {
15998bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16008bfffbccSCorey Minyard         }
16018bfffbccSCorey Minyard         if (cmd_len > 6) {
16028bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16038bfffbccSCorey Minyard         }
16048bfffbccSCorey Minyard         if (cmd_len > 7) {
16058bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16068bfffbccSCorey Minyard         }
16078bfffbccSCorey Minyard         break;
16088bfffbccSCorey Minyard     case 2: /* Disable bits */
16098bfffbccSCorey Minyard         if (cmd_len > 4) {
16108bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16118bfffbccSCorey Minyard         }
16128bfffbccSCorey Minyard         if (cmd_len > 5) {
16138bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16148bfffbccSCorey Minyard         }
16158bfffbccSCorey Minyard         if (cmd_len > 6) {
16168bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16178bfffbccSCorey Minyard         }
16188bfffbccSCorey Minyard         if (cmd_len > 7) {
16198bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
16208bfffbccSCorey Minyard         }
16218bfffbccSCorey Minyard         break;
16228bfffbccSCorey Minyard     case 3:
16236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1624d13ada5dSCédric Le Goater         return;
16258bfffbccSCorey Minyard     }
16268bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
16278bfffbccSCorey Minyard }
16288bfffbccSCorey Minyard 
16298bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
16308bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1631a580d820SCédric Le Goater                                   RspBuffer *rsp)
16328bfffbccSCorey Minyard {
16338bfffbccSCorey Minyard     IPMISensor *sens;
16348bfffbccSCorey Minyard 
163573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16368bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1638d13ada5dSCédric Le Goater         return;
16398bfffbccSCorey Minyard     }
16408bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1641a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1642a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1643a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1644a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1645a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
16468bfffbccSCorey Minyard }
16478bfffbccSCorey Minyard 
16488bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
16498bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1650a580d820SCédric Le Goater                               RspBuffer *rsp)
16518bfffbccSCorey Minyard {
16528bfffbccSCorey Minyard     IPMISensor *sens;
16538bfffbccSCorey Minyard 
165473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16558bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16566acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1657d13ada5dSCédric Le Goater         return;
16588bfffbccSCorey Minyard     }
16598bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16608bfffbccSCorey Minyard 
16618bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
16628bfffbccSCorey Minyard         /* Just clear everything */
16638bfffbccSCorey Minyard         sens->states = 0;
16648bfffbccSCorey Minyard         return;
16658bfffbccSCorey Minyard     }
1666d13ada5dSCédric Le Goater }
16678bfffbccSCorey Minyard 
16688bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
16698bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1670a580d820SCédric Le Goater                                   RspBuffer *rsp)
16718bfffbccSCorey Minyard {
16728bfffbccSCorey Minyard     IPMISensor *sens;
16738bfffbccSCorey Minyard 
167473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16758bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16766acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1677d13ada5dSCédric Le Goater         return;
16788bfffbccSCorey Minyard     }
16798bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1680a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1681a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1682a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1683a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1684a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1685a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
16868bfffbccSCorey Minyard }
16878bfffbccSCorey Minyard 
16888bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
16898bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1690a580d820SCédric Le Goater                                RspBuffer *rsp)
16918bfffbccSCorey Minyard {
16928bfffbccSCorey Minyard     IPMISensor *sens;
16938bfffbccSCorey Minyard 
169473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16958bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1697d13ada5dSCédric Le Goater         return;
16988bfffbccSCorey Minyard     }
16998bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1700a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1701a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1702a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17038bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1704a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17058bfffbccSCorey Minyard     }
17068bfffbccSCorey Minyard }
17078bfffbccSCorey Minyard 
1708728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1709728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1710a580d820SCédric Le Goater                             RspBuffer *rsp)
1711728710e1SCédric Le Goater {
1712728710e1SCédric Le Goater     IPMISensor *sens;
1713728710e1SCédric Le Goater 
1714728710e1SCédric Le Goater 
171573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1716728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17176acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1718728710e1SCédric Le Goater         return;
1719728710e1SCédric Le Goater     }
1720728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1721728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1722728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1723728710e1SCédric Le Goater }
1724728710e1SCédric Le Goater 
1725728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1726728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1727a580d820SCédric Le Goater                             RspBuffer *rsp)
1728728710e1SCédric Le Goater {
1729728710e1SCédric Le Goater     IPMISensor *sens;
1730728710e1SCédric Le Goater 
1731728710e1SCédric Le Goater 
173273d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1733728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17346acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1735728710e1SCédric Le Goater         return;
1736728710e1SCédric Le Goater     }
1737728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1738a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1739a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1740728710e1SCédric Le Goater }
1741728710e1SCédric Le Goater 
1742728710e1SCédric Le Goater 
174362a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
17444f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
17454f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
17464f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
17474f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
17488bfffbccSCorey Minyard };
17498bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
175062a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
17518bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
17528bfffbccSCorey Minyard };
17538bfffbccSCorey Minyard 
175462a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
17554f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
17564f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
17574f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
17584f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
17594f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
17604f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
17614f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
17628bfffbccSCorey Minyard };
17638bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
176462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
17658bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
17668bfffbccSCorey Minyard };
17678bfffbccSCorey Minyard 
176862a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
17694f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
17704f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
17714f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
17724f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
17734f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
17744f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
17754f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
17764f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
17774f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
17784f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
17794f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
17804f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
17814f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
17824f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
17834f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
17844f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
17858bfffbccSCorey Minyard };
17868bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
178762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
17888bfffbccSCorey Minyard     .cmd_handlers = app_cmds
17898bfffbccSCorey Minyard };
17908bfffbccSCorey Minyard 
179162a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
1792540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
1793540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
1794540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
17954f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
17964f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
17974f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
17984f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
17994f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
18004f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
18014f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
18024f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
18034f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
18044f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
1805*7f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
1806*7f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
18078bfffbccSCorey Minyard };
18088bfffbccSCorey Minyard 
18098bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
181062a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
18118bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
18128bfffbccSCorey Minyard };
18138bfffbccSCorey Minyard 
18148bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
18158bfffbccSCorey Minyard {
18168bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
18178bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
18188bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
18198bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
18208bfffbccSCorey Minyard }
18218bfffbccSCorey Minyard 
18225167560bSCédric Le Goater static uint8_t init_sdrs[] = {
18238bfffbccSCorey Minyard     /* Watchdog device */
18248bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
18258bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
18268bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18278bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
18288bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
18298bfffbccSCorey Minyard };
18308bfffbccSCorey Minyard 
18314fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
18324fa9f08eSCédric Le Goater {
18334fa9f08eSCédric Le Goater     unsigned int i;
18344fa9f08eSCédric Le Goater     int len;
18355167560bSCédric Le Goater     size_t sdrs_size;
18365167560bSCédric Le Goater     uint8_t *sdrs;
183752fc01d9SCédric Le Goater 
18385167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
18395167560bSCédric Le Goater     sdrs = init_sdrs;
18408c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
18418c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
18428c6fd7f3SCédric Le Goater                              NULL)) {
18438c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
18448c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
18458c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
18468c6fd7f3SCédric Le Goater     }
18475167560bSCédric Le Goater 
18485167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
184952fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
185052fc01d9SCédric Le Goater 
18515167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
18524fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
18538c6fd7f3SCédric Le Goater             break;
18544fa9f08eSCédric Le Goater         }
18555167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
18564fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
18575167560bSCédric Le Goater         if (i + len > sdrs_size) {
18584fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
18598c6fd7f3SCédric Le Goater             break;
18604fa9f08eSCédric Le Goater         }
18614fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
18624fa9f08eSCédric Le Goater     }
18638c6fd7f3SCédric Le Goater 
18648c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
18658c6fd7f3SCédric Le Goater         g_free(sdrs);
18668c6fd7f3SCédric Le Goater     }
18674fa9f08eSCédric Le Goater }
18684fa9f08eSCédric Le Goater 
1869bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1870bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1871bd66bcfcSCorey Minyard     .version_id = 1,
1872bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1873bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1874bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1875bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1876bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1877bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1878bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1879bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1880bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1881bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1882bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1883bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1884bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1885bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1886bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1887bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1888bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1889bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1890bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1891bd66bcfcSCorey Minyard                        IPMIBmcSim),
1892bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1893bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1894bd66bcfcSCorey Minyard     }
1895bd66bcfcSCorey Minyard };
1896bd66bcfcSCorey Minyard 
1897540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
1898540c07d3SCédric Le Goater {
1899540c07d3SCédric Le Goater     int fsize;
1900540c07d3SCédric Le Goater     int size = 0;
1901540c07d3SCédric Le Goater 
1902540c07d3SCédric Le Goater     if (!fru->filename) {
1903540c07d3SCédric Le Goater         goto out;
1904540c07d3SCédric Le Goater     }
1905540c07d3SCédric Le Goater 
1906540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
1907540c07d3SCédric Le Goater     if (fsize > 0) {
1908540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
1909540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1910540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
1911540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
1912540c07d3SCédric Le Goater             g_free(fru->data);
1913540c07d3SCédric Le Goater             fru->data = NULL;
1914540c07d3SCédric Le Goater         }
1915540c07d3SCédric Le Goater     }
1916540c07d3SCédric Le Goater 
1917540c07d3SCédric Le Goater out:
1918540c07d3SCédric Le Goater     if (!fru->data) {
1919540c07d3SCédric Le Goater         /* give one default FRU */
1920540c07d3SCédric Le Goater         size = fru->areasize;
1921540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1922540c07d3SCédric Le Goater     }
1923540c07d3SCédric Le Goater 
1924540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
1925540c07d3SCédric Le Goater }
1926540c07d3SCédric Le Goater 
19270bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
19288bfffbccSCorey Minyard {
19290bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
19308bfffbccSCorey Minyard     unsigned int i;
19318bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
19328bfffbccSCorey Minyard 
19338bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
19348bfffbccSCorey Minyard 
19358bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
19368bfffbccSCorey Minyard     ibs->device_id = 0x20;
19378bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1938b7088392SCédric Le Goater     ibs->restart_cause = 0;
19398bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
19408bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
19418bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
19428bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
19438bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
19448bfffbccSCorey Minyard     }
19458bfffbccSCorey Minyard 
19464fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
19478bfffbccSCorey Minyard 
1948540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
1949540c07d3SCédric Le Goater 
195052ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
195152ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
195252ba4d50SCédric Le Goater 
195352ba4d50SCédric Le Goater     if (qemu_uuid_set) {
19549c5ce8dbSFam Zheng         memcpy(&ibs->uuid, &qemu_uuid, 16);
195552ba4d50SCédric Le Goater     } else {
195652ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
195752ba4d50SCédric Le Goater     }
195852ba4d50SCédric Le Goater 
19598bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
19608bfffbccSCorey Minyard     register_cmds(ibs);
19618bfffbccSCorey Minyard 
19628bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1963bd66bcfcSCorey Minyard 
1964bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
19658bfffbccSCorey Minyard }
19668bfffbccSCorey Minyard 
19678c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
1968540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
1969540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
19708c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
19718c6fd7f3SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
19728c6fd7f3SCédric Le Goater };
19738c6fd7f3SCédric Le Goater 
19748bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
19758bfffbccSCorey Minyard {
19760bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
19778bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
19788bfffbccSCorey Minyard 
197966abfddbSCorey Minyard     dc->hotpluggable = false;
19800bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
19818c6fd7f3SCédric Le Goater     dc->props = ipmi_sim_properties;
19828bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
19838bfffbccSCorey Minyard }
19848bfffbccSCorey Minyard 
19858bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
19868bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
19878bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
19888bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
19898bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
19908bfffbccSCorey Minyard };
19918bfffbccSCorey Minyard 
19928bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
19938bfffbccSCorey Minyard {
19948bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
19958bfffbccSCorey Minyard }
19968bfffbccSCorey Minyard 
19978bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1998