Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-26-2019' into...
[qemu/ar7.git] / hw / ipmi / ipmi_bmc_sim.c
blob19805365171dc6a7a01dfacbe9d1cf7615c5b63a
1 /*
2 * IPMI BMC emulation
4 * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
25 #include "qemu/osdep.h"
26 #include "sysemu/sysemu.h"
27 #include "qemu/timer.h"
28 #include "hw/ipmi/ipmi.h"
29 #include "qemu/error-report.h"
30 #include "qemu/module.h"
31 #include "hw/loader.h"
33 #define IPMI_NETFN_CHASSIS 0x00
35 #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
36 #define IPMI_CMD_GET_CHASSIS_STATUS 0x01
37 #define IPMI_CMD_CHASSIS_CONTROL 0x02
38 #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
40 #define IPMI_NETFN_SENSOR_EVENT 0x04
42 #define IPMI_CMD_PLATFORM_EVENT_MSG 0x02
43 #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
44 #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
45 #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
46 #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
47 #define IPMI_CMD_GET_SENSOR_READING 0x2d
48 #define IPMI_CMD_SET_SENSOR_TYPE 0x2e
49 #define IPMI_CMD_GET_SENSOR_TYPE 0x2f
51 /* #define IPMI_NETFN_APP 0x06 In ipmi.h */
53 #define IPMI_CMD_GET_DEVICE_ID 0x01
54 #define IPMI_CMD_COLD_RESET 0x02
55 #define IPMI_CMD_WARM_RESET 0x03
56 #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
57 #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
58 #define IPMI_CMD_GET_DEVICE_GUID 0x08
59 #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
60 #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
61 #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
62 #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
63 #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
64 #define IPMI_CMD_CLR_MSG_FLAGS 0x30
65 #define IPMI_CMD_GET_MSG_FLAGS 0x31
66 #define IPMI_CMD_GET_MSG 0x33
67 #define IPMI_CMD_SEND_MSG 0x34
68 #define IPMI_CMD_READ_EVT_MSG_BUF 0x35
70 #define IPMI_NETFN_STORAGE 0x0a
72 #define IPMI_CMD_GET_SDR_REP_INFO 0x20
73 #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
74 #define IPMI_CMD_RESERVE_SDR_REP 0x22
75 #define IPMI_CMD_GET_SDR 0x23
76 #define IPMI_CMD_ADD_SDR 0x24
77 #define IPMI_CMD_PARTIAL_ADD_SDR 0x25
78 #define IPMI_CMD_DELETE_SDR 0x26
79 #define IPMI_CMD_CLEAR_SDR_REP 0x27
80 #define IPMI_CMD_GET_SDR_REP_TIME 0x28
81 #define IPMI_CMD_SET_SDR_REP_TIME 0x29
82 #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
83 #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
84 #define IPMI_CMD_RUN_INIT_AGENT 0x2C
85 #define IPMI_CMD_GET_FRU_AREA_INFO 0x10
86 #define IPMI_CMD_READ_FRU_DATA 0x11
87 #define IPMI_CMD_WRITE_FRU_DATA 0x12
88 #define IPMI_CMD_GET_SEL_INFO 0x40
89 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
90 #define IPMI_CMD_RESERVE_SEL 0x42
91 #define IPMI_CMD_GET_SEL_ENTRY 0x43
92 #define IPMI_CMD_ADD_SEL_ENTRY 0x44
93 #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
94 #define IPMI_CMD_DELETE_SEL_ENTRY 0x46
95 #define IPMI_CMD_CLEAR_SEL 0x47
96 #define IPMI_CMD_GET_SEL_TIME 0x48
97 #define IPMI_CMD_SET_SEL_TIME 0x49
100 /* Same as a timespec struct. */
101 struct ipmi_time {
102 long tv_sec;
103 long tv_nsec;
106 #define MAX_SEL_SIZE 128
108 typedef struct IPMISel {
109 uint8_t sel[MAX_SEL_SIZE][16];
110 unsigned int next_free;
111 long time_offset;
112 uint16_t reservation;
113 uint8_t last_addition[4];
114 uint8_t last_clear[4];
115 uint8_t overflow;
116 } IPMISel;
118 #define MAX_SDR_SIZE 16384
120 typedef struct IPMISdr {
121 uint8_t sdr[MAX_SDR_SIZE];
122 unsigned int next_free;
123 uint16_t next_rec_id;
124 uint16_t reservation;
125 uint8_t last_addition[4];
126 uint8_t last_clear[4];
127 uint8_t overflow;
128 } IPMISdr;
130 typedef struct IPMIFru {
131 char *filename;
132 unsigned int nentries;
133 uint16_t areasize;
134 uint8_t *data;
135 } IPMIFru;
137 typedef struct IPMISensor {
138 uint8_t status;
139 uint8_t reading;
140 uint16_t states_suppt;
141 uint16_t assert_suppt;
142 uint16_t deassert_suppt;
143 uint16_t states;
144 uint16_t assert_states;
145 uint16_t deassert_states;
146 uint16_t assert_enable;
147 uint16_t deassert_enable;
148 uint8_t sensor_type;
149 uint8_t evt_reading_type_code;
150 } IPMISensor;
151 #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
152 #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
153 !!(v))
154 #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
155 #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
156 ((!!(v)) << 6))
157 #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
158 #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
159 ((!!(v)) << 7))
160 #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
161 #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
162 (v & 0xc0))
163 #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
165 #define MAX_SENSORS 20
166 #define IPMI_WATCHDOG_SENSOR 0
168 typedef struct IPMIBmcSim IPMIBmcSim;
169 typedef struct RspBuffer RspBuffer;
171 #define MAX_NETFNS 64
173 typedef struct IPMICmdHandler {
174 void (*cmd_handler)(IPMIBmcSim *s,
175 uint8_t *cmd, unsigned int cmd_len,
176 RspBuffer *rsp);
177 unsigned int cmd_len_min;
178 } IPMICmdHandler;
180 typedef struct IPMINetfn {
181 unsigned int cmd_nums;
182 const IPMICmdHandler *cmd_handlers;
183 } IPMINetfn;
185 typedef struct IPMIRcvBufEntry {
186 QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
187 uint8_t len;
188 uint8_t buf[MAX_IPMI_MSG_SIZE];
189 } IPMIRcvBufEntry;
191 #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
192 #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
193 TYPE_IPMI_BMC_SIMULATOR)
194 struct IPMIBmcSim {
195 IPMIBmc parent;
197 QEMUTimer *timer;
199 uint8_t bmc_global_enables;
200 uint8_t msg_flags;
202 bool watchdog_initialized;
203 uint8_t watchdog_use;
204 uint8_t watchdog_action;
205 uint8_t watchdog_pretimeout; /* In seconds */
206 bool watchdog_expired;
207 uint16_t watchdog_timeout; /* in 100's of milliseconds */
209 bool watchdog_running;
210 bool watchdog_preaction_ran;
211 int64_t watchdog_expiry;
213 uint8_t device_id;
214 uint8_t ipmi_version;
215 uint8_t device_rev;
216 uint8_t fwrev1;
217 uint8_t fwrev2;
218 uint32_t mfg_id;
219 uint16_t product_id;
221 uint8_t restart_cause;
223 uint8_t acpi_power_state[2];
224 uint8_t uuid[16];
226 IPMISel sel;
227 IPMISdr sdr;
228 IPMIFru fru;
229 IPMISensor sensors[MAX_SENSORS];
230 char *sdr_filename;
232 /* Odd netfns are for responses, so we only need the even ones. */
233 const IPMINetfn *netfns[MAX_NETFNS / 2];
235 /* We allow one event in the buffer */
236 uint8_t evtbuf[16];
238 QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
241 #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
242 #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
243 #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
244 #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
245 (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
246 #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
247 (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
248 #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
249 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
251 #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
252 #define IPMI_BMC_EVBUF_FULL_INT_BIT 1
253 #define IPMI_BMC_EVENT_MSG_BUF_BIT 2
254 #define IPMI_BMC_EVENT_LOG_BIT 3
255 #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
256 (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
257 #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
258 (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
259 #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
260 (1 << IPMI_BMC_EVENT_LOG_BIT))
261 #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
262 (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
264 #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
265 #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
266 #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
267 #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
268 #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
269 #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
270 #define IPMI_BMC_WATCHDOG_PRE_NONE 0
271 #define IPMI_BMC_WATCHDOG_PRE_SMI 1
272 #define IPMI_BMC_WATCHDOG_PRE_NMI 2
273 #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
274 #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
275 #define IPMI_BMC_WATCHDOG_ACTION_NONE 0
276 #define IPMI_BMC_WATCHDOG_ACTION_RESET 1
277 #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
278 #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
280 struct RspBuffer {
281 uint8_t buffer[MAX_IPMI_MSG_SIZE];
282 unsigned int len;
285 #define RSP_BUFFER_INITIALIZER { }
287 static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
289 rsp->buffer[2] = byte;
292 /* Add a byte to the response. */
293 static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
295 if (rsp->len >= sizeof(rsp->buffer)) {
296 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
297 return;
299 rsp->buffer[rsp->len++] = byte;
302 static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
303 unsigned int n)
305 if (rsp->len + n >= sizeof(rsp->buffer)) {
306 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
307 return;
310 memcpy(&rsp->buffer[rsp->len], bytes, n);
311 rsp->len += n;
314 static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
316 static void ipmi_gettime(struct ipmi_time *time)
318 int64_t stime;
320 stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
321 time->tv_sec = stime / 1000000000LL;
322 time->tv_nsec = stime % 1000000000LL;
325 static int64_t ipmi_getmonotime(void)
327 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
330 static void ipmi_timeout(void *opaque)
332 IPMIBmcSim *ibs = opaque;
334 ipmi_sim_handle_timeout(ibs);
337 static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
339 unsigned int val;
340 struct ipmi_time now;
342 ipmi_gettime(&now);
343 val = now.tv_sec + ibs->sel.time_offset;
344 ts[0] = val & 0xff;
345 ts[1] = (val >> 8) & 0xff;
346 ts[2] = (val >> 16) & 0xff;
347 ts[3] = (val >> 24) & 0xff;
350 static void sdr_inc_reservation(IPMISdr *sdr)
352 sdr->reservation++;
353 if (sdr->reservation == 0) {
354 sdr->reservation = 1;
358 static int sdr_add_entry(IPMIBmcSim *ibs,
359 const struct ipmi_sdr_header *sdrh_entry,
360 unsigned int len, uint16_t *recid)
362 struct ipmi_sdr_header *sdrh =
363 (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
365 if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
366 return 1;
369 if (ipmi_sdr_length(sdrh_entry) != len) {
370 return 1;
373 if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
374 ibs->sdr.overflow = 1;
375 return 1;
378 memcpy(sdrh, sdrh_entry, len);
379 sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
380 sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
381 sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
383 if (recid) {
384 *recid = ibs->sdr.next_rec_id;
386 ibs->sdr.next_rec_id++;
387 set_timestamp(ibs, ibs->sdr.last_addition);
388 ibs->sdr.next_free += len;
389 sdr_inc_reservation(&ibs->sdr);
390 return 0;
393 static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
394 unsigned int *retpos, uint16_t *nextrec)
396 unsigned int pos = *retpos;
398 while (pos < sdr->next_free) {
399 struct ipmi_sdr_header *sdrh =
400 (struct ipmi_sdr_header *) &sdr->sdr[pos];
401 uint16_t trec = ipmi_sdr_recid(sdrh);
402 unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
404 if (trec == recid) {
405 if (nextrec) {
406 if (nextpos >= sdr->next_free) {
407 *nextrec = 0xffff;
408 } else {
409 *nextrec = (sdr->sdr[nextpos] |
410 (sdr->sdr[nextpos + 1] << 8));
413 *retpos = pos;
414 return 0;
416 pos = nextpos;
418 return 1;
421 int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
422 const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
425 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
426 unsigned int pos;
428 pos = 0;
429 if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
430 return -1;
433 *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
434 return 0;
437 static void sel_inc_reservation(IPMISel *sel)
439 sel->reservation++;
440 if (sel->reservation == 0) {
441 sel->reservation = 1;
445 /* Returns 1 if the SEL is full and can't hold the event. */
446 static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
448 uint8_t ts[4];
450 event[0] = 0xff;
451 event[1] = 0xff;
452 set_timestamp(ibs, ts);
453 if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
454 memcpy(event + 3, ts, 4);
456 if (ibs->sel.next_free == MAX_SEL_SIZE) {
457 ibs->sel.overflow = 1;
458 return 1;
460 event[0] = ibs->sel.next_free & 0xff;
461 event[1] = (ibs->sel.next_free >> 8) & 0xff;
462 memcpy(ibs->sel.last_addition, ts, 4);
463 memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
464 ibs->sel.next_free++;
465 sel_inc_reservation(&ibs->sel);
466 return 0;
469 static int attn_set(IPMIBmcSim *ibs)
471 return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
472 || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
473 || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
476 static int attn_irq_enabled(IPMIBmcSim *ibs)
478 return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
479 || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
480 IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
483 void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
485 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
486 IPMIInterface *s = ibs->parent.intf;
487 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
489 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
490 return;
493 if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
494 sel_add_event(ibs, evt);
497 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
498 goto out;
501 memcpy(ibs->evtbuf, evt, 16);
502 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
503 k->set_atn(s, 1, attn_irq_enabled(ibs));
504 out:
505 return;
507 static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
508 uint8_t evd1, uint8_t evd2, uint8_t evd3)
510 IPMIInterface *s = ibs->parent.intf;
511 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
512 uint8_t evt[16];
513 IPMISensor *sens = ibs->sensors + sens_num;
515 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
516 return;
518 if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
519 return;
522 evt[2] = 0x2; /* System event record */
523 evt[7] = ibs->parent.slave_addr;
524 evt[8] = 0;
525 evt[9] = 0x04; /* Format version */
526 evt[10] = sens->sensor_type;
527 evt[11] = sens_num;
528 evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
529 evt[13] = evd1;
530 evt[14] = evd2;
531 evt[15] = evd3;
533 if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
534 sel_add_event(ibs, evt);
537 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
538 return;
541 memcpy(ibs->evtbuf, evt, 16);
542 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
543 k->set_atn(s, 1, attn_irq_enabled(ibs));
546 static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
547 unsigned int bit, unsigned int val,
548 uint8_t evd1, uint8_t evd2, uint8_t evd3)
550 IPMISensor *sens;
551 uint16_t mask;
553 if (sensor >= MAX_SENSORS) {
554 return;
556 if (bit >= 16) {
557 return;
560 mask = (1 << bit);
561 sens = ibs->sensors + sensor;
562 if (val) {
563 sens->states |= mask & sens->states_suppt;
564 if (sens->assert_states & mask) {
565 return; /* Already asserted */
567 sens->assert_states |= mask & sens->assert_suppt;
568 if (sens->assert_enable & mask & sens->assert_states) {
569 /* Send an event on assert */
570 gen_event(ibs, sensor, 0, evd1, evd2, evd3);
572 } else {
573 sens->states &= ~(mask & sens->states_suppt);
574 if (sens->deassert_states & mask) {
575 return; /* Already deasserted */
577 sens->deassert_states |= mask & sens->deassert_suppt;
578 if (sens->deassert_enable & mask & sens->deassert_states) {
579 /* Send an event on deassert */
580 gen_event(ibs, sensor, 1, evd1, evd2, evd3);
585 static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
587 unsigned int i, pos;
588 IPMISensor *sens;
590 for (i = 0; i < MAX_SENSORS; i++) {
591 memset(s->sensors + i, 0, sizeof(*sens));
594 pos = 0;
595 for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
596 struct ipmi_sdr_compact *sdr =
597 (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
598 unsigned int len = sdr->header.rec_length;
600 if (len < 20) {
601 continue;
603 if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
604 continue; /* Not a sensor SDR we set from */
607 if (sdr->sensor_owner_number >= MAX_SENSORS) {
608 continue;
610 sens = s->sensors + sdr->sensor_owner_number;
612 IPMI_SENSOR_SET_PRESENT(sens, 1);
613 IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
614 IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
615 sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
616 sens->deassert_suppt =
617 sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
618 sens->states_suppt =
619 sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
620 sens->sensor_type = sdr->sensor_type;
621 sens->evt_reading_type_code = sdr->reading_type & 0x7f;
623 /* Enable all the events that are supported. */
624 sens->assert_enable = sens->assert_suppt;
625 sens->deassert_enable = sens->deassert_suppt;
629 static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
630 const IPMINetfn *netfnd)
632 if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
633 return -1;
635 s->netfns[netfn / 2] = netfnd;
636 return 0;
639 static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
640 unsigned int netfn,
641 unsigned int cmd)
643 const IPMICmdHandler *hdl;
645 if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
646 return NULL;
649 if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
650 return NULL;
653 hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
654 if (!hdl->cmd_handler) {
655 return NULL;
658 return hdl;
661 static void next_timeout(IPMIBmcSim *ibs)
663 int64_t next;
664 if (ibs->watchdog_running) {
665 next = ibs->watchdog_expiry;
666 } else {
667 /* Wait a minute */
668 next = ipmi_getmonotime() + 60 * 1000000000LL;
670 timer_mod_ns(ibs->timer, next);
673 static void ipmi_sim_handle_command(IPMIBmc *b,
674 uint8_t *cmd, unsigned int cmd_len,
675 unsigned int max_cmd_len,
676 uint8_t msg_id)
678 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
679 IPMIInterface *s = ibs->parent.intf;
680 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
681 const IPMICmdHandler *hdl;
682 RspBuffer rsp = RSP_BUFFER_INITIALIZER;
684 /* Set up the response, set the low bit of NETFN. */
685 /* Note that max_rsp_len must be at least 3 */
686 if (sizeof(rsp.buffer) < 3) {
687 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
688 goto out;
691 rsp_buffer_push(&rsp, cmd[0] | 0x04);
692 rsp_buffer_push(&rsp, cmd[1]);
693 rsp_buffer_push(&rsp, 0); /* Assume success */
695 /* If it's too short or it was truncated, return an error. */
696 if (cmd_len < 2) {
697 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
698 goto out;
700 if (cmd_len > max_cmd_len) {
701 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
702 goto out;
705 if ((cmd[0] & 0x03) != 0) {
706 /* Only have stuff on LUN 0 */
707 rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
708 goto out;
711 hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
712 if (!hdl) {
713 rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
714 goto out;
717 if (cmd_len < hdl->cmd_len_min) {
718 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
719 goto out;
722 hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
724 out:
725 k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
727 next_timeout(ibs);
730 static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
732 IPMIInterface *s = ibs->parent.intf;
733 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
735 if (!ibs->watchdog_running) {
736 goto out;
739 if (!ibs->watchdog_preaction_ran) {
740 switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
741 case IPMI_BMC_WATCHDOG_PRE_NMI:
742 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
743 k->do_hw_op(s, IPMI_SEND_NMI, 0);
744 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
745 0xc8, (2 << 4) | 0xf, 0xff);
746 break;
748 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
749 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
750 k->set_atn(s, 1, attn_irq_enabled(ibs));
751 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
752 0xc8, (3 << 4) | 0xf, 0xff);
753 break;
755 default:
756 goto do_full_expiry;
759 ibs->watchdog_preaction_ran = 1;
760 /* Issued the pretimeout, do the rest of the timeout now. */
761 ibs->watchdog_expiry = ipmi_getmonotime();
762 ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
763 goto out;
766 do_full_expiry:
767 ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
768 ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
769 switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
770 case IPMI_BMC_WATCHDOG_ACTION_NONE:
771 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
772 0xc0, ibs->watchdog_use & 0xf, 0xff);
773 break;
775 case IPMI_BMC_WATCHDOG_ACTION_RESET:
776 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
777 0xc1, ibs->watchdog_use & 0xf, 0xff);
778 k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
779 break;
781 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
782 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
783 0xc2, ibs->watchdog_use & 0xf, 0xff);
784 k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
785 break;
787 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
788 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
789 0xc3, ibs->watchdog_use & 0xf, 0xff);
790 k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
791 break;
794 out:
795 next_timeout(ibs);
798 static void chassis_capabilities(IPMIBmcSim *ibs,
799 uint8_t *cmd, unsigned int cmd_len,
800 RspBuffer *rsp)
802 rsp_buffer_push(rsp, 0);
803 rsp_buffer_push(rsp, ibs->parent.slave_addr);
804 rsp_buffer_push(rsp, ibs->parent.slave_addr);
805 rsp_buffer_push(rsp, ibs->parent.slave_addr);
806 rsp_buffer_push(rsp, ibs->parent.slave_addr);
809 static void chassis_status(IPMIBmcSim *ibs,
810 uint8_t *cmd, unsigned int cmd_len,
811 RspBuffer *rsp)
813 rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
814 rsp_buffer_push(rsp, 0);
815 rsp_buffer_push(rsp, 0);
816 rsp_buffer_push(rsp, 0);
819 static void chassis_control(IPMIBmcSim *ibs,
820 uint8_t *cmd, unsigned int cmd_len,
821 RspBuffer *rsp)
823 IPMIInterface *s = ibs->parent.intf;
824 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
826 switch (cmd[2] & 0xf) {
827 case 0: /* power down */
828 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
829 break;
830 case 1: /* power up */
831 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
832 break;
833 case 2: /* power cycle */
834 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
835 break;
836 case 3: /* hard reset */
837 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
838 break;
839 case 4: /* pulse diagnostic interrupt */
840 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
841 break;
842 case 5: /* soft shutdown via ACPI by overtemp emulation */
843 rsp_buffer_set_error(rsp, k->do_hw_op(s,
844 IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
845 break;
846 default:
847 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
848 return;
852 static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
853 uint8_t *cmd, unsigned int cmd_len,
854 RspBuffer *rsp)
857 rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
858 rsp_buffer_push(rsp, 0); /* Channel 0 */
861 static void get_device_id(IPMIBmcSim *ibs,
862 uint8_t *cmd, unsigned int cmd_len,
863 RspBuffer *rsp)
865 rsp_buffer_push(rsp, ibs->device_id);
866 rsp_buffer_push(rsp, ibs->device_rev & 0xf);
867 rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
868 rsp_buffer_push(rsp, ibs->fwrev2);
869 rsp_buffer_push(rsp, ibs->ipmi_version);
870 rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
871 rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
872 rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
873 rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
874 rsp_buffer_push(rsp, ibs->product_id & 0xff);
875 rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
878 static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
880 IPMIInterface *s = ibs->parent.intf;
881 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
882 bool irqs_on;
884 ibs->bmc_global_enables = val;
886 irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
887 IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
889 k->set_irq_enable(s, irqs_on);
892 static void cold_reset(IPMIBmcSim *ibs,
893 uint8_t *cmd, unsigned int cmd_len,
894 RspBuffer *rsp)
896 IPMIInterface *s = ibs->parent.intf;
897 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
899 /* Disable all interrupts */
900 set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
902 if (k->reset) {
903 k->reset(s, true);
907 static void warm_reset(IPMIBmcSim *ibs,
908 uint8_t *cmd, unsigned int cmd_len,
909 RspBuffer *rsp)
911 IPMIInterface *s = ibs->parent.intf;
912 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
914 if (k->reset) {
915 k->reset(s, false);
918 static void set_acpi_power_state(IPMIBmcSim *ibs,
919 uint8_t *cmd, unsigned int cmd_len,
920 RspBuffer *rsp)
922 ibs->acpi_power_state[0] = cmd[2];
923 ibs->acpi_power_state[1] = cmd[3];
926 static void get_acpi_power_state(IPMIBmcSim *ibs,
927 uint8_t *cmd, unsigned int cmd_len,
928 RspBuffer *rsp)
930 rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
931 rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
934 static void get_device_guid(IPMIBmcSim *ibs,
935 uint8_t *cmd, unsigned int cmd_len,
936 RspBuffer *rsp)
938 unsigned int i;
940 for (i = 0; i < 16; i++) {
941 rsp_buffer_push(rsp, ibs->uuid[i]);
945 static void set_bmc_global_enables(IPMIBmcSim *ibs,
946 uint8_t *cmd, unsigned int cmd_len,
947 RspBuffer *rsp)
949 set_global_enables(ibs, cmd[2]);
952 static void get_bmc_global_enables(IPMIBmcSim *ibs,
953 uint8_t *cmd, unsigned int cmd_len,
954 RspBuffer *rsp)
956 rsp_buffer_push(rsp, ibs->bmc_global_enables);
959 static void clr_msg_flags(IPMIBmcSim *ibs,
960 uint8_t *cmd, unsigned int cmd_len,
961 RspBuffer *rsp)
963 IPMIInterface *s = ibs->parent.intf;
964 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
966 ibs->msg_flags &= ~cmd[2];
967 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
970 static void get_msg_flags(IPMIBmcSim *ibs,
971 uint8_t *cmd, unsigned int cmd_len,
972 RspBuffer *rsp)
974 rsp_buffer_push(rsp, ibs->msg_flags);
977 static void read_evt_msg_buf(IPMIBmcSim *ibs,
978 uint8_t *cmd, unsigned int cmd_len,
979 RspBuffer *rsp)
981 IPMIInterface *s = ibs->parent.intf;
982 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
983 unsigned int i;
985 if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
986 rsp_buffer_set_error(rsp, 0x80);
987 return;
989 for (i = 0; i < 16; i++) {
990 rsp_buffer_push(rsp, ibs->evtbuf[i]);
992 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
993 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
996 static void get_msg(IPMIBmcSim *ibs,
997 uint8_t *cmd, unsigned int cmd_len,
998 RspBuffer *rsp)
1000 IPMIRcvBufEntry *msg;
1002 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
1003 rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
1004 goto out;
1006 rsp_buffer_push(rsp, 0); /* Channel 0 */
1007 msg = QTAILQ_FIRST(&ibs->rcvbufs);
1008 rsp_buffer_pushmore(rsp, msg->buf, msg->len);
1009 QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
1010 g_free(msg);
1012 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
1013 IPMIInterface *s = ibs->parent.intf;
1014 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1016 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1017 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
1020 out:
1021 return;
1024 static unsigned char
1025 ipmb_checksum(unsigned char *data, int size, unsigned char csum)
1027 for (; size > 0; size--, data++) {
1028 csum += *data;
1031 return -csum;
1034 static void send_msg(IPMIBmcSim *ibs,
1035 uint8_t *cmd, unsigned int cmd_len,
1036 RspBuffer *rsp)
1038 IPMIInterface *s = ibs->parent.intf;
1039 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1040 IPMIRcvBufEntry *msg;
1041 uint8_t *buf;
1042 uint8_t netfn, rqLun, rsLun, rqSeq;
1044 if (cmd[2] != 0) {
1045 /* We only handle channel 0 with no options */
1046 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1047 return;
1050 if (cmd_len < 10) {
1051 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
1052 return;
1055 if (cmd[3] != 0x40) {
1056 /* We only emulate a MC at address 0x40. */
1057 rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1058 return;
1061 cmd += 3; /* Skip the header. */
1062 cmd_len -= 3;
1065 * At this point we "send" the message successfully. Any error will
1066 * be returned in the response.
1068 if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
1069 cmd[3] != 0x20) { /* Improper response address */
1070 return; /* No response */
1073 netfn = cmd[1] >> 2;
1074 rqLun = cmd[4] & 0x3;
1075 rsLun = cmd[1] & 0x3;
1076 rqSeq = cmd[4] >> 2;
1078 if (rqLun != 2) {
1079 /* We only support LUN 2 coming back to us. */
1080 return;
1083 msg = g_malloc(sizeof(*msg));
1084 msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
1085 msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
1086 msg->buf[2] = cmd[0]; /* rsSA */
1087 msg->buf[3] = (rqSeq << 2) | rsLun;
1088 msg->buf[4] = cmd[5]; /* Cmd */
1089 msg->buf[5] = 0; /* Completion Code */
1090 msg->len = 6;
1092 if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
1093 /* Not a command we handle. */
1094 msg->buf[5] = IPMI_CC_INVALID_CMD;
1095 goto end_msg;
1098 buf = msg->buf + msg->len; /* After the CC */
1099 buf[0] = 0;
1100 buf[1] = 0;
1101 buf[2] = 0;
1102 buf[3] = 0;
1103 buf[4] = 0x51;
1104 buf[5] = 0;
1105 buf[6] = 0;
1106 buf[7] = 0;
1107 buf[8] = 0;
1108 buf[9] = 0;
1109 buf[10] = 0;
1110 msg->len += 11;
1112 end_msg:
1113 msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1114 msg->len++;
1115 QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1116 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1117 k->set_atn(s, 1, attn_irq_enabled(ibs));
1120 static void do_watchdog_reset(IPMIBmcSim *ibs)
1122 if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1123 IPMI_BMC_WATCHDOG_ACTION_NONE) {
1124 ibs->watchdog_running = 0;
1125 return;
1127 ibs->watchdog_preaction_ran = 0;
1130 /* Timeout is in tenths of a second, offset is in seconds */
1131 ibs->watchdog_expiry = ipmi_getmonotime();
1132 ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1133 if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1134 ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1136 ibs->watchdog_running = 1;
1139 static void reset_watchdog_timer(IPMIBmcSim *ibs,
1140 uint8_t *cmd, unsigned int cmd_len,
1141 RspBuffer *rsp)
1143 if (!ibs->watchdog_initialized) {
1144 rsp_buffer_set_error(rsp, 0x80);
1145 return;
1147 do_watchdog_reset(ibs);
1150 static void set_watchdog_timer(IPMIBmcSim *ibs,
1151 uint8_t *cmd, unsigned int cmd_len,
1152 RspBuffer *rsp)
1154 IPMIInterface *s = ibs->parent.intf;
1155 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1156 unsigned int val;
1158 val = cmd[2] & 0x7; /* Validate use */
1159 if (val == 0 || val > 5) {
1160 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1161 return;
1163 val = cmd[3] & 0x7; /* Validate action */
1164 switch (val) {
1165 case IPMI_BMC_WATCHDOG_ACTION_NONE:
1166 break;
1168 case IPMI_BMC_WATCHDOG_ACTION_RESET:
1169 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
1170 break;
1172 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
1173 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
1174 break;
1176 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
1177 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
1178 break;
1180 default:
1181 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1183 if (rsp->buffer[2]) {
1184 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1185 return;
1188 val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1189 switch (val) {
1190 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1191 case IPMI_BMC_WATCHDOG_PRE_NONE:
1192 break;
1194 case IPMI_BMC_WATCHDOG_PRE_NMI:
1195 if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
1196 /* NMI not supported. */
1197 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1198 return;
1200 break;
1202 default:
1203 /* We don't support PRE_SMI */
1204 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1205 return;
1208 ibs->watchdog_initialized = 1;
1209 ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1210 ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1211 ibs->watchdog_pretimeout = cmd[4];
1212 ibs->watchdog_expired &= ~cmd[5];
1213 ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1214 if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1215 do_watchdog_reset(ibs);
1216 } else {
1217 ibs->watchdog_running = 0;
1221 static void get_watchdog_timer(IPMIBmcSim *ibs,
1222 uint8_t *cmd, unsigned int cmd_len,
1223 RspBuffer *rsp)
1225 rsp_buffer_push(rsp, ibs->watchdog_use);
1226 rsp_buffer_push(rsp, ibs->watchdog_action);
1227 rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1228 rsp_buffer_push(rsp, ibs->watchdog_expired);
1229 if (ibs->watchdog_running) {
1230 long timeout;
1231 timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1232 / 100000000);
1233 rsp_buffer_push(rsp, timeout & 0xff);
1234 rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
1235 } else {
1236 rsp_buffer_push(rsp, 0);
1237 rsp_buffer_push(rsp, 0);
1241 static void get_sdr_rep_info(IPMIBmcSim *ibs,
1242 uint8_t *cmd, unsigned int cmd_len,
1243 RspBuffer *rsp)
1245 unsigned int i;
1247 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1248 rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1249 rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1250 rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1251 rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
1252 for (i = 0; i < 4; i++) {
1253 rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
1255 for (i = 0; i < 4; i++) {
1256 rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
1258 /* Only modal support, reserve supported */
1259 rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
1262 static void reserve_sdr_rep(IPMIBmcSim *ibs,
1263 uint8_t *cmd, unsigned int cmd_len,
1264 RspBuffer *rsp)
1266 rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1267 rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
1270 static void get_sdr(IPMIBmcSim *ibs,
1271 uint8_t *cmd, unsigned int cmd_len,
1272 RspBuffer *rsp)
1274 unsigned int pos;
1275 uint16_t nextrec;
1276 struct ipmi_sdr_header *sdrh;
1278 if (cmd[6]) {
1279 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1280 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1281 return;
1285 pos = 0;
1286 if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1287 &pos, &nextrec)) {
1288 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1289 return;
1292 sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1294 if (cmd[6] > ipmi_sdr_length(sdrh)) {
1295 rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1296 return;
1299 rsp_buffer_push(rsp, nextrec & 0xff);
1300 rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
1302 if (cmd[7] == 0xff) {
1303 cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
1306 if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
1307 rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1308 return;
1311 rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
1314 static void add_sdr(IPMIBmcSim *ibs,
1315 uint8_t *cmd, unsigned int cmd_len,
1316 RspBuffer *rsp)
1318 uint16_t recid;
1319 struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
1321 if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
1322 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1323 return;
1325 rsp_buffer_push(rsp, recid & 0xff);
1326 rsp_buffer_push(rsp, (recid >> 8) & 0xff);
1329 static void clear_sdr_rep(IPMIBmcSim *ibs,
1330 uint8_t *cmd, unsigned int cmd_len,
1331 RspBuffer *rsp)
1333 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1334 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1335 return;
1338 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1339 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1340 return;
1342 if (cmd[7] == 0xaa) {
1343 ibs->sdr.next_free = 0;
1344 ibs->sdr.overflow = 0;
1345 set_timestamp(ibs, ibs->sdr.last_clear);
1346 rsp_buffer_push(rsp, 1); /* Erasure complete */
1347 sdr_inc_reservation(&ibs->sdr);
1348 } else if (cmd[7] == 0) {
1349 rsp_buffer_push(rsp, 1); /* Erasure complete */
1350 } else {
1351 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1352 return;
1356 static void get_sel_info(IPMIBmcSim *ibs,
1357 uint8_t *cmd, unsigned int cmd_len,
1358 RspBuffer *rsp)
1360 unsigned int i, val;
1362 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1363 rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1364 rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
1365 val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1366 rsp_buffer_push(rsp, val & 0xff);
1367 rsp_buffer_push(rsp, (val >> 8) & 0xff);
1368 for (i = 0; i < 4; i++) {
1369 rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
1371 for (i = 0; i < 4; i++) {
1372 rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
1374 /* Only support Reserve SEL */
1375 rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
1378 static void get_fru_area_info(IPMIBmcSim *ibs,
1379 uint8_t *cmd, unsigned int cmd_len,
1380 RspBuffer *rsp)
1382 uint8_t fruid;
1383 uint16_t fru_entry_size;
1385 fruid = cmd[2];
1387 if (fruid >= ibs->fru.nentries) {
1388 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1389 return;
1392 fru_entry_size = ibs->fru.areasize;
1394 rsp_buffer_push(rsp, fru_entry_size & 0xff);
1395 rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1396 rsp_buffer_push(rsp, 0x0);
1399 static void read_fru_data(IPMIBmcSim *ibs,
1400 uint8_t *cmd, unsigned int cmd_len,
1401 RspBuffer *rsp)
1403 uint8_t fruid;
1404 uint16_t offset;
1405 int i;
1406 uint8_t *fru_entry;
1407 unsigned int count;
1409 fruid = cmd[2];
1410 offset = (cmd[3] | cmd[4] << 8);
1412 if (fruid >= ibs->fru.nentries) {
1413 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1414 return;
1417 if (offset >= ibs->fru.areasize - 1) {
1418 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1419 return;
1422 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1424 count = MIN(cmd[5], ibs->fru.areasize - offset);
1426 rsp_buffer_push(rsp, count & 0xff);
1427 for (i = 0; i < count; i++) {
1428 rsp_buffer_push(rsp, fru_entry[offset + i]);
1432 static void write_fru_data(IPMIBmcSim *ibs,
1433 uint8_t *cmd, unsigned int cmd_len,
1434 RspBuffer *rsp)
1436 uint8_t fruid;
1437 uint16_t offset;
1438 uint8_t *fru_entry;
1439 unsigned int count;
1441 fruid = cmd[2];
1442 offset = (cmd[3] | cmd[4] << 8);
1444 if (fruid >= ibs->fru.nentries) {
1445 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1446 return;
1449 if (offset >= ibs->fru.areasize - 1) {
1450 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1451 return;
1454 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1456 count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1458 memcpy(fru_entry + offset, cmd + 5, count);
1460 rsp_buffer_push(rsp, count & 0xff);
1463 static void reserve_sel(IPMIBmcSim *ibs,
1464 uint8_t *cmd, unsigned int cmd_len,
1465 RspBuffer *rsp)
1467 rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1468 rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
1471 static void get_sel_entry(IPMIBmcSim *ibs,
1472 uint8_t *cmd, unsigned int cmd_len,
1473 RspBuffer *rsp)
1475 unsigned int val;
1477 if (cmd[6]) {
1478 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1479 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1480 return;
1483 if (ibs->sel.next_free == 0) {
1484 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1485 return;
1487 if (cmd[6] > 15) {
1488 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1489 return;
1491 if (cmd[7] == 0xff) {
1492 cmd[7] = 16;
1493 } else if ((cmd[7] + cmd[6]) > 16) {
1494 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1495 return;
1496 } else {
1497 cmd[7] += cmd[6];
1500 val = cmd[4] | (cmd[5] << 8);
1501 if (val == 0xffff) {
1502 val = ibs->sel.next_free - 1;
1503 } else if (val >= ibs->sel.next_free) {
1504 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1505 return;
1507 if ((val + 1) == ibs->sel.next_free) {
1508 rsp_buffer_push(rsp, 0xff);
1509 rsp_buffer_push(rsp, 0xff);
1510 } else {
1511 rsp_buffer_push(rsp, (val + 1) & 0xff);
1512 rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
1514 for (; cmd[6] < cmd[7]; cmd[6]++) {
1515 rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
1519 static void add_sel_entry(IPMIBmcSim *ibs,
1520 uint8_t *cmd, unsigned int cmd_len,
1521 RspBuffer *rsp)
1523 if (sel_add_event(ibs, cmd + 2)) {
1524 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1525 return;
1527 /* sel_add_event fills in the record number. */
1528 rsp_buffer_push(rsp, cmd[2]);
1529 rsp_buffer_push(rsp, cmd[3]);
1532 static void clear_sel(IPMIBmcSim *ibs,
1533 uint8_t *cmd, unsigned int cmd_len,
1534 RspBuffer *rsp)
1536 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1537 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
1538 return;
1541 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1542 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1543 return;
1545 if (cmd[7] == 0xaa) {
1546 ibs->sel.next_free = 0;
1547 ibs->sel.overflow = 0;
1548 set_timestamp(ibs, ibs->sdr.last_clear);
1549 rsp_buffer_push(rsp, 1); /* Erasure complete */
1550 sel_inc_reservation(&ibs->sel);
1551 } else if (cmd[7] == 0) {
1552 rsp_buffer_push(rsp, 1); /* Erasure complete */
1553 } else {
1554 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1555 return;
1559 static void get_sel_time(IPMIBmcSim *ibs,
1560 uint8_t *cmd, unsigned int cmd_len,
1561 RspBuffer *rsp)
1563 uint32_t val;
1564 struct ipmi_time now;
1566 ipmi_gettime(&now);
1567 val = now.tv_sec + ibs->sel.time_offset;
1568 rsp_buffer_push(rsp, val & 0xff);
1569 rsp_buffer_push(rsp, (val >> 8) & 0xff);
1570 rsp_buffer_push(rsp, (val >> 16) & 0xff);
1571 rsp_buffer_push(rsp, (val >> 24) & 0xff);
1574 static void set_sel_time(IPMIBmcSim *ibs,
1575 uint8_t *cmd, unsigned int cmd_len,
1576 RspBuffer *rsp)
1578 uint32_t val;
1579 struct ipmi_time now;
1581 val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1582 ipmi_gettime(&now);
1583 ibs->sel.time_offset = now.tv_sec - ((long) val);
1586 static void platform_event_msg(IPMIBmcSim *ibs,
1587 uint8_t *cmd, unsigned int cmd_len,
1588 RspBuffer *rsp)
1590 uint8_t event[16];
1592 event[2] = 2; /* System event record */
1593 event[7] = cmd[2]; /* Generator ID */
1594 event[8] = 0;
1595 event[9] = cmd[3]; /* EvMRev */
1596 event[10] = cmd[4]; /* Sensor type */
1597 event[11] = cmd[5]; /* Sensor number */
1598 event[12] = cmd[6]; /* Event dir / Event type */
1599 event[13] = cmd[7]; /* Event data 1 */
1600 event[14] = cmd[8]; /* Event data 2 */
1601 event[15] = cmd[9]; /* Event data 3 */
1603 if (sel_add_event(ibs, event)) {
1604 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1608 static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1609 uint8_t *cmd, unsigned int cmd_len,
1610 RspBuffer *rsp)
1612 IPMISensor *sens;
1614 if ((cmd[2] >= MAX_SENSORS) ||
1615 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1616 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1617 return;
1619 sens = ibs->sensors + cmd[2];
1620 switch ((cmd[3] >> 4) & 0x3) {
1621 case 0: /* Do not change */
1622 break;
1623 case 1: /* Enable bits */
1624 if (cmd_len > 4) {
1625 sens->assert_enable |= cmd[4];
1627 if (cmd_len > 5) {
1628 sens->assert_enable |= cmd[5] << 8;
1630 if (cmd_len > 6) {
1631 sens->deassert_enable |= cmd[6];
1633 if (cmd_len > 7) {
1634 sens->deassert_enable |= cmd[7] << 8;
1636 break;
1637 case 2: /* Disable bits */
1638 if (cmd_len > 4) {
1639 sens->assert_enable &= ~cmd[4];
1641 if (cmd_len > 5) {
1642 sens->assert_enable &= ~(cmd[5] << 8);
1644 if (cmd_len > 6) {
1645 sens->deassert_enable &= ~cmd[6];
1647 if (cmd_len > 7) {
1648 sens->deassert_enable &= ~(cmd[7] << 8);
1650 break;
1651 case 3:
1652 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1653 return;
1655 IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
1658 static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1659 uint8_t *cmd, unsigned int cmd_len,
1660 RspBuffer *rsp)
1662 IPMISensor *sens;
1664 if ((cmd[2] >= MAX_SENSORS) ||
1665 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1666 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1667 return;
1669 sens = ibs->sensors + cmd[2];
1670 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1671 rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1672 rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1673 rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1674 rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
1677 static void rearm_sensor_evts(IPMIBmcSim *ibs,
1678 uint8_t *cmd, unsigned int cmd_len,
1679 RspBuffer *rsp)
1681 IPMISensor *sens;
1683 if ((cmd[2] >= MAX_SENSORS) ||
1684 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1685 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1686 return;
1688 sens = ibs->sensors + cmd[2];
1690 if ((cmd[3] & 0x80) == 0) {
1691 /* Just clear everything */
1692 sens->states = 0;
1693 return;
1697 static void get_sensor_evt_status(IPMIBmcSim *ibs,
1698 uint8_t *cmd, unsigned int cmd_len,
1699 RspBuffer *rsp)
1701 IPMISensor *sens;
1703 if ((cmd[2] >= MAX_SENSORS) ||
1704 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1705 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1706 return;
1708 sens = ibs->sensors + cmd[2];
1709 rsp_buffer_push(rsp, sens->reading);
1710 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1711 rsp_buffer_push(rsp, sens->assert_states & 0xff);
1712 rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1713 rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1714 rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
1717 static void get_sensor_reading(IPMIBmcSim *ibs,
1718 uint8_t *cmd, unsigned int cmd_len,
1719 RspBuffer *rsp)
1721 IPMISensor *sens;
1723 if ((cmd[2] >= MAX_SENSORS) ||
1724 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1725 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1726 return;
1728 sens = ibs->sensors + cmd[2];
1729 rsp_buffer_push(rsp, sens->reading);
1730 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1731 rsp_buffer_push(rsp, sens->states & 0xff);
1732 if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1733 rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
1737 static void set_sensor_type(IPMIBmcSim *ibs,
1738 uint8_t *cmd, unsigned int cmd_len,
1739 RspBuffer *rsp)
1741 IPMISensor *sens;
1744 if ((cmd[2] >= MAX_SENSORS) ||
1745 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1746 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1747 return;
1749 sens = ibs->sensors + cmd[2];
1750 sens->sensor_type = cmd[3];
1751 sens->evt_reading_type_code = cmd[4] & 0x7f;
1754 static void get_sensor_type(IPMIBmcSim *ibs,
1755 uint8_t *cmd, unsigned int cmd_len,
1756 RspBuffer *rsp)
1758 IPMISensor *sens;
1761 if ((cmd[2] >= MAX_SENSORS) ||
1762 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1763 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1764 return;
1766 sens = ibs->sensors + cmd[2];
1767 rsp_buffer_push(rsp, sens->sensor_type);
1768 rsp_buffer_push(rsp, sens->evt_reading_type_code);
1772 static const IPMICmdHandler chassis_cmds[] = {
1773 [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
1774 [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
1775 [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
1776 [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
1778 static const IPMINetfn chassis_netfn = {
1779 .cmd_nums = ARRAY_SIZE(chassis_cmds),
1780 .cmd_handlers = chassis_cmds
1783 static const IPMICmdHandler sensor_event_cmds[] = {
1784 [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
1785 [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
1786 [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
1787 [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
1788 [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
1789 [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
1790 [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
1791 [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
1793 static const IPMINetfn sensor_event_netfn = {
1794 .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
1795 .cmd_handlers = sensor_event_cmds
1798 static const IPMICmdHandler app_cmds[] = {
1799 [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
1800 [IPMI_CMD_COLD_RESET] = { cold_reset },
1801 [IPMI_CMD_WARM_RESET] = { warm_reset },
1802 [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
1803 [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
1804 [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
1805 [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
1806 [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
1807 [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
1808 [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
1809 [IPMI_CMD_GET_MSG] = { get_msg },
1810 [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
1811 [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
1812 [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
1813 [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
1814 [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
1816 static const IPMINetfn app_netfn = {
1817 .cmd_nums = ARRAY_SIZE(app_cmds),
1818 .cmd_handlers = app_cmds
1821 static const IPMICmdHandler storage_cmds[] = {
1822 [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
1823 [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
1824 [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
1825 [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
1826 [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
1827 [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
1828 [IPMI_CMD_ADD_SDR] = { add_sdr },
1829 [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
1830 [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
1831 [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
1832 [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
1833 [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
1834 [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
1835 [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
1836 [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
1839 static const IPMINetfn storage_netfn = {
1840 .cmd_nums = ARRAY_SIZE(storage_cmds),
1841 .cmd_handlers = storage_cmds
1844 static void register_cmds(IPMIBmcSim *s)
1846 ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
1847 ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
1848 ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
1849 ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
1852 static uint8_t init_sdrs[] = {
1853 /* Watchdog device */
1854 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
1855 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
1856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
1858 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
1861 static void ipmi_sdr_init(IPMIBmcSim *ibs)
1863 unsigned int i;
1864 int len;
1865 size_t sdrs_size;
1866 uint8_t *sdrs;
1868 sdrs_size = sizeof(init_sdrs);
1869 sdrs = init_sdrs;
1870 if (ibs->sdr_filename &&
1871 !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
1872 NULL)) {
1873 error_report("failed to load sdr file '%s'", ibs->sdr_filename);
1874 sdrs_size = sizeof(init_sdrs);
1875 sdrs = init_sdrs;
1878 for (i = 0; i < sdrs_size; i += len) {
1879 struct ipmi_sdr_header *sdrh;
1881 if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
1882 error_report("Problem with recid 0x%4.4x", i);
1883 break;
1885 sdrh = (struct ipmi_sdr_header *) &sdrs[i];
1886 len = ipmi_sdr_length(sdrh);
1887 if (i + len > sdrs_size) {
1888 error_report("Problem with recid 0x%4.4x", i);
1889 break;
1891 sdr_add_entry(ibs, sdrh, len, NULL);
1894 if (sdrs != init_sdrs) {
1895 g_free(sdrs);
1899 static const VMStateDescription vmstate_ipmi_sim = {
1900 .name = TYPE_IPMI_BMC_SIMULATOR,
1901 .version_id = 1,
1902 .minimum_version_id = 1,
1903 .fields = (VMStateField[]) {
1904 VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1905 VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1906 VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1907 VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1908 VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1909 VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1910 VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1911 VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1912 VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1913 VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1914 VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1915 VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1916 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1917 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1918 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1919 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1920 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1921 IPMIBmcSim),
1922 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1923 VMSTATE_END_OF_LIST()
1927 static void ipmi_fru_init(IPMIFru *fru)
1929 int fsize;
1930 int size = 0;
1932 if (!fru->filename) {
1933 goto out;
1936 fsize = get_image_size(fru->filename);
1937 if (fsize > 0) {
1938 size = QEMU_ALIGN_UP(fsize, fru->areasize);
1939 fru->data = g_malloc0(size);
1940 if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
1941 error_report("Could not load file '%s'", fru->filename);
1942 g_free(fru->data);
1943 fru->data = NULL;
1947 out:
1948 if (!fru->data) {
1949 /* give one default FRU */
1950 size = fru->areasize;
1951 fru->data = g_malloc0(size);
1954 fru->nentries = size / fru->areasize;
1957 static void ipmi_sim_realize(DeviceState *dev, Error **errp)
1959 IPMIBmc *b = IPMI_BMC(dev);
1960 unsigned int i;
1961 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
1963 QTAILQ_INIT(&ibs->rcvbufs);
1965 ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
1966 ibs->device_id = 0x20;
1967 ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1968 ibs->restart_cause = 0;
1969 for (i = 0; i < 4; i++) {
1970 ibs->sel.last_addition[i] = 0xff;
1971 ibs->sel.last_clear[i] = 0xff;
1972 ibs->sdr.last_addition[i] = 0xff;
1973 ibs->sdr.last_clear[i] = 0xff;
1976 ipmi_sdr_init(ibs);
1978 ipmi_fru_init(&ibs->fru);
1980 ibs->acpi_power_state[0] = 0;
1981 ibs->acpi_power_state[1] = 0;
1983 if (qemu_uuid_set) {
1984 memcpy(&ibs->uuid, &qemu_uuid, 16);
1985 } else {
1986 memset(&ibs->uuid, 0, 16);
1989 ipmi_init_sensors_from_sdrs(ibs);
1990 register_cmds(ibs);
1992 ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1994 vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
1997 static Property ipmi_sim_properties[] = {
1998 DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
1999 DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
2000 DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
2001 DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
2002 DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
2003 DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
2004 DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
2005 DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
2006 DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
2007 DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
2008 DEFINE_PROP_END_OF_LIST(),
2011 static void ipmi_sim_class_init(ObjectClass *oc, void *data)
2013 DeviceClass *dc = DEVICE_CLASS(oc);
2014 IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
2016 dc->hotpluggable = false;
2017 dc->realize = ipmi_sim_realize;
2018 dc->props = ipmi_sim_properties;
2019 bk->handle_command = ipmi_sim_handle_command;
2022 static const TypeInfo ipmi_sim_type = {
2023 .name = TYPE_IPMI_BMC_SIMULATOR,
2024 .parent = TYPE_IPMI_BMC,
2025 .instance_size = sizeof(IPMIBmcSim),
2026 .class_init = ipmi_sim_class_init,
2029 static void ipmi_sim_register_types(void)
2031 type_register_static(&ipmi_sim_type);
2034 type_init(ipmi_sim_register_types)