xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 7f9e7af40a1721e5adb95761754bc12af0f3d2f1)
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"
2632cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
278bfffbccSCorey Minyard #include "qemu/timer.h"
288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
298bfffbccSCorey Minyard #include "qemu/error-report.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
318c6fd7f3SCédric Le Goater #include "hw/loader.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
34d6454270SMarkus Armbruster #include "migration/vmstate.h"
358bfffbccSCorey Minyard 
368bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
378bfffbccSCorey Minyard 
388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
398bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
408bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
41b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
428bfffbccSCorey Minyard 
438bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
448bfffbccSCorey Minyard 
459380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG       0x02
468bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
478bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
488bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
508bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
51728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
52728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
53e3f7320cSCédric Le Goater #define IPMI_CMD_SET_SENSOR_READING       0x30
548bfffbccSCorey Minyard 
558bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
568bfffbccSCorey Minyard 
578bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
588bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
598bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
6052ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
6152ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
6252ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
638bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
648bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
658bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
668bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
678bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
688bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
698bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
708bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
718bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
728bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
73*7f9e7af4SNicholas Piggin #define IPMI_CMD_GET_CHANNEL_INFO         0x42
748bfffbccSCorey Minyard 
758bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
768bfffbccSCorey Minyard 
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
798bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
808bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
818bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
828bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
838bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
848bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
858bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
868bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
878bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
888bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
898bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
90540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO        0x10
91540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA            0x11
92540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA           0x12
938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
948bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
958bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
968bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
978bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
988bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
998bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
1008bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
1018bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
1028bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
1038bfffbccSCorey Minyard 
1048bfffbccSCorey Minyard 
1058bfffbccSCorey Minyard /* Same as a timespec struct. */
1068bfffbccSCorey Minyard struct ipmi_time {
1078bfffbccSCorey Minyard     long tv_sec;
1088bfffbccSCorey Minyard     long tv_nsec;
1098bfffbccSCorey Minyard };
1108bfffbccSCorey Minyard 
1118bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1128bfffbccSCorey Minyard 
1138bfffbccSCorey Minyard typedef struct IPMISel {
1148bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1158bfffbccSCorey Minyard     unsigned int next_free;
1168bfffbccSCorey Minyard     long time_offset;
1178bfffbccSCorey Minyard     uint16_t reservation;
1188bfffbccSCorey Minyard     uint8_t last_addition[4];
1198bfffbccSCorey Minyard     uint8_t last_clear[4];
1208bfffbccSCorey Minyard     uint8_t overflow;
1218bfffbccSCorey Minyard } IPMISel;
1228bfffbccSCorey Minyard 
1238bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1248bfffbccSCorey Minyard 
1258bfffbccSCorey Minyard typedef struct IPMISdr {
1268bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1278bfffbccSCorey Minyard     unsigned int next_free;
1288bfffbccSCorey Minyard     uint16_t next_rec_id;
1298bfffbccSCorey Minyard     uint16_t reservation;
1308bfffbccSCorey Minyard     uint8_t last_addition[4];
1318bfffbccSCorey Minyard     uint8_t last_clear[4];
1328bfffbccSCorey Minyard     uint8_t overflow;
1338bfffbccSCorey Minyard } IPMISdr;
1348bfffbccSCorey Minyard 
135540c07d3SCédric Le Goater typedef struct IPMIFru {
136540c07d3SCédric Le Goater     char *filename;
137540c07d3SCédric Le Goater     unsigned int nentries;
138540c07d3SCédric Le Goater     uint16_t areasize;
139540c07d3SCédric Le Goater     uint8_t *data;
140540c07d3SCédric Le Goater } IPMIFru;
141540c07d3SCédric Le Goater 
1428bfffbccSCorey Minyard typedef struct IPMISensor {
1438bfffbccSCorey Minyard     uint8_t status;
1448bfffbccSCorey Minyard     uint8_t reading;
1458bfffbccSCorey Minyard     uint16_t states_suppt;
1468bfffbccSCorey Minyard     uint16_t assert_suppt;
1478bfffbccSCorey Minyard     uint16_t deassert_suppt;
1488bfffbccSCorey Minyard     uint16_t states;
1498bfffbccSCorey Minyard     uint16_t assert_states;
1508bfffbccSCorey Minyard     uint16_t deassert_states;
1518bfffbccSCorey Minyard     uint16_t assert_enable;
1528bfffbccSCorey Minyard     uint16_t deassert_enable;
1538bfffbccSCorey Minyard     uint8_t  sensor_type;
1548bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1558bfffbccSCorey Minyard } IPMISensor;
1568bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1578bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1588bfffbccSCorey Minyard                                              !!(v))
1598bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1608bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1618bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1628bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1638bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1648bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1658bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1668bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1678bfffbccSCorey Minyard                                              (v & 0xc0))
1688bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1698bfffbccSCorey Minyard 
1708bfffbccSCorey Minyard #define MAX_SENSORS 20
1718bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1728bfffbccSCorey Minyard 
1738bfffbccSCorey Minyard #define MAX_NETFNS 64
1744f298a4bSCédric Le Goater 
1758bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1768bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1778bfffbccSCorey Minyard     uint8_t len;
1788bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1798bfffbccSCorey Minyard } IPMIRcvBufEntry;
1808bfffbccSCorey Minyard 
1818bfffbccSCorey Minyard struct IPMIBmcSim {
1828bfffbccSCorey Minyard     IPMIBmc parent;
1838bfffbccSCorey Minyard 
1848bfffbccSCorey Minyard     QEMUTimer *timer;
1858bfffbccSCorey Minyard 
1868bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1878bfffbccSCorey Minyard     uint8_t msg_flags;
1888bfffbccSCorey Minyard 
1898bfffbccSCorey Minyard     bool     watchdog_initialized;
1908bfffbccSCorey Minyard     uint8_t  watchdog_use;
1918bfffbccSCorey Minyard     uint8_t  watchdog_action;
1928bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1939e744990SJinhua Cao     uint8_t  watchdog_expired;
1948bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1958bfffbccSCorey Minyard 
1968bfffbccSCorey Minyard     bool     watchdog_running;
1978bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1988bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1998bfffbccSCorey Minyard 
2008bfffbccSCorey Minyard     uint8_t device_id;
2018bfffbccSCorey Minyard     uint8_t ipmi_version;
2028bfffbccSCorey Minyard     uint8_t device_rev;
2038bfffbccSCorey Minyard     uint8_t fwrev1;
2048bfffbccSCorey Minyard     uint8_t fwrev2;
20520b23364SCorey Minyard     uint32_t mfg_id;
20620b23364SCorey Minyard     uint16_t product_id;
2078bfffbccSCorey Minyard 
208b7088392SCédric Le Goater     uint8_t restart_cause;
209b7088392SCédric Le Goater 
21052ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
2117b0cd78bSCorey Minyard     QemuUUID uuid;
21252ba4d50SCédric Le Goater 
2138bfffbccSCorey Minyard     IPMISel sel;
2148bfffbccSCorey Minyard     IPMISdr sdr;
215540c07d3SCédric Le Goater     IPMIFru fru;
2168bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2178c6fd7f3SCédric Le Goater     char *sdr_filename;
2188bfffbccSCorey Minyard 
2198bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2208bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2218bfffbccSCorey Minyard 
2228bfffbccSCorey Minyard     /* We allow one event in the buffer */
2238bfffbccSCorey Minyard     uint8_t evtbuf[16];
2248bfffbccSCorey Minyard 
2258bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2268bfffbccSCorey Minyard };
2278bfffbccSCorey Minyard 
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2318bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2328bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2338bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2348bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2358bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2368bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2378bfffbccSCorey Minyard 
2388bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2398bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2418bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2438bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2448bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2458bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2468bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2478bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2488bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2498bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2508bfffbccSCorey Minyard 
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2668bfffbccSCorey Minyard 
267a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2688bfffbccSCorey Minyard 
269a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
270a580d820SCédric Le Goater                                        unsigned int n)
271a580d820SCédric Le Goater {
272a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
2736acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
274a580d820SCédric Le Goater         return;
275a580d820SCédric Le Goater     }
276a580d820SCédric Le Goater 
277a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
278a580d820SCédric Le Goater     rsp->len += n;
279a580d820SCédric Le Goater }
2808bfffbccSCorey Minyard 
2818bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2828bfffbccSCorey Minyard 
2838bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2848bfffbccSCorey Minyard {
2858bfffbccSCorey Minyard     int64_t stime;
2868bfffbccSCorey Minyard 
2878bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2888bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2898bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2908bfffbccSCorey Minyard }
2918bfffbccSCorey Minyard 
2928bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2938bfffbccSCorey Minyard {
2948bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2958bfffbccSCorey Minyard }
2968bfffbccSCorey Minyard 
2978bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2988bfffbccSCorey Minyard {
2998bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3008bfffbccSCorey Minyard 
3018bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3028bfffbccSCorey Minyard }
3038bfffbccSCorey Minyard 
3048bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3058bfffbccSCorey Minyard {
3068bfffbccSCorey Minyard     unsigned int val;
3078bfffbccSCorey Minyard     struct ipmi_time now;
3088bfffbccSCorey Minyard 
3098bfffbccSCorey Minyard     ipmi_gettime(&now);
3108bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3118bfffbccSCorey Minyard     ts[0] = val & 0xff;
3128bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3138bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3148bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3158bfffbccSCorey Minyard }
3168bfffbccSCorey Minyard 
3178bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3188bfffbccSCorey Minyard {
3198bfffbccSCorey Minyard     sdr->reservation++;
3208bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3218bfffbccSCorey Minyard         sdr->reservation = 1;
3228bfffbccSCorey Minyard     }
3238bfffbccSCorey Minyard }
3248bfffbccSCorey Minyard 
325a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
326a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3278bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3288bfffbccSCorey Minyard {
329a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
330a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
331a2295f0aSCédric Le Goater 
332a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3338bfffbccSCorey Minyard         return 1;
3348bfffbccSCorey Minyard     }
3358bfffbccSCorey Minyard 
336a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3378bfffbccSCorey Minyard         return 1;
3388bfffbccSCorey Minyard     }
3398bfffbccSCorey Minyard 
3408bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3418bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3428bfffbccSCorey Minyard         return 1;
3438bfffbccSCorey Minyard     }
3448bfffbccSCorey Minyard 
345a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
346a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
347a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
348a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3498bfffbccSCorey Minyard 
3508bfffbccSCorey Minyard     if (recid) {
3518bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3528bfffbccSCorey Minyard     }
3538bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3548bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3558bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3568bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3578bfffbccSCorey Minyard     return 0;
3588bfffbccSCorey Minyard }
3598bfffbccSCorey Minyard 
3608bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3618bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3628bfffbccSCorey Minyard {
3638bfffbccSCorey Minyard     unsigned int pos = *retpos;
3648bfffbccSCorey Minyard 
3658bfffbccSCorey Minyard     while (pos < sdr->next_free) {
366a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
367a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
368a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
369a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3708bfffbccSCorey Minyard 
3718bfffbccSCorey Minyard         if (trec == recid) {
3728bfffbccSCorey Minyard             if (nextrec) {
3738bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3748bfffbccSCorey Minyard                     *nextrec = 0xffff;
3758bfffbccSCorey Minyard                 } else {
3768bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3778bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3788bfffbccSCorey Minyard                 }
3798bfffbccSCorey Minyard             }
3808bfffbccSCorey Minyard             *retpos = pos;
3818bfffbccSCorey Minyard             return 0;
3828bfffbccSCorey Minyard         }
3838bfffbccSCorey Minyard         pos = nextpos;
3848bfffbccSCorey Minyard     }
3858bfffbccSCorey Minyard     return 1;
3868bfffbccSCorey Minyard }
3878bfffbccSCorey Minyard 
3887fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
3897fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
3907fabcdb9SCédric Le Goater 
3917fabcdb9SCédric Le Goater {
3927fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
3937fabcdb9SCédric Le Goater     unsigned int pos;
3947fabcdb9SCédric Le Goater 
3957fabcdb9SCédric Le Goater     pos = 0;
3967fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
3977fabcdb9SCédric Le Goater         return -1;
3987fabcdb9SCédric Le Goater     }
3997fabcdb9SCédric Le Goater 
4007fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4017fabcdb9SCédric Le Goater     return 0;
4027fabcdb9SCédric Le Goater }
4037fabcdb9SCédric Le Goater 
4048bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4058bfffbccSCorey Minyard {
4068bfffbccSCorey Minyard     sel->reservation++;
4078bfffbccSCorey Minyard     if (sel->reservation == 0) {
4088bfffbccSCorey Minyard         sel->reservation = 1;
4098bfffbccSCorey Minyard     }
4108bfffbccSCorey Minyard }
4118bfffbccSCorey Minyard 
4128bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4138bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4148bfffbccSCorey Minyard {
4159f7d1d92SCorey Minyard     uint8_t ts[4];
4169f7d1d92SCorey Minyard 
4178bfffbccSCorey Minyard     event[0] = 0xff;
4188bfffbccSCorey Minyard     event[1] = 0xff;
4199f7d1d92SCorey Minyard     set_timestamp(ibs, ts);
4209f7d1d92SCorey Minyard     if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4219f7d1d92SCorey Minyard         memcpy(event + 3, ts, 4);
4229f7d1d92SCorey Minyard     }
4238bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4248bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4258bfffbccSCorey Minyard         return 1;
4268bfffbccSCorey Minyard     }
4278bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4288bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4299f7d1d92SCorey Minyard     memcpy(ibs->sel.last_addition, ts, 4);
4308bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4318bfffbccSCorey Minyard     ibs->sel.next_free++;
4328bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4338bfffbccSCorey Minyard     return 0;
4348bfffbccSCorey Minyard }
4358bfffbccSCorey Minyard 
4368bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4378bfffbccSCorey Minyard {
4388bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4398bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4408bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4418bfffbccSCorey Minyard }
4428bfffbccSCorey Minyard 
4438bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4448bfffbccSCorey Minyard {
4458bc8af69SCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4468bc8af69SCorey Minyard             (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4478bc8af69SCorey Minyard              IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4488bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4498bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4508bfffbccSCorey Minyard }
4518bfffbccSCorey Minyard 
452cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
453cd60d85eSCédric Le Goater {
454cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
455cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
456cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
457cd60d85eSCédric Le Goater 
458cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
459cd60d85eSCédric Le Goater         return;
460cd60d85eSCédric Le Goater     }
461cd60d85eSCédric Le Goater 
462cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
463cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
464cd60d85eSCédric Le Goater     }
465cd60d85eSCédric Le Goater 
466cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
467cd60d85eSCédric Le Goater         goto out;
468cd60d85eSCédric Le Goater     }
469cd60d85eSCédric Le Goater 
470cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
471cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
472cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
473cd60d85eSCédric Le Goater  out:
474cd60d85eSCédric Le Goater     return;
475cd60d85eSCédric Le Goater }
4768bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4778bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4788bfffbccSCorey Minyard {
4798bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4808bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4818bfffbccSCorey Minyard     uint8_t evt[16];
4828bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4838bfffbccSCorey Minyard 
4848bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4858bfffbccSCorey Minyard         return;
4868bfffbccSCorey Minyard     }
4878bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4888bfffbccSCorey Minyard         return;
4898bfffbccSCorey Minyard     }
4908bfffbccSCorey Minyard 
4918bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4928bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4938bfffbccSCorey Minyard     evt[8] = 0;
4948bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4958bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4968bfffbccSCorey Minyard     evt[11] = sens_num;
4978bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4988bfffbccSCorey Minyard     evt[13] = evd1;
4998bfffbccSCorey Minyard     evt[14] = evd2;
5008bfffbccSCorey Minyard     evt[15] = evd3;
5018bfffbccSCorey Minyard 
5028bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5038bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5048bfffbccSCorey Minyard     }
5058bfffbccSCorey Minyard 
5068bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
507d13ada5dSCédric Le Goater         return;
5088bfffbccSCorey Minyard     }
5098bfffbccSCorey Minyard 
5108bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5118bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5128bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5138bfffbccSCorey Minyard }
5148bfffbccSCorey Minyard 
5158bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5168bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
5178bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
5188bfffbccSCorey Minyard {
5198bfffbccSCorey Minyard     IPMISensor *sens;
5208bfffbccSCorey Minyard     uint16_t mask;
5218bfffbccSCorey Minyard 
5228bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5238bfffbccSCorey Minyard         return;
5248bfffbccSCorey Minyard     }
5258bfffbccSCorey Minyard     if (bit >= 16) {
5268bfffbccSCorey Minyard         return;
5278bfffbccSCorey Minyard     }
5288bfffbccSCorey Minyard 
5298bfffbccSCorey Minyard     mask = (1 << bit);
5308bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5318bfffbccSCorey Minyard     if (val) {
5328bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5338bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5348bfffbccSCorey Minyard             return; /* Already asserted */
5358bfffbccSCorey Minyard         }
5368bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5378bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5388bfffbccSCorey Minyard             /* Send an event on assert */
5398bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5408bfffbccSCorey Minyard         }
5418bfffbccSCorey Minyard     } else {
5428bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5438bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5448bfffbccSCorey Minyard             return; /* Already deasserted */
5458bfffbccSCorey Minyard         }
5468bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5478bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5488bfffbccSCorey Minyard             /* Send an event on deassert */
5498bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5508bfffbccSCorey Minyard         }
5518bfffbccSCorey Minyard     }
5528bfffbccSCorey Minyard }
5538bfffbccSCorey Minyard 
5548bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5558bfffbccSCorey Minyard {
5568bfffbccSCorey Minyard     unsigned int i, pos;
5578bfffbccSCorey Minyard     IPMISensor *sens;
5588bfffbccSCorey Minyard 
5598bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5608bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5618bfffbccSCorey Minyard     }
5628bfffbccSCorey Minyard 
5638bfffbccSCorey Minyard     pos = 0;
5648bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
565a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
566a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
567a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5688bfffbccSCorey Minyard 
5698bfffbccSCorey Minyard         if (len < 20) {
5708bfffbccSCorey Minyard             continue;
5718bfffbccSCorey Minyard         }
572a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5738bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5748bfffbccSCorey Minyard         }
5758bfffbccSCorey Minyard 
57673d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5778bfffbccSCorey Minyard             continue;
5788bfffbccSCorey Minyard         }
579a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5808bfffbccSCorey Minyard 
5818bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
582a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
583a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
584a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
585a2295f0aSCédric Le Goater         sens->deassert_suppt =
586a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
587a2295f0aSCédric Le Goater         sens->states_suppt =
588a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
589a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
590a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5918bfffbccSCorey Minyard 
5928bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5938bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5948bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5958bfffbccSCorey Minyard     }
5968bfffbccSCorey Minyard }
5978bfffbccSCorey Minyard 
598ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5998bfffbccSCorey Minyard                         const IPMINetfn *netfnd)
6008bfffbccSCorey Minyard {
60193a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6028bfffbccSCorey Minyard         return -1;
6038bfffbccSCorey Minyard     }
6048bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6058bfffbccSCorey Minyard     return 0;
6068bfffbccSCorey Minyard }
6078bfffbccSCorey Minyard 
6084f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6094f298a4bSCédric Le Goater                                               unsigned int netfn,
6104f298a4bSCédric Le Goater                                               unsigned int cmd)
6114f298a4bSCédric Le Goater {
6124f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6134f298a4bSCédric Le Goater 
6144f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6154f298a4bSCédric Le Goater         return NULL;
6164f298a4bSCédric Le Goater     }
6174f298a4bSCédric Le Goater 
6184f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6194f298a4bSCédric Le Goater         return NULL;
6204f298a4bSCédric Le Goater     }
6214f298a4bSCédric Le Goater 
6224f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6234f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6244f298a4bSCédric Le Goater         return NULL;
6254f298a4bSCédric Le Goater     }
6264f298a4bSCédric Le Goater 
6274f298a4bSCédric Le Goater     return hdl;
6284f298a4bSCédric Le Goater }
6294f298a4bSCédric Le Goater 
6308bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6318bfffbccSCorey Minyard {
6328bfffbccSCorey Minyard     int64_t next;
6338bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6348bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6358bfffbccSCorey Minyard     } else {
6368bfffbccSCorey Minyard         /* Wait a minute */
6378bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6388bfffbccSCorey Minyard     }
6398bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6408bfffbccSCorey Minyard }
6418bfffbccSCorey Minyard 
6428bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6438bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6448bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6458bfffbccSCorey Minyard                                     uint8_t msg_id)
6468bfffbccSCorey Minyard {
6478bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6488bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6498bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6504f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
651a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6528bfffbccSCorey Minyard 
6538bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6548bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
655a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6566acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
657d13ada5dSCédric Le Goater         goto out;
658d13ada5dSCédric Le Goater     }
659d13ada5dSCédric Le Goater 
660a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
661a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
662a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6638bfffbccSCorey Minyard 
6648bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6658bfffbccSCorey Minyard     if (cmd_len < 2) {
6666acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6678bfffbccSCorey Minyard         goto out;
6688bfffbccSCorey Minyard     }
6698bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6706acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6718bfffbccSCorey Minyard         goto out;
6728bfffbccSCorey Minyard     }
6738bfffbccSCorey Minyard 
6748bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6758bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6766acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6778bfffbccSCorey Minyard         goto out;
6788bfffbccSCorey Minyard     }
6798bfffbccSCorey Minyard 
6804f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6814f298a4bSCédric Le Goater     if (!hdl) {
6826acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6838bfffbccSCorey Minyard         goto out;
6848bfffbccSCorey Minyard     }
6858bfffbccSCorey Minyard 
6864f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6876acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6884f298a4bSCédric Le Goater         goto out;
6894f298a4bSCédric Le Goater     }
6904f298a4bSCédric Le Goater 
691a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6928bfffbccSCorey Minyard 
6938bfffbccSCorey Minyard  out:
694a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6958bfffbccSCorey Minyard 
6968bfffbccSCorey Minyard     next_timeout(ibs);
6978bfffbccSCorey Minyard }
6988bfffbccSCorey Minyard 
6998bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7008bfffbccSCorey Minyard {
7018bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7028bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7038bfffbccSCorey Minyard 
7048bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7058bfffbccSCorey Minyard         goto out;
7068bfffbccSCorey Minyard     }
7078bfffbccSCorey Minyard 
7088bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7098bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7108bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7118bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7128bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7138bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7148bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
7158bfffbccSCorey Minyard             break;
7168bfffbccSCorey Minyard 
7178bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7188bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7198bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7208bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7218bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
7228bfffbccSCorey Minyard             break;
7238bfffbccSCorey Minyard 
7248bfffbccSCorey Minyard         default:
7258bfffbccSCorey Minyard             goto do_full_expiry;
7268bfffbccSCorey Minyard         }
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7298bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7308bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7318bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7328bfffbccSCorey Minyard         goto out;
7338bfffbccSCorey Minyard     }
7348bfffbccSCorey Minyard 
7358bfffbccSCorey Minyard  do_full_expiry:
7368bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7378bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7388bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7398bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7408bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7418bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7428bfffbccSCorey Minyard         break;
7438bfffbccSCorey Minyard 
7448bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7458bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7468bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7478bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7488bfffbccSCorey Minyard         break;
7498bfffbccSCorey Minyard 
7508bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7518bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7528bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7538bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7548bfffbccSCorey Minyard         break;
7558bfffbccSCorey Minyard 
7568bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7578bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7588bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7598bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7608bfffbccSCorey Minyard         break;
7618bfffbccSCorey Minyard     }
7628bfffbccSCorey Minyard 
7638bfffbccSCorey Minyard  out:
7648bfffbccSCorey Minyard     next_timeout(ibs);
7658bfffbccSCorey Minyard }
7668bfffbccSCorey Minyard 
7678bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7688bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
769a580d820SCédric Le Goater                                  RspBuffer *rsp)
7708bfffbccSCorey Minyard {
771a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
772a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
773a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
774a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
775a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7768bfffbccSCorey Minyard }
7778bfffbccSCorey Minyard 
7788bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7798bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
780a580d820SCédric Le Goater                            RspBuffer *rsp)
7818bfffbccSCorey Minyard {
782a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
783a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
784a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
785a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7868bfffbccSCorey Minyard }
7878bfffbccSCorey Minyard 
7888bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7898bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
790a580d820SCédric Le Goater                             RspBuffer *rsp)
7918bfffbccSCorey Minyard {
7928bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7938bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7948bfffbccSCorey Minyard 
7958bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7968bfffbccSCorey Minyard     case 0: /* power down */
7976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
7988bfffbccSCorey Minyard         break;
7998bfffbccSCorey Minyard     case 1: /* power up */
8006acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8018bfffbccSCorey Minyard         break;
8028bfffbccSCorey Minyard     case 2: /* power cycle */
8036acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8048bfffbccSCorey Minyard         break;
8058bfffbccSCorey Minyard     case 3: /* hard reset */
8066acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8078bfffbccSCorey Minyard         break;
8088bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8096acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8108bfffbccSCorey Minyard         break;
8118bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8126acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8136acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8148bfffbccSCorey Minyard         break;
8158bfffbccSCorey Minyard     default:
8166acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8178bfffbccSCorey Minyard         return;
8188bfffbccSCorey Minyard     }
819d13ada5dSCédric Le Goater }
8208bfffbccSCorey Minyard 
821b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
822b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
823a580d820SCédric Le Goater                            RspBuffer *rsp)
824a580d820SCédric Le Goater 
825b7088392SCédric Le Goater {
826a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
827a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
828b7088392SCédric Le Goater }
829b7088392SCédric Le Goater 
8308bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8318bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
832a580d820SCédric Le Goater                           RspBuffer *rsp)
8338bfffbccSCorey Minyard {
834a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
835a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
836a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
837a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
838a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
839a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
84020b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84120b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
84220b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
84320b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
84420b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8458bfffbccSCorey Minyard }
8468bfffbccSCorey Minyard 
8478bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8488bfffbccSCorey Minyard {
8498bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8508bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8518bfffbccSCorey Minyard     bool irqs_on;
8528bfffbccSCorey Minyard 
8538bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8548bfffbccSCorey Minyard 
8558bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8568bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8578bfffbccSCorey Minyard 
8588bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8598bfffbccSCorey Minyard }
8608bfffbccSCorey Minyard 
8618bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8628bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
863a580d820SCédric Le Goater                        RspBuffer *rsp)
8648bfffbccSCorey Minyard {
8658bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8668bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8678bfffbccSCorey Minyard 
8688bfffbccSCorey Minyard     /* Disable all interrupts */
8698bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8708bfffbccSCorey Minyard 
8718bfffbccSCorey Minyard     if (k->reset) {
8728bfffbccSCorey Minyard         k->reset(s, true);
8738bfffbccSCorey Minyard     }
8748bfffbccSCorey Minyard }
8758bfffbccSCorey Minyard 
8768bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8778bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
878a580d820SCédric Le Goater                        RspBuffer *rsp)
8798bfffbccSCorey Minyard {
8808bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8818bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8828bfffbccSCorey Minyard 
8838bfffbccSCorey Minyard     if (k->reset) {
8848bfffbccSCorey Minyard         k->reset(s, false);
8858bfffbccSCorey Minyard     }
8868bfffbccSCorey Minyard }
88752ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
88852ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
889a580d820SCédric Le Goater                                  RspBuffer *rsp)
89052ba4d50SCédric Le Goater {
89152ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
89252ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
89352ba4d50SCédric Le Goater }
89452ba4d50SCédric Le Goater 
89552ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
89652ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
897a580d820SCédric Le Goater                                  RspBuffer *rsp)
89852ba4d50SCédric Le Goater {
899a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
900a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90152ba4d50SCédric Le Goater }
90252ba4d50SCédric Le Goater 
90352ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
90452ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
905a580d820SCédric Le Goater                             RspBuffer *rsp)
90652ba4d50SCédric Le Goater {
90752ba4d50SCédric Le Goater     unsigned int i;
90852ba4d50SCédric Le Goater 
9097b0cd78bSCorey Minyard     /* An uninitialized uuid is all zeros, use that to know if it is set. */
91052ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
9117b0cd78bSCorey Minyard         if (ibs->uuid.data[i]) {
9127b0cd78bSCorey Minyard             goto uuid_set;
9137b0cd78bSCorey Minyard         }
9147b0cd78bSCorey Minyard     }
9157b0cd78bSCorey Minyard     /* No uuid is set, return an error. */
9167b0cd78bSCorey Minyard     rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9177b0cd78bSCorey Minyard     return;
9187b0cd78bSCorey Minyard 
9197b0cd78bSCorey Minyard  uuid_set:
9207b0cd78bSCorey Minyard     for (i = 0; i < 16; i++) {
9217b0cd78bSCorey Minyard         rsp_buffer_push(rsp, ibs->uuid.data[i]);
92252ba4d50SCédric Le Goater     }
92352ba4d50SCédric Le Goater }
9248bfffbccSCorey Minyard 
9258bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9268bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
927a580d820SCédric Le Goater                                    RspBuffer *rsp)
9288bfffbccSCorey Minyard {
9298bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9308bfffbccSCorey Minyard }
9318bfffbccSCorey Minyard 
9328bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9338bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
934a580d820SCédric Le Goater                                    RspBuffer *rsp)
9358bfffbccSCorey Minyard {
936a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9378bfffbccSCorey Minyard }
9388bfffbccSCorey Minyard 
9398bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9408bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
941a580d820SCédric Le Goater                           RspBuffer *rsp)
9428bfffbccSCorey Minyard {
9438bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9448bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9458bfffbccSCorey Minyard 
9468bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9478bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9488bfffbccSCorey Minyard }
9498bfffbccSCorey Minyard 
9508bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9518bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
952a580d820SCédric Le Goater                           RspBuffer *rsp)
9538bfffbccSCorey Minyard {
954a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9558bfffbccSCorey Minyard }
9568bfffbccSCorey Minyard 
9578bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9588bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
959a580d820SCédric Le Goater                              RspBuffer *rsp)
9608bfffbccSCorey Minyard {
9618bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9628bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9638bfffbccSCorey Minyard     unsigned int i;
9648bfffbccSCorey Minyard 
9658bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
967d13ada5dSCédric Le Goater         return;
9688bfffbccSCorey Minyard     }
9698bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
970a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9718bfffbccSCorey Minyard     }
9728bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9738bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9748bfffbccSCorey Minyard }
9758bfffbccSCorey Minyard 
9768bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9778bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
978a580d820SCédric Le Goater                     RspBuffer *rsp)
9798bfffbccSCorey Minyard {
9808bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9818bfffbccSCorey Minyard 
9828bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9836acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9848bfffbccSCorey Minyard         goto out;
9858bfffbccSCorey Minyard     }
986a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
9878bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
988a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9898bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9908bfffbccSCorey Minyard     g_free(msg);
9918bfffbccSCorey Minyard 
9928bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9938bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9948bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9958bfffbccSCorey Minyard 
9968bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9978bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9988bfffbccSCorey Minyard     }
9998bfffbccSCorey Minyard 
10008bfffbccSCorey Minyard out:
10018bfffbccSCorey Minyard     return;
10028bfffbccSCorey Minyard }
10038bfffbccSCorey Minyard 
10048bfffbccSCorey Minyard static unsigned char
10058bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10068bfffbccSCorey Minyard {
10078bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10088bfffbccSCorey Minyard             csum += *data;
10098bfffbccSCorey Minyard     }
10108bfffbccSCorey Minyard 
10118bfffbccSCorey Minyard     return -csum;
10128bfffbccSCorey Minyard }
10138bfffbccSCorey Minyard 
10148bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10158bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1016a580d820SCédric Le Goater                      RspBuffer *rsp)
10178bfffbccSCorey Minyard {
10188bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10198bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10208bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10218bfffbccSCorey Minyard     uint8_t *buf;
10228bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10238bfffbccSCorey Minyard 
1024*7f9e7af4SNicholas Piggin     if (cmd[2] != IPMI_CHANNEL_IPMB) {
1025*7f9e7af4SNicholas Piggin         /* We only handle channel 0h (IPMB) with no options */
10266acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1027d13ada5dSCédric Le Goater         return;
10288bfffbccSCorey Minyard     }
10298bfffbccSCorey Minyard 
10304f298a4bSCédric Le Goater     if (cmd_len < 10) {
10316acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10324f298a4bSCédric Le Goater         return;
10334f298a4bSCédric Le Goater     }
10344f298a4bSCédric Le Goater 
10358bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10368bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1038d13ada5dSCédric Le Goater         return;
10398bfffbccSCorey Minyard     }
10408bfffbccSCorey Minyard 
10418bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10428bfffbccSCorey Minyard     cmd_len -= 3;
10438bfffbccSCorey Minyard 
10448bfffbccSCorey Minyard     /*
10458bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10468bfffbccSCorey Minyard      * be returned in the response.
10478bfffbccSCorey Minyard      */
10488bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10498bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1050d13ada5dSCédric Le Goater         return; /* No response */
10518bfffbccSCorey Minyard     }
10528bfffbccSCorey Minyard 
10538bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10548bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10558bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10568bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10578bfffbccSCorey Minyard 
10588bfffbccSCorey Minyard     if (rqLun != 2) {
10598bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1060d13ada5dSCédric Le Goater         return;
10618bfffbccSCorey Minyard     }
10628bfffbccSCorey Minyard 
10638bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10648bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10658bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10668bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10678bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10688bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10698bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10708bfffbccSCorey Minyard     msg->len = 6;
10718bfffbccSCorey Minyard 
10728bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10738bfffbccSCorey Minyard         /* Not a command we handle. */
10748bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10758bfffbccSCorey Minyard         goto end_msg;
10768bfffbccSCorey Minyard     }
10778bfffbccSCorey Minyard 
10788bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10798bfffbccSCorey Minyard     buf[0] = 0;
10808bfffbccSCorey Minyard     buf[1] = 0;
10818bfffbccSCorey Minyard     buf[2] = 0;
10828bfffbccSCorey Minyard     buf[3] = 0;
10838bfffbccSCorey Minyard     buf[4] = 0x51;
10848bfffbccSCorey Minyard     buf[5] = 0;
10858bfffbccSCorey Minyard     buf[6] = 0;
10868bfffbccSCorey Minyard     buf[7] = 0;
10878bfffbccSCorey Minyard     buf[8] = 0;
10888bfffbccSCorey Minyard     buf[9] = 0;
10898bfffbccSCorey Minyard     buf[10] = 0;
10908bfffbccSCorey Minyard     msg->len += 11;
10918bfffbccSCorey Minyard 
10928bfffbccSCorey Minyard  end_msg:
10938bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10948bfffbccSCorey Minyard     msg->len++;
10958bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10968bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10978bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10988bfffbccSCorey Minyard }
10998bfffbccSCorey Minyard 
11008bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11018bfffbccSCorey Minyard {
11028bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11038bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11048bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11058bfffbccSCorey Minyard         return;
11068bfffbccSCorey Minyard     }
11078bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11088bfffbccSCorey Minyard 
11098bfffbccSCorey Minyard 
11108bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11118bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11128bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11138bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11148bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11158bfffbccSCorey Minyard     }
11168bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11178bfffbccSCorey Minyard }
11188bfffbccSCorey Minyard 
11198bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11208bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1121a580d820SCédric Le Goater                                  RspBuffer *rsp)
11228bfffbccSCorey Minyard {
11238bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11246acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1125d13ada5dSCédric Le Goater         return;
11268bfffbccSCorey Minyard     }
11278bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11288bfffbccSCorey Minyard }
11298bfffbccSCorey Minyard 
11308bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11318bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1132a580d820SCédric Le Goater                                RspBuffer *rsp)
11338bfffbccSCorey Minyard {
11348bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11358bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11368bfffbccSCorey Minyard     unsigned int val;
11378bfffbccSCorey Minyard 
11388bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11398bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1141d13ada5dSCédric Le Goater         return;
11428bfffbccSCorey Minyard     }
11438bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11448bfffbccSCorey Minyard     switch (val) {
11458bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11468bfffbccSCorey Minyard         break;
11478bfffbccSCorey Minyard 
11488bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11496acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11508bfffbccSCorey Minyard         break;
11518bfffbccSCorey Minyard 
11528bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11536acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11548bfffbccSCorey Minyard         break;
11558bfffbccSCorey Minyard 
11568bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11576acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11588bfffbccSCorey Minyard         break;
11598bfffbccSCorey Minyard 
11608bfffbccSCorey Minyard     default:
11616acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11628bfffbccSCorey Minyard     }
1163a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11646acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1165d13ada5dSCédric Le Goater         return;
11668bfffbccSCorey Minyard     }
11678bfffbccSCorey Minyard 
11688bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11698bfffbccSCorey Minyard     switch (val) {
11708bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11718bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11728bfffbccSCorey Minyard         break;
11738bfffbccSCorey Minyard 
11748bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11756af94767SCorey Minyard         if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11768bfffbccSCorey Minyard             /* NMI not supported. */
11776acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1178d13ada5dSCédric Le Goater             return;
11798bfffbccSCorey Minyard         }
118037eebb86SCorey Minyard         break;
118137eebb86SCorey Minyard 
11828bfffbccSCorey Minyard     default:
11838bfffbccSCorey Minyard         /* We don't support PRE_SMI */
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     ibs->watchdog_initialized = 1;
11898bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11908bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11918bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11928bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11938bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11948bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11958bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11968bfffbccSCorey Minyard     } else {
11978bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11988bfffbccSCorey Minyard     }
11998bfffbccSCorey Minyard }
12008bfffbccSCorey Minyard 
12018bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12028bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1203a580d820SCédric Le Goater                                RspBuffer *rsp)
12048bfffbccSCorey Minyard {
1205a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1206a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1207a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1208a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
1209fb45770bSCorey Minyard     rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1210fb45770bSCorey Minyard     rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12118bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12128bfffbccSCorey Minyard         long timeout;
12138bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12148bfffbccSCorey Minyard                    / 100000000);
1215a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1216a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12178bfffbccSCorey Minyard     } else {
1218a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1219a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12208bfffbccSCorey Minyard     }
12218bfffbccSCorey Minyard }
12228bfffbccSCorey Minyard 
1223*7f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs,
1224*7f9e7af4SNicholas Piggin                              uint8_t *cmd, unsigned int cmd_len,
1225*7f9e7af4SNicholas Piggin                              RspBuffer *rsp)
1226*7f9e7af4SNicholas Piggin {
1227*7f9e7af4SNicholas Piggin     IPMIInterface *s = ibs->parent.intf;
1228*7f9e7af4SNicholas Piggin     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1229*7f9e7af4SNicholas Piggin     IPMIFwInfo info = {};
1230*7f9e7af4SNicholas Piggin     uint8_t ch = cmd[2] & 0x0f;
1231*7f9e7af4SNicholas Piggin 
1232*7f9e7af4SNicholas Piggin     /* Only define channel 0h (IPMB) and Fh (system interface) */
1233*7f9e7af4SNicholas Piggin 
1234*7f9e7af4SNicholas Piggin     if (ch == 0x0e) { /* "This channel" */
1235*7f9e7af4SNicholas Piggin         ch = IPMI_CHANNEL_SYSTEM;
1236*7f9e7af4SNicholas Piggin     }
1237*7f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, ch);
1238*7f9e7af4SNicholas Piggin 
1239*7f9e7af4SNicholas Piggin     if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
1240*7f9e7af4SNicholas Piggin         /* Not a supported channel */
1241*7f9e7af4SNicholas Piggin         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1242*7f9e7af4SNicholas Piggin         return;
1243*7f9e7af4SNicholas Piggin     }
1244*7f9e7af4SNicholas Piggin 
1245*7f9e7af4SNicholas Piggin     if (k->get_fwinfo) {
1246*7f9e7af4SNicholas Piggin         k->get_fwinfo(s, &info);
1247*7f9e7af4SNicholas Piggin     }
1248*7f9e7af4SNicholas Piggin 
1249*7f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_IPMB) {
1250*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
1251*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
1252*7f9e7af4SNicholas Piggin     } else { /* IPMI_CHANNEL_SYSTEM */
1253*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
1254*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, info.ipmi_channel_protocol);
1255*7f9e7af4SNicholas Piggin     }
1256*7f9e7af4SNicholas Piggin 
1257*7f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00); /* Session-less */
1258*7f9e7af4SNicholas Piggin 
1259*7f9e7af4SNicholas Piggin     /* IPMI Enterprise Number for Vendor ID */
1260*7f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0xf2);
1261*7f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x1b);
1262*7f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00);
1263*7f9e7af4SNicholas Piggin 
1264*7f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_SYSTEM) {
1265*7f9e7af4SNicholas Piggin         uint8_t irq;
1266*7f9e7af4SNicholas Piggin 
1267*7f9e7af4SNicholas Piggin         if (info.irq_source == IPMI_ISA_IRQ) {
1268*7f9e7af4SNicholas Piggin             irq = info.interrupt_number;
1269*7f9e7af4SNicholas Piggin         } else if (info.irq_source == IPMI_PCI_IRQ) {
1270*7f9e7af4SNicholas Piggin             irq = 0x10 + info.interrupt_number;
1271*7f9e7af4SNicholas Piggin         } else {
1272*7f9e7af4SNicholas Piggin             irq = 0xff; /* no interrupt / unspecified */
1273*7f9e7af4SNicholas Piggin         }
1274*7f9e7af4SNicholas Piggin 
1275*7f9e7af4SNicholas Piggin         /* Both interrupts use the same irq number */
1276*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
1277*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
1278*7f9e7af4SNicholas Piggin     } else {
1279*7f9e7af4SNicholas Piggin         /* Reserved */
1280*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
1281*7f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
1282*7f9e7af4SNicholas Piggin     }
1283*7f9e7af4SNicholas Piggin }
1284*7f9e7af4SNicholas Piggin 
12858bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12868bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1287a580d820SCédric Le Goater                              RspBuffer *rsp)
12888bfffbccSCorey Minyard {
12898bfffbccSCorey Minyard     unsigned int i;
12908bfffbccSCorey Minyard 
1291a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1292a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1293a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1294a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1295a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12968bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1297a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12988bfffbccSCorey Minyard     }
12998bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1300a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
13018bfffbccSCorey Minyard     }
13028bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1303a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
13048bfffbccSCorey Minyard }
13058bfffbccSCorey Minyard 
13068bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
13078bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1308a580d820SCédric Le Goater                             RspBuffer *rsp)
13098bfffbccSCorey Minyard {
1310a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1311a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
13128bfffbccSCorey Minyard }
13138bfffbccSCorey Minyard 
13148bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
13158bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1316a580d820SCédric Le Goater                     RspBuffer *rsp)
13178bfffbccSCorey Minyard {
13188bfffbccSCorey Minyard     unsigned int pos;
13198bfffbccSCorey Minyard     uint16_t nextrec;
1320a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
13218bfffbccSCorey Minyard 
13228bfffbccSCorey Minyard     if (cmd[6]) {
13237f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13246acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13257f996411SCédric Le Goater             return;
13268bfffbccSCorey Minyard         }
13277f996411SCédric Le Goater     }
13287f996411SCédric Le Goater 
13298bfffbccSCorey Minyard     pos = 0;
13308bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
13318bfffbccSCorey Minyard                        &pos, &nextrec)) {
13326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1333d13ada5dSCédric Le Goater         return;
13348bfffbccSCorey Minyard     }
1335a2295f0aSCédric Le Goater 
1336a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1337a2295f0aSCédric Le Goater 
1338a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
13396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1340d13ada5dSCédric Le Goater         return;
13418bfffbccSCorey Minyard     }
13428bfffbccSCorey Minyard 
1343a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1344a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13458bfffbccSCorey Minyard 
13468bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1347a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13488bfffbccSCorey Minyard     }
13498bfffbccSCorey Minyard 
1350a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1352d13ada5dSCédric Le Goater         return;
13538bfffbccSCorey Minyard     }
1354a580d820SCédric Le Goater 
1355a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13568bfffbccSCorey Minyard }
13578bfffbccSCorey Minyard 
13588bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13598bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1360a580d820SCédric Le Goater                     RspBuffer *rsp)
13618bfffbccSCorey Minyard {
13628bfffbccSCorey Minyard     uint16_t recid;
1363a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13648bfffbccSCorey Minyard 
1365a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1367d13ada5dSCédric Le Goater         return;
13688bfffbccSCorey Minyard     }
1369a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1370a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13718bfffbccSCorey Minyard }
13728bfffbccSCorey Minyard 
13738bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13748bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1375a580d820SCédric Le Goater                           RspBuffer *rsp)
13768bfffbccSCorey Minyard {
13777f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13786acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13797f996411SCédric Le Goater         return;
13807f996411SCédric Le Goater     }
13817f996411SCédric Le Goater 
13828bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13836acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1384d13ada5dSCédric Le Goater         return;
13858bfffbccSCorey Minyard     }
13868bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13878bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13888bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13898bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1390a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13918bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
13928bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1393a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13948bfffbccSCorey Minyard     } else {
13956acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13968bfffbccSCorey Minyard         return;
13978bfffbccSCorey Minyard     }
1398d13ada5dSCédric Le Goater }
13998bfffbccSCorey Minyard 
14008bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
14018bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1402a580d820SCédric Le Goater                          RspBuffer *rsp)
14038bfffbccSCorey Minyard {
14048bfffbccSCorey Minyard     unsigned int i, val;
14058bfffbccSCorey Minyard 
1406a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1407a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1408a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
14098bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1410a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1411a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
14128bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1413a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
14148bfffbccSCorey Minyard     }
14158bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1416a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
14178bfffbccSCorey Minyard     }
14188bfffbccSCorey Minyard     /* Only support Reserve SEL */
1419a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
14208bfffbccSCorey Minyard }
14218bfffbccSCorey Minyard 
1422540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1423540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1424540c07d3SCédric Le Goater                          RspBuffer *rsp)
1425540c07d3SCédric Le Goater {
1426540c07d3SCédric Le Goater     uint8_t fruid;
1427540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1428540c07d3SCédric Le Goater 
1429540c07d3SCédric Le Goater     fruid = cmd[2];
1430540c07d3SCédric Le Goater 
1431540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1432540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1433540c07d3SCédric Le Goater         return;
1434540c07d3SCédric Le Goater     }
1435540c07d3SCédric Le Goater 
1436540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1437540c07d3SCédric Le Goater 
1438540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1439540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1440540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1441540c07d3SCédric Le Goater }
1442540c07d3SCédric Le Goater 
1443540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1444540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1445540c07d3SCédric Le Goater                          RspBuffer *rsp)
1446540c07d3SCédric Le Goater {
1447540c07d3SCédric Le Goater     uint8_t fruid;
1448540c07d3SCédric Le Goater     uint16_t offset;
1449540c07d3SCédric Le Goater     int i;
1450540c07d3SCédric Le Goater     uint8_t *fru_entry;
1451540c07d3SCédric Le Goater     unsigned int count;
1452540c07d3SCédric Le Goater 
1453540c07d3SCédric Le Goater     fruid = cmd[2];
1454540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1455540c07d3SCédric Le Goater 
1456540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1457540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1458540c07d3SCédric Le Goater         return;
1459540c07d3SCédric Le Goater     }
1460540c07d3SCédric Le Goater 
1461540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1462540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1463540c07d3SCédric Le Goater         return;
1464540c07d3SCédric Le Goater     }
1465540c07d3SCédric Le Goater 
1466540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1467540c07d3SCédric Le Goater 
1468540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1469540c07d3SCédric Le Goater 
1470540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1471540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1472540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1473540c07d3SCédric Le Goater     }
1474540c07d3SCédric Le Goater }
1475540c07d3SCédric Le Goater 
1476540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1477540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1478540c07d3SCédric Le Goater                          RspBuffer *rsp)
1479540c07d3SCédric Le Goater {
1480540c07d3SCédric Le Goater     uint8_t fruid;
1481540c07d3SCédric Le Goater     uint16_t offset;
1482540c07d3SCédric Le Goater     uint8_t *fru_entry;
1483540c07d3SCédric Le Goater     unsigned int count;
1484540c07d3SCédric Le Goater 
1485540c07d3SCédric Le Goater     fruid = cmd[2];
1486540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1487540c07d3SCédric Le Goater 
1488540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1489540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1490540c07d3SCédric Le Goater         return;
1491540c07d3SCédric Le Goater     }
1492540c07d3SCédric Le Goater 
1493540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1494540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1495540c07d3SCédric Le Goater         return;
1496540c07d3SCédric Le Goater     }
1497540c07d3SCédric Le Goater 
1498540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1499540c07d3SCédric Le Goater 
1500540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1501540c07d3SCédric Le Goater 
1502540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1503540c07d3SCédric Le Goater 
1504540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1505540c07d3SCédric Le Goater }
1506540c07d3SCédric Le Goater 
15078bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
15088bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1509a580d820SCédric Le Goater                         RspBuffer *rsp)
15108bfffbccSCorey Minyard {
1511a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1512a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
15138bfffbccSCorey Minyard }
15148bfffbccSCorey Minyard 
15158bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
15168bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1517a580d820SCédric Le Goater                           RspBuffer *rsp)
15188bfffbccSCorey Minyard {
15198bfffbccSCorey Minyard     unsigned int val;
15208bfffbccSCorey Minyard 
15218bfffbccSCorey Minyard     if (cmd[6]) {
15227f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15236acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15247f996411SCédric Le Goater             return;
15257f996411SCédric Le Goater         }
15268bfffbccSCorey Minyard     }
15278bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
15286acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1529d13ada5dSCédric Le Goater         return;
15308bfffbccSCorey Minyard     }
15318bfffbccSCorey Minyard     if (cmd[6] > 15) {
15326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1533d13ada5dSCédric Le Goater         return;
15348bfffbccSCorey Minyard     }
15358bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
15368bfffbccSCorey Minyard         cmd[7] = 16;
15378bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
15386acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1539d13ada5dSCédric Le Goater         return;
15408bfffbccSCorey Minyard     } else {
15418bfffbccSCorey Minyard         cmd[7] += cmd[6];
15428bfffbccSCorey Minyard     }
15438bfffbccSCorey Minyard 
15448bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
15458bfffbccSCorey Minyard     if (val == 0xffff) {
15468bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
15478bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
15486acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1549d13ada5dSCédric Le Goater         return;
15508bfffbccSCorey Minyard     }
15518bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1552a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1553a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15548bfffbccSCorey Minyard     } else {
1555a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1556a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15578bfffbccSCorey Minyard     }
15588bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1559a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15608bfffbccSCorey Minyard     }
15618bfffbccSCorey Minyard }
15628bfffbccSCorey Minyard 
15638bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15648bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1565a580d820SCédric Le Goater                           RspBuffer *rsp)
15668bfffbccSCorey Minyard {
15678bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15686acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1569d13ada5dSCédric Le Goater         return;
15708bfffbccSCorey Minyard     }
15718bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1572a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1573a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15748bfffbccSCorey Minyard }
15758bfffbccSCorey Minyard 
15768bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15778bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1578a580d820SCédric Le Goater                       RspBuffer *rsp)
15798bfffbccSCorey Minyard {
15807f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15827f996411SCédric Le Goater         return;
15837f996411SCédric Le Goater     }
15847f996411SCédric Le Goater 
15858bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15866acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1587d13ada5dSCédric Le Goater         return;
15888bfffbccSCorey Minyard     }
15898bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15908bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15918bfffbccSCorey Minyard         ibs->sel.overflow = 0;
15928bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1593a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15948bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
15958bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1596a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15978bfffbccSCorey Minyard     } else {
15986acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15998bfffbccSCorey Minyard         return;
16008bfffbccSCorey Minyard     }
1601d13ada5dSCédric Le Goater }
16028bfffbccSCorey Minyard 
16038bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
16048bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1605a580d820SCédric Le Goater                          RspBuffer *rsp)
16068bfffbccSCorey Minyard {
16078bfffbccSCorey Minyard     uint32_t val;
16088bfffbccSCorey Minyard     struct ipmi_time now;
16098bfffbccSCorey Minyard 
16108bfffbccSCorey Minyard     ipmi_gettime(&now);
16118bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1612a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1613a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1614a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1615a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
16168bfffbccSCorey Minyard }
16178bfffbccSCorey Minyard 
16188bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
16198bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1620a580d820SCédric Le Goater                          RspBuffer *rsp)
16218bfffbccSCorey Minyard {
16228bfffbccSCorey Minyard     uint32_t val;
16238bfffbccSCorey Minyard     struct ipmi_time now;
16248bfffbccSCorey Minyard 
16258bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
16268bfffbccSCorey Minyard     ipmi_gettime(&now);
16278bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
16288bfffbccSCorey Minyard }
16298bfffbccSCorey Minyard 
16309380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
16319380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
16329380d2edSCorey Minyard                                RspBuffer *rsp)
16339380d2edSCorey Minyard {
16349380d2edSCorey Minyard     uint8_t event[16];
16359380d2edSCorey Minyard 
16369380d2edSCorey Minyard     event[2] = 2; /* System event record */
16379380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
16389380d2edSCorey Minyard     event[8] = 0;
16399380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
16409380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
16419380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
16429380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
16439380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
16449380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
16459380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
16469380d2edSCorey Minyard 
16479380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
16489380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16499380d2edSCorey Minyard     }
16509380d2edSCorey Minyard }
16519380d2edSCorey Minyard 
16528bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16538bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1654a580d820SCédric Le Goater                                   RspBuffer *rsp)
16558bfffbccSCorey Minyard {
16568bfffbccSCorey Minyard     IPMISensor *sens;
16578bfffbccSCorey Minyard 
165873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16598bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1661d13ada5dSCédric Le Goater         return;
16628bfffbccSCorey Minyard     }
16638bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16648bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16658bfffbccSCorey Minyard     case 0: /* Do not change */
16668bfffbccSCorey Minyard         break;
16678bfffbccSCorey Minyard     case 1: /* Enable bits */
16688bfffbccSCorey Minyard         if (cmd_len > 4) {
16698bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16708bfffbccSCorey Minyard         }
16718bfffbccSCorey Minyard         if (cmd_len > 5) {
16728bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16738bfffbccSCorey Minyard         }
16748bfffbccSCorey Minyard         if (cmd_len > 6) {
16758bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16768bfffbccSCorey Minyard         }
16778bfffbccSCorey Minyard         if (cmd_len > 7) {
16788bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16798bfffbccSCorey Minyard         }
16808bfffbccSCorey Minyard         break;
16818bfffbccSCorey Minyard     case 2: /* Disable bits */
16828bfffbccSCorey Minyard         if (cmd_len > 4) {
16838bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16848bfffbccSCorey Minyard         }
16858bfffbccSCorey Minyard         if (cmd_len > 5) {
16868bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16878bfffbccSCorey Minyard         }
16888bfffbccSCorey Minyard         if (cmd_len > 6) {
16898bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16908bfffbccSCorey Minyard         }
16918bfffbccSCorey Minyard         if (cmd_len > 7) {
16928bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
16938bfffbccSCorey Minyard         }
16948bfffbccSCorey Minyard         break;
16958bfffbccSCorey Minyard     case 3:
16966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1697d13ada5dSCédric Le Goater         return;
16988bfffbccSCorey Minyard     }
16998bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
17008bfffbccSCorey Minyard }
17018bfffbccSCorey Minyard 
17028bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
17038bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1704a580d820SCédric Le Goater                                   RspBuffer *rsp)
17058bfffbccSCorey Minyard {
17068bfffbccSCorey Minyard     IPMISensor *sens;
17078bfffbccSCorey Minyard 
170873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17098bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17106acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1711d13ada5dSCédric Le Goater         return;
17128bfffbccSCorey Minyard     }
17138bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1714a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1715a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1716a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1717a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1718a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
17198bfffbccSCorey Minyard }
17208bfffbccSCorey Minyard 
17218bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
17228bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1723a580d820SCédric Le Goater                               RspBuffer *rsp)
17248bfffbccSCorey Minyard {
17258bfffbccSCorey Minyard     IPMISensor *sens;
17268bfffbccSCorey Minyard 
172773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17288bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17296acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1730d13ada5dSCédric Le Goater         return;
17318bfffbccSCorey Minyard     }
17328bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
17338bfffbccSCorey Minyard 
17348bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
17358bfffbccSCorey Minyard         /* Just clear everything */
17368bfffbccSCorey Minyard         sens->states = 0;
17378bfffbccSCorey Minyard         return;
17388bfffbccSCorey Minyard     }
1739d13ada5dSCédric Le Goater }
17408bfffbccSCorey Minyard 
17418bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
17428bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1743a580d820SCédric Le Goater                                   RspBuffer *rsp)
17448bfffbccSCorey Minyard {
17458bfffbccSCorey Minyard     IPMISensor *sens;
17468bfffbccSCorey Minyard 
174773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17488bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17496acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1750d13ada5dSCédric Le Goater         return;
17518bfffbccSCorey Minyard     }
17528bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1753a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1754a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1755a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1756a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1757a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1758a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17598bfffbccSCorey Minyard }
17608bfffbccSCorey Minyard 
17618bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17628bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1763a580d820SCédric Le Goater                                RspBuffer *rsp)
17648bfffbccSCorey Minyard {
17658bfffbccSCorey Minyard     IPMISensor *sens;
17668bfffbccSCorey Minyard 
176773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17688bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1770d13ada5dSCédric Le Goater         return;
17718bfffbccSCorey Minyard     }
17728bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1773a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1774a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1775a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17768bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1777a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17788bfffbccSCorey Minyard     }
17798bfffbccSCorey Minyard }
17808bfffbccSCorey Minyard 
1781728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1782728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1783a580d820SCédric Le Goater                             RspBuffer *rsp)
1784728710e1SCédric Le Goater {
1785728710e1SCédric Le Goater     IPMISensor *sens;
1786728710e1SCédric Le Goater 
1787728710e1SCédric Le Goater 
178873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1789728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17906acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1791728710e1SCédric Le Goater         return;
1792728710e1SCédric Le Goater     }
1793728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1794728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1795728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1796728710e1SCédric Le Goater }
1797728710e1SCédric Le Goater 
1798728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1799728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1800a580d820SCédric Le Goater                             RspBuffer *rsp)
1801728710e1SCédric Le Goater {
1802728710e1SCédric Le Goater     IPMISensor *sens;
1803728710e1SCédric Le Goater 
1804728710e1SCédric Le Goater 
180573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1806728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18076acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1808728710e1SCédric Le Goater         return;
1809728710e1SCédric Le Goater     }
1810728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1811a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1812a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1813728710e1SCédric Le Goater }
1814728710e1SCédric Le Goater 
1815e3f7320cSCédric Le Goater /*
1816e3f7320cSCédric Le Goater  * bytes   parameter
1817e3f7320cSCédric Le Goater  *    1    sensor number
1818e3f7320cSCédric Le Goater  *    2    operation (see below for bits meaning)
1819e3f7320cSCédric Le Goater  *    3    sensor reading
1820e3f7320cSCédric Le Goater  *  4:5    assertion states (optional)
1821e3f7320cSCédric Le Goater  *  6:7    deassertion states (optional)
1822e3f7320cSCédric Le Goater  *  8:10   event data 1,2,3 (optional)
1823e3f7320cSCédric Le Goater  */
1824e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1825e3f7320cSCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1826e3f7320cSCédric Le Goater                                RspBuffer *rsp)
1827e3f7320cSCédric Le Goater {
1828e3f7320cSCédric Le Goater     IPMISensor *sens;
1829e3f7320cSCédric Le Goater     uint8_t evd1 = 0;
1830e3f7320cSCédric Le Goater     uint8_t evd2 = 0;
1831e3f7320cSCédric Le Goater     uint8_t evd3 = 0;
1832e3f7320cSCédric Le Goater     uint8_t new_reading = 0;
1833e3f7320cSCédric Le Goater     uint16_t new_assert_states = 0;
1834e3f7320cSCédric Le Goater     uint16_t new_deassert_states = 0;
1835e3f7320cSCédric Le Goater     bool change_reading = false;
1836e3f7320cSCédric Le Goater     bool change_assert = false;
1837e3f7320cSCédric Le Goater     bool change_deassert = false;
1838e3f7320cSCédric Le Goater     enum {
1839e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_NONE,
1840e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_DATA,
1841e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_BMC,
1842e3f7320cSCédric Le Goater     } do_gen_event = SENSOR_GEN_EVENT_NONE;
1843e3f7320cSCédric Le Goater 
1844e3f7320cSCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1845e3f7320cSCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1846e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1847e3f7320cSCédric Le Goater         return;
1848e3f7320cSCédric Le Goater     }
1849e3f7320cSCédric Le Goater 
1850e3f7320cSCédric Le Goater     sens = ibs->sensors + cmd[2];
1851e3f7320cSCédric Le Goater 
1852e3f7320cSCédric Le Goater     /* [1:0] Sensor Reading operation */
1853e3f7320cSCédric Le Goater     switch ((cmd[3]) & 0x3) {
1854e3f7320cSCédric Le Goater     case 0: /* Do not change */
1855e3f7320cSCédric Le Goater         break;
1856e3f7320cSCédric Le Goater     case 1: /* write given value to sensor reading byte */
1857e3f7320cSCédric Le Goater         new_reading = cmd[4];
1858e3f7320cSCédric Le Goater         if (sens->reading != new_reading) {
1859e3f7320cSCédric Le Goater             change_reading = true;
1860e3f7320cSCédric Le Goater         }
1861e3f7320cSCédric Le Goater         break;
1862e3f7320cSCédric Le Goater     case 2:
1863e3f7320cSCédric Le Goater     case 3:
1864e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1865e3f7320cSCédric Le Goater         return;
1866e3f7320cSCédric Le Goater     }
1867e3f7320cSCédric Le Goater 
1868e3f7320cSCédric Le Goater     /* [3:2] Deassertion bits operation */
1869e3f7320cSCédric Le Goater     switch ((cmd[3] >> 2) & 0x3) {
1870e3f7320cSCédric Le Goater     case 0: /* Do not change */
1871e3f7320cSCédric Le Goater         break;
1872e3f7320cSCédric Le Goater     case 1: /* write given value */
1873e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1874e3f7320cSCédric Le Goater             new_deassert_states = cmd[7];
1875e3f7320cSCédric Le Goater             change_deassert = true;
1876e3f7320cSCédric Le Goater         }
1877e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1878e3f7320cSCédric Le Goater             new_deassert_states |= (cmd[8] << 8);
1879e3f7320cSCédric Le Goater         }
1880e3f7320cSCédric Le Goater         break;
1881e3f7320cSCédric Le Goater 
1882e3f7320cSCédric Le Goater     case 2: /* mask on */
1883e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1884e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states | cmd[7]);
1885e3f7320cSCédric Le Goater             change_deassert = true;
1886e3f7320cSCédric Le Goater         }
1887e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1888e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1889e3f7320cSCédric Le Goater         }
1890e3f7320cSCédric Le Goater         break;
1891e3f7320cSCédric Le Goater 
1892e3f7320cSCédric Le Goater     case 3: /* mask off */
1893e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1894e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states & cmd[7]);
1895e3f7320cSCédric Le Goater             change_deassert = true;
1896e3f7320cSCédric Le Goater         }
1897e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1898e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1899e3f7320cSCédric Le Goater         }
1900e3f7320cSCédric Le Goater         break;
1901e3f7320cSCédric Le Goater     }
1902e3f7320cSCédric Le Goater 
1903e3f7320cSCédric Le Goater     if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1904e3f7320cSCédric Le Goater         change_deassert = false;
1905e3f7320cSCédric Le Goater     }
1906e3f7320cSCédric Le Goater 
1907e3f7320cSCédric Le Goater     /* [5:4] Assertion bits operation */
1908e3f7320cSCédric Le Goater     switch ((cmd[3] >> 4) & 0x3) {
1909e3f7320cSCédric Le Goater     case 0: /* Do not change */
1910e3f7320cSCédric Le Goater         break;
1911e3f7320cSCédric Le Goater     case 1: /* write given value */
1912e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1913e3f7320cSCédric Le Goater             new_assert_states = cmd[5];
1914e3f7320cSCédric Le Goater             change_assert = true;
1915e3f7320cSCédric Le Goater         }
1916e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1917e3f7320cSCédric Le Goater             new_assert_states |= (cmd[6] << 8);
1918e3f7320cSCédric Le Goater         }
1919e3f7320cSCédric Le Goater         break;
1920e3f7320cSCédric Le Goater 
1921e3f7320cSCédric Le Goater     case 2: /* mask on */
1922e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1923e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states | cmd[5]);
1924e3f7320cSCédric Le Goater             change_assert = true;
1925e3f7320cSCédric Le Goater         }
1926e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1927e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1928e3f7320cSCédric Le Goater         }
1929e3f7320cSCédric Le Goater         break;
1930e3f7320cSCédric Le Goater 
1931e3f7320cSCédric Le Goater     case 3: /* mask off */
1932e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1933e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states & cmd[5]);
1934e3f7320cSCédric Le Goater             change_assert = true;
1935e3f7320cSCédric Le Goater         }
1936e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1937e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1938e3f7320cSCédric Le Goater         }
1939e3f7320cSCédric Le Goater         break;
1940e3f7320cSCédric Le Goater     }
1941e3f7320cSCédric Le Goater 
1942e3f7320cSCédric Le Goater     if (change_assert && (new_assert_states == sens->assert_states)) {
1943e3f7320cSCédric Le Goater         change_assert = false;
1944e3f7320cSCédric Le Goater     }
1945e3f7320cSCédric Le Goater 
1946e3f7320cSCédric Le Goater     if (cmd_len > 9) {
1947e3f7320cSCédric Le Goater         evd1 = cmd[9];
1948e3f7320cSCédric Le Goater     }
1949e3f7320cSCédric Le Goater     if (cmd_len > 10) {
1950e3f7320cSCédric Le Goater         evd2 = cmd[10];
1951e3f7320cSCédric Le Goater     }
1952e3f7320cSCédric Le Goater     if (cmd_len > 11) {
1953e3f7320cSCédric Le Goater         evd3 = cmd[11];
1954e3f7320cSCédric Le Goater     }
1955e3f7320cSCédric Le Goater 
1956e3f7320cSCédric Le Goater     /* [7:6] Event Data Bytes operation */
1957e3f7320cSCédric Le Goater     switch ((cmd[3] >> 6) & 0x3) {
1958e3f7320cSCédric Le Goater     case 0: /*
1959e3f7320cSCédric Le Goater              * Don’t use Event Data bytes from this command. BMC will
1960e3f7320cSCédric Le Goater              * generate it's own Event Data bytes based on its sensor
1961e3f7320cSCédric Le Goater              * implementation.
1962e3f7320cSCédric Le Goater              */
1963e3f7320cSCédric Le Goater         evd1 = evd2 = evd3 = 0x0;
1964e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_BMC;
1965e3f7320cSCédric Le Goater         break;
1966e3f7320cSCédric Le Goater     case 1: /*
1967e3f7320cSCédric Le Goater              * Write given values to event data bytes including bits
1968e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1969e3f7320cSCédric Le Goater              */
1970e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1971e3f7320cSCédric Le Goater         break;
1972e3f7320cSCédric Le Goater     case 2: /*
1973e3f7320cSCédric Le Goater              * Write given values to event data bytes excluding bits
1974e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1975e3f7320cSCédric Le Goater              */
1976e3f7320cSCédric Le Goater         evd1 &= 0xf0;
1977e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1978e3f7320cSCédric Le Goater         break;
1979e3f7320cSCédric Le Goater     case 3:
1980e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1981e3f7320cSCédric Le Goater         return;
1982e3f7320cSCédric Le Goater     }
1983e3f7320cSCédric Le Goater 
1984e3f7320cSCédric Le Goater     /*
1985e3f7320cSCédric Le Goater      * Event Data Bytes operation and parameter are inconsistent. The
1986e3f7320cSCédric Le Goater      * Specs are not clear on that topic but generating an error seems
1987e3f7320cSCédric Le Goater      * correct.
1988e3f7320cSCédric Le Goater      */
1989e3f7320cSCédric Le Goater     if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1990e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1991e3f7320cSCédric Le Goater         return;
1992e3f7320cSCédric Le Goater     }
1993e3f7320cSCédric Le Goater 
1994e3f7320cSCédric Le Goater     /* commit values */
1995e3f7320cSCédric Le Goater     if (change_reading) {
1996e3f7320cSCédric Le Goater         sens->reading = new_reading;
1997e3f7320cSCédric Le Goater     }
1998e3f7320cSCédric Le Goater 
1999e3f7320cSCédric Le Goater     if (change_assert) {
2000e3f7320cSCédric Le Goater         sens->assert_states = new_assert_states;
2001e3f7320cSCédric Le Goater     }
2002e3f7320cSCédric Le Goater 
2003e3f7320cSCédric Le Goater     if (change_deassert) {
2004e3f7320cSCédric Le Goater         sens->deassert_states = new_deassert_states;
2005e3f7320cSCédric Le Goater     }
2006e3f7320cSCédric Le Goater 
2007e3f7320cSCédric Le Goater     /* TODO: handle threshold sensor */
2008e3f7320cSCédric Le Goater     if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
2009e3f7320cSCédric Le Goater         return;
2010e3f7320cSCédric Le Goater     }
2011e3f7320cSCédric Le Goater 
2012e3f7320cSCédric Le Goater     switch (do_gen_event) {
2013e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_DATA: {
2014e3f7320cSCédric Le Goater         unsigned int bit = evd1 & 0xf;
2015e3f7320cSCédric Le Goater         uint16_t mask = (1 << bit);
2016e3f7320cSCédric Le Goater 
2017e3f7320cSCédric Le Goater         if (sens->assert_states & mask & sens->assert_enable) {
2018e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
2019e3f7320cSCédric Le Goater         }
2020e3f7320cSCédric Le Goater 
2021e3f7320cSCédric Le Goater         if (sens->deassert_states & mask & sens->deassert_enable) {
2022e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
2023e3f7320cSCédric Le Goater         }
2024e3f7320cSCédric Le Goater         break;
2025e3f7320cSCédric Le Goater     }
2026e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_BMC:
2027e3f7320cSCédric Le Goater         /*
2028e3f7320cSCédric Le Goater          * TODO: generate event and event data bytes depending on the
2029e3f7320cSCédric Le Goater          * sensor
2030e3f7320cSCédric Le Goater          */
2031e3f7320cSCédric Le Goater         break;
2032e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_NONE:
2033e3f7320cSCédric Le Goater         break;
2034e3f7320cSCédric Le Goater     }
2035e3f7320cSCédric Le Goater }
2036728710e1SCédric Le Goater 
203762a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
20384f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
20394f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
20404f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
20414f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
20428bfffbccSCorey Minyard };
20438bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
204462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
20458bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
20468bfffbccSCorey Minyard };
20478bfffbccSCorey Minyard 
204862a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
20499380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
20504f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
20514f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
20524f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
20534f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
20544f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
20554f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
20564f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
2057e3f7320cSCédric Le Goater     [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
20588bfffbccSCorey Minyard };
20598bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
206062a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
20618bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
20628bfffbccSCorey Minyard };
20638bfffbccSCorey Minyard 
206462a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20654f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20664f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
20674f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
20684f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20694f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20704f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20714f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20724f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20734f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20744f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20754f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
20764f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20774f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20784f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20794f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20804f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
2081*7f9e7af4SNicholas Piggin     [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
20828bfffbccSCorey Minyard };
20838bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
208462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
20858bfffbccSCorey Minyard     .cmd_handlers = app_cmds
20868bfffbccSCorey Minyard };
20878bfffbccSCorey Minyard 
208862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2089540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2090540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2091540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
20924f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
20934f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
20944f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
20954f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
20964f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
20974f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
20984f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
20994f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
21004f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
21014f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
21027f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
21037f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
21048bfffbccSCorey Minyard };
21058bfffbccSCorey Minyard 
21068bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
210762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
21088bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
21098bfffbccSCorey Minyard };
21108bfffbccSCorey Minyard 
21118bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
21128bfffbccSCorey Minyard {
2113ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2114ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2115ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2116ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
21178bfffbccSCorey Minyard }
21188bfffbccSCorey Minyard 
21195167560bSCédric Le Goater static uint8_t init_sdrs[] = {
21208bfffbccSCorey Minyard     /* Watchdog device */
21218bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
21228bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
21238bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21248bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
21258bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
21268bfffbccSCorey Minyard };
21278bfffbccSCorey Minyard 
21284fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
21294fa9f08eSCédric Le Goater {
21304fa9f08eSCédric Le Goater     unsigned int i;
21314fa9f08eSCédric Le Goater     int len;
21325167560bSCédric Le Goater     size_t sdrs_size;
21335167560bSCédric Le Goater     uint8_t *sdrs;
213452fc01d9SCédric Le Goater 
21355167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
21365167560bSCédric Le Goater     sdrs = init_sdrs;
21378c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
21388c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
21398c6fd7f3SCédric Le Goater                              NULL)) {
21408c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
21418c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
21428c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
21438c6fd7f3SCédric Le Goater     }
21445167560bSCédric Le Goater 
21455167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
214652fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
214752fc01d9SCédric Le Goater 
21485167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
21494fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21508c6fd7f3SCédric Le Goater             break;
21514fa9f08eSCédric Le Goater         }
21525167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
21534fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
21545167560bSCédric Le Goater         if (i + len > sdrs_size) {
21554fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21568c6fd7f3SCédric Le Goater             break;
21574fa9f08eSCédric Le Goater         }
21584fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
21594fa9f08eSCédric Le Goater     }
21608c6fd7f3SCédric Le Goater 
21618c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
21628c6fd7f3SCédric Le Goater         g_free(sdrs);
21638c6fd7f3SCédric Le Goater     }
21644fa9f08eSCédric Le Goater }
21654fa9f08eSCédric Le Goater 
2166bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2167bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
2168bd66bcfcSCorey Minyard     .version_id = 1,
2169bd66bcfcSCorey Minyard     .minimum_version_id = 1,
217009c6ac6dSRichard Henderson     .fields = (const VMStateField[]) {
2171bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2172bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2173bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2174bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2175bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2176bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21779e744990SJinhua Cao         VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2178bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2179bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2180bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2181bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2182bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2183bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2184bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2185bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2186bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2187bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2188bd66bcfcSCorey Minyard                        IPMIBmcSim),
2189bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2190bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
2191bd66bcfcSCorey Minyard     }
2192bd66bcfcSCorey Minyard };
2193bd66bcfcSCorey Minyard 
2194540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2195540c07d3SCédric Le Goater {
2196540c07d3SCédric Le Goater     int fsize;
2197540c07d3SCédric Le Goater     int size = 0;
2198540c07d3SCédric Le Goater 
2199540c07d3SCédric Le Goater     if (!fru->filename) {
2200540c07d3SCédric Le Goater         goto out;
2201540c07d3SCédric Le Goater     }
2202540c07d3SCédric Le Goater 
2203540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
2204540c07d3SCédric Le Goater     if (fsize > 0) {
2205540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
2206540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2207540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2208540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
2209540c07d3SCédric Le Goater             g_free(fru->data);
2210540c07d3SCédric Le Goater             fru->data = NULL;
2211540c07d3SCédric Le Goater         }
2212540c07d3SCédric Le Goater     }
2213540c07d3SCédric Le Goater 
2214540c07d3SCédric Le Goater out:
2215540c07d3SCédric Le Goater     if (!fru->data) {
2216540c07d3SCédric Le Goater         /* give one default FRU */
2217540c07d3SCédric Le Goater         size = fru->areasize;
2218540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2219540c07d3SCédric Le Goater     }
2220540c07d3SCédric Le Goater 
2221540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
2222540c07d3SCédric Le Goater }
2223540c07d3SCédric Le Goater 
22240bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
22258bfffbccSCorey Minyard {
22260bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
22278bfffbccSCorey Minyard     unsigned int i;
22288bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
22298bfffbccSCorey Minyard 
22308bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
22318bfffbccSCorey Minyard 
22328bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
22338bfffbccSCorey Minyard     ibs->device_id = 0x20;
22348bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2235b7088392SCédric Le Goater     ibs->restart_cause = 0;
22368bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
22378bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
22388bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
22398bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
22408bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
22418bfffbccSCorey Minyard     }
22428bfffbccSCorey Minyard 
22434fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
22448bfffbccSCorey Minyard 
2245540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
2246540c07d3SCédric Le Goater 
224752ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
224852ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
224952ba4d50SCédric Le Goater 
22508bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
22518bfffbccSCorey Minyard     register_cmds(ibs);
22528bfffbccSCorey Minyard 
22538bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
22548bfffbccSCorey Minyard }
22558bfffbccSCorey Minyard 
22562acf1403SRichard Henderson static const Property ipmi_sim_properties[] = {
2257540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2258540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
22598c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
226020b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
226120b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
226220b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
226320b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
226420b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
226520b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
226620b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22677b0cd78bSCorey Minyard     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22688c6fd7f3SCédric Le Goater };
22698c6fd7f3SCédric Le Goater 
22708bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
22718bfffbccSCorey Minyard {
22720bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
22738bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22748bfffbccSCorey Minyard 
227566abfddbSCorey Minyard     dc->hotpluggable = false;
22760bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
2277d11d904cSCorey Minyard     dc->vmsd = &vmstate_ipmi_sim;
22784f67d30bSMarc-André Lureau     device_class_set_props(dc, ipmi_sim_properties);
22798bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
22808bfffbccSCorey Minyard }
22818bfffbccSCorey Minyard 
22828bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22838bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
22848bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
22858bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
22868bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
22878bfffbccSCorey Minyard };
22888bfffbccSCorey Minyard 
22898bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
22908bfffbccSCorey Minyard {
22918bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
22928bfffbccSCorey Minyard }
22938bfffbccSCorey Minyard 
22948bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2295