xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision d9494ef96c859515aa9df450fb61e833da7cb7c7)
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
737f9e7af4SNicholas 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,
517*d9494ef9SNicholas Piggin                                     uint8_t evd1, uint8_t evd2, uint8_t evd3,
518*d9494ef9SNicholas Piggin                                     bool do_log)
5198bfffbccSCorey Minyard {
5208bfffbccSCorey Minyard     IPMISensor *sens;
5218bfffbccSCorey Minyard     uint16_t mask;
5228bfffbccSCorey Minyard 
5238bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5248bfffbccSCorey Minyard         return;
5258bfffbccSCorey Minyard     }
5268bfffbccSCorey Minyard     if (bit >= 16) {
5278bfffbccSCorey Minyard         return;
5288bfffbccSCorey Minyard     }
5298bfffbccSCorey Minyard 
5308bfffbccSCorey Minyard     mask = (1 << bit);
5318bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5328bfffbccSCorey Minyard     if (val) {
5338bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5348bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5358bfffbccSCorey Minyard             return; /* Already asserted */
5368bfffbccSCorey Minyard         }
5378bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
538*d9494ef9SNicholas Piggin         if (do_log && (sens->assert_enable & mask & sens->assert_states)) {
5398bfffbccSCorey Minyard             /* Send an event on assert */
5408bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5418bfffbccSCorey Minyard         }
5428bfffbccSCorey Minyard     } else {
5438bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5448bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5458bfffbccSCorey Minyard             return; /* Already deasserted */
5468bfffbccSCorey Minyard         }
5478bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
548*d9494ef9SNicholas Piggin         if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) {
5498bfffbccSCorey Minyard             /* Send an event on deassert */
5508bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5518bfffbccSCorey Minyard         }
5528bfffbccSCorey Minyard     }
5538bfffbccSCorey Minyard }
5548bfffbccSCorey Minyard 
5558bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5568bfffbccSCorey Minyard {
5578bfffbccSCorey Minyard     unsigned int i, pos;
5588bfffbccSCorey Minyard     IPMISensor *sens;
5598bfffbccSCorey Minyard 
5608bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5618bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5628bfffbccSCorey Minyard     }
5638bfffbccSCorey Minyard 
5648bfffbccSCorey Minyard     pos = 0;
5658bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
566a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
567a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
568a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5698bfffbccSCorey Minyard 
5708bfffbccSCorey Minyard         if (len < 20) {
5718bfffbccSCorey Minyard             continue;
5728bfffbccSCorey Minyard         }
573a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5748bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5758bfffbccSCorey Minyard         }
5768bfffbccSCorey Minyard 
57773d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5788bfffbccSCorey Minyard             continue;
5798bfffbccSCorey Minyard         }
580a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5818bfffbccSCorey Minyard 
5828bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
583a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
584a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
585a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
586a2295f0aSCédric Le Goater         sens->deassert_suppt =
587a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
588a2295f0aSCédric Le Goater         sens->states_suppt =
589a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
590a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
591a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5928bfffbccSCorey Minyard 
5938bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5948bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5958bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5968bfffbccSCorey Minyard     }
5978bfffbccSCorey Minyard }
5988bfffbccSCorey Minyard 
599ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
6008bfffbccSCorey Minyard                         const IPMINetfn *netfnd)
6018bfffbccSCorey Minyard {
60293a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6038bfffbccSCorey Minyard         return -1;
6048bfffbccSCorey Minyard     }
6058bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6068bfffbccSCorey Minyard     return 0;
6078bfffbccSCorey Minyard }
6088bfffbccSCorey Minyard 
6094f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6104f298a4bSCédric Le Goater                                               unsigned int netfn,
6114f298a4bSCédric Le Goater                                               unsigned int cmd)
6124f298a4bSCédric Le Goater {
6134f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6144f298a4bSCédric Le Goater 
6154f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6164f298a4bSCédric Le Goater         return NULL;
6174f298a4bSCédric Le Goater     }
6184f298a4bSCédric Le Goater 
6194f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6204f298a4bSCédric Le Goater         return NULL;
6214f298a4bSCédric Le Goater     }
6224f298a4bSCédric Le Goater 
6234f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6244f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6254f298a4bSCédric Le Goater         return NULL;
6264f298a4bSCédric Le Goater     }
6274f298a4bSCédric Le Goater 
6284f298a4bSCédric Le Goater     return hdl;
6294f298a4bSCédric Le Goater }
6304f298a4bSCédric Le Goater 
6318bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6328bfffbccSCorey Minyard {
6338bfffbccSCorey Minyard     int64_t next;
6348bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6358bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6368bfffbccSCorey Minyard     } else {
6378bfffbccSCorey Minyard         /* Wait a minute */
6388bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6398bfffbccSCorey Minyard     }
6408bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6418bfffbccSCorey Minyard }
6428bfffbccSCorey Minyard 
6438bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6448bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6458bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6468bfffbccSCorey Minyard                                     uint8_t msg_id)
6478bfffbccSCorey Minyard {
6488bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6498bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6508bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6514f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
652a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6538bfffbccSCorey Minyard 
6548bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6558bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
656a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6576acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
658d13ada5dSCédric Le Goater         goto out;
659d13ada5dSCédric Le Goater     }
660d13ada5dSCédric Le Goater 
661a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
662a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
663a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6648bfffbccSCorey Minyard 
6658bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6668bfffbccSCorey Minyard     if (cmd_len < 2) {
6676acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6688bfffbccSCorey Minyard         goto out;
6698bfffbccSCorey Minyard     }
6708bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6716acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6728bfffbccSCorey Minyard         goto out;
6738bfffbccSCorey Minyard     }
6748bfffbccSCorey Minyard 
6758bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6768bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6776acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6788bfffbccSCorey Minyard         goto out;
6798bfffbccSCorey Minyard     }
6808bfffbccSCorey Minyard 
6814f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6824f298a4bSCédric Le Goater     if (!hdl) {
6836acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6848bfffbccSCorey Minyard         goto out;
6858bfffbccSCorey Minyard     }
6868bfffbccSCorey Minyard 
6874f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6886acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6894f298a4bSCédric Le Goater         goto out;
6904f298a4bSCédric Le Goater     }
6914f298a4bSCédric Le Goater 
692a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6938bfffbccSCorey Minyard 
6948bfffbccSCorey Minyard  out:
695a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6968bfffbccSCorey Minyard 
6978bfffbccSCorey Minyard     next_timeout(ibs);
6988bfffbccSCorey Minyard }
6998bfffbccSCorey Minyard 
7008bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7018bfffbccSCorey Minyard {
7028bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7038bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
704*d9494ef9SNicholas Piggin     bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs);
7058bfffbccSCorey Minyard 
7068bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7078bfffbccSCorey Minyard         goto out;
7088bfffbccSCorey Minyard     }
7098bfffbccSCorey Minyard 
7108bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7118bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7128bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7138bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7148bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7158bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
716*d9494ef9SNicholas Piggin                                     0xc8, (2 << 4) | 0xf, 0xff,
717*d9494ef9SNicholas Piggin                                     do_log);
7188bfffbccSCorey Minyard             break;
7198bfffbccSCorey Minyard 
7208bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7218bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7228bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7238bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
724*d9494ef9SNicholas Piggin                                     0xc8, (3 << 4) | 0xf, 0xff,
725*d9494ef9SNicholas Piggin                                     do_log);
7268bfffbccSCorey Minyard             break;
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard         default:
7298bfffbccSCorey Minyard             goto do_full_expiry;
7308bfffbccSCorey Minyard         }
7318bfffbccSCorey Minyard 
7328bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7338bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7348bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7358bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7368bfffbccSCorey Minyard         goto out;
7378bfffbccSCorey Minyard     }
7388bfffbccSCorey Minyard 
7398bfffbccSCorey Minyard  do_full_expiry:
7408bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7418bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7428bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7438bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7448bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
745*d9494ef9SNicholas Piggin                                 0xc0, ibs->watchdog_use & 0xf, 0xff,
746*d9494ef9SNicholas Piggin                                 do_log);
7478bfffbccSCorey Minyard         break;
7488bfffbccSCorey Minyard 
7498bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7508bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
751*d9494ef9SNicholas Piggin                                 0xc1, ibs->watchdog_use & 0xf, 0xff,
752*d9494ef9SNicholas Piggin                                 do_log);
7538bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7548bfffbccSCorey Minyard         break;
7558bfffbccSCorey Minyard 
7568bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7578bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
758*d9494ef9SNicholas Piggin                                 0xc2, ibs->watchdog_use & 0xf, 0xff,
759*d9494ef9SNicholas Piggin                                 do_log);
7608bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7618bfffbccSCorey Minyard         break;
7628bfffbccSCorey Minyard 
7638bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7648bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
765*d9494ef9SNicholas Piggin                                 0xc3, ibs->watchdog_use & 0xf, 0xff,
766*d9494ef9SNicholas Piggin                                 do_log);
7678bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7688bfffbccSCorey Minyard         break;
7698bfffbccSCorey Minyard     }
7708bfffbccSCorey Minyard 
7718bfffbccSCorey Minyard  out:
7728bfffbccSCorey Minyard     next_timeout(ibs);
7738bfffbccSCorey Minyard }
7748bfffbccSCorey Minyard 
7758bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7768bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
777a580d820SCédric Le Goater                                  RspBuffer *rsp)
7788bfffbccSCorey Minyard {
779a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
780a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
781a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
782a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
783a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7848bfffbccSCorey Minyard }
7858bfffbccSCorey Minyard 
7868bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7878bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
788a580d820SCédric Le Goater                            RspBuffer *rsp)
7898bfffbccSCorey Minyard {
790a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
791a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
792a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
793a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7948bfffbccSCorey Minyard }
7958bfffbccSCorey Minyard 
7968bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7978bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
798a580d820SCédric Le Goater                             RspBuffer *rsp)
7998bfffbccSCorey Minyard {
8008bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8018bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8028bfffbccSCorey Minyard 
8038bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
8048bfffbccSCorey Minyard     case 0: /* power down */
8056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8068bfffbccSCorey Minyard         break;
8078bfffbccSCorey Minyard     case 1: /* power up */
8086acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8098bfffbccSCorey Minyard         break;
8108bfffbccSCorey Minyard     case 2: /* power cycle */
8116acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8128bfffbccSCorey Minyard         break;
8138bfffbccSCorey Minyard     case 3: /* hard reset */
8146acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8158bfffbccSCorey Minyard         break;
8168bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8176acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8188bfffbccSCorey Minyard         break;
8198bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8206acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8216acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8228bfffbccSCorey Minyard         break;
8238bfffbccSCorey Minyard     default:
8246acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8258bfffbccSCorey Minyard         return;
8268bfffbccSCorey Minyard     }
827d13ada5dSCédric Le Goater }
8288bfffbccSCorey Minyard 
829b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
830b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
831a580d820SCédric Le Goater                            RspBuffer *rsp)
832a580d820SCédric Le Goater 
833b7088392SCédric Le Goater {
834a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
835a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
836b7088392SCédric Le Goater }
837b7088392SCédric Le Goater 
8388bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8398bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
840a580d820SCédric Le Goater                           RspBuffer *rsp)
8418bfffbccSCorey Minyard {
842a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
843a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
844a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
845a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
846a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
847a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
84820b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84920b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
85020b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
85120b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
85220b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8538bfffbccSCorey Minyard }
8548bfffbccSCorey Minyard 
8558bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8568bfffbccSCorey Minyard {
8578bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8588bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8598bfffbccSCorey Minyard     bool irqs_on;
8608bfffbccSCorey Minyard 
8618bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8628bfffbccSCorey Minyard 
8638bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8648bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8658bfffbccSCorey Minyard 
8668bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8678bfffbccSCorey Minyard }
8688bfffbccSCorey Minyard 
8698bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8708bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
871a580d820SCédric Le Goater                        RspBuffer *rsp)
8728bfffbccSCorey Minyard {
8738bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8748bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8758bfffbccSCorey Minyard 
8768bfffbccSCorey Minyard     /* Disable all interrupts */
8778bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8788bfffbccSCorey Minyard 
8798bfffbccSCorey Minyard     if (k->reset) {
8808bfffbccSCorey Minyard         k->reset(s, true);
8818bfffbccSCorey Minyard     }
8828bfffbccSCorey Minyard }
8838bfffbccSCorey Minyard 
8848bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8858bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
886a580d820SCédric Le Goater                        RspBuffer *rsp)
8878bfffbccSCorey Minyard {
8888bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8898bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8908bfffbccSCorey Minyard 
8918bfffbccSCorey Minyard     if (k->reset) {
8928bfffbccSCorey Minyard         k->reset(s, false);
8938bfffbccSCorey Minyard     }
8948bfffbccSCorey Minyard }
89552ba4d50SCédric Le Goater static void set_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 {
89952ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
90052ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
90152ba4d50SCédric Le Goater }
90252ba4d50SCédric Le Goater 
90352ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
90452ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
905a580d820SCédric Le Goater                                  RspBuffer *rsp)
90652ba4d50SCédric Le Goater {
907a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
908a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90952ba4d50SCédric Le Goater }
91052ba4d50SCédric Le Goater 
91152ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
91252ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
913a580d820SCédric Le Goater                             RspBuffer *rsp)
91452ba4d50SCédric Le Goater {
91552ba4d50SCédric Le Goater     unsigned int i;
91652ba4d50SCédric Le Goater 
9177b0cd78bSCorey Minyard     /* An uninitialized uuid is all zeros, use that to know if it is set. */
91852ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
9197b0cd78bSCorey Minyard         if (ibs->uuid.data[i]) {
9207b0cd78bSCorey Minyard             goto uuid_set;
9217b0cd78bSCorey Minyard         }
9227b0cd78bSCorey Minyard     }
9237b0cd78bSCorey Minyard     /* No uuid is set, return an error. */
9247b0cd78bSCorey Minyard     rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9257b0cd78bSCorey Minyard     return;
9267b0cd78bSCorey Minyard 
9277b0cd78bSCorey Minyard  uuid_set:
9287b0cd78bSCorey Minyard     for (i = 0; i < 16; i++) {
9297b0cd78bSCorey Minyard         rsp_buffer_push(rsp, ibs->uuid.data[i]);
93052ba4d50SCédric Le Goater     }
93152ba4d50SCédric Le Goater }
9328bfffbccSCorey Minyard 
9338bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9348bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
935a580d820SCédric Le Goater                                    RspBuffer *rsp)
9368bfffbccSCorey Minyard {
9378bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9388bfffbccSCorey Minyard }
9398bfffbccSCorey Minyard 
9408bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9418bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
942a580d820SCédric Le Goater                                    RspBuffer *rsp)
9438bfffbccSCorey Minyard {
944a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9458bfffbccSCorey Minyard }
9468bfffbccSCorey Minyard 
9478bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9488bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
949a580d820SCédric Le Goater                           RspBuffer *rsp)
9508bfffbccSCorey Minyard {
9518bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9528bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9538bfffbccSCorey Minyard 
9548bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9558bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9568bfffbccSCorey Minyard }
9578bfffbccSCorey Minyard 
9588bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9598bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
960a580d820SCédric Le Goater                           RspBuffer *rsp)
9618bfffbccSCorey Minyard {
962a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9638bfffbccSCorey Minyard }
9648bfffbccSCorey Minyard 
9658bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9668bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
967a580d820SCédric Le Goater                              RspBuffer *rsp)
9688bfffbccSCorey Minyard {
9698bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9708bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9718bfffbccSCorey Minyard     unsigned int i;
9728bfffbccSCorey Minyard 
9738bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9746acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
975d13ada5dSCédric Le Goater         return;
9768bfffbccSCorey Minyard     }
9778bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
978a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9798bfffbccSCorey Minyard     }
9808bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9818bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9828bfffbccSCorey Minyard }
9838bfffbccSCorey Minyard 
9848bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9858bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
986a580d820SCédric Le Goater                     RspBuffer *rsp)
9878bfffbccSCorey Minyard {
9888bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9898bfffbccSCorey Minyard 
9908bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9916acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9928bfffbccSCorey Minyard         goto out;
9938bfffbccSCorey Minyard     }
994a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
9958bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
996a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9978bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9988bfffbccSCorey Minyard     g_free(msg);
9998bfffbccSCorey Minyard 
10008bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10018bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
10028bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10038bfffbccSCorey Minyard 
10048bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10058bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10068bfffbccSCorey Minyard     }
10078bfffbccSCorey Minyard 
10088bfffbccSCorey Minyard out:
10098bfffbccSCorey Minyard     return;
10108bfffbccSCorey Minyard }
10118bfffbccSCorey Minyard 
10128bfffbccSCorey Minyard static unsigned char
10138bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10148bfffbccSCorey Minyard {
10158bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10168bfffbccSCorey Minyard             csum += *data;
10178bfffbccSCorey Minyard     }
10188bfffbccSCorey Minyard 
10198bfffbccSCorey Minyard     return -csum;
10208bfffbccSCorey Minyard }
10218bfffbccSCorey Minyard 
10228bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10238bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1024a580d820SCédric Le Goater                      RspBuffer *rsp)
10258bfffbccSCorey Minyard {
10268bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10278bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10288bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10298bfffbccSCorey Minyard     uint8_t *buf;
10308bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10318bfffbccSCorey Minyard 
10327f9e7af4SNicholas Piggin     if (cmd[2] != IPMI_CHANNEL_IPMB) {
10337f9e7af4SNicholas Piggin         /* We only handle channel 0h (IPMB) with no options */
10346acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1035d13ada5dSCédric Le Goater         return;
10368bfffbccSCorey Minyard     }
10378bfffbccSCorey Minyard 
10384f298a4bSCédric Le Goater     if (cmd_len < 10) {
10396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10404f298a4bSCédric Le Goater         return;
10414f298a4bSCédric Le Goater     }
10424f298a4bSCédric Le Goater 
10438bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10448bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10456acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1046d13ada5dSCédric Le Goater         return;
10478bfffbccSCorey Minyard     }
10488bfffbccSCorey Minyard 
10498bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10508bfffbccSCorey Minyard     cmd_len -= 3;
10518bfffbccSCorey Minyard 
10528bfffbccSCorey Minyard     /*
10538bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10548bfffbccSCorey Minyard      * be returned in the response.
10558bfffbccSCorey Minyard      */
10568bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10578bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1058d13ada5dSCédric Le Goater         return; /* No response */
10598bfffbccSCorey Minyard     }
10608bfffbccSCorey Minyard 
10618bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10628bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10638bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10648bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10658bfffbccSCorey Minyard 
10668bfffbccSCorey Minyard     if (rqLun != 2) {
10678bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1068d13ada5dSCédric Le Goater         return;
10698bfffbccSCorey Minyard     }
10708bfffbccSCorey Minyard 
10718bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10728bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10738bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10748bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10758bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10768bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10778bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10788bfffbccSCorey Minyard     msg->len = 6;
10798bfffbccSCorey Minyard 
10808bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10818bfffbccSCorey Minyard         /* Not a command we handle. */
10828bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10838bfffbccSCorey Minyard         goto end_msg;
10848bfffbccSCorey Minyard     }
10858bfffbccSCorey Minyard 
10868bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10878bfffbccSCorey Minyard     buf[0] = 0;
10888bfffbccSCorey Minyard     buf[1] = 0;
10898bfffbccSCorey Minyard     buf[2] = 0;
10908bfffbccSCorey Minyard     buf[3] = 0;
10918bfffbccSCorey Minyard     buf[4] = 0x51;
10928bfffbccSCorey Minyard     buf[5] = 0;
10938bfffbccSCorey Minyard     buf[6] = 0;
10948bfffbccSCorey Minyard     buf[7] = 0;
10958bfffbccSCorey Minyard     buf[8] = 0;
10968bfffbccSCorey Minyard     buf[9] = 0;
10978bfffbccSCorey Minyard     buf[10] = 0;
10988bfffbccSCorey Minyard     msg->len += 11;
10998bfffbccSCorey Minyard 
11008bfffbccSCorey Minyard  end_msg:
11018bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11028bfffbccSCorey Minyard     msg->len++;
11038bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11048bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11058bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
11068bfffbccSCorey Minyard }
11078bfffbccSCorey Minyard 
11088bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11098bfffbccSCorey Minyard {
11108bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11118bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11128bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11138bfffbccSCorey Minyard         return;
11148bfffbccSCorey Minyard     }
11158bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11168bfffbccSCorey Minyard 
11178bfffbccSCorey Minyard 
11188bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11198bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11208bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11218bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11228bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11238bfffbccSCorey Minyard     }
11248bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11258bfffbccSCorey Minyard }
11268bfffbccSCorey Minyard 
11278bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11288bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1129a580d820SCédric Le Goater                                  RspBuffer *rsp)
11308bfffbccSCorey Minyard {
11318bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1133d13ada5dSCédric Le Goater         return;
11348bfffbccSCorey Minyard     }
11358bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11368bfffbccSCorey Minyard }
11378bfffbccSCorey Minyard 
11388bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11398bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1140a580d820SCédric Le Goater                                RspBuffer *rsp)
11418bfffbccSCorey Minyard {
11428bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11438bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11448bfffbccSCorey Minyard     unsigned int val;
11458bfffbccSCorey Minyard 
11468bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11478bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11486acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1149d13ada5dSCédric Le Goater         return;
11508bfffbccSCorey Minyard     }
11518bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11528bfffbccSCorey Minyard     switch (val) {
11538bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11548bfffbccSCorey Minyard         break;
11558bfffbccSCorey Minyard 
11568bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11576acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11588bfffbccSCorey Minyard         break;
11598bfffbccSCorey Minyard 
11608bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11616acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11628bfffbccSCorey Minyard         break;
11638bfffbccSCorey Minyard 
11648bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11656acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11668bfffbccSCorey Minyard         break;
11678bfffbccSCorey Minyard 
11688bfffbccSCorey Minyard     default:
11696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11708bfffbccSCorey Minyard     }
1171a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11726acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1173d13ada5dSCédric Le Goater         return;
11748bfffbccSCorey Minyard     }
11758bfffbccSCorey Minyard 
11768bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11778bfffbccSCorey Minyard     switch (val) {
11788bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11798bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11808bfffbccSCorey Minyard         break;
11818bfffbccSCorey Minyard 
11828bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11836af94767SCorey Minyard         if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11848bfffbccSCorey Minyard             /* NMI not supported. */
11856acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1186d13ada5dSCédric Le Goater             return;
11878bfffbccSCorey Minyard         }
118837eebb86SCorey Minyard         break;
118937eebb86SCorey Minyard 
11908bfffbccSCorey Minyard     default:
11918bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11926acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1193d13ada5dSCédric Le Goater         return;
11948bfffbccSCorey Minyard     }
11958bfffbccSCorey Minyard 
11968bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11978bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11988bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11998bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
12008bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
12018bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12028bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12038bfffbccSCorey Minyard         do_watchdog_reset(ibs);
12048bfffbccSCorey Minyard     } else {
12058bfffbccSCorey Minyard         ibs->watchdog_running = 0;
12068bfffbccSCorey Minyard     }
12078bfffbccSCorey Minyard }
12088bfffbccSCorey Minyard 
12098bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12108bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1211a580d820SCédric Le Goater                                RspBuffer *rsp)
12128bfffbccSCorey Minyard {
1213a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1214a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1215a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1216a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
1217fb45770bSCorey Minyard     rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1218fb45770bSCorey Minyard     rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12198bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12208bfffbccSCorey Minyard         long timeout;
12218bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12228bfffbccSCorey Minyard                    / 100000000);
1223a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1224a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12258bfffbccSCorey Minyard     } else {
1226a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1227a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12288bfffbccSCorey Minyard     }
12298bfffbccSCorey Minyard }
12308bfffbccSCorey Minyard 
12317f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs,
12327f9e7af4SNicholas Piggin                              uint8_t *cmd, unsigned int cmd_len,
12337f9e7af4SNicholas Piggin                              RspBuffer *rsp)
12347f9e7af4SNicholas Piggin {
12357f9e7af4SNicholas Piggin     IPMIInterface *s = ibs->parent.intf;
12367f9e7af4SNicholas Piggin     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
12377f9e7af4SNicholas Piggin     IPMIFwInfo info = {};
12387f9e7af4SNicholas Piggin     uint8_t ch = cmd[2] & 0x0f;
12397f9e7af4SNicholas Piggin 
12407f9e7af4SNicholas Piggin     /* Only define channel 0h (IPMB) and Fh (system interface) */
12417f9e7af4SNicholas Piggin 
12427f9e7af4SNicholas Piggin     if (ch == 0x0e) { /* "This channel" */
12437f9e7af4SNicholas Piggin         ch = IPMI_CHANNEL_SYSTEM;
12447f9e7af4SNicholas Piggin     }
12457f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, ch);
12467f9e7af4SNicholas Piggin 
12477f9e7af4SNicholas Piggin     if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
12487f9e7af4SNicholas Piggin         /* Not a supported channel */
12497f9e7af4SNicholas Piggin         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
12507f9e7af4SNicholas Piggin         return;
12517f9e7af4SNicholas Piggin     }
12527f9e7af4SNicholas Piggin 
12537f9e7af4SNicholas Piggin     if (k->get_fwinfo) {
12547f9e7af4SNicholas Piggin         k->get_fwinfo(s, &info);
12557f9e7af4SNicholas Piggin     }
12567f9e7af4SNicholas Piggin 
12577f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_IPMB) {
12587f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
12597f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
12607f9e7af4SNicholas Piggin     } else { /* IPMI_CHANNEL_SYSTEM */
12617f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
12627f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, info.ipmi_channel_protocol);
12637f9e7af4SNicholas Piggin     }
12647f9e7af4SNicholas Piggin 
12657f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00); /* Session-less */
12667f9e7af4SNicholas Piggin 
12677f9e7af4SNicholas Piggin     /* IPMI Enterprise Number for Vendor ID */
12687f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0xf2);
12697f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x1b);
12707f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00);
12717f9e7af4SNicholas Piggin 
12727f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_SYSTEM) {
12737f9e7af4SNicholas Piggin         uint8_t irq;
12747f9e7af4SNicholas Piggin 
12757f9e7af4SNicholas Piggin         if (info.irq_source == IPMI_ISA_IRQ) {
12767f9e7af4SNicholas Piggin             irq = info.interrupt_number;
12777f9e7af4SNicholas Piggin         } else if (info.irq_source == IPMI_PCI_IRQ) {
12787f9e7af4SNicholas Piggin             irq = 0x10 + info.interrupt_number;
12797f9e7af4SNicholas Piggin         } else {
12807f9e7af4SNicholas Piggin             irq = 0xff; /* no interrupt / unspecified */
12817f9e7af4SNicholas Piggin         }
12827f9e7af4SNicholas Piggin 
12837f9e7af4SNicholas Piggin         /* Both interrupts use the same irq number */
12847f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
12857f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
12867f9e7af4SNicholas Piggin     } else {
12877f9e7af4SNicholas Piggin         /* Reserved */
12887f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
12897f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
12907f9e7af4SNicholas Piggin     }
12917f9e7af4SNicholas Piggin }
12927f9e7af4SNicholas Piggin 
12938bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12948bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1295a580d820SCédric Le Goater                              RspBuffer *rsp)
12968bfffbccSCorey Minyard {
12978bfffbccSCorey Minyard     unsigned int i;
12988bfffbccSCorey Minyard 
1299a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1300a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1301a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1302a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1303a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
13048bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1305a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
13068bfffbccSCorey Minyard     }
13078bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1308a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
13098bfffbccSCorey Minyard     }
13108bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1311a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
13128bfffbccSCorey Minyard }
13138bfffbccSCorey Minyard 
13148bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
13158bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1316a580d820SCédric Le Goater                             RspBuffer *rsp)
13178bfffbccSCorey Minyard {
1318a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1319a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
13208bfffbccSCorey Minyard }
13218bfffbccSCorey Minyard 
13228bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
13238bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1324a580d820SCédric Le Goater                     RspBuffer *rsp)
13258bfffbccSCorey Minyard {
13268bfffbccSCorey Minyard     unsigned int pos;
13278bfffbccSCorey Minyard     uint16_t nextrec;
1328a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
13298bfffbccSCorey Minyard 
13308bfffbccSCorey Minyard     if (cmd[6]) {
13317f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13326acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13337f996411SCédric Le Goater             return;
13348bfffbccSCorey Minyard         }
13357f996411SCédric Le Goater     }
13367f996411SCédric Le Goater 
13378bfffbccSCorey Minyard     pos = 0;
13388bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
13398bfffbccSCorey Minyard                        &pos, &nextrec)) {
13406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1341d13ada5dSCédric Le Goater         return;
13428bfffbccSCorey Minyard     }
1343a2295f0aSCédric Le Goater 
1344a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1345a2295f0aSCédric Le Goater 
1346a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
13476acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1348d13ada5dSCédric Le Goater         return;
13498bfffbccSCorey Minyard     }
13508bfffbccSCorey Minyard 
1351a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1352a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13538bfffbccSCorey Minyard 
13548bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1355a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13568bfffbccSCorey Minyard     }
13578bfffbccSCorey Minyard 
1358a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13596acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1360d13ada5dSCédric Le Goater         return;
13618bfffbccSCorey Minyard     }
1362a580d820SCédric Le Goater 
1363a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13648bfffbccSCorey Minyard }
13658bfffbccSCorey Minyard 
13668bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13678bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1368a580d820SCédric Le Goater                     RspBuffer *rsp)
13698bfffbccSCorey Minyard {
13708bfffbccSCorey Minyard     uint16_t recid;
1371a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13728bfffbccSCorey Minyard 
1373a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13746acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1375d13ada5dSCédric Le Goater         return;
13768bfffbccSCorey Minyard     }
1377a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1378a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13798bfffbccSCorey Minyard }
13808bfffbccSCorey Minyard 
13818bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13828bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1383a580d820SCédric Le Goater                           RspBuffer *rsp)
13848bfffbccSCorey Minyard {
13857f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13866acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13877f996411SCédric Le Goater         return;
13887f996411SCédric Le Goater     }
13897f996411SCédric Le Goater 
13908bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13916acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1392d13ada5dSCédric Le Goater         return;
13938bfffbccSCorey Minyard     }
13948bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13958bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13968bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13978bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1398a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13998bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
14008bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1401a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14028bfffbccSCorey Minyard     } else {
14036acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
14048bfffbccSCorey Minyard         return;
14058bfffbccSCorey Minyard     }
1406d13ada5dSCédric Le Goater }
14078bfffbccSCorey Minyard 
14088bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
14098bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1410a580d820SCédric Le Goater                          RspBuffer *rsp)
14118bfffbccSCorey Minyard {
14128bfffbccSCorey Minyard     unsigned int i, val;
14138bfffbccSCorey Minyard 
1414a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1415a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1416a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
14178bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1418a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1419a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
14208bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1421a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
14228bfffbccSCorey Minyard     }
14238bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1424a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
14258bfffbccSCorey Minyard     }
14268bfffbccSCorey Minyard     /* Only support Reserve SEL */
1427a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
14288bfffbccSCorey Minyard }
14298bfffbccSCorey Minyard 
1430540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1431540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1432540c07d3SCédric Le Goater                          RspBuffer *rsp)
1433540c07d3SCédric Le Goater {
1434540c07d3SCédric Le Goater     uint8_t fruid;
1435540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1436540c07d3SCédric Le Goater 
1437540c07d3SCédric Le Goater     fruid = cmd[2];
1438540c07d3SCédric Le Goater 
1439540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1440540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1441540c07d3SCédric Le Goater         return;
1442540c07d3SCédric Le Goater     }
1443540c07d3SCédric Le Goater 
1444540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1445540c07d3SCédric Le Goater 
1446540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1447540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1448540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1449540c07d3SCédric Le Goater }
1450540c07d3SCédric Le Goater 
1451540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1452540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1453540c07d3SCédric Le Goater                          RspBuffer *rsp)
1454540c07d3SCédric Le Goater {
1455540c07d3SCédric Le Goater     uint8_t fruid;
1456540c07d3SCédric Le Goater     uint16_t offset;
1457540c07d3SCédric Le Goater     int i;
1458540c07d3SCédric Le Goater     uint8_t *fru_entry;
1459540c07d3SCédric Le Goater     unsigned int count;
1460540c07d3SCédric Le Goater 
1461540c07d3SCédric Le Goater     fruid = cmd[2];
1462540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1463540c07d3SCédric Le Goater 
1464540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1465540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1466540c07d3SCédric Le Goater         return;
1467540c07d3SCédric Le Goater     }
1468540c07d3SCédric Le Goater 
1469540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1470540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1471540c07d3SCédric Le Goater         return;
1472540c07d3SCédric Le Goater     }
1473540c07d3SCédric Le Goater 
1474540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1475540c07d3SCédric Le Goater 
1476540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1477540c07d3SCédric Le Goater 
1478540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1479540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1480540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1481540c07d3SCédric Le Goater     }
1482540c07d3SCédric Le Goater }
1483540c07d3SCédric Le Goater 
1484540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1485540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1486540c07d3SCédric Le Goater                          RspBuffer *rsp)
1487540c07d3SCédric Le Goater {
1488540c07d3SCédric Le Goater     uint8_t fruid;
1489540c07d3SCédric Le Goater     uint16_t offset;
1490540c07d3SCédric Le Goater     uint8_t *fru_entry;
1491540c07d3SCédric Le Goater     unsigned int count;
1492540c07d3SCédric Le Goater 
1493540c07d3SCédric Le Goater     fruid = cmd[2];
1494540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1495540c07d3SCédric Le Goater 
1496540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1497540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1498540c07d3SCédric Le Goater         return;
1499540c07d3SCédric Le Goater     }
1500540c07d3SCédric Le Goater 
1501540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1502540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1503540c07d3SCédric Le Goater         return;
1504540c07d3SCédric Le Goater     }
1505540c07d3SCédric Le Goater 
1506540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1507540c07d3SCédric Le Goater 
1508540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1509540c07d3SCédric Le Goater 
1510540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1511540c07d3SCédric Le Goater 
1512540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1513540c07d3SCédric Le Goater }
1514540c07d3SCédric Le Goater 
15158bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
15168bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1517a580d820SCédric Le Goater                         RspBuffer *rsp)
15188bfffbccSCorey Minyard {
1519a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1520a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
15218bfffbccSCorey Minyard }
15228bfffbccSCorey Minyard 
15238bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
15248bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1525a580d820SCédric Le Goater                           RspBuffer *rsp)
15268bfffbccSCorey Minyard {
15278bfffbccSCorey Minyard     unsigned int val;
15288bfffbccSCorey Minyard 
15298bfffbccSCorey Minyard     if (cmd[6]) {
15307f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15316acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15327f996411SCédric Le Goater             return;
15337f996411SCédric Le Goater         }
15348bfffbccSCorey Minyard     }
15358bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
15366acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1537d13ada5dSCédric Le Goater         return;
15388bfffbccSCorey Minyard     }
15398bfffbccSCorey Minyard     if (cmd[6] > 15) {
15406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1541d13ada5dSCédric Le Goater         return;
15428bfffbccSCorey Minyard     }
15438bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
15448bfffbccSCorey Minyard         cmd[7] = 16;
15458bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
15466acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1547d13ada5dSCédric Le Goater         return;
15488bfffbccSCorey Minyard     } else {
15498bfffbccSCorey Minyard         cmd[7] += cmd[6];
15508bfffbccSCorey Minyard     }
15518bfffbccSCorey Minyard 
15528bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
15538bfffbccSCorey Minyard     if (val == 0xffff) {
15548bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
15558bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
15566acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1557d13ada5dSCédric Le Goater         return;
15588bfffbccSCorey Minyard     }
15598bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1560a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1561a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15628bfffbccSCorey Minyard     } else {
1563a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1564a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15658bfffbccSCorey Minyard     }
15668bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1567a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15688bfffbccSCorey Minyard     }
15698bfffbccSCorey Minyard }
15708bfffbccSCorey Minyard 
15718bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15728bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1573a580d820SCédric Le Goater                           RspBuffer *rsp)
15748bfffbccSCorey Minyard {
15758bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15766acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1577d13ada5dSCédric Le Goater         return;
15788bfffbccSCorey Minyard     }
15798bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1580a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1581a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15828bfffbccSCorey Minyard }
15838bfffbccSCorey Minyard 
15848bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15858bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1586a580d820SCédric Le Goater                       RspBuffer *rsp)
15878bfffbccSCorey Minyard {
15887f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15896acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15907f996411SCédric Le Goater         return;
15917f996411SCédric Le Goater     }
15927f996411SCédric Le Goater 
15938bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1595d13ada5dSCédric Le Goater         return;
15968bfffbccSCorey Minyard     }
15978bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15988bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15998bfffbccSCorey Minyard         ibs->sel.overflow = 0;
16008bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1601a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
16028bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
16038bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1604a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
16058bfffbccSCorey Minyard     } else {
16066acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
16078bfffbccSCorey Minyard         return;
16088bfffbccSCorey Minyard     }
1609d13ada5dSCédric Le Goater }
16108bfffbccSCorey Minyard 
16118bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
16128bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1613a580d820SCédric Le Goater                          RspBuffer *rsp)
16148bfffbccSCorey Minyard {
16158bfffbccSCorey Minyard     uint32_t val;
16168bfffbccSCorey Minyard     struct ipmi_time now;
16178bfffbccSCorey Minyard 
16188bfffbccSCorey Minyard     ipmi_gettime(&now);
16198bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1620a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1621a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1622a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1623a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
16248bfffbccSCorey Minyard }
16258bfffbccSCorey Minyard 
16268bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
16278bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1628a580d820SCédric Le Goater                          RspBuffer *rsp)
16298bfffbccSCorey Minyard {
16308bfffbccSCorey Minyard     uint32_t val;
16318bfffbccSCorey Minyard     struct ipmi_time now;
16328bfffbccSCorey Minyard 
16338bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
16348bfffbccSCorey Minyard     ipmi_gettime(&now);
16358bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
16368bfffbccSCorey Minyard }
16378bfffbccSCorey Minyard 
16389380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
16399380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
16409380d2edSCorey Minyard                                RspBuffer *rsp)
16419380d2edSCorey Minyard {
16429380d2edSCorey Minyard     uint8_t event[16];
16439380d2edSCorey Minyard 
16449380d2edSCorey Minyard     event[2] = 2; /* System event record */
16459380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
16469380d2edSCorey Minyard     event[8] = 0;
16479380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
16489380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
16499380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
16509380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
16519380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
16529380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
16539380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
16549380d2edSCorey Minyard 
16559380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
16569380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16579380d2edSCorey Minyard     }
16589380d2edSCorey Minyard }
16599380d2edSCorey Minyard 
16608bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16618bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1662a580d820SCédric Le Goater                                   RspBuffer *rsp)
16638bfffbccSCorey Minyard {
16648bfffbccSCorey Minyard     IPMISensor *sens;
16658bfffbccSCorey Minyard 
166673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16678bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16686acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1669d13ada5dSCédric Le Goater         return;
16708bfffbccSCorey Minyard     }
16718bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16728bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16738bfffbccSCorey Minyard     case 0: /* Do not change */
16748bfffbccSCorey Minyard         break;
16758bfffbccSCorey Minyard     case 1: /* Enable bits */
16768bfffbccSCorey Minyard         if (cmd_len > 4) {
16778bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16788bfffbccSCorey Minyard         }
16798bfffbccSCorey Minyard         if (cmd_len > 5) {
16808bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16818bfffbccSCorey Minyard         }
16828bfffbccSCorey Minyard         if (cmd_len > 6) {
16838bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16848bfffbccSCorey Minyard         }
16858bfffbccSCorey Minyard         if (cmd_len > 7) {
16868bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16878bfffbccSCorey Minyard         }
16888bfffbccSCorey Minyard         break;
16898bfffbccSCorey Minyard     case 2: /* Disable bits */
16908bfffbccSCorey Minyard         if (cmd_len > 4) {
16918bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16928bfffbccSCorey Minyard         }
16938bfffbccSCorey Minyard         if (cmd_len > 5) {
16948bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16958bfffbccSCorey Minyard         }
16968bfffbccSCorey Minyard         if (cmd_len > 6) {
16978bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16988bfffbccSCorey Minyard         }
16998bfffbccSCorey Minyard         if (cmd_len > 7) {
17008bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
17018bfffbccSCorey Minyard         }
17028bfffbccSCorey Minyard         break;
17038bfffbccSCorey Minyard     case 3:
17046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1705d13ada5dSCédric Le Goater         return;
17068bfffbccSCorey Minyard     }
17078bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
17088bfffbccSCorey Minyard }
17098bfffbccSCorey Minyard 
17108bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
17118bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1712a580d820SCédric Le Goater                                   RspBuffer *rsp)
17138bfffbccSCorey Minyard {
17148bfffbccSCorey Minyard     IPMISensor *sens;
17158bfffbccSCorey Minyard 
171673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17178bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17186acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1719d13ada5dSCédric Le Goater         return;
17208bfffbccSCorey Minyard     }
17218bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1722a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1723a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1724a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1725a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1726a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
17278bfffbccSCorey Minyard }
17288bfffbccSCorey Minyard 
17298bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
17308bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1731a580d820SCédric Le Goater                               RspBuffer *rsp)
17328bfffbccSCorey Minyard {
17338bfffbccSCorey Minyard     IPMISensor *sens;
17348bfffbccSCorey Minyard 
173573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17368bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1738d13ada5dSCédric Le Goater         return;
17398bfffbccSCorey Minyard     }
17408bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
17418bfffbccSCorey Minyard 
17428bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
17438bfffbccSCorey Minyard         /* Just clear everything */
17448bfffbccSCorey Minyard         sens->states = 0;
17458bfffbccSCorey Minyard         return;
17468bfffbccSCorey Minyard     }
1747d13ada5dSCédric Le Goater }
17488bfffbccSCorey Minyard 
17498bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
17508bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1751a580d820SCédric Le Goater                                   RspBuffer *rsp)
17528bfffbccSCorey Minyard {
17538bfffbccSCorey Minyard     IPMISensor *sens;
17548bfffbccSCorey Minyard 
175573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17568bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17576acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1758d13ada5dSCédric Le Goater         return;
17598bfffbccSCorey Minyard     }
17608bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1761a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1762a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1763a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1764a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1765a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1766a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17678bfffbccSCorey Minyard }
17688bfffbccSCorey Minyard 
17698bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17708bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1771a580d820SCédric Le Goater                                RspBuffer *rsp)
17728bfffbccSCorey Minyard {
17738bfffbccSCorey Minyard     IPMISensor *sens;
17748bfffbccSCorey Minyard 
177573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17768bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17776acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1778d13ada5dSCédric Le Goater         return;
17798bfffbccSCorey Minyard     }
17808bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1781a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1782a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1783a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17848bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1785a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17868bfffbccSCorey Minyard     }
17878bfffbccSCorey Minyard }
17888bfffbccSCorey Minyard 
1789728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1790728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1791a580d820SCédric Le Goater                             RspBuffer *rsp)
1792728710e1SCédric Le Goater {
1793728710e1SCédric Le Goater     IPMISensor *sens;
1794728710e1SCédric Le Goater 
1795728710e1SCédric Le Goater 
179673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1797728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17986acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1799728710e1SCédric Le Goater         return;
1800728710e1SCédric Le Goater     }
1801728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1802728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1803728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1804728710e1SCédric Le Goater }
1805728710e1SCédric Le Goater 
1806728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1807728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1808a580d820SCédric Le Goater                             RspBuffer *rsp)
1809728710e1SCédric Le Goater {
1810728710e1SCédric Le Goater     IPMISensor *sens;
1811728710e1SCédric Le Goater 
1812728710e1SCédric Le Goater 
181373d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1814728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18156acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1816728710e1SCédric Le Goater         return;
1817728710e1SCédric Le Goater     }
1818728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1819a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1820a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1821728710e1SCédric Le Goater }
1822728710e1SCédric Le Goater 
1823e3f7320cSCédric Le Goater /*
1824e3f7320cSCédric Le Goater  * bytes   parameter
1825e3f7320cSCédric Le Goater  *    1    sensor number
1826e3f7320cSCédric Le Goater  *    2    operation (see below for bits meaning)
1827e3f7320cSCédric Le Goater  *    3    sensor reading
1828e3f7320cSCédric Le Goater  *  4:5    assertion states (optional)
1829e3f7320cSCédric Le Goater  *  6:7    deassertion states (optional)
1830e3f7320cSCédric Le Goater  *  8:10   event data 1,2,3 (optional)
1831e3f7320cSCédric Le Goater  */
1832e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1833e3f7320cSCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1834e3f7320cSCédric Le Goater                                RspBuffer *rsp)
1835e3f7320cSCédric Le Goater {
1836e3f7320cSCédric Le Goater     IPMISensor *sens;
1837e3f7320cSCédric Le Goater     uint8_t evd1 = 0;
1838e3f7320cSCédric Le Goater     uint8_t evd2 = 0;
1839e3f7320cSCédric Le Goater     uint8_t evd3 = 0;
1840e3f7320cSCédric Le Goater     uint8_t new_reading = 0;
1841e3f7320cSCédric Le Goater     uint16_t new_assert_states = 0;
1842e3f7320cSCédric Le Goater     uint16_t new_deassert_states = 0;
1843e3f7320cSCédric Le Goater     bool change_reading = false;
1844e3f7320cSCédric Le Goater     bool change_assert = false;
1845e3f7320cSCédric Le Goater     bool change_deassert = false;
1846e3f7320cSCédric Le Goater     enum {
1847e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_NONE,
1848e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_DATA,
1849e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_BMC,
1850e3f7320cSCédric Le Goater     } do_gen_event = SENSOR_GEN_EVENT_NONE;
1851e3f7320cSCédric Le Goater 
1852e3f7320cSCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1853e3f7320cSCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1854e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1855e3f7320cSCédric Le Goater         return;
1856e3f7320cSCédric Le Goater     }
1857e3f7320cSCédric Le Goater 
1858e3f7320cSCédric Le Goater     sens = ibs->sensors + cmd[2];
1859e3f7320cSCédric Le Goater 
1860e3f7320cSCédric Le Goater     /* [1:0] Sensor Reading operation */
1861e3f7320cSCédric Le Goater     switch ((cmd[3]) & 0x3) {
1862e3f7320cSCédric Le Goater     case 0: /* Do not change */
1863e3f7320cSCédric Le Goater         break;
1864e3f7320cSCédric Le Goater     case 1: /* write given value to sensor reading byte */
1865e3f7320cSCédric Le Goater         new_reading = cmd[4];
1866e3f7320cSCédric Le Goater         if (sens->reading != new_reading) {
1867e3f7320cSCédric Le Goater             change_reading = true;
1868e3f7320cSCédric Le Goater         }
1869e3f7320cSCédric Le Goater         break;
1870e3f7320cSCédric Le Goater     case 2:
1871e3f7320cSCédric Le Goater     case 3:
1872e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1873e3f7320cSCédric Le Goater         return;
1874e3f7320cSCédric Le Goater     }
1875e3f7320cSCédric Le Goater 
1876e3f7320cSCédric Le Goater     /* [3:2] Deassertion bits operation */
1877e3f7320cSCédric Le Goater     switch ((cmd[3] >> 2) & 0x3) {
1878e3f7320cSCédric Le Goater     case 0: /* Do not change */
1879e3f7320cSCédric Le Goater         break;
1880e3f7320cSCédric Le Goater     case 1: /* write given value */
1881e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1882e3f7320cSCédric Le Goater             new_deassert_states = cmd[7];
1883e3f7320cSCédric Le Goater             change_deassert = true;
1884e3f7320cSCédric Le Goater         }
1885e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1886e3f7320cSCédric Le Goater             new_deassert_states |= (cmd[8] << 8);
1887e3f7320cSCédric Le Goater         }
1888e3f7320cSCédric Le Goater         break;
1889e3f7320cSCédric Le Goater 
1890e3f7320cSCédric Le Goater     case 2: /* mask on */
1891e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1892e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states | cmd[7]);
1893e3f7320cSCédric Le Goater             change_deassert = true;
1894e3f7320cSCédric Le Goater         }
1895e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1896e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1897e3f7320cSCédric Le Goater         }
1898e3f7320cSCédric Le Goater         break;
1899e3f7320cSCédric Le Goater 
1900e3f7320cSCédric Le Goater     case 3: /* mask off */
1901e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1902e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states & cmd[7]);
1903e3f7320cSCédric Le Goater             change_deassert = true;
1904e3f7320cSCédric Le Goater         }
1905e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1906e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1907e3f7320cSCédric Le Goater         }
1908e3f7320cSCédric Le Goater         break;
1909e3f7320cSCédric Le Goater     }
1910e3f7320cSCédric Le Goater 
1911e3f7320cSCédric Le Goater     if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1912e3f7320cSCédric Le Goater         change_deassert = false;
1913e3f7320cSCédric Le Goater     }
1914e3f7320cSCédric Le Goater 
1915e3f7320cSCédric Le Goater     /* [5:4] Assertion bits operation */
1916e3f7320cSCédric Le Goater     switch ((cmd[3] >> 4) & 0x3) {
1917e3f7320cSCédric Le Goater     case 0: /* Do not change */
1918e3f7320cSCédric Le Goater         break;
1919e3f7320cSCédric Le Goater     case 1: /* write given value */
1920e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1921e3f7320cSCédric Le Goater             new_assert_states = cmd[5];
1922e3f7320cSCédric Le Goater             change_assert = true;
1923e3f7320cSCédric Le Goater         }
1924e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1925e3f7320cSCédric Le Goater             new_assert_states |= (cmd[6] << 8);
1926e3f7320cSCédric Le Goater         }
1927e3f7320cSCédric Le Goater         break;
1928e3f7320cSCédric Le Goater 
1929e3f7320cSCédric Le Goater     case 2: /* mask on */
1930e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1931e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states | cmd[5]);
1932e3f7320cSCédric Le Goater             change_assert = true;
1933e3f7320cSCédric Le Goater         }
1934e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1935e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1936e3f7320cSCédric Le Goater         }
1937e3f7320cSCédric Le Goater         break;
1938e3f7320cSCédric Le Goater 
1939e3f7320cSCédric Le Goater     case 3: /* mask off */
1940e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1941e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states & cmd[5]);
1942e3f7320cSCédric Le Goater             change_assert = true;
1943e3f7320cSCédric Le Goater         }
1944e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1945e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1946e3f7320cSCédric Le Goater         }
1947e3f7320cSCédric Le Goater         break;
1948e3f7320cSCédric Le Goater     }
1949e3f7320cSCédric Le Goater 
1950e3f7320cSCédric Le Goater     if (change_assert && (new_assert_states == sens->assert_states)) {
1951e3f7320cSCédric Le Goater         change_assert = false;
1952e3f7320cSCédric Le Goater     }
1953e3f7320cSCédric Le Goater 
1954e3f7320cSCédric Le Goater     if (cmd_len > 9) {
1955e3f7320cSCédric Le Goater         evd1 = cmd[9];
1956e3f7320cSCédric Le Goater     }
1957e3f7320cSCédric Le Goater     if (cmd_len > 10) {
1958e3f7320cSCédric Le Goater         evd2 = cmd[10];
1959e3f7320cSCédric Le Goater     }
1960e3f7320cSCédric Le Goater     if (cmd_len > 11) {
1961e3f7320cSCédric Le Goater         evd3 = cmd[11];
1962e3f7320cSCédric Le Goater     }
1963e3f7320cSCédric Le Goater 
1964e3f7320cSCédric Le Goater     /* [7:6] Event Data Bytes operation */
1965e3f7320cSCédric Le Goater     switch ((cmd[3] >> 6) & 0x3) {
1966e3f7320cSCédric Le Goater     case 0: /*
1967e3f7320cSCédric Le Goater              * Don’t use Event Data bytes from this command. BMC will
1968e3f7320cSCédric Le Goater              * generate it's own Event Data bytes based on its sensor
1969e3f7320cSCédric Le Goater              * implementation.
1970e3f7320cSCédric Le Goater              */
1971e3f7320cSCédric Le Goater         evd1 = evd2 = evd3 = 0x0;
1972e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_BMC;
1973e3f7320cSCédric Le Goater         break;
1974e3f7320cSCédric Le Goater     case 1: /*
1975e3f7320cSCédric Le Goater              * Write given values to event data bytes including bits
1976e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1977e3f7320cSCédric Le Goater              */
1978e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1979e3f7320cSCédric Le Goater         break;
1980e3f7320cSCédric Le Goater     case 2: /*
1981e3f7320cSCédric Le Goater              * Write given values to event data bytes excluding bits
1982e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1983e3f7320cSCédric Le Goater              */
1984e3f7320cSCédric Le Goater         evd1 &= 0xf0;
1985e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1986e3f7320cSCédric Le Goater         break;
1987e3f7320cSCédric Le Goater     case 3:
1988e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1989e3f7320cSCédric Le Goater         return;
1990e3f7320cSCédric Le Goater     }
1991e3f7320cSCédric Le Goater 
1992e3f7320cSCédric Le Goater     /*
1993e3f7320cSCédric Le Goater      * Event Data Bytes operation and parameter are inconsistent. The
1994e3f7320cSCédric Le Goater      * Specs are not clear on that topic but generating an error seems
1995e3f7320cSCédric Le Goater      * correct.
1996e3f7320cSCédric Le Goater      */
1997e3f7320cSCédric Le Goater     if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1998e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1999e3f7320cSCédric Le Goater         return;
2000e3f7320cSCédric Le Goater     }
2001e3f7320cSCédric Le Goater 
2002e3f7320cSCédric Le Goater     /* commit values */
2003e3f7320cSCédric Le Goater     if (change_reading) {
2004e3f7320cSCédric Le Goater         sens->reading = new_reading;
2005e3f7320cSCédric Le Goater     }
2006e3f7320cSCédric Le Goater 
2007e3f7320cSCédric Le Goater     if (change_assert) {
2008e3f7320cSCédric Le Goater         sens->assert_states = new_assert_states;
2009e3f7320cSCédric Le Goater     }
2010e3f7320cSCédric Le Goater 
2011e3f7320cSCédric Le Goater     if (change_deassert) {
2012e3f7320cSCédric Le Goater         sens->deassert_states = new_deassert_states;
2013e3f7320cSCédric Le Goater     }
2014e3f7320cSCédric Le Goater 
2015e3f7320cSCédric Le Goater     /* TODO: handle threshold sensor */
2016e3f7320cSCédric Le Goater     if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
2017e3f7320cSCédric Le Goater         return;
2018e3f7320cSCédric Le Goater     }
2019e3f7320cSCédric Le Goater 
2020e3f7320cSCédric Le Goater     switch (do_gen_event) {
2021e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_DATA: {
2022e3f7320cSCédric Le Goater         unsigned int bit = evd1 & 0xf;
2023e3f7320cSCédric Le Goater         uint16_t mask = (1 << bit);
2024e3f7320cSCédric Le Goater 
2025e3f7320cSCédric Le Goater         if (sens->assert_states & mask & sens->assert_enable) {
2026e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
2027e3f7320cSCédric Le Goater         }
2028e3f7320cSCédric Le Goater 
2029e3f7320cSCédric Le Goater         if (sens->deassert_states & mask & sens->deassert_enable) {
2030e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
2031e3f7320cSCédric Le Goater         }
2032e3f7320cSCédric Le Goater         break;
2033e3f7320cSCédric Le Goater     }
2034e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_BMC:
2035e3f7320cSCédric Le Goater         /*
2036e3f7320cSCédric Le Goater          * TODO: generate event and event data bytes depending on the
2037e3f7320cSCédric Le Goater          * sensor
2038e3f7320cSCédric Le Goater          */
2039e3f7320cSCédric Le Goater         break;
2040e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_NONE:
2041e3f7320cSCédric Le Goater         break;
2042e3f7320cSCédric Le Goater     }
2043e3f7320cSCédric Le Goater }
2044728710e1SCédric Le Goater 
204562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
20464f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
20474f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
20484f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
20494f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
20508bfffbccSCorey Minyard };
20518bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
205262a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
20538bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
20548bfffbccSCorey Minyard };
20558bfffbccSCorey Minyard 
205662a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
20579380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
20584f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
20594f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
20604f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
20614f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
20624f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
20634f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
20644f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
2065e3f7320cSCédric Le Goater     [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
20668bfffbccSCorey Minyard };
20678bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
206862a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
20698bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
20708bfffbccSCorey Minyard };
20718bfffbccSCorey Minyard 
207262a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20734f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20744f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
20754f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
20764f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20774f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20784f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20794f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20804f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20814f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20824f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20834f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
20844f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20854f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20864f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20874f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20884f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
20897f9e7af4SNicholas Piggin     [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
20908bfffbccSCorey Minyard };
20918bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
209262a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
20938bfffbccSCorey Minyard     .cmd_handlers = app_cmds
20948bfffbccSCorey Minyard };
20958bfffbccSCorey Minyard 
209662a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2097540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2098540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2099540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
21004f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
21014f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
21024f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
21034f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
21044f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
21054f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
21064f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
21074f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
21084f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
21094f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
21107f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
21117f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
21128bfffbccSCorey Minyard };
21138bfffbccSCorey Minyard 
21148bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
211562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
21168bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
21178bfffbccSCorey Minyard };
21188bfffbccSCorey Minyard 
21198bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
21208bfffbccSCorey Minyard {
2121ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2122ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2123ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2124ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
21258bfffbccSCorey Minyard }
21268bfffbccSCorey Minyard 
21275167560bSCédric Le Goater static uint8_t init_sdrs[] = {
21288bfffbccSCorey Minyard     /* Watchdog device */
21298bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
21308bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
21318bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21328bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
21338bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
21348bfffbccSCorey Minyard };
21358bfffbccSCorey Minyard 
21364fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
21374fa9f08eSCédric Le Goater {
21384fa9f08eSCédric Le Goater     unsigned int i;
21394fa9f08eSCédric Le Goater     int len;
21405167560bSCédric Le Goater     size_t sdrs_size;
21415167560bSCédric Le Goater     uint8_t *sdrs;
214252fc01d9SCédric Le Goater 
21435167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
21445167560bSCédric Le Goater     sdrs = init_sdrs;
21458c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
21468c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
21478c6fd7f3SCédric Le Goater                              NULL)) {
21488c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
21498c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
21508c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
21518c6fd7f3SCédric Le Goater     }
21525167560bSCédric Le Goater 
21535167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
215452fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
215552fc01d9SCédric Le Goater 
21565167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
21574fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21588c6fd7f3SCédric Le Goater             break;
21594fa9f08eSCédric Le Goater         }
21605167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
21614fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
21625167560bSCédric Le Goater         if (i + len > sdrs_size) {
21634fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21648c6fd7f3SCédric Le Goater             break;
21654fa9f08eSCédric Le Goater         }
21664fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
21674fa9f08eSCédric Le Goater     }
21688c6fd7f3SCédric Le Goater 
21698c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
21708c6fd7f3SCédric Le Goater         g_free(sdrs);
21718c6fd7f3SCédric Le Goater     }
21724fa9f08eSCédric Le Goater }
21734fa9f08eSCédric Le Goater 
2174bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2175bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
2176bd66bcfcSCorey Minyard     .version_id = 1,
2177bd66bcfcSCorey Minyard     .minimum_version_id = 1,
217809c6ac6dSRichard Henderson     .fields = (const VMStateField[]) {
2179bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2180bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2181bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2182bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2183bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2184bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21859e744990SJinhua Cao         VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2186bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2187bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2188bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2189bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2190bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2191bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2192bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2193bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2194bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2195bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2196bd66bcfcSCorey Minyard                        IPMIBmcSim),
2197bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2198bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
2199bd66bcfcSCorey Minyard     }
2200bd66bcfcSCorey Minyard };
2201bd66bcfcSCorey Minyard 
2202540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2203540c07d3SCédric Le Goater {
2204540c07d3SCédric Le Goater     int fsize;
2205540c07d3SCédric Le Goater     int size = 0;
2206540c07d3SCédric Le Goater 
2207540c07d3SCédric Le Goater     if (!fru->filename) {
2208540c07d3SCédric Le Goater         goto out;
2209540c07d3SCédric Le Goater     }
2210540c07d3SCédric Le Goater 
2211540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
2212540c07d3SCédric Le Goater     if (fsize > 0) {
2213540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
2214540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2215540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2216540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
2217540c07d3SCédric Le Goater             g_free(fru->data);
2218540c07d3SCédric Le Goater             fru->data = NULL;
2219540c07d3SCédric Le Goater         }
2220540c07d3SCédric Le Goater     }
2221540c07d3SCédric Le Goater 
2222540c07d3SCédric Le Goater out:
2223540c07d3SCédric Le Goater     if (!fru->data) {
2224540c07d3SCédric Le Goater         /* give one default FRU */
2225540c07d3SCédric Le Goater         size = fru->areasize;
2226540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2227540c07d3SCédric Le Goater     }
2228540c07d3SCédric Le Goater 
2229540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
2230540c07d3SCédric Le Goater }
2231540c07d3SCédric Le Goater 
22320bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
22338bfffbccSCorey Minyard {
22340bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
22358bfffbccSCorey Minyard     unsigned int i;
22368bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
22378bfffbccSCorey Minyard 
22388bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
22398bfffbccSCorey Minyard 
22408bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
22418bfffbccSCorey Minyard     ibs->device_id = 0x20;
22428bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2243b7088392SCédric Le Goater     ibs->restart_cause = 0;
22448bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
22458bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
22468bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
22478bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
22488bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
22498bfffbccSCorey Minyard     }
22508bfffbccSCorey Minyard 
22514fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
22528bfffbccSCorey Minyard 
2253540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
2254540c07d3SCédric Le Goater 
225552ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
225652ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
225752ba4d50SCédric Le Goater 
22588bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
22598bfffbccSCorey Minyard     register_cmds(ibs);
22608bfffbccSCorey Minyard 
22618bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
22628bfffbccSCorey Minyard }
22638bfffbccSCorey Minyard 
22642acf1403SRichard Henderson static const Property ipmi_sim_properties[] = {
2265540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2266540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
22678c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
226820b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
226920b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
227020b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
227120b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
227220b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
227320b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
227420b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22757b0cd78bSCorey Minyard     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22768c6fd7f3SCédric Le Goater };
22778c6fd7f3SCédric Le Goater 
22788bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
22798bfffbccSCorey Minyard {
22800bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
22818bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22828bfffbccSCorey Minyard 
228366abfddbSCorey Minyard     dc->hotpluggable = false;
22840bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
2285d11d904cSCorey Minyard     dc->vmsd = &vmstate_ipmi_sim;
22864f67d30bSMarc-André Lureau     device_class_set_props(dc, ipmi_sim_properties);
22878bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
22888bfffbccSCorey Minyard }
22898bfffbccSCorey Minyard 
22908bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22918bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
22928bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
22938bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
22948bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
22958bfffbccSCorey Minyard };
22968bfffbccSCorey Minyard 
22978bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
22988bfffbccSCorey Minyard {
22998bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
23008bfffbccSCorey Minyard }
23018bfffbccSCorey Minyard 
23028bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2303