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