xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 0b8fa32f551e863bb548a11394239239270dd3dc)
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"
30*0b8fa32fSMarkus Armbruster #include "qemu/module.h"
318c6fd7f3SCédric Le Goater #include "hw/loader.h"
328bfffbccSCorey Minyard 
338bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
348bfffbccSCorey Minyard 
358bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
368bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
378bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
38b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
398bfffbccSCorey Minyard 
408bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
418bfffbccSCorey Minyard 
429380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG       0x02
438bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
458bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
468bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
478bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
48728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
49728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
508bfffbccSCorey Minyard 
518bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
528bfffbccSCorey Minyard 
538bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
548bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
558bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5652ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5752ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
5852ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
598bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
608bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
618bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
628bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
638bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
648bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
658bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
668bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
678bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
688bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
698bfffbccSCorey Minyard 
708bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
718bfffbccSCorey Minyard 
728bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
748bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
758bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
768bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
778bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
788bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
798bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
808bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
818bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
828bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
838bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
848bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
85540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO        0x10
86540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA            0x11
87540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA           0x12
888bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
898bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
908bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
918bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
928bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
938bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
948bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
958bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
968bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
978bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
988bfffbccSCorey Minyard 
998bfffbccSCorey Minyard 
1008bfffbccSCorey Minyard /* Same as a timespec struct. */
1018bfffbccSCorey Minyard struct ipmi_time {
1028bfffbccSCorey Minyard     long tv_sec;
1038bfffbccSCorey Minyard     long tv_nsec;
1048bfffbccSCorey Minyard };
1058bfffbccSCorey Minyard 
1068bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1078bfffbccSCorey Minyard 
1088bfffbccSCorey Minyard typedef struct IPMISel {
1098bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1108bfffbccSCorey Minyard     unsigned int next_free;
1118bfffbccSCorey Minyard     long time_offset;
1128bfffbccSCorey Minyard     uint16_t reservation;
1138bfffbccSCorey Minyard     uint8_t last_addition[4];
1148bfffbccSCorey Minyard     uint8_t last_clear[4];
1158bfffbccSCorey Minyard     uint8_t overflow;
1168bfffbccSCorey Minyard } IPMISel;
1178bfffbccSCorey Minyard 
1188bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1198bfffbccSCorey Minyard 
1208bfffbccSCorey Minyard typedef struct IPMISdr {
1218bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1228bfffbccSCorey Minyard     unsigned int next_free;
1238bfffbccSCorey Minyard     uint16_t next_rec_id;
1248bfffbccSCorey Minyard     uint16_t reservation;
1258bfffbccSCorey Minyard     uint8_t last_addition[4];
1268bfffbccSCorey Minyard     uint8_t last_clear[4];
1278bfffbccSCorey Minyard     uint8_t overflow;
1288bfffbccSCorey Minyard } IPMISdr;
1298bfffbccSCorey Minyard 
130540c07d3SCédric Le Goater typedef struct IPMIFru {
131540c07d3SCédric Le Goater     char *filename;
132540c07d3SCédric Le Goater     unsigned int nentries;
133540c07d3SCédric Le Goater     uint16_t areasize;
134540c07d3SCédric Le Goater     uint8_t *data;
135540c07d3SCédric Le Goater } IPMIFru;
136540c07d3SCédric Le Goater 
1378bfffbccSCorey Minyard typedef struct IPMISensor {
1388bfffbccSCorey Minyard     uint8_t status;
1398bfffbccSCorey Minyard     uint8_t reading;
1408bfffbccSCorey Minyard     uint16_t states_suppt;
1418bfffbccSCorey Minyard     uint16_t assert_suppt;
1428bfffbccSCorey Minyard     uint16_t deassert_suppt;
1438bfffbccSCorey Minyard     uint16_t states;
1448bfffbccSCorey Minyard     uint16_t assert_states;
1458bfffbccSCorey Minyard     uint16_t deassert_states;
1468bfffbccSCorey Minyard     uint16_t assert_enable;
1478bfffbccSCorey Minyard     uint16_t deassert_enable;
1488bfffbccSCorey Minyard     uint8_t  sensor_type;
1498bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1508bfffbccSCorey Minyard } IPMISensor;
1518bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1528bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1538bfffbccSCorey Minyard                                              !!(v))
1548bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1558bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1568bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1578bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1588bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1598bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1608bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1618bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1628bfffbccSCorey Minyard                                              (v & 0xc0))
1638bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1648bfffbccSCorey Minyard 
1658bfffbccSCorey Minyard #define MAX_SENSORS 20
1668bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1678bfffbccSCorey Minyard 
1688bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
169a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1708bfffbccSCorey Minyard 
1718bfffbccSCorey Minyard #define MAX_NETFNS 64
1724f298a4bSCédric Le Goater 
1734f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1744f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1758bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
176a580d820SCédric Le Goater                         RspBuffer *rsp);
1774f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1784f298a4bSCédric Le Goater } IPMICmdHandler;
1794f298a4bSCédric Le Goater 
1808bfffbccSCorey Minyard typedef struct IPMINetfn {
1818bfffbccSCorey Minyard     unsigned int cmd_nums;
1828bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1838bfffbccSCorey Minyard } IPMINetfn;
1848bfffbccSCorey Minyard 
1858bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1868bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1878bfffbccSCorey Minyard     uint8_t len;
1888bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1898bfffbccSCorey Minyard } IPMIRcvBufEntry;
1908bfffbccSCorey Minyard 
1918bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1928bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1938bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1948bfffbccSCorey Minyard struct IPMIBmcSim {
1958bfffbccSCorey Minyard     IPMIBmc parent;
1968bfffbccSCorey Minyard 
1978bfffbccSCorey Minyard     QEMUTimer *timer;
1988bfffbccSCorey Minyard 
1998bfffbccSCorey Minyard     uint8_t bmc_global_enables;
2008bfffbccSCorey Minyard     uint8_t msg_flags;
2018bfffbccSCorey Minyard 
2028bfffbccSCorey Minyard     bool     watchdog_initialized;
2038bfffbccSCorey Minyard     uint8_t  watchdog_use;
2048bfffbccSCorey Minyard     uint8_t  watchdog_action;
2058bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
2068bfffbccSCorey Minyard     bool     watchdog_expired;
2078bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
2088bfffbccSCorey Minyard 
2098bfffbccSCorey Minyard     bool     watchdog_running;
2108bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
2118bfffbccSCorey Minyard     int64_t  watchdog_expiry;
2128bfffbccSCorey Minyard 
2138bfffbccSCorey Minyard     uint8_t device_id;
2148bfffbccSCorey Minyard     uint8_t ipmi_version;
2158bfffbccSCorey Minyard     uint8_t device_rev;
2168bfffbccSCorey Minyard     uint8_t fwrev1;
2178bfffbccSCorey Minyard     uint8_t fwrev2;
21820b23364SCorey Minyard     uint32_t mfg_id;
21920b23364SCorey Minyard     uint16_t product_id;
2208bfffbccSCorey Minyard 
221b7088392SCédric Le Goater     uint8_t restart_cause;
222b7088392SCédric Le Goater 
22352ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
22452ba4d50SCédric Le Goater     uint8_t uuid[16];
22552ba4d50SCédric Le Goater 
2268bfffbccSCorey Minyard     IPMISel sel;
2278bfffbccSCorey Minyard     IPMISdr sdr;
228540c07d3SCédric Le Goater     IPMIFru fru;
2298bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2308c6fd7f3SCédric Le Goater     char *sdr_filename;
2318bfffbccSCorey Minyard 
2328bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2338bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2348bfffbccSCorey Minyard 
2358bfffbccSCorey Minyard     /* We allow one event in the buffer */
2368bfffbccSCorey Minyard     uint8_t evtbuf[16];
2378bfffbccSCorey Minyard 
2388bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2398bfffbccSCorey Minyard };
2408bfffbccSCorey Minyard 
2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2438bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2448bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2458bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2468bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2478bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2488bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2498bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2508bfffbccSCorey Minyard 
2518bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2528bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2538bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2548bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2558bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2568bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2578bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2588bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2598bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2608bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2618bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2628bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2638bfffbccSCorey Minyard 
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2678bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2688bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2698bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2708bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2718bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2728bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2738bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2748bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2758bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2768bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2778bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2788bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2798bfffbccSCorey Minyard 
280a580d820SCédric Le Goater struct RspBuffer {
281a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
282a580d820SCédric Le Goater     unsigned int len;
283a580d820SCédric Le Goater };
284a580d820SCédric Le Goater 
285a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2868bfffbccSCorey Minyard 
2876acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
2886acb971aSCédric Le Goater {
2896acb971aSCédric Le Goater     rsp->buffer[2] = byte;
2906acb971aSCédric Le Goater }
2916acb971aSCédric Le Goater 
2928bfffbccSCorey Minyard /* Add a byte to the response. */
293a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
294a580d820SCédric Le Goater {
295a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
2966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
297a580d820SCédric Le Goater         return;
298a580d820SCédric Le Goater     }
299a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
300a580d820SCédric Le Goater }
301a580d820SCédric Le Goater 
302a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
303a580d820SCédric Le Goater                                        unsigned int n)
304a580d820SCédric Le Goater {
305a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
3066acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
307a580d820SCédric Le Goater         return;
308a580d820SCédric Le Goater     }
309a580d820SCédric Le Goater 
310a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
311a580d820SCédric Le Goater     rsp->len += n;
312a580d820SCédric Le Goater }
3138bfffbccSCorey Minyard 
3148bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
3158bfffbccSCorey Minyard 
3168bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
3178bfffbccSCorey Minyard {
3188bfffbccSCorey Minyard     int64_t stime;
3198bfffbccSCorey Minyard 
3208bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3218bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3228bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3238bfffbccSCorey Minyard }
3248bfffbccSCorey Minyard 
3258bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3268bfffbccSCorey Minyard {
3278bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3288bfffbccSCorey Minyard }
3298bfffbccSCorey Minyard 
3308bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3318bfffbccSCorey Minyard {
3328bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3338bfffbccSCorey Minyard 
3348bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3358bfffbccSCorey Minyard }
3368bfffbccSCorey Minyard 
3378bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3388bfffbccSCorey Minyard {
3398bfffbccSCorey Minyard     unsigned int val;
3408bfffbccSCorey Minyard     struct ipmi_time now;
3418bfffbccSCorey Minyard 
3428bfffbccSCorey Minyard     ipmi_gettime(&now);
3438bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3448bfffbccSCorey Minyard     ts[0] = val & 0xff;
3458bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3468bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3478bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3488bfffbccSCorey Minyard }
3498bfffbccSCorey Minyard 
3508bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3518bfffbccSCorey Minyard {
3528bfffbccSCorey Minyard     sdr->reservation++;
3538bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3548bfffbccSCorey Minyard         sdr->reservation = 1;
3558bfffbccSCorey Minyard     }
3568bfffbccSCorey Minyard }
3578bfffbccSCorey Minyard 
358a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
359a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3608bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3618bfffbccSCorey Minyard {
362a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
363a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
364a2295f0aSCédric Le Goater 
365a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3668bfffbccSCorey Minyard         return 1;
3678bfffbccSCorey Minyard     }
3688bfffbccSCorey Minyard 
369a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3708bfffbccSCorey Minyard         return 1;
3718bfffbccSCorey Minyard     }
3728bfffbccSCorey Minyard 
3738bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3748bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3758bfffbccSCorey Minyard         return 1;
3768bfffbccSCorey Minyard     }
3778bfffbccSCorey Minyard 
378a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
379a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
380a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
381a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3828bfffbccSCorey Minyard 
3838bfffbccSCorey Minyard     if (recid) {
3848bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3858bfffbccSCorey Minyard     }
3868bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3878bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3888bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3898bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3908bfffbccSCorey Minyard     return 0;
3918bfffbccSCorey Minyard }
3928bfffbccSCorey Minyard 
3938bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3948bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3958bfffbccSCorey Minyard {
3968bfffbccSCorey Minyard     unsigned int pos = *retpos;
3978bfffbccSCorey Minyard 
3988bfffbccSCorey Minyard     while (pos < sdr->next_free) {
399a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
400a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
401a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
402a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
4038bfffbccSCorey Minyard 
4048bfffbccSCorey Minyard         if (trec == recid) {
4058bfffbccSCorey Minyard             if (nextrec) {
4068bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
4078bfffbccSCorey Minyard                     *nextrec = 0xffff;
4088bfffbccSCorey Minyard                 } else {
4098bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
4108bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
4118bfffbccSCorey Minyard                 }
4128bfffbccSCorey Minyard             }
4138bfffbccSCorey Minyard             *retpos = pos;
4148bfffbccSCorey Minyard             return 0;
4158bfffbccSCorey Minyard         }
4168bfffbccSCorey Minyard         pos = nextpos;
4178bfffbccSCorey Minyard     }
4188bfffbccSCorey Minyard     return 1;
4198bfffbccSCorey Minyard }
4208bfffbccSCorey Minyard 
4217fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
4227fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
4237fabcdb9SCédric Le Goater 
4247fabcdb9SCédric Le Goater {
4257fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
4267fabcdb9SCédric Le Goater     unsigned int pos;
4277fabcdb9SCédric Le Goater 
4287fabcdb9SCédric Le Goater     pos = 0;
4297fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
4307fabcdb9SCédric Le Goater         return -1;
4317fabcdb9SCédric Le Goater     }
4327fabcdb9SCédric Le Goater 
4337fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4347fabcdb9SCédric Le Goater     return 0;
4357fabcdb9SCédric Le Goater }
4367fabcdb9SCédric Le Goater 
4378bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4388bfffbccSCorey Minyard {
4398bfffbccSCorey Minyard     sel->reservation++;
4408bfffbccSCorey Minyard     if (sel->reservation == 0) {
4418bfffbccSCorey Minyard         sel->reservation = 1;
4428bfffbccSCorey Minyard     }
4438bfffbccSCorey Minyard }
4448bfffbccSCorey Minyard 
4458bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4468bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4478bfffbccSCorey Minyard {
4489f7d1d92SCorey Minyard     uint8_t ts[4];
4499f7d1d92SCorey Minyard 
4508bfffbccSCorey Minyard     event[0] = 0xff;
4518bfffbccSCorey Minyard     event[1] = 0xff;
4529f7d1d92SCorey Minyard     set_timestamp(ibs, ts);
4539f7d1d92SCorey Minyard     if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4549f7d1d92SCorey Minyard         memcpy(event + 3, ts, 4);
4559f7d1d92SCorey Minyard     }
4568bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4578bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4588bfffbccSCorey Minyard         return 1;
4598bfffbccSCorey Minyard     }
4608bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4618bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4629f7d1d92SCorey Minyard     memcpy(ibs->sel.last_addition, ts, 4);
4638bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4648bfffbccSCorey Minyard     ibs->sel.next_free++;
4658bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4668bfffbccSCorey Minyard     return 0;
4678bfffbccSCorey Minyard }
4688bfffbccSCorey Minyard 
4698bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4708bfffbccSCorey Minyard {
4718bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4728bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4738bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4748bfffbccSCorey Minyard }
4758bfffbccSCorey Minyard 
4768bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4778bfffbccSCorey Minyard {
4788bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4798bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4808bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4818bfffbccSCorey Minyard }
4828bfffbccSCorey Minyard 
483cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
484cd60d85eSCédric Le Goater {
485cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
486cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
487cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
488cd60d85eSCédric Le Goater 
489cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
490cd60d85eSCédric Le Goater         return;
491cd60d85eSCédric Le Goater     }
492cd60d85eSCédric Le Goater 
493cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
494cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
495cd60d85eSCédric Le Goater     }
496cd60d85eSCédric Le Goater 
497cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
498cd60d85eSCédric Le Goater         goto out;
499cd60d85eSCédric Le Goater     }
500cd60d85eSCédric Le Goater 
501cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
502cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
503cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
504cd60d85eSCédric Le Goater  out:
505cd60d85eSCédric Le Goater     return;
506cd60d85eSCédric Le Goater }
5078bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
5088bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
5098bfffbccSCorey Minyard {
5108bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5118bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5128bfffbccSCorey Minyard     uint8_t evt[16];
5138bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
5148bfffbccSCorey Minyard 
5158bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
5168bfffbccSCorey Minyard         return;
5178bfffbccSCorey Minyard     }
5188bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
5198bfffbccSCorey Minyard         return;
5208bfffbccSCorey Minyard     }
5218bfffbccSCorey Minyard 
5228bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
5238bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
5248bfffbccSCorey Minyard     evt[8] = 0;
5258bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
5268bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
5278bfffbccSCorey Minyard     evt[11] = sens_num;
5288bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
5298bfffbccSCorey Minyard     evt[13] = evd1;
5308bfffbccSCorey Minyard     evt[14] = evd2;
5318bfffbccSCorey Minyard     evt[15] = evd3;
5328bfffbccSCorey Minyard 
5338bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5348bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5358bfffbccSCorey Minyard     }
5368bfffbccSCorey Minyard 
5378bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
538d13ada5dSCédric Le Goater         return;
5398bfffbccSCorey Minyard     }
5408bfffbccSCorey Minyard 
5418bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5428bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5438bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5448bfffbccSCorey Minyard }
5458bfffbccSCorey Minyard 
5468bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5478bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
5488bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
5498bfffbccSCorey Minyard {
5508bfffbccSCorey Minyard     IPMISensor *sens;
5518bfffbccSCorey Minyard     uint16_t mask;
5528bfffbccSCorey Minyard 
5538bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5548bfffbccSCorey Minyard         return;
5558bfffbccSCorey Minyard     }
5568bfffbccSCorey Minyard     if (bit >= 16) {
5578bfffbccSCorey Minyard         return;
5588bfffbccSCorey Minyard     }
5598bfffbccSCorey Minyard 
5608bfffbccSCorey Minyard     mask = (1 << bit);
5618bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5628bfffbccSCorey Minyard     if (val) {
5638bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5648bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5658bfffbccSCorey Minyard             return; /* Already asserted */
5668bfffbccSCorey Minyard         }
5678bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5688bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5698bfffbccSCorey Minyard             /* Send an event on assert */
5708bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5718bfffbccSCorey Minyard         }
5728bfffbccSCorey Minyard     } else {
5738bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5748bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5758bfffbccSCorey Minyard             return; /* Already deasserted */
5768bfffbccSCorey Minyard         }
5778bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5788bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5798bfffbccSCorey Minyard             /* Send an event on deassert */
5808bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5818bfffbccSCorey Minyard         }
5828bfffbccSCorey Minyard     }
5838bfffbccSCorey Minyard }
5848bfffbccSCorey Minyard 
5858bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5868bfffbccSCorey Minyard {
5878bfffbccSCorey Minyard     unsigned int i, pos;
5888bfffbccSCorey Minyard     IPMISensor *sens;
5898bfffbccSCorey Minyard 
5908bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5918bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5928bfffbccSCorey Minyard     }
5938bfffbccSCorey Minyard 
5948bfffbccSCorey Minyard     pos = 0;
5958bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
596a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
597a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
598a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5998bfffbccSCorey Minyard 
6008bfffbccSCorey Minyard         if (len < 20) {
6018bfffbccSCorey Minyard             continue;
6028bfffbccSCorey Minyard         }
603a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
6048bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
6058bfffbccSCorey Minyard         }
6068bfffbccSCorey Minyard 
60773d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
6088bfffbccSCorey Minyard             continue;
6098bfffbccSCorey Minyard         }
610a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
6118bfffbccSCorey Minyard 
6128bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
613a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
614a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
615a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
616a2295f0aSCédric Le Goater         sens->deassert_suppt =
617a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
618a2295f0aSCédric Le Goater         sens->states_suppt =
619a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
620a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
621a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
6228bfffbccSCorey Minyard 
6238bfffbccSCorey Minyard         /* Enable all the events that are supported. */
6248bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
6258bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
6268bfffbccSCorey Minyard     }
6278bfffbccSCorey Minyard }
6288bfffbccSCorey Minyard 
6298bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
6308bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
6318bfffbccSCorey Minyard {
63293a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6338bfffbccSCorey Minyard         return -1;
6348bfffbccSCorey Minyard     }
6358bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6368bfffbccSCorey Minyard     return 0;
6378bfffbccSCorey Minyard }
6388bfffbccSCorey Minyard 
6394f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6404f298a4bSCédric Le Goater                                               unsigned int netfn,
6414f298a4bSCédric Le Goater                                               unsigned int cmd)
6424f298a4bSCédric Le Goater {
6434f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6444f298a4bSCédric Le Goater 
6454f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6464f298a4bSCédric Le Goater         return NULL;
6474f298a4bSCédric Le Goater     }
6484f298a4bSCédric Le Goater 
6494f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6504f298a4bSCédric Le Goater         return NULL;
6514f298a4bSCédric Le Goater     }
6524f298a4bSCédric Le Goater 
6534f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6544f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6554f298a4bSCédric Le Goater         return NULL;
6564f298a4bSCédric Le Goater     }
6574f298a4bSCédric Le Goater 
6584f298a4bSCédric Le Goater     return hdl;
6594f298a4bSCédric Le Goater }
6604f298a4bSCédric Le Goater 
6618bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6628bfffbccSCorey Minyard {
6638bfffbccSCorey Minyard     int64_t next;
6648bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6658bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6668bfffbccSCorey Minyard     } else {
6678bfffbccSCorey Minyard         /* Wait a minute */
6688bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6698bfffbccSCorey Minyard     }
6708bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6718bfffbccSCorey Minyard }
6728bfffbccSCorey Minyard 
6738bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6748bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6758bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6768bfffbccSCorey Minyard                                     uint8_t msg_id)
6778bfffbccSCorey Minyard {
6788bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6798bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6808bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6814f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
682a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6838bfffbccSCorey Minyard 
6848bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6858bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
686a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6876acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
688d13ada5dSCédric Le Goater         goto out;
689d13ada5dSCédric Le Goater     }
690d13ada5dSCédric Le Goater 
691a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
692a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
693a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6948bfffbccSCorey Minyard 
6958bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6968bfffbccSCorey Minyard     if (cmd_len < 2) {
6976acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6988bfffbccSCorey Minyard         goto out;
6998bfffbccSCorey Minyard     }
7008bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
7016acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
7028bfffbccSCorey Minyard         goto out;
7038bfffbccSCorey Minyard     }
7048bfffbccSCorey Minyard 
7058bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
7068bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
7076acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
7088bfffbccSCorey Minyard         goto out;
7098bfffbccSCorey Minyard     }
7108bfffbccSCorey Minyard 
7114f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
7124f298a4bSCédric Le Goater     if (!hdl) {
7136acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
7148bfffbccSCorey Minyard         goto out;
7158bfffbccSCorey Minyard     }
7168bfffbccSCorey Minyard 
7174f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
7186acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
7194f298a4bSCédric Le Goater         goto out;
7204f298a4bSCédric Le Goater     }
7214f298a4bSCédric Le Goater 
722a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
7238bfffbccSCorey Minyard 
7248bfffbccSCorey Minyard  out:
725a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
7268bfffbccSCorey Minyard 
7278bfffbccSCorey Minyard     next_timeout(ibs);
7288bfffbccSCorey Minyard }
7298bfffbccSCorey Minyard 
7308bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7318bfffbccSCorey Minyard {
7328bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7338bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7348bfffbccSCorey Minyard 
7358bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7368bfffbccSCorey Minyard         goto out;
7378bfffbccSCorey Minyard     }
7388bfffbccSCorey Minyard 
7398bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7408bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7418bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7428bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7438bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7448bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7458bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
7468bfffbccSCorey Minyard             break;
7478bfffbccSCorey Minyard 
7488bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7498bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7508bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7518bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7528bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
7538bfffbccSCorey Minyard             break;
7548bfffbccSCorey Minyard 
7558bfffbccSCorey Minyard         default:
7568bfffbccSCorey Minyard             goto do_full_expiry;
7578bfffbccSCorey Minyard         }
7588bfffbccSCorey Minyard 
7598bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7608bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7618bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7628bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7638bfffbccSCorey Minyard         goto out;
7648bfffbccSCorey Minyard     }
7658bfffbccSCorey Minyard 
7668bfffbccSCorey Minyard  do_full_expiry:
7678bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7688bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7698bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7708bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7718bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7728bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7738bfffbccSCorey Minyard         break;
7748bfffbccSCorey Minyard 
7758bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7768bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7778bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7788bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7798bfffbccSCorey Minyard         break;
7808bfffbccSCorey Minyard 
7818bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7828bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7838bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7848bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7858bfffbccSCorey Minyard         break;
7868bfffbccSCorey Minyard 
7878bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7888bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7898bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7908bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7918bfffbccSCorey Minyard         break;
7928bfffbccSCorey Minyard     }
7938bfffbccSCorey Minyard 
7948bfffbccSCorey Minyard  out:
7958bfffbccSCorey Minyard     next_timeout(ibs);
7968bfffbccSCorey Minyard }
7978bfffbccSCorey Minyard 
7988bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7998bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
800a580d820SCédric Le Goater                                  RspBuffer *rsp)
8018bfffbccSCorey Minyard {
802a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
803a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
804a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
805a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
806a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
8078bfffbccSCorey Minyard }
8088bfffbccSCorey Minyard 
8098bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
8108bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
811a580d820SCédric Le Goater                            RspBuffer *rsp)
8128bfffbccSCorey Minyard {
813a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
814a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
815a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
816a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
8178bfffbccSCorey Minyard }
8188bfffbccSCorey Minyard 
8198bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
8208bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
821a580d820SCédric Le Goater                             RspBuffer *rsp)
8228bfffbccSCorey Minyard {
8238bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8248bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8258bfffbccSCorey Minyard 
8268bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
8278bfffbccSCorey Minyard     case 0: /* power down */
8286acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8298bfffbccSCorey Minyard         break;
8308bfffbccSCorey Minyard     case 1: /* power up */
8316acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8328bfffbccSCorey Minyard         break;
8338bfffbccSCorey Minyard     case 2: /* power cycle */
8346acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8358bfffbccSCorey Minyard         break;
8368bfffbccSCorey Minyard     case 3: /* hard reset */
8376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8388bfffbccSCorey Minyard         break;
8398bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8418bfffbccSCorey Minyard         break;
8428bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8436acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8446acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8458bfffbccSCorey Minyard         break;
8468bfffbccSCorey Minyard     default:
8476acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8488bfffbccSCorey Minyard         return;
8498bfffbccSCorey Minyard     }
850d13ada5dSCédric Le Goater }
8518bfffbccSCorey Minyard 
852b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
853b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
854a580d820SCédric Le Goater                            RspBuffer *rsp)
855a580d820SCédric Le Goater 
856b7088392SCédric Le Goater {
857a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
858a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
859b7088392SCédric Le Goater }
860b7088392SCédric Le Goater 
8618bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8628bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
863a580d820SCédric Le Goater                           RspBuffer *rsp)
8648bfffbccSCorey Minyard {
865a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
866a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
867a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
868a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
869a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
870a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
87120b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
87220b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
87320b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
87420b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
87520b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8768bfffbccSCorey Minyard }
8778bfffbccSCorey Minyard 
8788bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8798bfffbccSCorey Minyard {
8808bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8818bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8828bfffbccSCorey Minyard     bool irqs_on;
8838bfffbccSCorey Minyard 
8848bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8858bfffbccSCorey Minyard 
8868bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8878bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8888bfffbccSCorey Minyard 
8898bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8908bfffbccSCorey Minyard }
8918bfffbccSCorey Minyard 
8928bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8938bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
894a580d820SCédric Le Goater                        RspBuffer *rsp)
8958bfffbccSCorey Minyard {
8968bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8978bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8988bfffbccSCorey Minyard 
8998bfffbccSCorey Minyard     /* Disable all interrupts */
9008bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
9018bfffbccSCorey Minyard 
9028bfffbccSCorey Minyard     if (k->reset) {
9038bfffbccSCorey Minyard         k->reset(s, true);
9048bfffbccSCorey Minyard     }
9058bfffbccSCorey Minyard }
9068bfffbccSCorey Minyard 
9078bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
9088bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
909a580d820SCédric Le Goater                        RspBuffer *rsp)
9108bfffbccSCorey Minyard {
9118bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9128bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9138bfffbccSCorey Minyard 
9148bfffbccSCorey Minyard     if (k->reset) {
9158bfffbccSCorey Minyard         k->reset(s, false);
9168bfffbccSCorey Minyard     }
9178bfffbccSCorey Minyard }
91852ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
91952ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
920a580d820SCédric Le Goater                                  RspBuffer *rsp)
92152ba4d50SCédric Le Goater {
92252ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
92352ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
92452ba4d50SCédric Le Goater }
92552ba4d50SCédric Le Goater 
92652ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
92752ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
928a580d820SCédric Le Goater                                  RspBuffer *rsp)
92952ba4d50SCédric Le Goater {
930a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
931a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
93252ba4d50SCédric Le Goater }
93352ba4d50SCédric Le Goater 
93452ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
93552ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
936a580d820SCédric Le Goater                             RspBuffer *rsp)
93752ba4d50SCédric Le Goater {
93852ba4d50SCédric Le Goater     unsigned int i;
93952ba4d50SCédric Le Goater 
94052ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
941a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->uuid[i]);
94252ba4d50SCédric Le Goater     }
94352ba4d50SCédric Le Goater }
9448bfffbccSCorey Minyard 
9458bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9468bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
947a580d820SCédric Le Goater                                    RspBuffer *rsp)
9488bfffbccSCorey Minyard {
9498bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9508bfffbccSCorey Minyard }
9518bfffbccSCorey Minyard 
9528bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9538bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
954a580d820SCédric Le Goater                                    RspBuffer *rsp)
9558bfffbccSCorey Minyard {
956a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9578bfffbccSCorey Minyard }
9588bfffbccSCorey Minyard 
9598bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9608bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
961a580d820SCédric Le Goater                           RspBuffer *rsp)
9628bfffbccSCorey Minyard {
9638bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9648bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9658bfffbccSCorey Minyard 
9668bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9678bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9688bfffbccSCorey Minyard }
9698bfffbccSCorey Minyard 
9708bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9718bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
972a580d820SCédric Le Goater                           RspBuffer *rsp)
9738bfffbccSCorey Minyard {
974a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9758bfffbccSCorey Minyard }
9768bfffbccSCorey Minyard 
9778bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9788bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
979a580d820SCédric Le Goater                              RspBuffer *rsp)
9808bfffbccSCorey Minyard {
9818bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9828bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9838bfffbccSCorey Minyard     unsigned int i;
9848bfffbccSCorey Minyard 
9858bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9866acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
987d13ada5dSCédric Le Goater         return;
9888bfffbccSCorey Minyard     }
9898bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
990a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9918bfffbccSCorey Minyard     }
9928bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9938bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9948bfffbccSCorey Minyard }
9958bfffbccSCorey Minyard 
9968bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9978bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
998a580d820SCédric Le Goater                     RspBuffer *rsp)
9998bfffbccSCorey Minyard {
10008bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10018bfffbccSCorey Minyard 
10028bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10036acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
10048bfffbccSCorey Minyard         goto out;
10058bfffbccSCorey Minyard     }
1006a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
10078bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
1008a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
10098bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
10108bfffbccSCorey Minyard     g_free(msg);
10118bfffbccSCorey Minyard 
10128bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10138bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
10148bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10158bfffbccSCorey Minyard 
10168bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10178bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10188bfffbccSCorey Minyard     }
10198bfffbccSCorey Minyard 
10208bfffbccSCorey Minyard out:
10218bfffbccSCorey Minyard     return;
10228bfffbccSCorey Minyard }
10238bfffbccSCorey Minyard 
10248bfffbccSCorey Minyard static unsigned char
10258bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10268bfffbccSCorey Minyard {
10278bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10288bfffbccSCorey Minyard             csum += *data;
10298bfffbccSCorey Minyard     }
10308bfffbccSCorey Minyard 
10318bfffbccSCorey Minyard     return -csum;
10328bfffbccSCorey Minyard }
10338bfffbccSCorey Minyard 
10348bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10358bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1036a580d820SCédric Le Goater                      RspBuffer *rsp)
10378bfffbccSCorey Minyard {
10388bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10398bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10408bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10418bfffbccSCorey Minyard     uint8_t *buf;
10428bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10438bfffbccSCorey Minyard 
10448bfffbccSCorey Minyard     if (cmd[2] != 0) {
10458bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
10466acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1047d13ada5dSCédric Le Goater         return;
10488bfffbccSCorey Minyard     }
10498bfffbccSCorey Minyard 
10504f298a4bSCédric Le Goater     if (cmd_len < 10) {
10516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10524f298a4bSCédric Le Goater         return;
10534f298a4bSCédric Le Goater     }
10544f298a4bSCédric Le Goater 
10558bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10568bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10576acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1058d13ada5dSCédric Le Goater         return;
10598bfffbccSCorey Minyard     }
10608bfffbccSCorey Minyard 
10618bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10628bfffbccSCorey Minyard     cmd_len -= 3;
10638bfffbccSCorey Minyard 
10648bfffbccSCorey Minyard     /*
10658bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10668bfffbccSCorey Minyard      * be returned in the response.
10678bfffbccSCorey Minyard      */
10688bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10698bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1070d13ada5dSCédric Le Goater         return; /* No response */
10718bfffbccSCorey Minyard     }
10728bfffbccSCorey Minyard 
10738bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10748bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10758bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10768bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10778bfffbccSCorey Minyard 
10788bfffbccSCorey Minyard     if (rqLun != 2) {
10798bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1080d13ada5dSCédric Le Goater         return;
10818bfffbccSCorey Minyard     }
10828bfffbccSCorey Minyard 
10838bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10848bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10858bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10868bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10878bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10888bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10898bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10908bfffbccSCorey Minyard     msg->len = 6;
10918bfffbccSCorey Minyard 
10928bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10938bfffbccSCorey Minyard         /* Not a command we handle. */
10948bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10958bfffbccSCorey Minyard         goto end_msg;
10968bfffbccSCorey Minyard     }
10978bfffbccSCorey Minyard 
10988bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10998bfffbccSCorey Minyard     buf[0] = 0;
11008bfffbccSCorey Minyard     buf[1] = 0;
11018bfffbccSCorey Minyard     buf[2] = 0;
11028bfffbccSCorey Minyard     buf[3] = 0;
11038bfffbccSCorey Minyard     buf[4] = 0x51;
11048bfffbccSCorey Minyard     buf[5] = 0;
11058bfffbccSCorey Minyard     buf[6] = 0;
11068bfffbccSCorey Minyard     buf[7] = 0;
11078bfffbccSCorey Minyard     buf[8] = 0;
11088bfffbccSCorey Minyard     buf[9] = 0;
11098bfffbccSCorey Minyard     buf[10] = 0;
11108bfffbccSCorey Minyard     msg->len += 11;
11118bfffbccSCorey Minyard 
11128bfffbccSCorey Minyard  end_msg:
11138bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11148bfffbccSCorey Minyard     msg->len++;
11158bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11168bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11178bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
11188bfffbccSCorey Minyard }
11198bfffbccSCorey Minyard 
11208bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11218bfffbccSCorey Minyard {
11228bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11238bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11248bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11258bfffbccSCorey Minyard         return;
11268bfffbccSCorey Minyard     }
11278bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11288bfffbccSCorey Minyard 
11298bfffbccSCorey Minyard 
11308bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11318bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11328bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11338bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11348bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11358bfffbccSCorey Minyard     }
11368bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11378bfffbccSCorey Minyard }
11388bfffbccSCorey Minyard 
11398bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11408bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1141a580d820SCédric Le Goater                                  RspBuffer *rsp)
11428bfffbccSCorey Minyard {
11438bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1145d13ada5dSCédric Le Goater         return;
11468bfffbccSCorey Minyard     }
11478bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11488bfffbccSCorey Minyard }
11498bfffbccSCorey Minyard 
11508bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11518bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1152a580d820SCédric Le Goater                                RspBuffer *rsp)
11538bfffbccSCorey Minyard {
11548bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11558bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11568bfffbccSCorey Minyard     unsigned int val;
11578bfffbccSCorey Minyard 
11588bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11598bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1161d13ada5dSCédric Le Goater         return;
11628bfffbccSCorey Minyard     }
11638bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11648bfffbccSCorey Minyard     switch (val) {
11658bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11668bfffbccSCorey Minyard         break;
11678bfffbccSCorey Minyard 
11688bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11708bfffbccSCorey Minyard         break;
11718bfffbccSCorey Minyard 
11728bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11736acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11748bfffbccSCorey Minyard         break;
11758bfffbccSCorey Minyard 
11768bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11776acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11788bfffbccSCorey Minyard         break;
11798bfffbccSCorey Minyard 
11808bfffbccSCorey Minyard     default:
11816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11828bfffbccSCorey Minyard     }
1183a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1185d13ada5dSCédric Le Goater         return;
11868bfffbccSCorey Minyard     }
11878bfffbccSCorey Minyard 
11888bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11898bfffbccSCorey Minyard     switch (val) {
11908bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11918bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11928bfffbccSCorey Minyard         break;
11938bfffbccSCorey Minyard 
11948bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11958bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11968bfffbccSCorey Minyard             /* NMI not supported. */
11976acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1198d13ada5dSCédric Le Goater             return;
11998bfffbccSCorey Minyard         }
120037eebb86SCorey Minyard         break;
120137eebb86SCorey Minyard 
12028bfffbccSCorey Minyard     default:
12038bfffbccSCorey Minyard         /* We don't support PRE_SMI */
12046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1205d13ada5dSCédric Le Goater         return;
12068bfffbccSCorey Minyard     }
12078bfffbccSCorey Minyard 
12088bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
12098bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
12108bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
12118bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
12128bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
12138bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12148bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12158bfffbccSCorey Minyard         do_watchdog_reset(ibs);
12168bfffbccSCorey Minyard     } else {
12178bfffbccSCorey Minyard         ibs->watchdog_running = 0;
12188bfffbccSCorey Minyard     }
12198bfffbccSCorey Minyard }
12208bfffbccSCorey Minyard 
12218bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12228bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1223a580d820SCédric Le Goater                                RspBuffer *rsp)
12248bfffbccSCorey Minyard {
1225a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1226a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1227a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1228a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
12298bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12308bfffbccSCorey Minyard         long timeout;
12318bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12328bfffbccSCorey Minyard                    / 100000000);
1233a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1234a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12358bfffbccSCorey Minyard     } else {
1236a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1237a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12388bfffbccSCorey Minyard     }
12398bfffbccSCorey Minyard }
12408bfffbccSCorey Minyard 
12418bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12428bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1243a580d820SCédric Le Goater                              RspBuffer *rsp)
12448bfffbccSCorey Minyard {
12458bfffbccSCorey Minyard     unsigned int i;
12468bfffbccSCorey Minyard 
1247a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1248a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1249a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1250a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1251a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12528bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1253a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12548bfffbccSCorey Minyard     }
12558bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1256a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12578bfffbccSCorey Minyard     }
12588bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1259a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12608bfffbccSCorey Minyard }
12618bfffbccSCorey Minyard 
12628bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12638bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1264a580d820SCédric Le Goater                             RspBuffer *rsp)
12658bfffbccSCorey Minyard {
1266a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1267a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12688bfffbccSCorey Minyard }
12698bfffbccSCorey Minyard 
12708bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12718bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1272a580d820SCédric Le Goater                     RspBuffer *rsp)
12738bfffbccSCorey Minyard {
12748bfffbccSCorey Minyard     unsigned int pos;
12758bfffbccSCorey Minyard     uint16_t nextrec;
1276a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12778bfffbccSCorey Minyard 
12788bfffbccSCorey Minyard     if (cmd[6]) {
12797f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12806acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12817f996411SCédric Le Goater             return;
12828bfffbccSCorey Minyard         }
12837f996411SCédric Le Goater     }
12847f996411SCédric Le Goater 
12858bfffbccSCorey Minyard     pos = 0;
12868bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12878bfffbccSCorey Minyard                        &pos, &nextrec)) {
12886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1289d13ada5dSCédric Le Goater         return;
12908bfffbccSCorey Minyard     }
1291a2295f0aSCédric Le Goater 
1292a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1293a2295f0aSCédric Le Goater 
1294a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12956acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1296d13ada5dSCédric Le Goater         return;
12978bfffbccSCorey Minyard     }
12988bfffbccSCorey Minyard 
1299a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1300a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13018bfffbccSCorey Minyard 
13028bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1303a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13048bfffbccSCorey Minyard     }
13058bfffbccSCorey Minyard 
1306a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13076acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1308d13ada5dSCédric Le Goater         return;
13098bfffbccSCorey Minyard     }
1310a580d820SCédric Le Goater 
1311a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13128bfffbccSCorey Minyard }
13138bfffbccSCorey Minyard 
13148bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13158bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1316a580d820SCédric Le Goater                     RspBuffer *rsp)
13178bfffbccSCorey Minyard {
13188bfffbccSCorey Minyard     uint16_t recid;
1319a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13208bfffbccSCorey Minyard 
1321a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13226acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1323d13ada5dSCédric Le Goater         return;
13248bfffbccSCorey Minyard     }
1325a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1326a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13278bfffbccSCorey Minyard }
13288bfffbccSCorey Minyard 
13298bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13308bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1331a580d820SCédric Le Goater                           RspBuffer *rsp)
13328bfffbccSCorey Minyard {
13337f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13346acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13357f996411SCédric Le Goater         return;
13367f996411SCédric Le Goater     }
13377f996411SCédric Le Goater 
13388bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1340d13ada5dSCédric Le Goater         return;
13418bfffbccSCorey Minyard     }
13428bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13438bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13448bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13458bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1346a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13478bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
13488bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1349a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13508bfffbccSCorey Minyard     } else {
13516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13528bfffbccSCorey Minyard         return;
13538bfffbccSCorey Minyard     }
1354d13ada5dSCédric Le Goater }
13558bfffbccSCorey Minyard 
13568bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13578bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1358a580d820SCédric Le Goater                          RspBuffer *rsp)
13598bfffbccSCorey Minyard {
13608bfffbccSCorey Minyard     unsigned int i, val;
13618bfffbccSCorey Minyard 
1362a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1363a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1364a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13658bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1366a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1367a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13688bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1369a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13708bfffbccSCorey Minyard     }
13718bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1372a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13738bfffbccSCorey Minyard     }
13748bfffbccSCorey Minyard     /* Only support Reserve SEL */
1375a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13768bfffbccSCorey Minyard }
13778bfffbccSCorey Minyard 
1378540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1379540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1380540c07d3SCédric Le Goater                          RspBuffer *rsp)
1381540c07d3SCédric Le Goater {
1382540c07d3SCédric Le Goater     uint8_t fruid;
1383540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1384540c07d3SCédric Le Goater 
1385540c07d3SCédric Le Goater     fruid = cmd[2];
1386540c07d3SCédric Le Goater 
1387540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1388540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1389540c07d3SCédric Le Goater         return;
1390540c07d3SCédric Le Goater     }
1391540c07d3SCédric Le Goater 
1392540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1393540c07d3SCédric Le Goater 
1394540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1395540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1396540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1397540c07d3SCédric Le Goater }
1398540c07d3SCédric Le Goater 
1399540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1400540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1401540c07d3SCédric Le Goater                          RspBuffer *rsp)
1402540c07d3SCédric Le Goater {
1403540c07d3SCédric Le Goater     uint8_t fruid;
1404540c07d3SCédric Le Goater     uint16_t offset;
1405540c07d3SCédric Le Goater     int i;
1406540c07d3SCédric Le Goater     uint8_t *fru_entry;
1407540c07d3SCédric Le Goater     unsigned int count;
1408540c07d3SCédric Le Goater 
1409540c07d3SCédric Le Goater     fruid = cmd[2];
1410540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1411540c07d3SCédric Le Goater 
1412540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1413540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1414540c07d3SCédric Le Goater         return;
1415540c07d3SCédric Le Goater     }
1416540c07d3SCédric Le Goater 
1417540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1418540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1419540c07d3SCédric Le Goater         return;
1420540c07d3SCédric Le Goater     }
1421540c07d3SCédric Le Goater 
1422540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1423540c07d3SCédric Le Goater 
1424540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1425540c07d3SCédric Le Goater 
1426540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1427540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1428540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1429540c07d3SCédric Le Goater     }
1430540c07d3SCédric Le Goater }
1431540c07d3SCédric Le Goater 
1432540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1433540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1434540c07d3SCédric Le Goater                          RspBuffer *rsp)
1435540c07d3SCédric Le Goater {
1436540c07d3SCédric Le Goater     uint8_t fruid;
1437540c07d3SCédric Le Goater     uint16_t offset;
1438540c07d3SCédric Le Goater     uint8_t *fru_entry;
1439540c07d3SCédric Le Goater     unsigned int count;
1440540c07d3SCédric Le Goater 
1441540c07d3SCédric Le Goater     fruid = cmd[2];
1442540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1443540c07d3SCédric Le Goater 
1444540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1445540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1446540c07d3SCédric Le Goater         return;
1447540c07d3SCédric Le Goater     }
1448540c07d3SCédric Le Goater 
1449540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1450540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1451540c07d3SCédric Le Goater         return;
1452540c07d3SCédric Le Goater     }
1453540c07d3SCédric Le Goater 
1454540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1455540c07d3SCédric Le Goater 
1456540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1457540c07d3SCédric Le Goater 
1458540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1459540c07d3SCédric Le Goater 
1460540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1461540c07d3SCédric Le Goater }
1462540c07d3SCédric Le Goater 
14638bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
14648bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1465a580d820SCédric Le Goater                         RspBuffer *rsp)
14668bfffbccSCorey Minyard {
1467a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1468a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
14698bfffbccSCorey Minyard }
14708bfffbccSCorey Minyard 
14718bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
14728bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1473a580d820SCédric Le Goater                           RspBuffer *rsp)
14748bfffbccSCorey Minyard {
14758bfffbccSCorey Minyard     unsigned int val;
14768bfffbccSCorey Minyard 
14778bfffbccSCorey Minyard     if (cmd[6]) {
14787f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
14796acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
14807f996411SCédric Le Goater             return;
14817f996411SCédric Le Goater         }
14828bfffbccSCorey Minyard     }
14838bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
14846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1485d13ada5dSCédric Le Goater         return;
14868bfffbccSCorey Minyard     }
14878bfffbccSCorey Minyard     if (cmd[6] > 15) {
14886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1489d13ada5dSCédric Le Goater         return;
14908bfffbccSCorey Minyard     }
14918bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
14928bfffbccSCorey Minyard         cmd[7] = 16;
14938bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
14946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1495d13ada5dSCédric Le Goater         return;
14968bfffbccSCorey Minyard     } else {
14978bfffbccSCorey Minyard         cmd[7] += cmd[6];
14988bfffbccSCorey Minyard     }
14998bfffbccSCorey Minyard 
15008bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
15018bfffbccSCorey Minyard     if (val == 0xffff) {
15028bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
15038bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
15046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1505d13ada5dSCédric Le Goater         return;
15068bfffbccSCorey Minyard     }
15078bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1508a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1509a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15108bfffbccSCorey Minyard     } else {
1511a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1512a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15138bfffbccSCorey Minyard     }
15148bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1515a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15168bfffbccSCorey Minyard     }
15178bfffbccSCorey Minyard }
15188bfffbccSCorey Minyard 
15198bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15208bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1521a580d820SCédric Le Goater                           RspBuffer *rsp)
15228bfffbccSCorey Minyard {
15238bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15246acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1525d13ada5dSCédric Le Goater         return;
15268bfffbccSCorey Minyard     }
15278bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1528a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1529a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15308bfffbccSCorey Minyard }
15318bfffbccSCorey Minyard 
15328bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15338bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1534a580d820SCédric Le Goater                       RspBuffer *rsp)
15358bfffbccSCorey Minyard {
15367f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15387f996411SCédric Le Goater         return;
15397f996411SCédric Le Goater     }
15407f996411SCédric Le Goater 
15418bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15426acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1543d13ada5dSCédric Le Goater         return;
15448bfffbccSCorey Minyard     }
15458bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15468bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15478bfffbccSCorey Minyard         ibs->sel.overflow = 0;
15488bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1549a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15508bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
15518bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1552a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15538bfffbccSCorey Minyard     } else {
15546acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15558bfffbccSCorey Minyard         return;
15568bfffbccSCorey Minyard     }
1557d13ada5dSCédric Le Goater }
15588bfffbccSCorey Minyard 
15598bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
15608bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1561a580d820SCédric Le Goater                          RspBuffer *rsp)
15628bfffbccSCorey Minyard {
15638bfffbccSCorey Minyard     uint32_t val;
15648bfffbccSCorey Minyard     struct ipmi_time now;
15658bfffbccSCorey Minyard 
15668bfffbccSCorey Minyard     ipmi_gettime(&now);
15678bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1568a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1569a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1570a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1571a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
15728bfffbccSCorey Minyard }
15738bfffbccSCorey Minyard 
15748bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
15758bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1576a580d820SCédric Le Goater                          RspBuffer *rsp)
15778bfffbccSCorey Minyard {
15788bfffbccSCorey Minyard     uint32_t val;
15798bfffbccSCorey Minyard     struct ipmi_time now;
15808bfffbccSCorey Minyard 
15818bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
15828bfffbccSCorey Minyard     ipmi_gettime(&now);
15838bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
15848bfffbccSCorey Minyard }
15858bfffbccSCorey Minyard 
15869380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
15879380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
15889380d2edSCorey Minyard                                RspBuffer *rsp)
15899380d2edSCorey Minyard {
15909380d2edSCorey Minyard     uint8_t event[16];
15919380d2edSCorey Minyard 
15929380d2edSCorey Minyard     event[2] = 2; /* System event record */
15939380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
15949380d2edSCorey Minyard     event[8] = 0;
15959380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
15969380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
15979380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
15989380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
15999380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
16009380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
16019380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
16029380d2edSCorey Minyard 
16039380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
16049380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16059380d2edSCorey Minyard     }
16069380d2edSCorey Minyard }
16079380d2edSCorey Minyard 
16088bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16098bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1610a580d820SCédric Le Goater                                   RspBuffer *rsp)
16118bfffbccSCorey Minyard {
16128bfffbccSCorey Minyard     IPMISensor *sens;
16138bfffbccSCorey Minyard 
161473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16158bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16166acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1617d13ada5dSCédric Le Goater         return;
16188bfffbccSCorey Minyard     }
16198bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16208bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16218bfffbccSCorey Minyard     case 0: /* Do not change */
16228bfffbccSCorey Minyard         break;
16238bfffbccSCorey Minyard     case 1: /* Enable bits */
16248bfffbccSCorey Minyard         if (cmd_len > 4) {
16258bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16268bfffbccSCorey Minyard         }
16278bfffbccSCorey Minyard         if (cmd_len > 5) {
16288bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16298bfffbccSCorey Minyard         }
16308bfffbccSCorey Minyard         if (cmd_len > 6) {
16318bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16328bfffbccSCorey Minyard         }
16338bfffbccSCorey Minyard         if (cmd_len > 7) {
16348bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16358bfffbccSCorey Minyard         }
16368bfffbccSCorey Minyard         break;
16378bfffbccSCorey Minyard     case 2: /* Disable bits */
16388bfffbccSCorey Minyard         if (cmd_len > 4) {
16398bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16408bfffbccSCorey Minyard         }
16418bfffbccSCorey Minyard         if (cmd_len > 5) {
16428bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16438bfffbccSCorey Minyard         }
16448bfffbccSCorey Minyard         if (cmd_len > 6) {
16458bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16468bfffbccSCorey Minyard         }
16478bfffbccSCorey Minyard         if (cmd_len > 7) {
16488bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
16498bfffbccSCorey Minyard         }
16508bfffbccSCorey Minyard         break;
16518bfffbccSCorey Minyard     case 3:
16526acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1653d13ada5dSCédric Le Goater         return;
16548bfffbccSCorey Minyard     }
16558bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
16568bfffbccSCorey Minyard }
16578bfffbccSCorey Minyard 
16588bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
16598bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1660a580d820SCédric Le Goater                                   RspBuffer *rsp)
16618bfffbccSCorey Minyard {
16628bfffbccSCorey Minyard     IPMISensor *sens;
16638bfffbccSCorey Minyard 
166473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16658bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1667d13ada5dSCédric Le Goater         return;
16688bfffbccSCorey Minyard     }
16698bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1670a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1671a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1672a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1673a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1674a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
16758bfffbccSCorey Minyard }
16768bfffbccSCorey Minyard 
16778bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
16788bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1679a580d820SCédric Le Goater                               RspBuffer *rsp)
16808bfffbccSCorey Minyard {
16818bfffbccSCorey Minyard     IPMISensor *sens;
16828bfffbccSCorey Minyard 
168373d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16848bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16856acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1686d13ada5dSCédric Le Goater         return;
16878bfffbccSCorey Minyard     }
16888bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16898bfffbccSCorey Minyard 
16908bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
16918bfffbccSCorey Minyard         /* Just clear everything */
16928bfffbccSCorey Minyard         sens->states = 0;
16938bfffbccSCorey Minyard         return;
16948bfffbccSCorey Minyard     }
1695d13ada5dSCédric Le Goater }
16968bfffbccSCorey Minyard 
16978bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
16988bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1699a580d820SCédric Le Goater                                   RspBuffer *rsp)
17008bfffbccSCorey Minyard {
17018bfffbccSCorey Minyard     IPMISensor *sens;
17028bfffbccSCorey Minyard 
170373d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17048bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1706d13ada5dSCédric Le Goater         return;
17078bfffbccSCorey Minyard     }
17088bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1709a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1710a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1711a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1712a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1713a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1714a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17158bfffbccSCorey Minyard }
17168bfffbccSCorey Minyard 
17178bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17188bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1719a580d820SCédric Le Goater                                RspBuffer *rsp)
17208bfffbccSCorey Minyard {
17218bfffbccSCorey Minyard     IPMISensor *sens;
17228bfffbccSCorey Minyard 
172373d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17248bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17256acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1726d13ada5dSCédric Le Goater         return;
17278bfffbccSCorey Minyard     }
17288bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1729a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1730a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1731a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17328bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1733a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17348bfffbccSCorey Minyard     }
17358bfffbccSCorey Minyard }
17368bfffbccSCorey Minyard 
1737728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1738728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1739a580d820SCédric Le Goater                             RspBuffer *rsp)
1740728710e1SCédric Le Goater {
1741728710e1SCédric Le Goater     IPMISensor *sens;
1742728710e1SCédric Le Goater 
1743728710e1SCédric Le Goater 
174473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1745728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17466acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1747728710e1SCédric Le Goater         return;
1748728710e1SCédric Le Goater     }
1749728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1750728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1751728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1752728710e1SCédric Le Goater }
1753728710e1SCédric Le Goater 
1754728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1755728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1756a580d820SCédric Le Goater                             RspBuffer *rsp)
1757728710e1SCédric Le Goater {
1758728710e1SCédric Le Goater     IPMISensor *sens;
1759728710e1SCédric Le Goater 
1760728710e1SCédric Le Goater 
176173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1762728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17636acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1764728710e1SCédric Le Goater         return;
1765728710e1SCédric Le Goater     }
1766728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1767a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1768a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1769728710e1SCédric Le Goater }
1770728710e1SCédric Le Goater 
1771728710e1SCédric Le Goater 
177262a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
17734f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
17744f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
17754f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
17764f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
17778bfffbccSCorey Minyard };
17788bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
177962a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
17808bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
17818bfffbccSCorey Minyard };
17828bfffbccSCorey Minyard 
178362a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
17849380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
17854f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
17864f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
17874f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
17884f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
17894f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
17904f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
17914f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
17928bfffbccSCorey Minyard };
17938bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
179462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
17958bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
17968bfffbccSCorey Minyard };
17978bfffbccSCorey Minyard 
179862a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
17994f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
18004f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
18014f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
18024f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
18034f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
18044f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
18054f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
18064f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
18074f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
18084f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
18094f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
18104f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
18114f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
18124f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
18134f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
18144f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
18158bfffbccSCorey Minyard };
18168bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
181762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
18188bfffbccSCorey Minyard     .cmd_handlers = app_cmds
18198bfffbccSCorey Minyard };
18208bfffbccSCorey Minyard 
182162a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
1822540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
1823540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
1824540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
18254f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
18264f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
18274f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
18284f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
18294f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
18304f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
18314f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
18324f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
18334f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
18344f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
18357f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
18367f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
18378bfffbccSCorey Minyard };
18388bfffbccSCorey Minyard 
18398bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
184062a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
18418bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
18428bfffbccSCorey Minyard };
18438bfffbccSCorey Minyard 
18448bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
18458bfffbccSCorey Minyard {
18468bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
18478bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
18488bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
18498bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
18508bfffbccSCorey Minyard }
18518bfffbccSCorey Minyard 
18525167560bSCédric Le Goater static uint8_t init_sdrs[] = {
18538bfffbccSCorey Minyard     /* Watchdog device */
18548bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
18558bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
18568bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18578bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
18588bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
18598bfffbccSCorey Minyard };
18608bfffbccSCorey Minyard 
18614fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
18624fa9f08eSCédric Le Goater {
18634fa9f08eSCédric Le Goater     unsigned int i;
18644fa9f08eSCédric Le Goater     int len;
18655167560bSCédric Le Goater     size_t sdrs_size;
18665167560bSCédric Le Goater     uint8_t *sdrs;
186752fc01d9SCédric Le Goater 
18685167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
18695167560bSCédric Le Goater     sdrs = init_sdrs;
18708c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
18718c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
18728c6fd7f3SCédric Le Goater                              NULL)) {
18738c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
18748c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
18758c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
18768c6fd7f3SCédric Le Goater     }
18775167560bSCédric Le Goater 
18785167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
187952fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
188052fc01d9SCédric Le Goater 
18815167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
18824fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
18838c6fd7f3SCédric Le Goater             break;
18844fa9f08eSCédric Le Goater         }
18855167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
18864fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
18875167560bSCédric Le Goater         if (i + len > sdrs_size) {
18884fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
18898c6fd7f3SCédric Le Goater             break;
18904fa9f08eSCédric Le Goater         }
18914fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
18924fa9f08eSCédric Le Goater     }
18938c6fd7f3SCédric Le Goater 
18948c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
18958c6fd7f3SCédric Le Goater         g_free(sdrs);
18968c6fd7f3SCédric Le Goater     }
18974fa9f08eSCédric Le Goater }
18984fa9f08eSCédric Le Goater 
1899bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1900bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1901bd66bcfcSCorey Minyard     .version_id = 1,
1902bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1903bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1904bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1905bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1906bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1907bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1908bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1909bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1910bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1911bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1912bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1913bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1914bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1915bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1916bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1917bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1918bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1919bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1920bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1921bd66bcfcSCorey Minyard                        IPMIBmcSim),
1922bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1923bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1924bd66bcfcSCorey Minyard     }
1925bd66bcfcSCorey Minyard };
1926bd66bcfcSCorey Minyard 
1927540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
1928540c07d3SCédric Le Goater {
1929540c07d3SCédric Le Goater     int fsize;
1930540c07d3SCédric Le Goater     int size = 0;
1931540c07d3SCédric Le Goater 
1932540c07d3SCédric Le Goater     if (!fru->filename) {
1933540c07d3SCédric Le Goater         goto out;
1934540c07d3SCédric Le Goater     }
1935540c07d3SCédric Le Goater 
1936540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
1937540c07d3SCédric Le Goater     if (fsize > 0) {
1938540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
1939540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1940540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
1941540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
1942540c07d3SCédric Le Goater             g_free(fru->data);
1943540c07d3SCédric Le Goater             fru->data = NULL;
1944540c07d3SCédric Le Goater         }
1945540c07d3SCédric Le Goater     }
1946540c07d3SCédric Le Goater 
1947540c07d3SCédric Le Goater out:
1948540c07d3SCédric Le Goater     if (!fru->data) {
1949540c07d3SCédric Le Goater         /* give one default FRU */
1950540c07d3SCédric Le Goater         size = fru->areasize;
1951540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1952540c07d3SCédric Le Goater     }
1953540c07d3SCédric Le Goater 
1954540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
1955540c07d3SCédric Le Goater }
1956540c07d3SCédric Le Goater 
19570bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
19588bfffbccSCorey Minyard {
19590bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
19608bfffbccSCorey Minyard     unsigned int i;
19618bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
19628bfffbccSCorey Minyard 
19638bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
19648bfffbccSCorey Minyard 
19658bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
19668bfffbccSCorey Minyard     ibs->device_id = 0x20;
19678bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1968b7088392SCédric Le Goater     ibs->restart_cause = 0;
19698bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
19708bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
19718bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
19728bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
19738bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
19748bfffbccSCorey Minyard     }
19758bfffbccSCorey Minyard 
19764fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
19778bfffbccSCorey Minyard 
1978540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
1979540c07d3SCédric Le Goater 
198052ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
198152ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
198252ba4d50SCédric Le Goater 
198352ba4d50SCédric Le Goater     if (qemu_uuid_set) {
19849c5ce8dbSFam Zheng         memcpy(&ibs->uuid, &qemu_uuid, 16);
198552ba4d50SCédric Le Goater     } else {
198652ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
198752ba4d50SCédric Le Goater     }
198852ba4d50SCédric Le Goater 
19898bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
19908bfffbccSCorey Minyard     register_cmds(ibs);
19918bfffbccSCorey Minyard 
19928bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1993bd66bcfcSCorey Minyard 
1994bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
19958bfffbccSCorey Minyard }
19968bfffbccSCorey Minyard 
19978c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
1998540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
1999540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
20008c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
200120b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
200220b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
200320b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
200420b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
200520b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
200620b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
200720b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
20088c6fd7f3SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
20098c6fd7f3SCédric Le Goater };
20108c6fd7f3SCédric Le Goater 
20118bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
20128bfffbccSCorey Minyard {
20130bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
20148bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
20158bfffbccSCorey Minyard 
201666abfddbSCorey Minyard     dc->hotpluggable = false;
20170bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
20188c6fd7f3SCédric Le Goater     dc->props = ipmi_sim_properties;
20198bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
20208bfffbccSCorey Minyard }
20218bfffbccSCorey Minyard 
20228bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
20238bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
20248bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
20258bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
20268bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
20278bfffbccSCorey Minyard };
20288bfffbccSCorey Minyard 
20298bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
20308bfffbccSCorey Minyard {
20318bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
20328bfffbccSCorey Minyard }
20338bfffbccSCorey Minyard 
20348bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2035