18bfffbccSCorey Minyard /* 28bfffbccSCorey Minyard * IPMI BMC emulation 38bfffbccSCorey Minyard * 48bfffbccSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 58bfffbccSCorey Minyard * 68bfffbccSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 78bfffbccSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 88bfffbccSCorey Minyard * in the Software without restriction, including without limitation the rights 98bfffbccSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108bfffbccSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 118bfffbccSCorey Minyard * furnished to do so, subject to the following conditions: 128bfffbccSCorey Minyard * 138bfffbccSCorey Minyard * The above copyright notice and this permission notice shall be included in 148bfffbccSCorey Minyard * all copies or substantial portions of the Software. 158bfffbccSCorey Minyard * 168bfffbccSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178bfffbccSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188bfffbccSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198bfffbccSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208bfffbccSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218bfffbccSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228bfffbccSCorey Minyard * THE SOFTWARE. 238bfffbccSCorey Minyard */ 248bfffbccSCorey Minyard 250430891cSPeter Maydell #include "qemu/osdep.h" 2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h" 278bfffbccSCorey Minyard #include "qemu/timer.h" 288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 298bfffbccSCorey Minyard #include "qemu/error-report.h" 300b8fa32fSMarkus Armbruster #include "qemu/module.h" 318c6fd7f3SCédric Le Goater #include "hw/loader.h" 32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 33d6454270SMarkus Armbruster #include "migration/vmstate.h" 348bfffbccSCorey Minyard 358bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 368bfffbccSCorey Minyard 378bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 398bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 40b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 418bfffbccSCorey Minyard 428bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 438bfffbccSCorey Minyard 449380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG 0x02 458bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 468bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 478bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 488bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 50728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 51728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 528bfffbccSCorey Minyard 538bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 548bfffbccSCorey Minyard 558bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 568bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 578bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 5852ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 5952ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 6052ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08 618bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 628bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 638bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 648bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 658bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 668bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 678bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 688bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 698bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 708bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 718bfffbccSCorey Minyard 728bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 738bfffbccSCorey Minyard 748bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 758bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 768bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 788bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 798bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 808bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 818bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 828bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 838bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 848bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 858bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 868bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 87540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO 0x10 88540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA 0x11 89540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA 0x12 908bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 918bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 928bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 948bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 958bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 968bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 978bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 988bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 998bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 1008bfffbccSCorey Minyard 1018bfffbccSCorey Minyard 1028bfffbccSCorey Minyard /* Same as a timespec struct. */ 1038bfffbccSCorey Minyard struct ipmi_time { 1048bfffbccSCorey Minyard long tv_sec; 1058bfffbccSCorey Minyard long tv_nsec; 1068bfffbccSCorey Minyard }; 1078bfffbccSCorey Minyard 1088bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 1098bfffbccSCorey Minyard 1108bfffbccSCorey Minyard typedef struct IPMISel { 1118bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1128bfffbccSCorey Minyard unsigned int next_free; 1138bfffbccSCorey Minyard long time_offset; 1148bfffbccSCorey Minyard uint16_t reservation; 1158bfffbccSCorey Minyard uint8_t last_addition[4]; 1168bfffbccSCorey Minyard uint8_t last_clear[4]; 1178bfffbccSCorey Minyard uint8_t overflow; 1188bfffbccSCorey Minyard } IPMISel; 1198bfffbccSCorey Minyard 1208bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1218bfffbccSCorey Minyard 1228bfffbccSCorey Minyard typedef struct IPMISdr { 1238bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1248bfffbccSCorey Minyard unsigned int next_free; 1258bfffbccSCorey Minyard uint16_t next_rec_id; 1268bfffbccSCorey Minyard uint16_t reservation; 1278bfffbccSCorey Minyard uint8_t last_addition[4]; 1288bfffbccSCorey Minyard uint8_t last_clear[4]; 1298bfffbccSCorey Minyard uint8_t overflow; 1308bfffbccSCorey Minyard } IPMISdr; 1318bfffbccSCorey Minyard 132540c07d3SCédric Le Goater typedef struct IPMIFru { 133540c07d3SCédric Le Goater char *filename; 134540c07d3SCédric Le Goater unsigned int nentries; 135540c07d3SCédric Le Goater uint16_t areasize; 136540c07d3SCédric Le Goater uint8_t *data; 137540c07d3SCédric Le Goater } IPMIFru; 138540c07d3SCédric Le Goater 1398bfffbccSCorey Minyard typedef struct IPMISensor { 1408bfffbccSCorey Minyard uint8_t status; 1418bfffbccSCorey Minyard uint8_t reading; 1428bfffbccSCorey Minyard uint16_t states_suppt; 1438bfffbccSCorey Minyard uint16_t assert_suppt; 1448bfffbccSCorey Minyard uint16_t deassert_suppt; 1458bfffbccSCorey Minyard uint16_t states; 1468bfffbccSCorey Minyard uint16_t assert_states; 1478bfffbccSCorey Minyard uint16_t deassert_states; 1488bfffbccSCorey Minyard uint16_t assert_enable; 1498bfffbccSCorey Minyard uint16_t deassert_enable; 1508bfffbccSCorey Minyard uint8_t sensor_type; 1518bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1528bfffbccSCorey Minyard } IPMISensor; 1538bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1548bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1558bfffbccSCorey Minyard !!(v)) 1568bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1578bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1588bfffbccSCorey Minyard ((!!(v)) << 6)) 1598bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1608bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1618bfffbccSCorey Minyard ((!!(v)) << 7)) 1628bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1638bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1648bfffbccSCorey Minyard (v & 0xc0)) 1658bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1668bfffbccSCorey Minyard 1678bfffbccSCorey Minyard #define MAX_SENSORS 20 1688bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1698bfffbccSCorey Minyard 1708bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 171a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer; 1728bfffbccSCorey Minyard 1738bfffbccSCorey Minyard #define MAX_NETFNS 64 1744f298a4bSCédric Le Goater 1754f298a4bSCédric Le Goater typedef struct IPMICmdHandler { 1764f298a4bSCédric Le Goater void (*cmd_handler)(IPMIBmcSim *s, 1778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 178a580d820SCédric Le Goater RspBuffer *rsp); 1794f298a4bSCédric Le Goater unsigned int cmd_len_min; 1804f298a4bSCédric Le Goater } IPMICmdHandler; 1814f298a4bSCédric Le Goater 1828bfffbccSCorey Minyard typedef struct IPMINetfn { 1838bfffbccSCorey Minyard unsigned int cmd_nums; 1848bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1858bfffbccSCorey Minyard } IPMINetfn; 1868bfffbccSCorey Minyard 1878bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1888bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1898bfffbccSCorey Minyard uint8_t len; 1908bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1918bfffbccSCorey Minyard } IPMIRcvBufEntry; 1928bfffbccSCorey Minyard 1938bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1948bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1958bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1968bfffbccSCorey Minyard struct IPMIBmcSim { 1978bfffbccSCorey Minyard IPMIBmc parent; 1988bfffbccSCorey Minyard 1998bfffbccSCorey Minyard QEMUTimer *timer; 2008bfffbccSCorey Minyard 2018bfffbccSCorey Minyard uint8_t bmc_global_enables; 2028bfffbccSCorey Minyard uint8_t msg_flags; 2038bfffbccSCorey Minyard 2048bfffbccSCorey Minyard bool watchdog_initialized; 2058bfffbccSCorey Minyard uint8_t watchdog_use; 2068bfffbccSCorey Minyard uint8_t watchdog_action; 2078bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 2088bfffbccSCorey Minyard bool watchdog_expired; 2098bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 2108bfffbccSCorey Minyard 2118bfffbccSCorey Minyard bool watchdog_running; 2128bfffbccSCorey Minyard bool watchdog_preaction_ran; 2138bfffbccSCorey Minyard int64_t watchdog_expiry; 2148bfffbccSCorey Minyard 2158bfffbccSCorey Minyard uint8_t device_id; 2168bfffbccSCorey Minyard uint8_t ipmi_version; 2178bfffbccSCorey Minyard uint8_t device_rev; 2188bfffbccSCorey Minyard uint8_t fwrev1; 2198bfffbccSCorey Minyard uint8_t fwrev2; 22020b23364SCorey Minyard uint32_t mfg_id; 22120b23364SCorey Minyard uint16_t product_id; 2228bfffbccSCorey Minyard 223b7088392SCédric Le Goater uint8_t restart_cause; 224b7088392SCédric Le Goater 22552ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 226*7b0cd78bSCorey Minyard QemuUUID uuid; 22752ba4d50SCédric Le Goater 2288bfffbccSCorey Minyard IPMISel sel; 2298bfffbccSCorey Minyard IPMISdr sdr; 230540c07d3SCédric Le Goater IPMIFru fru; 2318bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2328c6fd7f3SCédric Le Goater char *sdr_filename; 2338bfffbccSCorey Minyard 2348bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2358bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2368bfffbccSCorey Minyard 2378bfffbccSCorey Minyard /* We allow one event in the buffer */ 2388bfffbccSCorey Minyard uint8_t evtbuf[16]; 2398bfffbccSCorey Minyard 2408bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2418bfffbccSCorey Minyard }; 2428bfffbccSCorey Minyard 2438bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2448bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2458bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2468bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2478bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2488bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2498bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2508bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2518bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2528bfffbccSCorey Minyard 2538bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2548bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2558bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2568bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2578bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2588bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2598bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2608bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2618bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2628bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2638bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2648bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2658bfffbccSCorey Minyard 2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2678bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2688bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2698bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2708bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2718bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2728bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2738bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2748bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2758bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2768bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2778bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2788bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2798bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2808bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2818bfffbccSCorey Minyard 282a580d820SCédric Le Goater struct RspBuffer { 283a580d820SCédric Le Goater uint8_t buffer[MAX_IPMI_MSG_SIZE]; 284a580d820SCédric Le Goater unsigned int len; 285a580d820SCédric Le Goater }; 286a580d820SCédric Le Goater 287a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { } 2888bfffbccSCorey Minyard 2896acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte) 2906acb971aSCédric Le Goater { 2916acb971aSCédric Le Goater rsp->buffer[2] = byte; 2926acb971aSCédric Le Goater } 2936acb971aSCédric Le Goater 2948bfffbccSCorey Minyard /* Add a byte to the response. */ 295a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte) 296a580d820SCédric Le Goater { 297a580d820SCédric Le Goater if (rsp->len >= sizeof(rsp->buffer)) { 2986acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 299a580d820SCédric Le Goater return; 300a580d820SCédric Le Goater } 301a580d820SCédric Le Goater rsp->buffer[rsp->len++] = byte; 302a580d820SCédric Le Goater } 303a580d820SCédric Le Goater 304a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 305a580d820SCédric Le Goater unsigned int n) 306a580d820SCédric Le Goater { 307a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 3086acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 309a580d820SCédric Le Goater return; 310a580d820SCédric Le Goater } 311a580d820SCédric Le Goater 312a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 313a580d820SCédric Le Goater rsp->len += n; 314a580d820SCédric Le Goater } 3158bfffbccSCorey Minyard 3168bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 3178bfffbccSCorey Minyard 3188bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 3198bfffbccSCorey Minyard { 3208bfffbccSCorey Minyard int64_t stime; 3218bfffbccSCorey Minyard 3228bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 3238bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 3248bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 3258bfffbccSCorey Minyard } 3268bfffbccSCorey Minyard 3278bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3288bfffbccSCorey Minyard { 3298bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3308bfffbccSCorey Minyard } 3318bfffbccSCorey Minyard 3328bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3338bfffbccSCorey Minyard { 3348bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3358bfffbccSCorey Minyard 3368bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3378bfffbccSCorey Minyard } 3388bfffbccSCorey Minyard 3398bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3408bfffbccSCorey Minyard { 3418bfffbccSCorey Minyard unsigned int val; 3428bfffbccSCorey Minyard struct ipmi_time now; 3438bfffbccSCorey Minyard 3448bfffbccSCorey Minyard ipmi_gettime(&now); 3458bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3468bfffbccSCorey Minyard ts[0] = val & 0xff; 3478bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3488bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3498bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3508bfffbccSCorey Minyard } 3518bfffbccSCorey Minyard 3528bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3538bfffbccSCorey Minyard { 3548bfffbccSCorey Minyard sdr->reservation++; 3558bfffbccSCorey Minyard if (sdr->reservation == 0) { 3568bfffbccSCorey Minyard sdr->reservation = 1; 3578bfffbccSCorey Minyard } 3588bfffbccSCorey Minyard } 3598bfffbccSCorey Minyard 360a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 361a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3628bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3638bfffbccSCorey Minyard { 364a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 365a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 366a2295f0aSCédric Le Goater 367a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3688bfffbccSCorey Minyard return 1; 3698bfffbccSCorey Minyard } 3708bfffbccSCorey Minyard 371a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3728bfffbccSCorey Minyard return 1; 3738bfffbccSCorey Minyard } 3748bfffbccSCorey Minyard 3758bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3768bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3778bfffbccSCorey Minyard return 1; 3788bfffbccSCorey Minyard } 3798bfffbccSCorey Minyard 380a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 381a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 382a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 383a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3848bfffbccSCorey Minyard 3858bfffbccSCorey Minyard if (recid) { 3868bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3878bfffbccSCorey Minyard } 3888bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3898bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3908bfffbccSCorey Minyard ibs->sdr.next_free += len; 3918bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3928bfffbccSCorey Minyard return 0; 3938bfffbccSCorey Minyard } 3948bfffbccSCorey Minyard 3958bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3968bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3978bfffbccSCorey Minyard { 3988bfffbccSCorey Minyard unsigned int pos = *retpos; 3998bfffbccSCorey Minyard 4008bfffbccSCorey Minyard while (pos < sdr->next_free) { 401a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 402a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 403a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 404a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 4058bfffbccSCorey Minyard 4068bfffbccSCorey Minyard if (trec == recid) { 4078bfffbccSCorey Minyard if (nextrec) { 4088bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 4098bfffbccSCorey Minyard *nextrec = 0xffff; 4108bfffbccSCorey Minyard } else { 4118bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 4128bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 4138bfffbccSCorey Minyard } 4148bfffbccSCorey Minyard } 4158bfffbccSCorey Minyard *retpos = pos; 4168bfffbccSCorey Minyard return 0; 4178bfffbccSCorey Minyard } 4188bfffbccSCorey Minyard pos = nextpos; 4198bfffbccSCorey Minyard } 4208bfffbccSCorey Minyard return 1; 4218bfffbccSCorey Minyard } 4228bfffbccSCorey Minyard 4237fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid, 4247fabcdb9SCédric Le Goater const struct ipmi_sdr_compact **sdr, uint16_t *nextrec) 4257fabcdb9SCédric Le Goater 4267fabcdb9SCédric Le Goater { 4277fabcdb9SCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 4287fabcdb9SCédric Le Goater unsigned int pos; 4297fabcdb9SCédric Le Goater 4307fabcdb9SCédric Le Goater pos = 0; 4317fabcdb9SCédric Le Goater if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) { 4327fabcdb9SCédric Le Goater return -1; 4337fabcdb9SCédric Le Goater } 4347fabcdb9SCédric Le Goater 4357fabcdb9SCédric Le Goater *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos]; 4367fabcdb9SCédric Le Goater return 0; 4377fabcdb9SCédric Le Goater } 4387fabcdb9SCédric Le Goater 4398bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4408bfffbccSCorey Minyard { 4418bfffbccSCorey Minyard sel->reservation++; 4428bfffbccSCorey Minyard if (sel->reservation == 0) { 4438bfffbccSCorey Minyard sel->reservation = 1; 4448bfffbccSCorey Minyard } 4458bfffbccSCorey Minyard } 4468bfffbccSCorey Minyard 4478bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4488bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4498bfffbccSCorey Minyard { 4509f7d1d92SCorey Minyard uint8_t ts[4]; 4519f7d1d92SCorey Minyard 4528bfffbccSCorey Minyard event[0] = 0xff; 4538bfffbccSCorey Minyard event[1] = 0xff; 4549f7d1d92SCorey Minyard set_timestamp(ibs, ts); 4559f7d1d92SCorey Minyard if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */ 4569f7d1d92SCorey Minyard memcpy(event + 3, ts, 4); 4579f7d1d92SCorey Minyard } 4588bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4598bfffbccSCorey Minyard ibs->sel.overflow = 1; 4608bfffbccSCorey Minyard return 1; 4618bfffbccSCorey Minyard } 4628bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4638bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4649f7d1d92SCorey Minyard memcpy(ibs->sel.last_addition, ts, 4); 4658bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4668bfffbccSCorey Minyard ibs->sel.next_free++; 4678bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4688bfffbccSCorey Minyard return 0; 4698bfffbccSCorey Minyard } 4708bfffbccSCorey Minyard 4718bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4728bfffbccSCorey Minyard { 4738bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4748bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4758bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4768bfffbccSCorey Minyard } 4778bfffbccSCorey Minyard 4788bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4798bfffbccSCorey Minyard { 4808bc8af69SCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && 4818bc8af69SCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) || 4828bc8af69SCorey Minyard IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs))) 4838bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4848bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4858bfffbccSCorey Minyard } 4868bfffbccSCorey Minyard 487cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log) 488cd60d85eSCédric Le Goater { 489cd60d85eSCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 490cd60d85eSCédric Le Goater IPMIInterface *s = ibs->parent.intf; 491cd60d85eSCédric Le Goater IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 492cd60d85eSCédric Le Goater 493cd60d85eSCédric Le Goater if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 494cd60d85eSCédric Le Goater return; 495cd60d85eSCédric Le Goater } 496cd60d85eSCédric Le Goater 497cd60d85eSCédric Le Goater if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 498cd60d85eSCédric Le Goater sel_add_event(ibs, evt); 499cd60d85eSCédric Le Goater } 500cd60d85eSCédric Le Goater 501cd60d85eSCédric Le Goater if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 502cd60d85eSCédric Le Goater goto out; 503cd60d85eSCédric Le Goater } 504cd60d85eSCédric Le Goater 505cd60d85eSCédric Le Goater memcpy(ibs->evtbuf, evt, 16); 506cd60d85eSCédric Le Goater ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 507cd60d85eSCédric Le Goater k->set_atn(s, 1, attn_irq_enabled(ibs)); 508cd60d85eSCédric Le Goater out: 509cd60d85eSCédric Le Goater return; 510cd60d85eSCédric Le Goater } 5118bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 5128bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 5138bfffbccSCorey Minyard { 5148bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 5158bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 5168bfffbccSCorey Minyard uint8_t evt[16]; 5178bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 5188bfffbccSCorey Minyard 5198bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 5208bfffbccSCorey Minyard return; 5218bfffbccSCorey Minyard } 5228bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 5238bfffbccSCorey Minyard return; 5248bfffbccSCorey Minyard } 5258bfffbccSCorey Minyard 5268bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 5278bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 5288bfffbccSCorey Minyard evt[8] = 0; 5298bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 5308bfffbccSCorey Minyard evt[10] = sens->sensor_type; 5318bfffbccSCorey Minyard evt[11] = sens_num; 5328bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 5338bfffbccSCorey Minyard evt[13] = evd1; 5348bfffbccSCorey Minyard evt[14] = evd2; 5358bfffbccSCorey Minyard evt[15] = evd3; 5368bfffbccSCorey Minyard 5378bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 5388bfffbccSCorey Minyard sel_add_event(ibs, evt); 5398bfffbccSCorey Minyard } 5408bfffbccSCorey Minyard 5418bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 542d13ada5dSCédric Le Goater return; 5438bfffbccSCorey Minyard } 5448bfffbccSCorey Minyard 5458bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 5468bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 5478bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 5488bfffbccSCorey Minyard } 5498bfffbccSCorey Minyard 5508bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 5518bfffbccSCorey Minyard unsigned int bit, unsigned int val, 5528bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 5538bfffbccSCorey Minyard { 5548bfffbccSCorey Minyard IPMISensor *sens; 5558bfffbccSCorey Minyard uint16_t mask; 5568bfffbccSCorey Minyard 5578bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 5588bfffbccSCorey Minyard return; 5598bfffbccSCorey Minyard } 5608bfffbccSCorey Minyard if (bit >= 16) { 5618bfffbccSCorey Minyard return; 5628bfffbccSCorey Minyard } 5638bfffbccSCorey Minyard 5648bfffbccSCorey Minyard mask = (1 << bit); 5658bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5668bfffbccSCorey Minyard if (val) { 5678bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5688bfffbccSCorey Minyard if (sens->assert_states & mask) { 5698bfffbccSCorey Minyard return; /* Already asserted */ 5708bfffbccSCorey Minyard } 5718bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5728bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5738bfffbccSCorey Minyard /* Send an event on assert */ 5748bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5758bfffbccSCorey Minyard } 5768bfffbccSCorey Minyard } else { 5778bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5788bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5798bfffbccSCorey Minyard return; /* Already deasserted */ 5808bfffbccSCorey Minyard } 5818bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5828bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5838bfffbccSCorey Minyard /* Send an event on deassert */ 5848bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5858bfffbccSCorey Minyard } 5868bfffbccSCorey Minyard } 5878bfffbccSCorey Minyard } 5888bfffbccSCorey Minyard 5898bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5908bfffbccSCorey Minyard { 5918bfffbccSCorey Minyard unsigned int i, pos; 5928bfffbccSCorey Minyard IPMISensor *sens; 5938bfffbccSCorey Minyard 5948bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5958bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5968bfffbccSCorey Minyard } 5978bfffbccSCorey Minyard 5988bfffbccSCorey Minyard pos = 0; 5998bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 600a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 601a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 602a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 6038bfffbccSCorey Minyard 6048bfffbccSCorey Minyard if (len < 20) { 6058bfffbccSCorey Minyard continue; 6068bfffbccSCorey Minyard } 607a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 6088bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 6098bfffbccSCorey Minyard } 6108bfffbccSCorey Minyard 61173d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 6128bfffbccSCorey Minyard continue; 6138bfffbccSCorey Minyard } 614a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 6158bfffbccSCorey Minyard 6168bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 617a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 618a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 619a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 620a2295f0aSCédric Le Goater sens->deassert_suppt = 621a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 622a2295f0aSCédric Le Goater sens->states_suppt = 623a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 624a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 625a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 6268bfffbccSCorey Minyard 6278bfffbccSCorey Minyard /* Enable all the events that are supported. */ 6288bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 6298bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 6308bfffbccSCorey Minyard } 6318bfffbccSCorey Minyard } 6328bfffbccSCorey Minyard 6338bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 6348bfffbccSCorey Minyard const IPMINetfn *netfnd) 6358bfffbccSCorey Minyard { 63693a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 6378bfffbccSCorey Minyard return -1; 6388bfffbccSCorey Minyard } 6398bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 6408bfffbccSCorey Minyard return 0; 6418bfffbccSCorey Minyard } 6428bfffbccSCorey Minyard 6434f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 6444f298a4bSCédric Le Goater unsigned int netfn, 6454f298a4bSCédric Le Goater unsigned int cmd) 6464f298a4bSCédric Le Goater { 6474f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 6484f298a4bSCédric Le Goater 6494f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 6504f298a4bSCédric Le Goater return NULL; 6514f298a4bSCédric Le Goater } 6524f298a4bSCédric Le Goater 6534f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 6544f298a4bSCédric Le Goater return NULL; 6554f298a4bSCédric Le Goater } 6564f298a4bSCédric Le Goater 6574f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 6584f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 6594f298a4bSCédric Le Goater return NULL; 6604f298a4bSCédric Le Goater } 6614f298a4bSCédric Le Goater 6624f298a4bSCédric Le Goater return hdl; 6634f298a4bSCédric Le Goater } 6644f298a4bSCédric Le Goater 6658bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6668bfffbccSCorey Minyard { 6678bfffbccSCorey Minyard int64_t next; 6688bfffbccSCorey Minyard if (ibs->watchdog_running) { 6698bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6708bfffbccSCorey Minyard } else { 6718bfffbccSCorey Minyard /* Wait a minute */ 6728bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6738bfffbccSCorey Minyard } 6748bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6758bfffbccSCorey Minyard } 6768bfffbccSCorey Minyard 6778bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6788bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6798bfffbccSCorey Minyard unsigned int max_cmd_len, 6808bfffbccSCorey Minyard uint8_t msg_id) 6818bfffbccSCorey Minyard { 6828bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6838bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6848bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6854f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 686a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6878bfffbccSCorey Minyard 6888bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6898bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 690a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6916acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 692d13ada5dSCédric Le Goater goto out; 693d13ada5dSCédric Le Goater } 694d13ada5dSCédric Le Goater 695a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 696a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 697a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6988bfffbccSCorey Minyard 6998bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 7008bfffbccSCorey Minyard if (cmd_len < 2) { 7016acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 7028bfffbccSCorey Minyard goto out; 7038bfffbccSCorey Minyard } 7048bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 7056acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 7068bfffbccSCorey Minyard goto out; 7078bfffbccSCorey Minyard } 7088bfffbccSCorey Minyard 7098bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 7108bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 7116acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 7128bfffbccSCorey Minyard goto out; 7138bfffbccSCorey Minyard } 7148bfffbccSCorey Minyard 7154f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 7164f298a4bSCédric Le Goater if (!hdl) { 7176acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 7188bfffbccSCorey Minyard goto out; 7198bfffbccSCorey Minyard } 7208bfffbccSCorey Minyard 7214f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 7226acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 7234f298a4bSCédric Le Goater goto out; 7244f298a4bSCédric Le Goater } 7254f298a4bSCédric Le Goater 726a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 7278bfffbccSCorey Minyard 7288bfffbccSCorey Minyard out: 729a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 7308bfffbccSCorey Minyard 7318bfffbccSCorey Minyard next_timeout(ibs); 7328bfffbccSCorey Minyard } 7338bfffbccSCorey Minyard 7348bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 7358bfffbccSCorey Minyard { 7368bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7378bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7388bfffbccSCorey Minyard 7398bfffbccSCorey Minyard if (!ibs->watchdog_running) { 7408bfffbccSCorey Minyard goto out; 7418bfffbccSCorey Minyard } 7428bfffbccSCorey Minyard 7438bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 7448bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 7458bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 7468bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7478bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 7488bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7498bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 7508bfffbccSCorey Minyard break; 7518bfffbccSCorey Minyard 7528bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 7538bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7548bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 7558bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7568bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 7578bfffbccSCorey Minyard break; 7588bfffbccSCorey Minyard 7598bfffbccSCorey Minyard default: 7608bfffbccSCorey Minyard goto do_full_expiry; 7618bfffbccSCorey Minyard } 7628bfffbccSCorey Minyard 7638bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7648bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7658bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7668bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7678bfffbccSCorey Minyard goto out; 7688bfffbccSCorey Minyard } 7698bfffbccSCorey Minyard 7708bfffbccSCorey Minyard do_full_expiry: 7718bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7728bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7738bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7748bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7758bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7768bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7778bfffbccSCorey Minyard break; 7788bfffbccSCorey Minyard 7798bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7808bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7818bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7828bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7838bfffbccSCorey Minyard break; 7848bfffbccSCorey Minyard 7858bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7868bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7878bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7888bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7898bfffbccSCorey Minyard break; 7908bfffbccSCorey Minyard 7918bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7928bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7938bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7948bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7958bfffbccSCorey Minyard break; 7968bfffbccSCorey Minyard } 7978bfffbccSCorey Minyard 7988bfffbccSCorey Minyard out: 7998bfffbccSCorey Minyard next_timeout(ibs); 8008bfffbccSCorey Minyard } 8018bfffbccSCorey Minyard 8028bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 8038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 804a580d820SCédric Le Goater RspBuffer *rsp) 8058bfffbccSCorey Minyard { 806a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 807a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 808a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 809a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 810a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 8118bfffbccSCorey Minyard } 8128bfffbccSCorey Minyard 8138bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 8148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 815a580d820SCédric Le Goater RspBuffer *rsp) 8168bfffbccSCorey Minyard { 817a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 818a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 819a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 820a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 8218bfffbccSCorey Minyard } 8228bfffbccSCorey Minyard 8238bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 8248bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 825a580d820SCédric Le Goater RspBuffer *rsp) 8268bfffbccSCorey Minyard { 8278bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8288bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8298bfffbccSCorey Minyard 8308bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 8318bfffbccSCorey Minyard case 0: /* power down */ 8326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 8338bfffbccSCorey Minyard break; 8348bfffbccSCorey Minyard case 1: /* power up */ 8356acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 8368bfffbccSCorey Minyard break; 8378bfffbccSCorey Minyard case 2: /* power cycle */ 8386acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 8398bfffbccSCorey Minyard break; 8408bfffbccSCorey Minyard case 3: /* hard reset */ 8416acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 8428bfffbccSCorey Minyard break; 8438bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 8446acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 8458bfffbccSCorey Minyard break; 8468bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 8476acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 8486acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 8498bfffbccSCorey Minyard break; 8508bfffbccSCorey Minyard default: 8516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 8528bfffbccSCorey Minyard return; 8538bfffbccSCorey Minyard } 854d13ada5dSCédric Le Goater } 8558bfffbccSCorey Minyard 856b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 857b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 858a580d820SCédric Le Goater RspBuffer *rsp) 859a580d820SCédric Le Goater 860b7088392SCédric Le Goater { 861a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 862a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 863b7088392SCédric Le Goater } 864b7088392SCédric Le Goater 8658bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8668bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 867a580d820SCédric Le Goater RspBuffer *rsp) 8688bfffbccSCorey Minyard { 869a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 870a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 871a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 872a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 873a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 874a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 87520b23364SCorey Minyard rsp_buffer_push(rsp, ibs->mfg_id & 0xff); 87620b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff); 87720b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff); 87820b23364SCorey Minyard rsp_buffer_push(rsp, ibs->product_id & 0xff); 87920b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff); 8808bfffbccSCorey Minyard } 8818bfffbccSCorey Minyard 8828bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8838bfffbccSCorey Minyard { 8848bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8858bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8868bfffbccSCorey Minyard bool irqs_on; 8878bfffbccSCorey Minyard 8888bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8898bfffbccSCorey Minyard 8908bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8918bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8928bfffbccSCorey Minyard 8938bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8948bfffbccSCorey Minyard } 8958bfffbccSCorey Minyard 8968bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8978bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 898a580d820SCédric Le Goater RspBuffer *rsp) 8998bfffbccSCorey Minyard { 9008bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9018bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9028bfffbccSCorey Minyard 9038bfffbccSCorey Minyard /* Disable all interrupts */ 9048bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 9058bfffbccSCorey Minyard 9068bfffbccSCorey Minyard if (k->reset) { 9078bfffbccSCorey Minyard k->reset(s, true); 9088bfffbccSCorey Minyard } 9098bfffbccSCorey Minyard } 9108bfffbccSCorey Minyard 9118bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 9128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 913a580d820SCédric Le Goater RspBuffer *rsp) 9148bfffbccSCorey Minyard { 9158bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9168bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9178bfffbccSCorey Minyard 9188bfffbccSCorey Minyard if (k->reset) { 9198bfffbccSCorey Minyard k->reset(s, false); 9208bfffbccSCorey Minyard } 9218bfffbccSCorey Minyard } 92252ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 92352ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 924a580d820SCédric Le Goater RspBuffer *rsp) 92552ba4d50SCédric Le Goater { 92652ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 92752ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 92852ba4d50SCédric Le Goater } 92952ba4d50SCédric Le Goater 93052ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 93152ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 932a580d820SCédric Le Goater RspBuffer *rsp) 93352ba4d50SCédric Le Goater { 934a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 935a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 93652ba4d50SCédric Le Goater } 93752ba4d50SCédric Le Goater 93852ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 93952ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 940a580d820SCédric Le Goater RspBuffer *rsp) 94152ba4d50SCédric Le Goater { 94252ba4d50SCédric Le Goater unsigned int i; 94352ba4d50SCédric Le Goater 944*7b0cd78bSCorey Minyard /* An uninitialized uuid is all zeros, use that to know if it is set. */ 94552ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 946*7b0cd78bSCorey Minyard if (ibs->uuid.data[i]) { 947*7b0cd78bSCorey Minyard goto uuid_set; 948*7b0cd78bSCorey Minyard } 949*7b0cd78bSCorey Minyard } 950*7b0cd78bSCorey Minyard /* No uuid is set, return an error. */ 951*7b0cd78bSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD); 952*7b0cd78bSCorey Minyard return; 953*7b0cd78bSCorey Minyard 954*7b0cd78bSCorey Minyard uuid_set: 955*7b0cd78bSCorey Minyard for (i = 0; i < 16; i++) { 956*7b0cd78bSCorey Minyard rsp_buffer_push(rsp, ibs->uuid.data[i]); 95752ba4d50SCédric Le Goater } 95852ba4d50SCédric Le Goater } 9598bfffbccSCorey Minyard 9608bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 9618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 962a580d820SCédric Le Goater RspBuffer *rsp) 9638bfffbccSCorey Minyard { 9648bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 9658bfffbccSCorey Minyard } 9668bfffbccSCorey Minyard 9678bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 9688bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 969a580d820SCédric Le Goater RspBuffer *rsp) 9708bfffbccSCorey Minyard { 971a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 9728bfffbccSCorey Minyard } 9738bfffbccSCorey Minyard 9748bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 976a580d820SCédric Le Goater RspBuffer *rsp) 9778bfffbccSCorey Minyard { 9788bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9798bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9808bfffbccSCorey Minyard 9818bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9828bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9838bfffbccSCorey Minyard } 9848bfffbccSCorey Minyard 9858bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9868bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 987a580d820SCédric Le Goater RspBuffer *rsp) 9888bfffbccSCorey Minyard { 989a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9908bfffbccSCorey Minyard } 9918bfffbccSCorey Minyard 9928bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9938bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 994a580d820SCédric Le Goater RspBuffer *rsp) 9958bfffbccSCorey Minyard { 9968bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9978bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9988bfffbccSCorey Minyard unsigned int i; 9998bfffbccSCorey Minyard 10008bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 10016acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1002d13ada5dSCédric Le Goater return; 10038bfffbccSCorey Minyard } 10048bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 1005a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 10068bfffbccSCorey Minyard } 10078bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 10088bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 10098bfffbccSCorey Minyard } 10108bfffbccSCorey Minyard 10118bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 10128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1013a580d820SCédric Le Goater RspBuffer *rsp) 10148bfffbccSCorey Minyard { 10158bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 10168bfffbccSCorey Minyard 10178bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 10186acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 10198bfffbccSCorey Minyard goto out; 10208bfffbccSCorey Minyard } 1021a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 10228bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 1023a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 10248bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 10258bfffbccSCorey Minyard g_free(msg); 10268bfffbccSCorey Minyard 10278bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 10288bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10298bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10308bfffbccSCorey Minyard 10318bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10328bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 10338bfffbccSCorey Minyard } 10348bfffbccSCorey Minyard 10358bfffbccSCorey Minyard out: 10368bfffbccSCorey Minyard return; 10378bfffbccSCorey Minyard } 10388bfffbccSCorey Minyard 10398bfffbccSCorey Minyard static unsigned char 10408bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 10418bfffbccSCorey Minyard { 10428bfffbccSCorey Minyard for (; size > 0; size--, data++) { 10438bfffbccSCorey Minyard csum += *data; 10448bfffbccSCorey Minyard } 10458bfffbccSCorey Minyard 10468bfffbccSCorey Minyard return -csum; 10478bfffbccSCorey Minyard } 10488bfffbccSCorey Minyard 10498bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 10508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1051a580d820SCédric Le Goater RspBuffer *rsp) 10528bfffbccSCorey Minyard { 10538bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10548bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10558bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 10568bfffbccSCorey Minyard uint8_t *buf; 10578bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 10588bfffbccSCorey Minyard 10598bfffbccSCorey Minyard if (cmd[2] != 0) { 10608bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 10616acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1062d13ada5dSCédric Le Goater return; 10638bfffbccSCorey Minyard } 10648bfffbccSCorey Minyard 10654f298a4bSCédric Le Goater if (cmd_len < 10) { 10666acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 10674f298a4bSCédric Le Goater return; 10684f298a4bSCédric Le Goater } 10694f298a4bSCédric Le Goater 10708bfffbccSCorey Minyard if (cmd[3] != 0x40) { 10718bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 10726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1073d13ada5dSCédric Le Goater return; 10748bfffbccSCorey Minyard } 10758bfffbccSCorey Minyard 10768bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10778bfffbccSCorey Minyard cmd_len -= 3; 10788bfffbccSCorey Minyard 10798bfffbccSCorey Minyard /* 10808bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10818bfffbccSCorey Minyard * be returned in the response. 10828bfffbccSCorey Minyard */ 10838bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10848bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1085d13ada5dSCédric Le Goater return; /* No response */ 10868bfffbccSCorey Minyard } 10878bfffbccSCorey Minyard 10888bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10898bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10908bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10918bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10928bfffbccSCorey Minyard 10938bfffbccSCorey Minyard if (rqLun != 2) { 10948bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1095d13ada5dSCédric Le Goater return; 10968bfffbccSCorey Minyard } 10978bfffbccSCorey Minyard 10988bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10998bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 11008bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 11018bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 11028bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 11038bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 11048bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 11058bfffbccSCorey Minyard msg->len = 6; 11068bfffbccSCorey Minyard 11078bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 11088bfffbccSCorey Minyard /* Not a command we handle. */ 11098bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 11108bfffbccSCorey Minyard goto end_msg; 11118bfffbccSCorey Minyard } 11128bfffbccSCorey Minyard 11138bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 11148bfffbccSCorey Minyard buf[0] = 0; 11158bfffbccSCorey Minyard buf[1] = 0; 11168bfffbccSCorey Minyard buf[2] = 0; 11178bfffbccSCorey Minyard buf[3] = 0; 11188bfffbccSCorey Minyard buf[4] = 0x51; 11198bfffbccSCorey Minyard buf[5] = 0; 11208bfffbccSCorey Minyard buf[6] = 0; 11218bfffbccSCorey Minyard buf[7] = 0; 11228bfffbccSCorey Minyard buf[8] = 0; 11238bfffbccSCorey Minyard buf[9] = 0; 11248bfffbccSCorey Minyard buf[10] = 0; 11258bfffbccSCorey Minyard msg->len += 11; 11268bfffbccSCorey Minyard 11278bfffbccSCorey Minyard end_msg: 11288bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 11298bfffbccSCorey Minyard msg->len++; 11308bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 11318bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 11328bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 11338bfffbccSCorey Minyard } 11348bfffbccSCorey Minyard 11358bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 11368bfffbccSCorey Minyard { 11378bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 11388bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 11398bfffbccSCorey Minyard ibs->watchdog_running = 0; 11408bfffbccSCorey Minyard return; 11418bfffbccSCorey Minyard } 11428bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 11438bfffbccSCorey Minyard 11448bfffbccSCorey Minyard 11458bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 11468bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 11478bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 11488bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 11498bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 11508bfffbccSCorey Minyard } 11518bfffbccSCorey Minyard ibs->watchdog_running = 1; 11528bfffbccSCorey Minyard } 11538bfffbccSCorey Minyard 11548bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 11558bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1156a580d820SCédric Le Goater RspBuffer *rsp) 11578bfffbccSCorey Minyard { 11588bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 11596acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1160d13ada5dSCédric Le Goater return; 11618bfffbccSCorey Minyard } 11628bfffbccSCorey Minyard do_watchdog_reset(ibs); 11638bfffbccSCorey Minyard } 11648bfffbccSCorey Minyard 11658bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 11668bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1167a580d820SCédric Le Goater RspBuffer *rsp) 11688bfffbccSCorey Minyard { 11698bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 11708bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 11718bfffbccSCorey Minyard unsigned int val; 11728bfffbccSCorey Minyard 11738bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11748bfffbccSCorey Minyard if (val == 0 || val > 5) { 11756acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1176d13ada5dSCédric Le Goater return; 11778bfffbccSCorey Minyard } 11788bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11798bfffbccSCorey Minyard switch (val) { 11808bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11818bfffbccSCorey Minyard break; 11828bfffbccSCorey Minyard 11838bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11858bfffbccSCorey Minyard break; 11868bfffbccSCorey Minyard 11878bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11898bfffbccSCorey Minyard break; 11908bfffbccSCorey Minyard 11918bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11926acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11938bfffbccSCorey Minyard break; 11948bfffbccSCorey Minyard 11958bfffbccSCorey Minyard default: 11966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11978bfffbccSCorey Minyard } 1198a580d820SCédric Le Goater if (rsp->buffer[2]) { 11996acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1200d13ada5dSCédric Le Goater return; 12018bfffbccSCorey Minyard } 12028bfffbccSCorey Minyard 12038bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 12048bfffbccSCorey Minyard switch (val) { 12058bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 12068bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 12078bfffbccSCorey Minyard break; 12088bfffbccSCorey Minyard 12098bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 12106af94767SCorey Minyard if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 12118bfffbccSCorey Minyard /* NMI not supported. */ 12126acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1213d13ada5dSCédric Le Goater return; 12148bfffbccSCorey Minyard } 121537eebb86SCorey Minyard break; 121637eebb86SCorey Minyard 12178bfffbccSCorey Minyard default: 12188bfffbccSCorey Minyard /* We don't support PRE_SMI */ 12196acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1220d13ada5dSCédric Le Goater return; 12218bfffbccSCorey Minyard } 12228bfffbccSCorey Minyard 12238bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 12248bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 12258bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 12268bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 12278bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 12288bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 12298bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 12308bfffbccSCorey Minyard do_watchdog_reset(ibs); 12318bfffbccSCorey Minyard } else { 12328bfffbccSCorey Minyard ibs->watchdog_running = 0; 12338bfffbccSCorey Minyard } 12348bfffbccSCorey Minyard } 12358bfffbccSCorey Minyard 12368bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 12378bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1238a580d820SCédric Le Goater RspBuffer *rsp) 12398bfffbccSCorey Minyard { 1240a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1241a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1242a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1243a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 1244fb45770bSCorey Minyard rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff); 1245fb45770bSCorey Minyard rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff); 12468bfffbccSCorey Minyard if (ibs->watchdog_running) { 12478bfffbccSCorey Minyard long timeout; 12488bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 12498bfffbccSCorey Minyard / 100000000); 1250a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1251a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 12528bfffbccSCorey Minyard } else { 1253a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1254a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 12558bfffbccSCorey Minyard } 12568bfffbccSCorey Minyard } 12578bfffbccSCorey Minyard 12588bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 12598bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1260a580d820SCédric Le Goater RspBuffer *rsp) 12618bfffbccSCorey Minyard { 12628bfffbccSCorey Minyard unsigned int i; 12638bfffbccSCorey Minyard 1264a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1265a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1266a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1267a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1268a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 12698bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1270a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 12718bfffbccSCorey Minyard } 12728bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1273a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 12748bfffbccSCorey Minyard } 12758bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1276a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 12778bfffbccSCorey Minyard } 12788bfffbccSCorey Minyard 12798bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12808bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1281a580d820SCédric Le Goater RspBuffer *rsp) 12828bfffbccSCorey Minyard { 1283a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1284a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 12858bfffbccSCorey Minyard } 12868bfffbccSCorey Minyard 12878bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1289a580d820SCédric Le Goater RspBuffer *rsp) 12908bfffbccSCorey Minyard { 12918bfffbccSCorey Minyard unsigned int pos; 12928bfffbccSCorey Minyard uint16_t nextrec; 1293a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12948bfffbccSCorey Minyard 12958bfffbccSCorey Minyard if (cmd[6]) { 12967f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12987f996411SCédric Le Goater return; 12998bfffbccSCorey Minyard } 13007f996411SCédric Le Goater } 13017f996411SCédric Le Goater 13028bfffbccSCorey Minyard pos = 0; 13038bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 13048bfffbccSCorey Minyard &pos, &nextrec)) { 13056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1306d13ada5dSCédric Le Goater return; 13078bfffbccSCorey Minyard } 1308a2295f0aSCédric Le Goater 1309a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1310a2295f0aSCédric Le Goater 1311a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 13126acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1313d13ada5dSCédric Le Goater return; 13148bfffbccSCorey Minyard } 13158bfffbccSCorey Minyard 1316a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1317a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 13188bfffbccSCorey Minyard 13198bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1320a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 13218bfffbccSCorey Minyard } 13228bfffbccSCorey Minyard 1323a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 13246acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1325d13ada5dSCédric Le Goater return; 13268bfffbccSCorey Minyard } 1327a580d820SCédric Le Goater 1328a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 13298bfffbccSCorey Minyard } 13308bfffbccSCorey Minyard 13318bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 13328bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1333a580d820SCédric Le Goater RspBuffer *rsp) 13348bfffbccSCorey Minyard { 13358bfffbccSCorey Minyard uint16_t recid; 1336a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 13378bfffbccSCorey Minyard 1338a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 13396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1340d13ada5dSCédric Le Goater return; 13418bfffbccSCorey Minyard } 1342a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1343a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 13448bfffbccSCorey Minyard } 13458bfffbccSCorey Minyard 13468bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 13478bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1348a580d820SCédric Le Goater RspBuffer *rsp) 13498bfffbccSCorey Minyard { 13507f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13527f996411SCédric Le Goater return; 13537f996411SCédric Le Goater } 13547f996411SCédric Le Goater 13558bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13566acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1357d13ada5dSCédric Le Goater return; 13588bfffbccSCorey Minyard } 13598bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13608bfffbccSCorey Minyard ibs->sdr.next_free = 0; 13618bfffbccSCorey Minyard ibs->sdr.overflow = 0; 13628bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1363a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13648bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 13658bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1366a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13678bfffbccSCorey Minyard } else { 13686acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 13698bfffbccSCorey Minyard return; 13708bfffbccSCorey Minyard } 1371d13ada5dSCédric Le Goater } 13728bfffbccSCorey Minyard 13738bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 13748bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1375a580d820SCédric Le Goater RspBuffer *rsp) 13768bfffbccSCorey Minyard { 13778bfffbccSCorey Minyard unsigned int i, val; 13788bfffbccSCorey Minyard 1379a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1380a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1381a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 13828bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1383a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1384a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 13858bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1386a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 13878bfffbccSCorey Minyard } 13888bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1389a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 13908bfffbccSCorey Minyard } 13918bfffbccSCorey Minyard /* Only support Reserve SEL */ 1392a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 13938bfffbccSCorey Minyard } 13948bfffbccSCorey Minyard 1395540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs, 1396540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1397540c07d3SCédric Le Goater RspBuffer *rsp) 1398540c07d3SCédric Le Goater { 1399540c07d3SCédric Le Goater uint8_t fruid; 1400540c07d3SCédric Le Goater uint16_t fru_entry_size; 1401540c07d3SCédric Le Goater 1402540c07d3SCédric Le Goater fruid = cmd[2]; 1403540c07d3SCédric Le Goater 1404540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1405540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1406540c07d3SCédric Le Goater return; 1407540c07d3SCédric Le Goater } 1408540c07d3SCédric Le Goater 1409540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize; 1410540c07d3SCédric Le Goater 1411540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff); 1412540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff); 1413540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0); 1414540c07d3SCédric Le Goater } 1415540c07d3SCédric Le Goater 1416540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs, 1417540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1418540c07d3SCédric Le Goater RspBuffer *rsp) 1419540c07d3SCédric Le Goater { 1420540c07d3SCédric Le Goater uint8_t fruid; 1421540c07d3SCédric Le Goater uint16_t offset; 1422540c07d3SCédric Le Goater int i; 1423540c07d3SCédric Le Goater uint8_t *fru_entry; 1424540c07d3SCédric Le Goater unsigned int count; 1425540c07d3SCédric Le Goater 1426540c07d3SCédric Le Goater fruid = cmd[2]; 1427540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1428540c07d3SCédric Le Goater 1429540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1430540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1431540c07d3SCédric Le Goater return; 1432540c07d3SCédric Le Goater } 1433540c07d3SCédric Le Goater 1434540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1435540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1436540c07d3SCédric Le Goater return; 1437540c07d3SCédric Le Goater } 1438540c07d3SCédric Le Goater 1439540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1440540c07d3SCédric Le Goater 1441540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset); 1442540c07d3SCédric Le Goater 1443540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1444540c07d3SCédric Le Goater for (i = 0; i < count; i++) { 1445540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]); 1446540c07d3SCédric Le Goater } 1447540c07d3SCédric Le Goater } 1448540c07d3SCédric Le Goater 1449540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs, 1450540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1451540c07d3SCédric Le Goater RspBuffer *rsp) 1452540c07d3SCédric Le Goater { 1453540c07d3SCédric Le Goater uint8_t fruid; 1454540c07d3SCédric Le Goater uint16_t offset; 1455540c07d3SCédric Le Goater uint8_t *fru_entry; 1456540c07d3SCédric Le Goater unsigned int count; 1457540c07d3SCédric Le Goater 1458540c07d3SCédric Le Goater fruid = cmd[2]; 1459540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1460540c07d3SCédric Le Goater 1461540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1462540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1463540c07d3SCédric Le Goater return; 1464540c07d3SCédric Le Goater } 1465540c07d3SCédric Le Goater 1466540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1467540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1468540c07d3SCédric Le Goater return; 1469540c07d3SCédric Le Goater } 1470540c07d3SCédric Le Goater 1471540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1472540c07d3SCédric Le Goater 1473540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset); 1474540c07d3SCédric Le Goater 1475540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count); 1476540c07d3SCédric Le Goater 1477540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1478540c07d3SCédric Le Goater } 1479540c07d3SCédric Le Goater 14808bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 14818bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1482a580d820SCédric Le Goater RspBuffer *rsp) 14838bfffbccSCorey Minyard { 1484a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1485a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 14868bfffbccSCorey Minyard } 14878bfffbccSCorey Minyard 14888bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 14898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1490a580d820SCédric Le Goater RspBuffer *rsp) 14918bfffbccSCorey Minyard { 14928bfffbccSCorey Minyard unsigned int val; 14938bfffbccSCorey Minyard 14948bfffbccSCorey Minyard if (cmd[6]) { 14957f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 14966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 14977f996411SCédric Le Goater return; 14987f996411SCédric Le Goater } 14998bfffbccSCorey Minyard } 15008bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 15016acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1502d13ada5dSCédric Le Goater return; 15038bfffbccSCorey Minyard } 15048bfffbccSCorey Minyard if (cmd[6] > 15) { 15056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1506d13ada5dSCédric Le Goater return; 15078bfffbccSCorey Minyard } 15088bfffbccSCorey Minyard if (cmd[7] == 0xff) { 15098bfffbccSCorey Minyard cmd[7] = 16; 15108bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 15116acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1512d13ada5dSCédric Le Goater return; 15138bfffbccSCorey Minyard } else { 15148bfffbccSCorey Minyard cmd[7] += cmd[6]; 15158bfffbccSCorey Minyard } 15168bfffbccSCorey Minyard 15178bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 15188bfffbccSCorey Minyard if (val == 0xffff) { 15198bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 15208bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 15216acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1522d13ada5dSCédric Le Goater return; 15238bfffbccSCorey Minyard } 15248bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1525a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1526a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 15278bfffbccSCorey Minyard } else { 1528a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1529a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 15308bfffbccSCorey Minyard } 15318bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1532a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 15338bfffbccSCorey Minyard } 15348bfffbccSCorey Minyard } 15358bfffbccSCorey Minyard 15368bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 15378bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1538a580d820SCédric Le Goater RspBuffer *rsp) 15398bfffbccSCorey Minyard { 15408bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 15416acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1542d13ada5dSCédric Le Goater return; 15438bfffbccSCorey Minyard } 15448bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1545a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1546a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 15478bfffbccSCorey Minyard } 15488bfffbccSCorey Minyard 15498bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 15508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1551a580d820SCédric Le Goater RspBuffer *rsp) 15528bfffbccSCorey Minyard { 15537f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15546acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15557f996411SCédric Le Goater return; 15567f996411SCédric Le Goater } 15577f996411SCédric Le Goater 15588bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 15596acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1560d13ada5dSCédric Le Goater return; 15618bfffbccSCorey Minyard } 15628bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 15638bfffbccSCorey Minyard ibs->sel.next_free = 0; 15648bfffbccSCorey Minyard ibs->sel.overflow = 0; 15658bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1566a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15678bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 15688bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1569a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15708bfffbccSCorey Minyard } else { 15716acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 15728bfffbccSCorey Minyard return; 15738bfffbccSCorey Minyard } 1574d13ada5dSCédric Le Goater } 15758bfffbccSCorey Minyard 15768bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 15778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1578a580d820SCédric Le Goater RspBuffer *rsp) 15798bfffbccSCorey Minyard { 15808bfffbccSCorey Minyard uint32_t val; 15818bfffbccSCorey Minyard struct ipmi_time now; 15828bfffbccSCorey Minyard 15838bfffbccSCorey Minyard ipmi_gettime(&now); 15848bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1585a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1586a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1587a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1588a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 15898bfffbccSCorey Minyard } 15908bfffbccSCorey Minyard 15918bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 15928bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1593a580d820SCédric Le Goater RspBuffer *rsp) 15948bfffbccSCorey Minyard { 15958bfffbccSCorey Minyard uint32_t val; 15968bfffbccSCorey Minyard struct ipmi_time now; 15978bfffbccSCorey Minyard 15988bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 15998bfffbccSCorey Minyard ipmi_gettime(&now); 16008bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 16018bfffbccSCorey Minyard } 16028bfffbccSCorey Minyard 16039380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs, 16049380d2edSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 16059380d2edSCorey Minyard RspBuffer *rsp) 16069380d2edSCorey Minyard { 16079380d2edSCorey Minyard uint8_t event[16]; 16089380d2edSCorey Minyard 16099380d2edSCorey Minyard event[2] = 2; /* System event record */ 16109380d2edSCorey Minyard event[7] = cmd[2]; /* Generator ID */ 16119380d2edSCorey Minyard event[8] = 0; 16129380d2edSCorey Minyard event[9] = cmd[3]; /* EvMRev */ 16139380d2edSCorey Minyard event[10] = cmd[4]; /* Sensor type */ 16149380d2edSCorey Minyard event[11] = cmd[5]; /* Sensor number */ 16159380d2edSCorey Minyard event[12] = cmd[6]; /* Event dir / Event type */ 16169380d2edSCorey Minyard event[13] = cmd[7]; /* Event data 1 */ 16179380d2edSCorey Minyard event[14] = cmd[8]; /* Event data 2 */ 16189380d2edSCorey Minyard event[15] = cmd[9]; /* Event data 3 */ 16199380d2edSCorey Minyard 16209380d2edSCorey Minyard if (sel_add_event(ibs, event)) { 16219380d2edSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 16229380d2edSCorey Minyard } 16239380d2edSCorey Minyard } 16249380d2edSCorey Minyard 16258bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 16268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1627a580d820SCédric Le Goater RspBuffer *rsp) 16288bfffbccSCorey Minyard { 16298bfffbccSCorey Minyard IPMISensor *sens; 16308bfffbccSCorey Minyard 163173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16328bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16336acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1634d13ada5dSCédric Le Goater return; 16358bfffbccSCorey Minyard } 16368bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 16378bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 16388bfffbccSCorey Minyard case 0: /* Do not change */ 16398bfffbccSCorey Minyard break; 16408bfffbccSCorey Minyard case 1: /* Enable bits */ 16418bfffbccSCorey Minyard if (cmd_len > 4) { 16428bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 16438bfffbccSCorey Minyard } 16448bfffbccSCorey Minyard if (cmd_len > 5) { 16458bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 16468bfffbccSCorey Minyard } 16478bfffbccSCorey Minyard if (cmd_len > 6) { 16488bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 16498bfffbccSCorey Minyard } 16508bfffbccSCorey Minyard if (cmd_len > 7) { 16518bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 16528bfffbccSCorey Minyard } 16538bfffbccSCorey Minyard break; 16548bfffbccSCorey Minyard case 2: /* Disable bits */ 16558bfffbccSCorey Minyard if (cmd_len > 4) { 16568bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 16578bfffbccSCorey Minyard } 16588bfffbccSCorey Minyard if (cmd_len > 5) { 16598bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 16608bfffbccSCorey Minyard } 16618bfffbccSCorey Minyard if (cmd_len > 6) { 16628bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 16638bfffbccSCorey Minyard } 16648bfffbccSCorey Minyard if (cmd_len > 7) { 16658bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 16668bfffbccSCorey Minyard } 16678bfffbccSCorey Minyard break; 16688bfffbccSCorey Minyard case 3: 16696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1670d13ada5dSCédric Le Goater return; 16718bfffbccSCorey Minyard } 16728bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 16738bfffbccSCorey Minyard } 16748bfffbccSCorey Minyard 16758bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 16768bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1677a580d820SCédric Le Goater RspBuffer *rsp) 16788bfffbccSCorey Minyard { 16798bfffbccSCorey Minyard IPMISensor *sens; 16808bfffbccSCorey Minyard 168173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16828bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16836acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1684d13ada5dSCédric Le Goater return; 16858bfffbccSCorey Minyard } 16868bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1687a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1688a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1689a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1690a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1691a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 16928bfffbccSCorey Minyard } 16938bfffbccSCorey Minyard 16948bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 16958bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1696a580d820SCédric Le Goater RspBuffer *rsp) 16978bfffbccSCorey Minyard { 16988bfffbccSCorey Minyard IPMISensor *sens; 16998bfffbccSCorey Minyard 170073d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17018bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17026acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1703d13ada5dSCédric Le Goater return; 17048bfffbccSCorey Minyard } 17058bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 17068bfffbccSCorey Minyard 17078bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 17088bfffbccSCorey Minyard /* Just clear everything */ 17098bfffbccSCorey Minyard sens->states = 0; 17108bfffbccSCorey Minyard return; 17118bfffbccSCorey Minyard } 1712d13ada5dSCédric Le Goater } 17138bfffbccSCorey Minyard 17148bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 17158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1716a580d820SCédric Le Goater RspBuffer *rsp) 17178bfffbccSCorey Minyard { 17188bfffbccSCorey Minyard IPMISensor *sens; 17198bfffbccSCorey Minyard 172073d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17218bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17226acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1723d13ada5dSCédric Le Goater return; 17248bfffbccSCorey Minyard } 17258bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1726a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1727a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1728a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1729a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1730a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1731a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 17328bfffbccSCorey Minyard } 17338bfffbccSCorey Minyard 17348bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 17358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1736a580d820SCédric Le Goater RspBuffer *rsp) 17378bfffbccSCorey Minyard { 17388bfffbccSCorey Minyard IPMISensor *sens; 17398bfffbccSCorey Minyard 174073d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17418bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17426acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1743d13ada5dSCédric Le Goater return; 17448bfffbccSCorey Minyard } 17458bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1746a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1747a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1748a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 17498bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1750a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 17518bfffbccSCorey Minyard } 17528bfffbccSCorey Minyard } 17538bfffbccSCorey Minyard 1754728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1755728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1756a580d820SCédric Le Goater RspBuffer *rsp) 1757728710e1SCédric Le Goater { 1758728710e1SCédric Le Goater IPMISensor *sens; 1759728710e1SCédric Le Goater 1760728710e1SCédric Le Goater 176173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1762728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17636acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1764728710e1SCédric Le Goater return; 1765728710e1SCédric Le Goater } 1766728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1767728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1768728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1769728710e1SCédric Le Goater } 1770728710e1SCédric Le Goater 1771728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1772728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1773a580d820SCédric Le Goater RspBuffer *rsp) 1774728710e1SCédric Le Goater { 1775728710e1SCédric Le Goater IPMISensor *sens; 1776728710e1SCédric Le Goater 1777728710e1SCédric Le Goater 177873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1779728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17806acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1781728710e1SCédric Le Goater return; 1782728710e1SCédric Le Goater } 1783728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1784a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1785a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1786728710e1SCédric Le Goater } 1787728710e1SCédric Le Goater 1788728710e1SCédric Le Goater 178962a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 17904f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 17914f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 17924f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 17934f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 17948bfffbccSCorey Minyard }; 17958bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 179662a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 17978bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 17988bfffbccSCorey Minyard }; 17998bfffbccSCorey Minyard 180062a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 18019380d2edSCorey Minyard [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 }, 18024f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 18034f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 18044f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 18054f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 18064f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 18074f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 18084f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 18098bfffbccSCorey Minyard }; 18108bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 181162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 18128bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 18138bfffbccSCorey Minyard }; 18148bfffbccSCorey Minyard 181562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 18164f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 18174f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 18184f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 18194f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 18204f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 18214f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 18224f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 18234f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 18244f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 18254f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 18264f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 18274f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 18284f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 18294f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 18304f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 18314f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 18328bfffbccSCorey Minyard }; 18338bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 183462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 18358bfffbccSCorey Minyard .cmd_handlers = app_cmds 18368bfffbccSCorey Minyard }; 18378bfffbccSCorey Minyard 183862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 1839540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 }, 1840540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 }, 1841540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 }, 18424f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 18434f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 18444f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 18454f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 18464f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 18474f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 18484f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 18494f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 18504f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 18514f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 18527f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time }, 18537f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 }, 18548bfffbccSCorey Minyard }; 18558bfffbccSCorey Minyard 18568bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 185762a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 18588bfffbccSCorey Minyard .cmd_handlers = storage_cmds 18598bfffbccSCorey Minyard }; 18608bfffbccSCorey Minyard 18618bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 18628bfffbccSCorey Minyard { 18638bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 18648bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 18658bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 18668bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 18678bfffbccSCorey Minyard } 18688bfffbccSCorey Minyard 18695167560bSCédric Le Goater static uint8_t init_sdrs[] = { 18708bfffbccSCorey Minyard /* Watchdog device */ 18718bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 18728bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 18738bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18748bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 18758bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 18768bfffbccSCorey Minyard }; 18778bfffbccSCorey Minyard 18784fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 18794fa9f08eSCédric Le Goater { 18804fa9f08eSCédric Le Goater unsigned int i; 18814fa9f08eSCédric Le Goater int len; 18825167560bSCédric Le Goater size_t sdrs_size; 18835167560bSCédric Le Goater uint8_t *sdrs; 188452fc01d9SCédric Le Goater 18855167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs); 18865167560bSCédric Le Goater sdrs = init_sdrs; 18878c6fd7f3SCédric Le Goater if (ibs->sdr_filename && 18888c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size, 18898c6fd7f3SCédric Le Goater NULL)) { 18908c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename); 18918c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs); 18928c6fd7f3SCédric Le Goater sdrs = init_sdrs; 18938c6fd7f3SCédric Le Goater } 18945167560bSCédric Le Goater 18955167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) { 189652fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh; 189752fc01d9SCédric Le Goater 18985167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) { 18994fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 19008c6fd7f3SCédric Le Goater break; 19014fa9f08eSCédric Le Goater } 19025167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i]; 19034fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 19045167560bSCédric Le Goater if (i + len > sdrs_size) { 19054fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 19068c6fd7f3SCédric Le Goater break; 19074fa9f08eSCédric Le Goater } 19084fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 19094fa9f08eSCédric Le Goater } 19108c6fd7f3SCédric Le Goater 19118c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) { 19128c6fd7f3SCédric Le Goater g_free(sdrs); 19138c6fd7f3SCédric Le Goater } 19144fa9f08eSCédric Le Goater } 19154fa9f08eSCédric Le Goater 1916bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1917bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1918bd66bcfcSCorey Minyard .version_id = 1, 1919bd66bcfcSCorey Minyard .minimum_version_id = 1, 1920bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1921bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1922bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1923bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1924bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1925bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1926bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1927bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1928bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1929bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1930bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1931bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1932bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1933bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1934bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1935bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1936bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1937bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1938bd66bcfcSCorey Minyard IPMIBmcSim), 1939bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1940bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1941bd66bcfcSCorey Minyard } 1942bd66bcfcSCorey Minyard }; 1943bd66bcfcSCorey Minyard 1944540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru) 1945540c07d3SCédric Le Goater { 1946540c07d3SCédric Le Goater int fsize; 1947540c07d3SCédric Le Goater int size = 0; 1948540c07d3SCédric Le Goater 1949540c07d3SCédric Le Goater if (!fru->filename) { 1950540c07d3SCédric Le Goater goto out; 1951540c07d3SCédric Le Goater } 1952540c07d3SCédric Le Goater 1953540c07d3SCédric Le Goater fsize = get_image_size(fru->filename); 1954540c07d3SCédric Le Goater if (fsize > 0) { 1955540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize); 1956540c07d3SCédric Le Goater fru->data = g_malloc0(size); 1957540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) { 1958540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename); 1959540c07d3SCédric Le Goater g_free(fru->data); 1960540c07d3SCédric Le Goater fru->data = NULL; 1961540c07d3SCédric Le Goater } 1962540c07d3SCédric Le Goater } 1963540c07d3SCédric Le Goater 1964540c07d3SCédric Le Goater out: 1965540c07d3SCédric Le Goater if (!fru->data) { 1966540c07d3SCédric Le Goater /* give one default FRU */ 1967540c07d3SCédric Le Goater size = fru->areasize; 1968540c07d3SCédric Le Goater fru->data = g_malloc0(size); 1969540c07d3SCédric Le Goater } 1970540c07d3SCédric Le Goater 1971540c07d3SCédric Le Goater fru->nentries = size / fru->areasize; 1972540c07d3SCédric Le Goater } 1973540c07d3SCédric Le Goater 19740bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 19758bfffbccSCorey Minyard { 19760bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 19778bfffbccSCorey Minyard unsigned int i; 19788bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 19798bfffbccSCorey Minyard 19808bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 19818bfffbccSCorey Minyard 19828bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 19838bfffbccSCorey Minyard ibs->device_id = 0x20; 19848bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1985b7088392SCédric Le Goater ibs->restart_cause = 0; 19868bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 19878bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 19888bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 19898bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 19908bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 19918bfffbccSCorey Minyard } 19928bfffbccSCorey Minyard 19934fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 19948bfffbccSCorey Minyard 1995540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru); 1996540c07d3SCédric Le Goater 199752ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 199852ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 199952ba4d50SCédric Le Goater 20008bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 20018bfffbccSCorey Minyard register_cmds(ibs); 20028bfffbccSCorey Minyard 20038bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 2004bd66bcfcSCorey Minyard 2005bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 20068bfffbccSCorey Minyard } 20078bfffbccSCorey Minyard 20088c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = { 2009540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024), 2010540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename), 20118c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), 201220b23364SCorey Minyard DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20), 201320b23364SCorey Minyard DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02), 201420b23364SCorey Minyard DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0), 201520b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0), 201620b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0), 201720b23364SCorey Minyard DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0), 201820b23364SCorey Minyard DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0), 2019*7b0cd78bSCorey Minyard DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid), 20208c6fd7f3SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 20218c6fd7f3SCédric Le Goater }; 20228c6fd7f3SCédric Le Goater 20238bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 20248bfffbccSCorey Minyard { 20250bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 20268bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 20278bfffbccSCorey Minyard 202866abfddbSCorey Minyard dc->hotpluggable = false; 20290bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 20308c6fd7f3SCédric Le Goater dc->props = ipmi_sim_properties; 20318bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 20328bfffbccSCorey Minyard } 20338bfffbccSCorey Minyard 20348bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 20358bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 20368bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 20378bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 20388bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 20398bfffbccSCorey Minyard }; 20408bfffbccSCorey Minyard 20418bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 20428bfffbccSCorey Minyard { 20438bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 20448bfffbccSCorey Minyard } 20458bfffbccSCorey Minyard 20468bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 2047